Merge branch 'maint'

This commit is contained in:
Christopher Lam 2021-09-12 22:44:34 +08:00
commit 017ab06939
31 changed files with 269 additions and 262 deletions

View File

@ -1116,6 +1116,7 @@ gnc_scm2query_and_terms (SCM and_terms, query_version_t vers)
if (q_and)
{
q_new = qof_query_merge (q, q_and, QOF_QUERY_AND);
qof_query_destroy (q_and);
if (q_new)
{
@ -1158,6 +1159,7 @@ gnc_scm2query_or_terms (SCM or_terms, query_version_t vers)
if (q_or)
{
q_new = qof_query_merge (q, q_or, QOF_QUERY_OR);
qof_query_destroy (q_or);
if (q_new)
{

View File

@ -2,6 +2,7 @@ from unittest import main
from gnucash import Transaction, Book, Account, Split
from unittest_support import *
from datetime import datetime, timezone
from test_book import BookSession
@ -138,5 +139,12 @@ class TestTransaction(TransactionSession):
self.trans.SetNotes(NOTE)
self.assertEqual( NOTE, self.trans.GetNotes() )
def test_date(self):
ZERODATE=datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
DATE=datetime(2020, 2, 20, 10, 59, 0, tzinfo=timezone.utc)
self.assertEqual(ZERODATE, self.trans.GetDate().astimezone(timezone.utc))
self.trans.SetDate(DATE.day, DATE.month, DATE.year)
self.assertEqual(DATE, self.trans.GetDate().astimezone(timezone.utc))
if __name__ == '__main__':
main()

View File

@ -372,6 +372,7 @@ sort_by_xxx_value (xaccGetBalanceInCurrencyFn fn,
gpointer user_data)
{
const Account *account_a, *account_b;
const gnc_commodity *cur = gnc_default_currency();
gnc_numeric balance_a, balance_b;
gint result;
@ -379,8 +380,8 @@ sort_by_xxx_value (xaccGetBalanceInCurrencyFn fn,
sort_cb_setup (f_model, f_iter_a, f_iter_b, &account_a, &account_b);
/* Get balances */
balance_a = gnc_ui_account_get_balance_full(fn, account_a, recurse, NULL, NULL);
balance_b = gnc_ui_account_get_balance_full(fn, account_b, recurse, NULL, NULL);
balance_a = gnc_ui_account_get_balance_full(fn, account_a, recurse, NULL, cur);
balance_b = gnc_ui_account_get_balance_full(fn, account_b, recurse, NULL, cur);
result = gnc_numeric_compare(balance_a, balance_b);
if (result != 0)

View File

@ -930,6 +930,8 @@ gnc_customer_search (GtkWindow *parent, GncCustomer *start, QofBook *book)
/* Build the column list in reverse order */
if (columns == NULL)
{
columns = gnc_search_param_prepend (columns, _("Shipping Contact"), NULL, type,
CUSTOMER_SHIPADDR, ADDRESS_NAME, NULL);
columns = gnc_search_param_prepend (columns, _("Contact"), NULL, type,
CUSTOMER_ADDR, ADDRESS_NAME, NULL);
columns = gnc_search_param_prepend (columns, _("Company"), NULL, type,

View File

@ -136,10 +136,10 @@ gnc_report_system_file_stream_cb (const char *location, char ** data, int *len)
static gboolean
gnc_report_system_report_stream_cb (const char *location, char ** data, int *len)
{
gboolean ok;
gchar *captured_str;
ok = gnc_run_report_id_string_with_error_handling (location, data, &captured_str);
gchar *captured_str = NULL;
gboolean ok =
gnc_run_report_id_string_with_error_handling (location, data,
&captured_str);
if (!ok)
{

View File

@ -2120,6 +2120,9 @@ recn_destroy_cb (GtkWidget *w, gpointer data)
if (recnData->delete_refresh)
gnc_resume_gui_refresh ();
//Disable the actions, the handlers try to access recnData
gtk_action_group_set_sensitive(recnData->action_group, FALSE);
g_free (recnData);
}

View File

@ -30,6 +30,7 @@
#endif
#include "gnucash-commands.hpp"
#include "gnucash-core-app.hpp"
extern "C" {
#include <gnc-engine-guile.h>
@ -173,8 +174,7 @@ scm_run_report (void *data,
scm_c_use_module ("gnucash reports");
gnc_report_init ();
// load_system_config();
// load_user_config();
Gnucash::gnc_load_scm_config();
gnc_prefs_init ();
qof_event_suspend ();
@ -303,6 +303,7 @@ scm_report_show (void *data,
scm_c_use_module ("gnucash app-utils");
scm_c_use_module ("gnucash reports");
gnc_report_init ();
Gnucash::gnc_load_scm_config();
if (!args->file_to_load.empty())
{
@ -334,6 +335,7 @@ scm_report_list ([[maybe_unused]] void *data,
scm_c_use_module ("gnucash app-utils");
scm_c_use_module ("gnucash reports");
gnc_report_init ();
Gnucash::gnc_load_scm_config();
scm_call_1 (scm_c_eval_string ("gnc:cmdline-report-list"),
scm_current_output_port ());

View File

@ -40,5 +40,9 @@ namespace Gnucash {
int report_list (void);
int report_show (const bo_str& file_to_load,
const bo_str& run_report);
// A helper function to load scm config files (SYSCONFIGDIR/config
// and USERCONFIGDIR/config-user.scm) on demand
void gnc_load_scm_config(void);
}
#endif

View File

@ -86,25 +86,6 @@ gnc_print_unstable_message(void)
<< bl::format (bl::translate ("To find the last stable version, please refer to {1}")) % PACKAGE_URL << "\n";
}
static gboolean
try_load_config_array(const gchar *fns[])
{
gchar *filename;
int i;
for (i = 0; fns[i]; i++)
{
filename = gnc_build_userdata_path(fns[i]);
if (gfec_try_load(filename))
{
g_free(filename);
return TRUE;
}
g_free(filename);
}
return FALSE;
}
static void
update_message(const gchar *msg)
{
@ -112,52 +93,30 @@ update_message(const gchar *msg)
g_message("%s", msg);
}
static void
load_system_config(void)
void
Gnucash::gnc_load_scm_config (void)
{
static int is_system_config_loaded = FALSE;
gchar *system_config_dir;
gchar *system_config;
if (is_system_config_loaded) return;
update_message("loading system configuration");
system_config_dir = gnc_path_get_pkgsysconfdir();
system_config = g_build_filename(system_config_dir, "config", nullptr);
is_system_config_loaded = gfec_try_load(system_config);
g_free(system_config_dir);
g_free(system_config);
}
static void
load_user_config(void)
{
/* Don't continue adding to this list. When 3.0 rolls around bump
the 2.4 files off the list. */
static const gchar *saved_report_files[] =
static auto is_system_config_loaded = false;
if (!is_system_config_loaded)
{
SAVED_REPORTS_FILE, SAVED_REPORTS_FILE_OLD_REV, NULL
};
static const gchar *stylesheet_files[] = { "stylesheets-2.0", NULL};
static int is_user_config_loaded = FALSE;
if (is_user_config_loaded)
return;
else is_user_config_loaded = TRUE;
update_message("loading user configuration");
{
gchar *config_filename;
config_filename = g_build_filename (gnc_userconfig_dir (),
"config-user.scm", (char *)NULL);
gfec_try_load(config_filename);
g_free(config_filename);
auto msg = bl::translate ("Loading system scm configuration...").str (gnc_get_boost_locale());
update_message (msg.c_str());
auto system_config_dir = gnc_path_get_pkgsysconfdir ();
auto system_config = g_build_filename (system_config_dir, "config", nullptr);
is_system_config_loaded = gfec_try_load (system_config);
g_free (system_config_dir);
g_free (system_config);
}
update_message("loading saved reports");
try_load_config_array(saved_report_files);
update_message("loading stylesheets");
try_load_config_array(stylesheet_files);
static auto is_user_config_loaded = false;
if (!is_user_config_loaded)
{
auto msg = bl::translate ("Loading user scm configuration...").str (gnc_get_boost_locale());
update_message (msg.c_str());
auto config_filename = g_build_filename (gnc_userconfig_dir (), "config-user.scm", nullptr);
is_user_config_loaded = gfec_try_load (config_filename);
g_free (config_filename);
}
}
static void

View File

@ -70,5 +70,6 @@ private:
char *sys_locale = nullptr;
};
void gnc_load_scm_config(void);
}
#endif

View File

@ -73,56 +73,6 @@ namespace bl = boost::locale;
static QofLogModule log_module = GNC_MOD_GUI;
static gchar *userdata_migration_msg = NULL;
static void
update_message(const gchar *msg)
{
gnc_update_splash_screen(msg, GNC_SPLASH_PERCENTAGE_UNKNOWN);
g_message("%s", msg);
}
static void
load_system_config(void)
{
static int is_system_config_loaded = FALSE;
gchar *system_config_dir;
gchar *system_config;
if (is_system_config_loaded) return;
update_message("loading system configuration");
system_config_dir = gnc_path_get_pkgsysconfdir();
system_config = g_build_filename(system_config_dir, "config", nullptr);
is_system_config_loaded = gfec_try_load(system_config);
g_free(system_config_dir);
g_free(system_config);
}
static void
load_user_config(void)
{
/* Don't continue adding to this list. When 3.0 rolls around bump
the 2.4 files off the list. */
static const gchar *saved_report_files[] =
{
SAVED_REPORTS_FILE, SAVED_REPORTS_FILE_OLD_REV, NULL
};
static const gchar *stylesheet_files[] = { "stylesheets-2.0", NULL};
static int is_user_config_loaded = FALSE;
if (is_user_config_loaded)
return;
else is_user_config_loaded = TRUE;
update_message("loading user configuration");
{
gchar *config_filename;
config_filename = g_build_filename (gnc_userconfig_dir (),
"config-user.scm", (char *)NULL);
gfec_try_load(config_filename);
g_free(config_filename);
}
}
static void
load_gnucash_plugins()
{
@ -207,11 +157,10 @@ scm_run_gnucash (void *data, [[maybe_unused]] int argc, [[maybe_unused]] char **
load_gnucash_plugins();
load_gnucash_modules();
/* Load the config before starting up the gui. This insures that
/* Load the scm config files before starting up the gui. This ensures that
* custom reports have been read into memory before the Reports
* menu is created. */
load_system_config();
load_user_config();
Gnucash::gnc_load_scm_config();
/* Setting-up the report menu must come after the module
loading but before the gui initializat*ion. */

View File

@ -721,11 +721,11 @@
</child>
<child>
<object class="GtkCheckButton" id="pref/dialogs.sxs.since-last-run/review-transactions">
<property name="label" translatable="yes">Set 'Re_view Created Transactions' as default</property>
<property name="label" translatable="yes">Re_view created transactions</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Set 'Review Created Transactions' as the default in the 'Since Last Run' dialog.</property>
<property name="tooltip_text" translatable="yes">Set 'Review created transactions' as the default in the "since last run" dialog.</property>
<property name="halign">start</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>

View File

@ -1048,6 +1048,93 @@ gnc_import_process_trans_item (GncImportMatchMap *matchmap,
return FALSE;
}
/********************************************************************\
* check_trans_online_id() Callback function used by
* gnc_import_exists_online_id. Takes pointers to transaction and split,
* returns 0 if their online_ids do NOT match, or if the split
* belongs to the transaction
\********************************************************************/
static gint check_trans_online_id(Transaction *trans1, void *user_data)
{
Account *account;
Split *split1;
Split *split2 = user_data;
const gchar *online_id1;
const gchar *online_id2;
account = xaccSplitGetAccount(split2);
split1 = xaccTransFindSplitByAccount(trans1, account);
if (split1 == split2)
return 0;
/* hack - we really want to iterate over the _splits_ of the account
instead of the transactions */
g_assert(split1 != NULL);
if (gnc_import_split_has_online_id(split1))
online_id1 = gnc_import_get_split_online_id(split1);
else
online_id1 = gnc_import_get_trans_online_id(trans1);
online_id2 = gnc_import_get_split_online_id(split2);
if ((online_id1 == NULL) ||
(online_id2 == NULL) ||
(strcmp(online_id1, online_id2) != 0))
{
return 0;
}
else
{
/*printf("test_trans_online_id(): Duplicate found\n");*/
return 1;
}
}
/** Checks whether the given transaction's online_id already exists in
its parent account. */
gboolean gnc_import_exists_online_id (Transaction *trans, GHashTable* acct_id_hash)
{
gboolean online_id_exists = FALSE;
Account *dest_acct;
Split *source_split;
/* Look for an online_id in the first split */
source_split = xaccTransGetSplit(trans, 0);
g_assert(source_split);
// No online id, no point in continuing. We'd crash if we tried.
if (!gnc_import_get_split_online_id (source_split))
return FALSE;
// Create a hash per account of a hash of all split IDs. Then the test below will be fast if
// we have many transactions to import.
dest_acct = xaccSplitGetAccount (source_split);
if (!g_hash_table_contains (acct_id_hash, dest_acct))
{
GHashTable* new_hash = g_hash_table_new (g_str_hash, g_str_equal);
GList* split_list = xaccAccountGetSplitList(dest_acct);
g_hash_table_insert (acct_id_hash, dest_acct, new_hash);
for (;split_list;split_list=split_list->next)
{
if (gnc_import_split_has_online_id (split_list->data))
g_hash_table_add (new_hash, (void*) gnc_import_get_split_online_id (split_list->data));
}
}
online_id_exists = g_hash_table_contains (g_hash_table_lookup (acct_id_hash, dest_acct),
gnc_import_get_split_online_id (source_split));
/* If it does, abort the process for this transaction, since it is
already in the system. */
if (online_id_exists == TRUE)
{
DEBUG("%s", "Transaction with same online ID exists, destroying current transaction");
xaccTransDestroy(trans);
xaccTransCommitEdit(trans);
}
return online_id_exists;
}
/* ******************************************************************
*/

View File

@ -57,6 +57,15 @@ typedef enum _action
/** @name Non-GUI Functions */
/*@{*/
/** Checks whether the given transaction's online_id already exists in
* its parent account. The given transaction has to be open for
* editing. If a matching online_id exists, the transaction is
* destroyed (!) and TRUE is returned, otherwise FALSE is returned.
*
* @param trans The transaction for which to check for an existing
* online_id. */
gboolean gnc_import_exists_online_id (Transaction *trans, GHashTable* acct_id_hash);
/** Evaluates the match between trans_info and split using the provided parameters.
*
* @param trans_info The TransInfo for the imported transaction

View File

@ -76,6 +76,7 @@ struct _main_matcher_info
gboolean add_toggled; // flag to indicate that add has been toggled to stop selection
gint id;
GSList* temp_trans_list; // Temporary list of imported transactions
GHashTable* acct_id_hash; // Hash table, per account, of list of transaction IDs.
GSList* edited_accounts; // List of accounts currently edited.
};
@ -143,6 +144,14 @@ static gboolean query_tooltip_tree_view_cb (GtkWidget *widget, gint x, gint y,
gpointer user_data);
/* end local prototypes */
static
gboolean delete_hash (gpointer key, gpointer value, gpointer user_data)
{
// Value is a hash table that needs to be destroyed.
g_hash_table_destroy (value);
return TRUE;
}
static void
update_all_balances (GNCImportMainMatcher *info)
{
@ -209,6 +218,8 @@ gnc_gen_trans_list_delete (GNCImportMainMatcher *info)
// We've deferred balance computations on many accounts. Let's do it now that we're done.
update_all_balances (info);
g_hash_table_foreach_remove (info->acct_id_hash, delete_hash, NULL);
info->acct_id_hash = NULL;
g_free (info);
}
@ -1133,6 +1144,8 @@ gnc_gen_trans_init_view (GNCImportMainMatcher *info,
G_CALLBACK(gnc_gen_trans_onButtonPressed_cb), info);
g_signal_connect (view, "popup-menu",
G_CALLBACK(gnc_gen_trans_onPopupMenu_cb), info);
info->acct_id_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
}
static void
@ -1713,11 +1726,16 @@ gnc_gen_trans_list_add_trans_with_ref_id (GNCImportMainMatcher *gui, Transaction
g_assert (gui);
g_assert (trans);
transaction_info = gnc_import_TransInfo_new (trans, NULL);
gnc_import_TransInfo_set_ref_id (transaction_info, ref_id);
// It's much faster to gather the imported transactions into a GSList than directly into the
// treeview.
gui->temp_trans_list = g_slist_prepend (gui->temp_trans_list, transaction_info);
if (gnc_import_exists_online_id (trans, gui->acct_id_hash))
return;
else
{
transaction_info = gnc_import_TransInfo_new (trans, NULL);
gnc_import_TransInfo_set_ref_id (transaction_info, ref_id);
// It's much faster to gather the imported transactions into a GSList than directly into the
// treeview.
gui->temp_trans_list = g_slist_prepend (gui->temp_trans_list, transaction_info);
}
return;
}
@ -1781,6 +1799,8 @@ create_hash_of_potential_matches (GList *candidate_txns,
{
Account* split_account;
GSList* split_list;
if (gnc_import_split_has_online_id (candidate->data))
continue;
split_account = xaccSplitGetAccount (candidate->data);
/* g_hash_table_steal_extended would do the two calls in one shot but is
* not available until GLib 2.58.

View File

@ -57,6 +57,29 @@ void gnc_import_set_acc_online_id (Account *account, const gchar *id)
xaccAccountCommitEdit (account);
}
const gchar * gnc_import_get_trans_online_id (Transaction * transaction)
{
gchar *id = NULL;
qof_instance_get (QOF_INSTANCE (transaction), "online-id", &id, NULL);
return id;
}
/* Not actually used */
void gnc_import_set_trans_online_id (Transaction *transaction,
const gchar *id)
{
g_return_if_fail (transaction != NULL);
xaccTransBeginEdit (transaction);
qof_instance_set (QOF_INSTANCE (transaction), "online-id", id, NULL);
xaccTransCommitEdit (transaction);
}
gboolean gnc_import_trans_has_online_id(Transaction * transaction)
{
const gchar * online_id;
online_id = gnc_import_get_trans_online_id(transaction);
return (online_id != NULL && strlen(online_id) > 0);
}
const gchar * gnc_import_get_split_online_id (Split * split)
{
gchar *id = NULL;

View File

@ -49,6 +49,17 @@ const gchar * gnc_import_get_acc_online_id(Account * account);
void gnc_import_set_acc_online_id(Account * account,
const gchar * string_value);
/** @} */
/** @name Setter-getters
Setter and getter functions for the online_id field for
Transactions.
@{
*/
const gchar * gnc_import_get_trans_online_id(Transaction * transaction);
void gnc_import_set_trans_online_id(Transaction * transaction,
const gchar * string_value);
/** @} */
gboolean gnc_import_trans_has_online_id(Transaction * transaction);
/** @name Setter-getters
Setter and getter functions for the online_id field for

View File

@ -94,15 +94,6 @@
(lambda () (cons 'absolute (current-time)))
#f 'absolute #f ))
;; This is another date option, but the user can also select
;; the time.
(add-option
(gnc:make-date-option
(N_ "Hello, World!") (N_ "Time and Date Option")
"e" (N_ "This is a date option with time.")
(lambda () (cons 'absolute (current-time)))
#t 'absolute #f ))
(add-option
(gnc:make-date-option
(N_ "Hello, World!") (N_ "Combo Date Option")
@ -234,8 +225,6 @@ option like this.")
(string-val (op-value "Hello, World!" "String Option"))
(date-val (gnc:date-option-absolute-time
(op-value "Hello, World!" "Just a Date Option")))
(date2-val (gnc:date-option-absolute-time
(op-value "Hello, World!" "Time and Date Option")))
(rel-date-val (gnc:date-option-absolute-time
(op-value "Hello, World!" "Relative Date Option")))
(combo-date-val (gnc:date-option-absolute-time
@ -258,7 +247,6 @@ option like this.")
;; qof-print-date
(let ((time-string (gnc-print-time64 (current-time) "%X"))
(date-string (gnc-print-time64 date-val "%x"))
(date-string2 (gnc-print-time64 date2-val "%x %X"))
(rel-date-string (gnc-print-time64 rel-date-val "%x"))
(combo-date-string (gnc-print-time64 combo-date-val "%x")))
@ -369,11 +357,6 @@ new, totally cool report, consult the mailing list ~a.")
(G_ "The date option is ~a.")
(gnc:html-markup-b date-string)))
(gnc:html-markup-p
(gnc:html-markup/format
(G_ "The date and time option is ~a.")
(gnc:html-markup-b date-string2)))
(gnc:html-markup-p
(gnc:html-markup/format
(G_ "The relative date option is ~a.")

View File

@ -719,10 +719,14 @@ the option '~a'."))
(begin
(rpterror-earlier "date" item (car full-list))
0)))
(let* ((value (default-getter))
(if show-time
(issue-deprecation-warning
(format #f "Date options with time of day values are deprecated and will be removed in GnuCash 5.")))
(let* ((value (default-getter))
(value->string (lambda ()
(string-append "'" (gnc:value->string value)))))
(gnc:make-option
(gnc:make-option
section name sort-tag 'date documentation-string
(lambda () value)
(lambda (date)

View File

@ -171,8 +171,11 @@ GncXmlBackend::session_end()
if (!m_linkfile.empty())
g_unlink (m_linkfile.c_str());
if (m_lockfd > 0)
if (m_lockfd != -1)
{
close (m_lockfd);
m_lockfd = -1;
}
if (!m_lockfile.empty())
{
@ -638,12 +641,13 @@ GncXmlBackend::get_file_lock ()
{
/* oops .. file is locked by another user .. */
set_error(ERR_BACKEND_LOCKED);
m_lockfile.clear();
return false;
}
m_lockfd = g_open (m_lockfile.c_str(), O_RDWR | O_CREAT | O_EXCL ,
S_IRUSR | S_IWUSR);
if (m_lockfd < 0)
if (m_lockfd == -1)
{
/* oops .. we can't create the lockfile .. */
switch (errno)
@ -661,87 +665,11 @@ GncXmlBackend::get_file_lock ()
PWARN ("Unable to create the lockfile %s: %s",
m_lockfile.c_str(), strerror(errno));
set_error(be_err);
m_lockfile.clear();
return false;
}
/* OK, now work around some NFS atomic lock race condition
* mumbo-jumbo. We do this by linking a unique file, and
* then examining the link count. At least that's what the
* NFS programmers guide suggests.
* Note: the "unique filename" must be unique for the
* triplet filename-host-process, otherwise accidental
* aliases can occur.
*/
/* apparently, even this code may not work for some NFS
* implementations. In the long run, I am told that
* ftp.debian.org
* /pub/debian/dists/unstable/main/source/libs/liblockfile_0.1-6.tar.gz
* provides a better long-term solution.
*/
#ifndef G_OS_WIN32
auto path = m_lockfile.find_last_of('.');
std::stringstream linkfile;
if (path != std::string::npos)
linkfile << m_lockfile.substr(0, path);
else
linkfile << m_lockfile;
linkfile << "." << gethostid() << "." << getpid() << ".LNK";
rc = link (m_lockfile.c_str(), linkfile.str().c_str());
if (rc)
{
/* If hard links aren't supported, just allow the lock. */
if (errno == EPERM || errno == ENOSYS
# ifdef EOPNOTSUPP
|| errno == EOPNOTSUPP
# endif
# ifdef ENOTSUP
|| errno == ENOTSUP
# endif
)
{
return true;
}
/* Otherwise, something else is wrong. */
set_error(ERR_BACKEND_LOCKED);
g_unlink (linkfile.str().c_str());
close (m_lockfd);
g_unlink (m_lockfile.c_str());
return false;
}
rc = g_stat (m_lockfile.c_str(), &statbuf);
if (rc)
{
/* oops .. stat failed! This can't happen! */
set_error(ERR_BACKEND_LOCKED);
std::string msg{"Failed to stat lockfile "};
set_message(msg + m_lockfile);
g_unlink (linkfile.str().c_str());
close (m_lockfd);
g_unlink (m_lockfile.c_str());
return false;
}
if (statbuf.st_nlink != 2)
{
set_error(ERR_BACKEND_LOCKED);
g_unlink (linkfile.str().c_str());
close (m_lockfd);
g_unlink (m_lockfile.c_str());
return false;
}
m_linkfile = linkfile.str();
return true;
#else /* ifndef G_OS_WIN32 */
/* On windows, there is no NFS and the open(,O_CREAT | O_EXCL)
is sufficient for locking. */
return true;
#endif /* ifndef G_OS_WIN32 */
}
bool

View File

@ -60,7 +60,7 @@ private:
std::string m_dirname;
std::string m_lockfile;
std::string m_linkfile;
int m_lockfd;
int m_lockfd = -1;
QofBook* m_book = nullptr; /* The primary, main open book */
};

View File

@ -127,7 +127,7 @@ sxtg_book_begin (QofBook *book)
static void
sxtg_book_end (QofBook *book)
{
// gnc_book_set_template_root (book, NULL);
gnc_book_set_template_root (book, NULL);
}
static gboolean

View File

@ -612,7 +612,7 @@ gnc_transaction_get_commodity_imbalance (Transaction *trans,
/* GFunc wrapper for xaccSplitDestroy */
static void
destroy_split (void* ptr, void* data)
destroy_split (void* ptr)
{
Split *split = GNC_SPLIT (ptr);
if (split)
@ -642,7 +642,10 @@ xaccTransClearTradingSplits (Transaction *trans)
return;
xaccTransBeginEdit (trans);
g_list_foreach (trading_splits, destroy_split, NULL);
/* destroy_splits doesn't actually free the splits but this gets
* the list ifself freed.
*/
g_list_free_full (trading_splits, destroy_split);
xaccTransCommitEdit (trans);
}

View File

@ -2107,6 +2107,7 @@ xaccSplitGetOtherSplit (const Split *split)
{
Split *s = n->data;
if ((s == split) ||
(!xaccTransStillHasSplit(trans, s)) ||
(xaccAccountGetType (xaccSplitGetAccount (s)) == ACCT_TYPE_TRADING) ||
(qof_instance_has_slot (QOF_INSTANCE (s), "lot-split")))
continue;

View File

@ -73,8 +73,8 @@ cashobjects_register(void)
g_return_val_if_fail(xaccAccountRegister(), FALSE);
g_return_val_if_fail ( xaccTransRegister(), FALSE);
g_return_val_if_fail ( xaccSplitRegister(), FALSE);
g_return_val_if_fail ( SXRegister (), FALSE);
g_return_val_if_fail ( gnc_sxtt_register(), FALSE);
g_return_val_if_fail ( SXRegister (), FALSE);
g_return_val_if_fail(gnc_pricedb_register(), FALSE);
g_return_val_if_fail (gnc_budget_register(), FALSE);
g_return_val_if_fail ( gnc_lot_register (), FALSE);

View File

@ -704,7 +704,7 @@ GncTaxTableList * gncTaxTableGetTables (QofBook *book)
if (!book) return NULL;
bi = qof_book_get_data (book, _GNC_MOD_NAME);
return bi->tables;
return bi ? bi->tables : NULL;
}
const char *gncTaxTableGetName (const GncTaxTable *table)

View File

@ -60,6 +60,15 @@ xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
return mockaccount ? mockaccount->for_each_transaction(proc, data) : 0;
}
SplitList *
xaccAccountGetSplitList (const Account *account)
{
SCOPED_TRACE("");
auto mockaccount = gnc_mockaccount(account);
return mockaccount ? mockaccount->xaccAccountGetSplitList() : nullptr;
}
GncImportMatchMap *
gnc_account_imap_create_imap (Account *acc)
{

View File

@ -43,6 +43,7 @@ public:
MOCK_METHOD0(commit_edit, void());
MOCK_CONST_METHOD0(get_book, QofBook*());
MOCK_CONST_METHOD2(for_each_transaction, gint(TransactionCallback, void*));
MOCK_CONST_METHOD0(xaccAccountGetSplitList, SplitList*());
MOCK_METHOD0(create_imap, GncImportMatchMap*());
protected:

View File

@ -36,6 +36,7 @@ if ($( != 0) {
exit 0 if ($input ne "y");
}
CPAN::Shell->install('Test2'); #Required by an F::Q dependency but cpan doesn't notice.
CPAN::Shell->install('Date::Manip'); #Required by gnc-fq-helper
CPAN::Shell->install('Finance::Quote');

View File

@ -36,7 +36,7 @@ msgstr ""
"Report-Msgid-Bugs-To: https://bugs.gnucash.org/enter_bug."
"cgi?product=GnuCash&component=Translations\n"
"POT-Creation-Date: 2021-06-30 07:34+0200\n"
"PO-Revision-Date: 2021-08-16 20:35+0000\n"
"PO-Revision-Date: 2021-09-05 21:35+0000\n"
"Last-Translator: Christian Wehling <christian.wehling@web.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/gnucash/gnucash/"
"de/>\n"
@ -45,7 +45,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.8-dev\n"
"X-Generator: Weblate 4.8.1-dev\n"
#: bindings/guile/commodity-table.scm:44
msgid "ALL NON-CURRENCY"
@ -17134,7 +17134,7 @@ msgstr "Zahl, Datum, Zeit"
# erreichbar. Können wir das vereinheitlichen?
#: gnucash/gtkbuilder/dialog-preferences.glade:1417
msgid "Perform account list _setup on new file"
msgstr "Bei neuer Datei erstellen: Konten_einrichtung anzeigen"
msgstr "Bei neuer Datei erstellen: Konten_einrichtung starten"
#: gnucash/gtkbuilder/dialog-preferences.glade:1423
msgid "Present the new account list dialog when you choose File->New File."
@ -18328,7 +18328,7 @@ msgstr "<b>Voreinstellungen Buchungseditor</b>"
#: gnucash/gtkbuilder/dialog-sx.glade:545
msgid "_Run when data file opened"
msgstr "Seit-Letztem-Aufruf Fenster starten, wenn eine _Datei geöffnet wird"
msgstr "Ausführen, wenn eine _Datei geöffnet wird"
#: gnucash/gtkbuilder/dialog-sx.glade:549
msgid "Run the \"since last run\" process when a file is opened."
@ -18388,10 +18388,8 @@ msgid "R_emind in advance"
msgstr "Im Voraus er_innern"
#: gnucash/gtkbuilder/dialog-sx.glade:724
#, fuzzy
#| msgid "_Review created transactions"
msgid "Set 'Re_view Created Transactions' as default"
msgstr "Erzeugte Buchungen _durchsehen"
msgstr "'Erstellte _Buchungen durchsehen' als Standard festlegen"
#: gnucash/gtkbuilder/dialog-sx.glade:728
msgid ""

View File

@ -23,7 +23,7 @@ msgstr ""
"Report-Msgid-Bugs-To: https://bugs.gnucash.org/enter_bug."
"cgi?product=GnuCash&component=Translations\n"
"POT-Creation-Date: 2021-06-30 07:34+0200\n"
"PO-Revision-Date: 2021-08-31 14:33+0000\n"
"PO-Revision-Date: 2021-09-10 16:33+0000\n"
"Last-Translator: TianXing_Yi <ytx.cash@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"gnucash/gnucash/zh_Hans/>\n"
@ -32,7 +32,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 4.8.1-dev\n"
"X-Generator: Weblate 4.9-dev\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
#: bindings/guile/commodity-table.scm:44
@ -2162,7 +2162,7 @@ msgstr "入账日期"
#: gnucash/gnome/dialog-invoice.c:872
msgid "Post to Account"
msgstr "入账科目"
msgstr "入账科目"
#: gnucash/gnome/dialog-invoice.c:873
msgid "Accumulate Splits?"
@ -3643,7 +3643,7 @@ msgstr "打开查找项目对话框"
#: gnucash/gnome/gnc-plugin-business.c:238
#: gnucash/gnome/gnc-plugin-business.c:271
msgid "_Process Payment..."
msgstr "处理收付(_P)..."
msgstr "收付(_P)..."
#: gnucash/gnome/gnc-plugin-business.c:196
#: gnucash/gnome/gnc-plugin-business.c:239
@ -4946,7 +4946,7 @@ msgstr "显示员工报表"
#: gnucash/gnome/gnc-plugin-page-owner-tree.c:293
msgid "New Voucher"
msgstr "新建支出凭证"
msgstr "新建报销"
#: gnucash/gnome/gnc-plugin-page-owner-tree.c:446
msgid "Owners"
@ -9239,7 +9239,7 @@ msgstr "重新计算(_R)"
#: gnucash/report/trep-engine.scm:168 gnucash/report/trep-engine.scm:956
#: gnucash/report/trep-engine.scm:1045
msgid "Account Name"
msgstr "科目名称"
msgstr "名称"
#: gnucash/gnome-utils/gnc-tree-view-account.c:816
#: gnucash/gnome-utils/gnc-tree-view-split-reg.c:2919
@ -10877,13 +10877,13 @@ msgstr ""
msgid ""
"Set \"Review Created Transactions\" as the default for the \"since last run"
"\" dialog."
msgstr ""
msgstr "将 \"审查创建的交易 \"设为 \"自上次运行以来 \"对话框的默认值。"
#: gnucash/gschemas/org.gnucash.dialogs.sxs.gschema.xml.in:28
msgid ""
"This setting controls whether as default the \"review created transactions\" "
"is set for the \"since last run\" dialog."
msgstr ""
msgstr "此设置控制 \"自上次运行以来 \"对话框是否默认设置 \"审查已创建的交易\"。"
#: gnucash/gschemas/org.gnucash.dialogs.sxs.gschema.xml.in:35
msgid "Set the \"auto create\" flag by default"
@ -11238,7 +11238,7 @@ msgstr "新打开的标签页前置,而非最后"
msgid ""
"If active, new tabs are opened adjacent to current tab. If inactive, the new "
"tabs are opened instead at the end."
msgstr ""
msgstr "如果激活,新标签会在当前标签的旁边打开。如果不激活,新标签将在最后打开。"
#: gnucash/gschemas/org.gnucash.gschema.xml.in:140
#: gnucash/gtkbuilder/dialog-preferences.glade:940
@ -11330,7 +11330,7 @@ msgstr "最大的几个月又回到过去。"
msgid ""
"Dates will be completed so that they are close to the current date. Enter "
"the maximum number of months to go backwards in time when completing dates."
msgstr "录入月份和本月差值在限额内(小于等于),即本年;超出(大于)为明年。"
msgstr "相隔月数小于等于设定值为本年,大于设定值为明年。"
#: gnucash/gschemas/org.gnucash.gschema.xml.in:180
msgid "Show Horizontal Grid Lines"
@ -15973,7 +15973,7 @@ msgstr "<b>日期补全</b>"
#: gnucash/gtkbuilder/dialog-preferences.glade:1112
msgid "When a date is entered without year, it should be taken"
msgstr "输入的日期没有年份时,其应属于"
msgstr "没有年份的日期,其应属于"
#: gnucash/gtkbuilder/dialog-preferences.glade:1128
msgid ""
@ -15984,9 +15984,7 @@ msgstr "日期年份补全为本年。"
msgid ""
"In a sliding 12-month window starting this\n"
"many months before the current month"
msgstr ""
"从现在开始这个次数,它追溯到过去,\n"
"它被认为是那个月的12个月内的日期"
msgstr "相隔月数定年份"
#: gnucash/gtkbuilder/dialog-preferences.glade:1165
msgid "Enter number of months."
@ -16257,13 +16255,13 @@ msgstr "不可能的匹配日阈值 (_U)"
msgid ""
"A transaction whose date is within the threshold is likely to be a match. "
"Default is 4 days."
msgstr ""
msgstr "日期在阈值内的交易可能是匹配的。默认为4天。"
#: gnucash/gtkbuilder/dialog-preferences.glade:2340
msgid ""
"A transaction whose date is outside the threshold is unlikely to be a match. "
"Default is 14 days."
msgstr ""
msgstr "日期在阈值之外的交易不太可能是匹配的。默认为14天。"
#: gnucash/gtkbuilder/dialog-preferences.glade:2385
msgid "<b>Checks</b>"
@ -17203,7 +17201,7 @@ msgstr "默认复核已创建交易(_R)"
msgid ""
"Set 'Review Created Transactions' as the default in the 'Since Last Run' "
"dialog."
msgstr ""
msgstr "在 \"自上次运行 \"对话框中,将 \"审查创建的交易 \"设置为默认值。"
#: gnucash/gtkbuilder/dialog-sx.glade:765
msgid "Edit Scheduled Transaction"
@ -17356,7 +17354,7 @@ msgstr "GnuCash 每日提示"
#: gnucash/gtkbuilder/dialog-totd.glade:26
msgid "_Previous"
msgstr "去年末(_P)"
msgstr "上一个(_P)"
#: gnucash/gtkbuilder/dialog-totd.glade:41
msgid "_Next"
@ -21349,7 +21347,7 @@ msgstr "小计"
#: gnucash/report/reports/standard/owner-report.scm:56
#: libgnucash/app-utils/business-options.scm:78
msgid "Tax"
msgstr "税"
msgstr "税"
#: gnucash/register/ledger-core/gncEntryLedgerModel.c:127
msgid "Billable?"
@ -21968,7 +21966,7 @@ msgstr "价格信息的来源。"
#: gnucash/report/options-utilities.scm:144
msgid "Average cost of purchases weighted by volume"
msgstr ""
msgstr "按数量加权的平均采购成本"
#: gnucash/report/options-utilities.scm:145
msgid "Weighted average of all transactions in the past"
@ -22103,7 +22101,7 @@ msgstr "收入支出(_I)"
#: gnucash/report/report-core.scm:154
msgid "_Taxes"
msgstr "税(_U)"
msgstr "税(_U)"
#: gnucash/report/report-core.scm:155
msgid "E_xamples"
@ -24537,7 +24535,7 @@ msgstr "以逐条求和计算么?"
#: gnucash/report/reports/standard/budget-barchart.scm:142
msgid "Select which chart type to use."
msgstr ""
msgstr "选择要使用的图表类型。"
#: gnucash/report/reports/standard/budget-barchart.scm:144
#: gnucash/report/reports/standard/category-barchart.scm:156