From 4c1fc1d555a154f276ef093926ba821f8bd4fdd8 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Sun, 26 Sep 2021 13:07:51 +0100 Subject: [PATCH 1/4] Bug 798262 - Add test case for basic scheduled transactions Test these scheduled transactions: * 2 splits with fixed amounts "123" * 2 splits with fixed amounts "0" * 2 splits with empty amounts "" Verify that automatically created scheduled transactions exist. --- libgnucash/app-utils/test/CMakeLists.txt | 4 +- libgnucash/app-utils/test/test-sx.cpp | 126 ++++++++++++++++++++++- 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/libgnucash/app-utils/test/CMakeLists.txt b/libgnucash/app-utils/test/CMakeLists.txt index 77ba839765..962ab4197c 100644 --- a/libgnucash/app-utils/test/CMakeLists.txt +++ b/libgnucash/app-utils/test/CMakeLists.txt @@ -26,7 +26,9 @@ add_app_utils_test(test-print-parse-amount test-print-parse-amount.cpp) gnc_add_test_with_guile(test-scm-query-string test-scm-query-string.cpp APP_UTILS_TEST_INCLUDE_DIRS APP_UTILS_TEST_LIBS ) -add_app_utils_test(test-sx test-sx.cpp) +gnc_add_test_with_guile(test-sx test-sx.cpp + APP_UTILS_TEST_INCLUDE_DIRS APP_UTILS_TEST_LIBS +) set(GUILE_DEPENDS scm-test-engine diff --git a/libgnucash/app-utils/test/test-sx.cpp b/libgnucash/app-utils/test/test-sx.cpp index c6070d9ab3..aafbef9f12 100644 --- a/libgnucash/app-utils/test/test-sx.cpp +++ b/libgnucash/app-utils/test/test-sx.cpp @@ -20,12 +20,15 @@ #include #include +#include extern "C" { #include #include "SX-book.h" +#include "SX-ttinfo.h" #include "gnc-date.h" +#include "gnc-session.h" #include "gnc-sx-instance-model.h" #include "gnc-ui-util.h" @@ -214,8 +217,116 @@ test_state_changes() remove_sx(foo); } -int -main(int argc, char **argv) +static void +make_one_transaction_begin(TTInfo **tti, Account **account1, Account **account2) +{ + QofBook *book = qof_session_get_book(gnc_get_current_session()); + + *account1 = get_random_account(book); + *account2 = get_random_account(book); + *tti = gnc_ttinfo_malloc(); + + // Both accounts need to have the same currency + xaccAccountBeginEdit(*account2); + xaccAccountSetCommodity(*account2, xaccAccountGetCommodity(*account1)); + xaccAccountCommitEdit(*account2); + + gnc_ttinfo_set_currency(*tti, xaccAccountGetCommodity(*account1)); +} + +static void +make_one_transaction_end(TTInfo **tti, SchedXaction *sx) +{ + QofBook *book = qof_session_get_book(gnc_get_current_session()); + GList *txns = g_list_append(NULL, *tti); + xaccSchedXactionSetTemplateTrans(sx, txns, book); + gnc_ttinfo_free(*tti); + *tti = NULL; +} + +static void +make_one_transaction_with_two_splits(SchedXaction *sx, const char *value1, const char *value2) +{ + TTInfo *tti; + Account *account1; + Account *account2; + + make_one_transaction_begin(&tti, &account1, &account2); + + TTSplitInfo *split1 = gnc_ttsplitinfo_malloc(); + TTSplitInfo *split2 = gnc_ttsplitinfo_malloc(); + + gnc_ttsplitinfo_set_account(split1, account1); + gnc_ttsplitinfo_set_debit_formula(split1, value1); + gnc_ttinfo_append_template_split(tti, split1); + + gnc_ttsplitinfo_set_account(split2, account2); + gnc_ttsplitinfo_set_credit_formula(split2, value2); + gnc_ttinfo_append_template_split(tti, split2); + + make_one_transaction_end(&tti, sx); +} + +static void +make_one_transaction(SchedXaction *sx) +{ + make_one_transaction_with_two_splits(sx, "123", "123"); +} + +static void +make_one_zero_transaction(SchedXaction *sx) +{ + make_one_transaction_with_two_splits(sx, "0", "0"); +} + +static void +make_one_empty_transaction(SchedXaction *sx) +{ + make_one_transaction_with_two_splits(sx, "", ""); +} + +static void +test_auto_create_transactions(const char *name, void (*populate_sx)(SchedXaction*), unsigned int expected_txns) +{ + GncSxInstanceModel *model; + GDate yesterday, today; + SchedXaction *one_sx; + GncSxSummary summary; + GList *auto_created_txns = NULL; + + g_date_clear(&today, 1); + gnc_gdate_set_today(&today); + + yesterday = today; + g_date_subtract_days(&yesterday, 1); + + one_sx = add_daily_sx(name, &yesterday, NULL, NULL); + + xaccSchedXactionSetNumOccur(one_sx, 1); + xaccSchedXactionSetRemOccur(one_sx, 1); + xaccSchedXactionSetAutoCreate(one_sx, TRUE, FALSE); + + populate_sx(one_sx); + + model = gnc_sx_get_current_instances(); + gnc_sx_instance_model_summarize(model, &summary); + gnc_sx_instance_model_effect_change(model, TRUE, &auto_created_txns, NULL); + + do_test_args(summary.need_dialog == 0, "Dialog not required", + __FILE__, __LINE__, "for %s", name); + do_test_args(summary.num_auto_create_no_notify_instances == 1, "1 automatically created instance", + __FILE__, __LINE__, "for %s", name); + do_test_args(g_list_length(auto_created_txns) == expected_txns, "Automatically created transactions", + __FILE__, __LINE__, "for %s: auto_created_txns = %u, expected_txns = %u", + name, g_list_length(auto_created_txns), expected_txns); + + g_list_free(auto_created_txns); + g_object_unref(model); + remove_sx(one_sx); +} + +static void +real_main(void *closure, int argc, char **argv) { g_setenv ("GNC_UNINSTALLED", "1", TRUE); qof_init(); @@ -230,6 +341,17 @@ main(int argc, char **argv) test_basic(); test_state_changes(); + test_auto_create_transactions("make_one_transaction", make_one_transaction, 1); + test_auto_create_transactions("make_one_zero_transaction", make_one_zero_transaction, 1); + test_auto_create_transactions("make_one_empty_transaction", make_one_empty_transaction, 1); + print_test_results(); exit(get_rv()); } + +int main(int argc, char **argv) +{ + /* do things this way so we can test scheme function calls from expressions */ + scm_boot_guile(argc, argv, real_main, NULL); + return 0; +} From 229f6f5e85a8579b371d87f407862910a416d2dd Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 12 Aug 2022 12:58:58 -0700 Subject: [PATCH 2/4] Fix gdate adjustments. --- libgnucash/app-utils/test/test-sx.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libgnucash/app-utils/test/test-sx.cpp b/libgnucash/app-utils/test/test-sx.cpp index aafbef9f12..a26d1cbcba 100644 --- a/libgnucash/app-utils/test/test-sx.cpp +++ b/libgnucash/app-utils/test/test-sx.cpp @@ -117,7 +117,10 @@ test_once() gnc_gdate_set_today (when); while (random_offset_within_one_year == 0) random_offset_within_one_year = get_random_int_in_range(-365, 365); - g_date_add_days(when, random_offset_within_one_year); + if (random_offset_within_one_year > 0) + g_date_add_days(when, random_offset_within_one_year); + else + g_date_subtract_days(when, -random_offset_within_one_year); end = g_date_new(); g_date_clear(end, 1); From 410db42df00f9a6ad79ba2bd43a7a35e442e5e0a Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 14 Aug 2022 15:28:14 -0700 Subject: [PATCH 3/4] Test case where the template txn doesn't have a set currency. --- libgnucash/app-utils/test/test-sx.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/libgnucash/app-utils/test/test-sx.cpp b/libgnucash/app-utils/test/test-sx.cpp index a26d1cbcba..7047deb1f7 100644 --- a/libgnucash/app-utils/test/test-sx.cpp +++ b/libgnucash/app-utils/test/test-sx.cpp @@ -234,7 +234,6 @@ make_one_transaction_begin(TTInfo **tti, Account **account1, Account **account2) xaccAccountSetCommodity(*account2, xaccAccountGetCommodity(*account1)); xaccAccountCommitEdit(*account2); - gnc_ttinfo_set_currency(*tti, xaccAccountGetCommodity(*account1)); } static void @@ -248,7 +247,8 @@ make_one_transaction_end(TTInfo **tti, SchedXaction *sx) } static void -make_one_transaction_with_two_splits(SchedXaction *sx, const char *value1, const char *value2) +make_one_transaction_with_two_splits(SchedXaction *sx, const char *value1, + const char *value2, int set_txcurr) { TTInfo *tti; Account *account1; @@ -256,6 +256,9 @@ make_one_transaction_with_two_splits(SchedXaction *sx, const char *value1, const make_one_transaction_begin(&tti, &account1, &account2); + if (set_txcurr) + gnc_ttinfo_set_currency(tti, xaccAccountGetCommodity(account1)); + TTSplitInfo *split1 = gnc_ttsplitinfo_malloc(); TTSplitInfo *split2 = gnc_ttsplitinfo_malloc(); @@ -273,19 +276,25 @@ make_one_transaction_with_two_splits(SchedXaction *sx, const char *value1, const static void make_one_transaction(SchedXaction *sx) { - make_one_transaction_with_two_splits(sx, "123", "123"); + make_one_transaction_with_two_splits(sx, "123", "123", FALSE); } static void make_one_zero_transaction(SchedXaction *sx) { - make_one_transaction_with_two_splits(sx, "0", "0"); + make_one_transaction_with_two_splits(sx, "0", "0", FALSE); } static void make_one_empty_transaction(SchedXaction *sx) { - make_one_transaction_with_two_splits(sx, "", ""); + make_one_transaction_with_two_splits(sx, "", "", FALSE); +} + +static void +make_one_empty_transaction_with_txcurr(SchedXaction *sx) +{ + make_one_transaction_with_two_splits(sx, "", "", TRUE); } static void @@ -347,6 +356,7 @@ real_main(void *closure, int argc, char **argv) test_auto_create_transactions("make_one_transaction", make_one_transaction, 1); test_auto_create_transactions("make_one_zero_transaction", make_one_zero_transaction, 1); test_auto_create_transactions("make_one_empty_transaction", make_one_empty_transaction, 1); + test_auto_create_transactions("make_one_empty_transaction_with_txcurr", make_one_empty_transaction_with_txcurr, 1); print_test_results(); exit(get_rv()); From 087501d316f9627748560210a95a66841849a9c4 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 14 Aug 2022 15:31:46 -0700 Subject: [PATCH 4/4] Bug 798262 - Scheduled transactions with blank amounts do not get created. Handle template transactions that don't have any splits with empty credit and debit strings and those having no set transaction account. Set the concrete transaction commodity to the first found of: The template transaction's commodity The commodity of the first split with a credit or debit string The commodity of the first split. --- libgnucash/app-utils/gnc-sx-instance-model.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libgnucash/app-utils/gnc-sx-instance-model.c b/libgnucash/app-utils/gnc-sx-instance-model.c index 4e114eb11b..1f69e1ee27 100644 --- a/libgnucash/app-utils/gnc-sx-instance-model.c +++ b/libgnucash/app-utils/gnc-sx-instance-model.c @@ -1206,7 +1206,8 @@ static gnc_commodity* get_transaction_currency(SxTxnCreationData *creation_data, SchedXaction *sx, Transaction *template_txn) { - gnc_commodity *first_currency = NULL, *first_cmdty = NULL; + gnc_commodity *first_currency = NULL, *first_cmdty = NULL, + *fallback_cmdty = NULL; gboolean err_flag = FALSE, txn_cmdty_in_splits = FALSE; gnc_commodity *txn_cmdty = xaccTransGetCurrency (template_txn); GList* txn_splits = xaccTransGetSplitList (template_txn); @@ -1234,6 +1235,9 @@ get_transaction_currency(SxTxnCreationData *creation_data, /* Don't consider the commodity of a transaction that has * neither a credit nor a debit formula. */ + if (!fallback_cmdty) + fallback_cmdty = xaccAccountGetCommodity (split_account); + if (split_is_marker(t_split)) continue; @@ -1256,9 +1260,11 @@ get_transaction_currency(SxTxnCreationData *creation_data, if (first_currency && (!txn_cmdty_in_splits || !gnc_commodity_is_currency (txn_cmdty))) return first_currency; - if (!txn_cmdty_in_splits) + if (!txn_cmdty_in_splits && first_cmdty) return first_cmdty; - return txn_cmdty; + if (txn_cmdty) + return txn_cmdty; + return fallback_cmdty; } static gboolean