gnucash master: Multiple changes pushed
Christopher Lam
clam at code.gnucash.org
Fri Dec 3 06:13:29 EST 2021
Updated via https://github.com/Gnucash/gnucash/commit/9d1c73f9 (commit)
via https://github.com/Gnucash/gnucash/commit/91b1d291 (commit)
via https://github.com/Gnucash/gnucash/commit/972fd452 (commit)
via https://github.com/Gnucash/gnucash/commit/ab8277e9 (commit)
via https://github.com/Gnucash/gnucash/commit/329ca0e4 (commit)
via https://github.com/Gnucash/gnucash/commit/73822f97 (commit)
via https://github.com/Gnucash/gnucash/commit/99c2c82c (commit)
via https://github.com/Gnucash/gnucash/commit/6070aecd (commit)
via https://github.com/Gnucash/gnucash/commit/5dab3369 (commit)
from https://github.com/Gnucash/gnucash/commit/88ecf8dd (commit)
commit 9d1c73f91a62e1184565a198dfdd8ee4830ddc03
Merge: 88ecf8dd1 91b1d291a
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Fri Dec 3 17:41:33 2021 +0800
Merge branch 'master-fix-budget-signs' PR #585
commit 91b1d291a54e3ea44b3bb82fa174c57cd0029c82
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Thu Dec 2 22:28:49 2021 +0800
[3/3][gnc-ui-util.c] Remove unused functions
These functions were used to (optionally) reverse amounts according to
whether the feature GNC_FEATURE_BUDGET_UNREVERSED was set. They are
now obsolete because code will now assume feature is set for all
loaded datafiles.
diff --git a/libgnucash/app-utils/app-utils.i b/libgnucash/app-utils/app-utils.i
index 28730bc61..31d5066b2 100644
--- a/libgnucash/app-utils/app-utils.i
+++ b/libgnucash/app-utils/app-utils.i
@@ -108,8 +108,6 @@ const char * xaccPrintAmount (gnc_numeric val, GNCPrintAmountInfo info);
gchar *number_to_words(gdouble val, gint64 denom);
const gchar *printable_value (gdouble val, gint denom);
-gboolean gnc_using_unreversed_budgets (QofBook* book);
-gboolean gnc_reverse_budget_balance (const Account *account, gboolean unreversed);
gboolean gnc_reverse_balance (const Account *account);
gboolean gnc_is_euro_currency(const gnc_commodity * currency);
diff --git a/libgnucash/app-utils/gnc-ui-util.c b/libgnucash/app-utils/gnc-ui-util.c
index aea6bbba3..86ded4791 100644
--- a/libgnucash/app-utils/gnc-ui-util.c
+++ b/libgnucash/app-utils/gnc-ui-util.c
@@ -177,23 +177,6 @@ gnc_reverse_balance (const Account *account)
return reverse_type[type];
}
-gboolean gnc_using_unreversed_budgets (QofBook* book)
-{
- return gnc_features_check_used (book, GNC_FEATURE_BUDGET_UNREVERSED);
-}
-
-/* similar to gnc_reverse_balance but also accepts a gboolean
- unreversed which specifies the reversal strategy - FALSE = pre-4.x
- always-assume-credit-accounts, TRUE = all amounts unreversed */
-gboolean
-gnc_reverse_budget_balance (const Account *account, gboolean unreversed)
-{
- if (unreversed == gnc_using_unreversed_budgets(gnc_account_get_book(account)))
- return gnc_reverse_balance (account);
-
- return FALSE;
-}
-
gboolean gnc_using_equity_type_opening_balance_account (QofBook* book)
{
return gnc_features_check_used (book, GNC_FEATURE_EQUITY_TYPE_OPENING_BALANCE);
diff --git a/libgnucash/app-utils/gnc-ui-util.h b/libgnucash/app-utils/gnc-ui-util.h
index b9bb385c6..b6627e09d 100644
--- a/libgnucash/app-utils/gnc-ui-util.h
+++ b/libgnucash/app-utils/gnc-ui-util.h
@@ -46,16 +46,6 @@ typedef QofSession * (*QofSessionCB) (void);
gchar *gnc_normalize_account_separator (const gchar* separator);
gboolean gnc_reverse_balance(const Account *account);
-/* Backward compatibility *******************************************
- * Return book's UNREVERSED_BUDGET feature check. */
-gboolean gnc_using_unreversed_budgets (QofBook* book);
-
-/* Backward compatibility *******************************************
- * Compare book's UNREVERSED_BUDGET with unreverse_check. If they
- * match, return account reversal according to global pref. If they
- * don't match, return FALSE. */
-gboolean gnc_reverse_budget_balance (const Account *account, gboolean unreversed);
-
/* Backward compatibility *******************************************
* Return that book's support opening balance accounts by equity type slot */
void gnc_set_use_equity_type_opening_balance_account (QofBook* book);
commit 972fd452025f68e917bfe72549fae7086ee2dc14
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Thu Dec 2 22:31:29 2021 +0800
[2/3][budget editor] remove backward-compatibility code
Previously the budget editor would sign-reverse budget amounts for
some account types prior to saving in datafile. This code is now
obsolete. Sign reversal is now a display mechanic in the budget viewer
only.
diff --git a/gnucash/gnome/gnc-budget-view.c b/gnucash/gnome/gnc-budget-view.c
index c9a1e4672..05a037771 100644
--- a/gnucash/gnome/gnc-budget-view.c
+++ b/gnucash/gnome/gnc-budget-view.c
@@ -1077,8 +1077,7 @@ gbv_get_accumulated_budget_amount (GncBudget *budget, Account *account, guint pe
else
info.total = gnc_budget_get_account_period_value (budget, account, period_num);
- if (gnc_reverse_budget_balance (account, TRUE))
- info.total = gnc_numeric_neg (info.total);
+ info.total = gnc_numeric_neg (info.total);
return info.total;
}
@@ -1141,8 +1140,7 @@ budget_col_source (Account *account, GtkTreeViewColumn *col,
strcpy (amtbuff, "error");
else
{
- if (gnc_reverse_budget_balance (account, TRUE))
- numeric = gnc_numeric_neg (numeric);
+ numeric = gnc_numeric_neg (numeric);
xaccSPrintAmount (amtbuff, numeric,
gnc_account_print_info (account, FALSE));
@@ -1192,8 +1190,7 @@ bgv_get_total_for_account (Account *account, GncBudget *budget, gnc_commodity *n
{
numeric = gbv_get_accumulated_budget_amount (budget, account, period_num);
- if (gnc_reverse_budget_balance (account, TRUE))
- numeric = gnc_numeric_neg (numeric);
+ numeric = gnc_numeric_neg (numeric);
if (new_currency)
{
@@ -1220,8 +1217,7 @@ bgv_get_total_for_account (Account *account, GncBudget *budget, gnc_commodity *n
}
}
- if (gnc_reverse_budget_balance (account, TRUE))
- total = gnc_numeric_neg (total);
+ total = gnc_numeric_neg (total);
return total;
}
@@ -1284,8 +1280,7 @@ budget_col_edited (Account *account, GtkTreeViewColumn *col,
gnc_budget_unset_account_period_value (priv->budget, account, period_num);
else
{
- if (gnc_reverse_budget_balance (account, TRUE))
- numeric = gnc_numeric_neg (numeric);
+ numeric = gnc_numeric_neg (numeric);
gnc_budget_set_account_period_value (priv->budget, account, period_num,
numeric);
}
@@ -1342,65 +1337,31 @@ totals_col_source (GtkTreeViewColumn *col, GtkCellRenderer *cell,
currency = gnc_account_get_currency_or_parent (account);
acctype = xaccAccountGetType (account);
- if (gnc_using_unreversed_budgets (gnc_account_get_book (account)))
- { /* using book with unreversed-budgets feature. This will be
- the default in 4.x after budget scrubbing*/
- neg = gnc_reverse_balance (account);
-
- switch (row_type)
- {
- case TOTALS_TYPE_ASSET_LIAB_EQ:
- if ((acctype != ACCT_TYPE_ASSET) &&
- (acctype != ACCT_TYPE_LIABILITY) &&
- (acctype != ACCT_TYPE_EQUITY))
- continue;
- neg = !neg;
- break;
- case TOTALS_TYPE_EXPENSES:
- if (acctype != ACCT_TYPE_EXPENSE)
- continue;
- break;
- case TOTALS_TYPE_INCOME:
- if (acctype != ACCT_TYPE_INCOME)
- continue;
- neg = !neg;
- break;
- case TOTALS_TYPE_REMAINDER:
- neg = !neg;
- break;
- default:
- continue; /* don't count if unexpected total row type is passed in... */
- }
- }
- else
- { /* this section is for backward compatibility, to be
- removed when unreversed-budgets are mandatory */
- neg = FALSE;
+ neg = gnc_reverse_balance (account);
- switch (row_type)
- {
- case TOTALS_TYPE_ASSET_LIAB_EQ:
- if ((acctype != ACCT_TYPE_ASSET) &&
- (acctype != ACCT_TYPE_LIABILITY) &&
- (acctype != ACCT_TYPE_EQUITY))
- continue;
- neg = (acctype == ACCT_TYPE_ASSET);
- break;
- case TOTALS_TYPE_EXPENSES:
- if (acctype != ACCT_TYPE_EXPENSE)
- continue;
- break;
- case TOTALS_TYPE_INCOME:
- if (acctype != ACCT_TYPE_INCOME)
- continue;
- break;
- case TOTALS_TYPE_REMAINDER:
- neg = ((acctype == ACCT_TYPE_ASSET) ||
- (acctype == ACCT_TYPE_EXPENSE));
- break;
- default:
- continue; /* don't count if unexpected total row type is passed in... */
- }
+ switch (row_type)
+ {
+ case TOTALS_TYPE_ASSET_LIAB_EQ:
+ if ((acctype != ACCT_TYPE_ASSET) &&
+ (acctype != ACCT_TYPE_LIABILITY) &&
+ (acctype != ACCT_TYPE_EQUITY))
+ continue;
+ neg = !neg;
+ break;
+ case TOTALS_TYPE_EXPENSES:
+ if (acctype != ACCT_TYPE_EXPENSE)
+ continue;
+ break;
+ case TOTALS_TYPE_INCOME:
+ if (acctype != ACCT_TYPE_INCOME)
+ continue;
+ neg = !neg;
+ break;
+ case TOTALS_TYPE_REMAINDER:
+ neg = !neg;
+ break;
+ default:
+ continue; /* don't count if unexpected total row type is passed in... */
}
// find the total for this account
diff --git a/gnucash/gnome/gnc-plugin-page-budget.c b/gnucash/gnome/gnc-plugin-page-budget.c
index 67da7eba2..064761526 100644
--- a/gnucash/gnome/gnc-plugin-page-budget.c
+++ b/gnucash/gnome/gnc-plugin-page-budget.c
@@ -968,9 +968,6 @@ estimate_budget_helper (GtkTreeModel *model, GtkTreePath *path,
GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
GNC_HOW_RND_ROUND_HALF_UP);
- if (gnc_reverse_budget_balance (acct, FALSE))
- num = gnc_numeric_neg (num);
-
for (i = 0; i < num_periods; i++)
{
gnc_budget_set_account_period_value (priv->budget, acct, i, num);
@@ -986,9 +983,6 @@ estimate_budget_helper (GtkTreeModel *model, GtkTreePath *path,
if (!gnc_numeric_check (num))
{
- if (gnc_reverse_budget_balance (acct, FALSE))
- num = gnc_numeric_neg (num);
-
num = gnc_numeric_convert (num, GNC_DENOM_AUTO,
GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
GNC_HOW_RND_ROUND_HALF_UP);
@@ -1095,8 +1089,7 @@ allperiods_budget_helper (GtkTreeModel *model, GtkTreePath *path,
acct = gnc_budget_view_get_account_from_path (priv->budget_view, path);
num_periods = gnc_budget_get_num_periods (priv->budget);
allvalue = priv->allValue;
- if (gnc_reverse_budget_balance (acct, TRUE))
- allvalue = gnc_numeric_neg (allvalue);
+ allvalue = gnc_numeric_neg (allvalue);
for (i = 0; i < num_periods; i++)
{
commit ab8277e9c415e267c4d47674c76e32c5cedb7153
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Thu Dec 2 22:31:16 2021 +0800
[1/3][reports.scm] remove backward-compatibility code
We can now assume that all budget amounts now use natural
numbers. Remove handling old reversed-budget amounts.
diff --git a/gnucash/report/reports/standard/budget-balance-sheet.scm b/gnucash/report/reports/standard/budget-balance-sheet.scm
index c1dc21b9a..c7b6ed3b4 100644
--- a/gnucash/report/reports/standard/budget-balance-sheet.scm
+++ b/gnucash/report/reports/standard/budget-balance-sheet.scm
@@ -257,7 +257,7 @@
(define (get-budget-account-budget-balance budget account)
(let ((bal (gnc:budget-account-get-net budget account #f #f)))
- (if (gnc-reverse-budget-balance account #t) (gnc:collector- bal) bal)))
+ (if (gnc-reverse-balance account) (gnc:collector- bal) bal)))
(define (get-budget-account-initial-balance budget account)
(gnc:budget-account-get-initial-balance budget account))
diff --git a/gnucash/report/reports/standard/budget-income-statement.scm b/gnucash/report/reports/standard/budget-income-statement.scm
index 5428b0197..c239c313c 100644
--- a/gnucash/report/reports/standard/budget-income-statement.scm
+++ b/gnucash/report/reports/standard/budget-income-statement.scm
@@ -308,7 +308,7 @@
(define (get-budget-account-budget-balance budget account period-start period-end)
(let ((bal (gnc:budget-account-get-net budget account period-start period-end)))
- (if (gnc-reverse-budget-balance account #t) (gnc:collector- bal) bal)))
+ (if (gnc-reverse-balance account) (gnc:collector- bal) bal)))
(gnc:report-starting reportname)
diff --git a/gnucash/report/reports/standard/budget.scm b/gnucash/report/reports/standard/budget.scm
index a960d50c7..cea15d449 100644
--- a/gnucash/report/reports/standard/budget.scm
+++ b/gnucash/report/reports/standard/budget.scm
@@ -348,8 +348,6 @@
(let* ((comm (xaccAccountGetCommodity acct))
(reverse-balance? (gnc-reverse-balance acct))
(maybe-negate (lambda (amt) (if reverse-balance? (- amt) amt)))
- (unreversed? (gnc-using-unreversed-budgets
- (gnc-get-current-book))) ;fwd-compatibility
(allperiods (filter number? (gnc:list-flatten column-list)))
(total-periods (if (and accumulate? (not (null? allperiods)))
(iota (1+ (apply max allperiods)))
@@ -399,8 +397,7 @@
((null? column-list)
#f)
- ;; fwd-compatibility for unreversed budgets
- ((and (eq? (car column-list) 'total) unreversed?)
+ ((eq? (car column-list) 'total)
(let* ((bgt-total (maybe-negate
(gnc:get-account-periodlist-budget-value
budget acct total-periods)))
@@ -412,21 +409,7 @@
(disp-cols "total-number-cell" current-col
bgt-total act-total dif-total #f))))
- ((eq? (car column-list) 'total)
- (let* ((bgt-total (gnc:get-account-periodlist-budget-value
- budget acct total-periods))
- (act-total (gnc:get-account-periodlist-actual-value
- budget acct total-periods))
- (act-total (if reverse-balance? (- act-total) act-total))
- (dif-total (if income-acct?
- (- act-total bgt-total)
- (- bgt-total act-total))))
- (loop (cdr column-list)
- (disp-cols "total-number-cell" current-col
- bgt-total act-total dif-total #f))))
-
- ;; fwd-compatibility for unreversed budgets
- (unreversed?
+ (else
(let* ((period-list (cond
((list? (car column-list)) (car column-list))
(accumulate? (iota (1+ (car column-list))))
@@ -441,28 +424,6 @@
(gnc:get-account-periodlist-actual-value
budget acct period-list)))
(dif-val (- bgt-val act-val)))
- (loop (cdr column-list)
- (disp-cols "number-cell" current-col
- bgt-val act-val dif-val note))))
-
- (else
- (let* ((period-list (cond
- ((list? (car column-list)) (car column-list))
- (accumulate? (iota (1+ (car column-list))))
- (else (list (car column-list)))))
- (note (and (= 1 (length period-list))
- (gnc-budget-get-account-period-note
- budget acct (car period-list))))
- (bgt-val (gnc:get-account-periodlist-budget-value
- budget acct period-list))
- (act-abs (gnc:get-account-periodlist-actual-value
- budget acct period-list))
- (act-val (if reverse-balance?
- (- act-abs)
- act-abs))
- (dif-val (if income-acct?
- (- act-val bgt-val)
- (- bgt-val act-val))))
(loop (cdr column-list)
(disp-cols "number-cell" current-col
bgt-val act-val dif-val note))))))))
diff --git a/gnucash/report/reports/standard/test/test-budget.scm b/gnucash/report/reports/standard/test/test-budget.scm
index fbd9fd36e..93adc3a3f 100644
--- a/gnucash/report/reports/standard/test/test-budget.scm
+++ b/gnucash/report/reports/standard/test/test-budget.scm
@@ -98,8 +98,8 @@
(sxml->table-row-col sxml 1 5 #f))
(test-equal "income"
'("Income" "-$55.00 " "1" "-$55.00" "$0.00" "." "$0.00" "."
- "-$65.00" "-$67.00" "-$2.00" "-$75.00" "-$77.00" "-$2.00" "."
- "$0.00" "." "." "$0.00" "." "-$195.00" "-$199.00" "-$4.00")
+ "-$65.00" "-$67.00" "$2.00" "-$75.00" "-$77.00" "$2.00" "."
+ "$0.00" "." "." "$0.00" "." "-$195.00" "-$199.00" "$4.00")
(sxml->table-row-col sxml 1 9 #f))
(test-equal "expense"
'("Expenses" "." "$20.00" "-$20.00" "$30.00 " "2" "$20.00"
commit 329ca0e4916df2f5042c19e8079f650d6aa83dad
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Fri Aug 27 20:37:58 2021 +0800
[2/2][gnc-file.c] launch scrubbing and inform user after file-load
Note the feature check and checking for budgets is done in
ScrubBudget.c
diff --git a/gnucash/gnome-utils/gnc-file.c b/gnucash/gnome-utils/gnc-file.c
index 677125c1e..76af4de3f 100644
--- a/gnucash/gnome-utils/gnc-file.c
+++ b/gnucash/gnome-utils/gnc-file.c
@@ -46,6 +46,7 @@
#include "gnc-plugin-file-history.h"
#include "qof.h"
#include "Scrub.h"
+#include "ScrubBudget.h"
#include "TransLog.h"
#include "gnc-session.h"
#include "gnc-state.h"
@@ -701,6 +702,26 @@ gnc_file_query_save (GtkWindow *parent, gboolean can_cancel)
#define RESPONSE_READONLY 4
#define RESPONSE_FILE 5
+/* This function is called after loading datafile. It's meant to
+ collect all scrubbing routines. */
+static void
+run_post_load_scrubs (GtkWindow *parent, QofBook *book)
+{
+ qof_event_suspend();
+
+ /* If feature GNC_FEATURE_BUDGET_UNREVERSED is not set, and there
+ are budgets, fix signs */
+ if (gnc_maybe_scrub_all_budget_signs (book))
+ gnc_info_dialog (parent, "%s", _("This book has budgets. \
+The internal representation of amounts is now fixed. Please review \
+budgets and amend signs if necessary."));
+
+ // Fix account color slots being set to 'Not Set', should run once on a book
+ xaccAccountScrubColorNotSet (book);
+
+ qof_event_resume();
+}
+
static gboolean
gnc_post_file_open (GtkWindow *parent, const char * filename, gboolean is_readonly)
{
@@ -1104,10 +1125,7 @@ RESTART:
g_list_free_full (invalid_account_names, g_free);
}
- // Fix account color slots being set to 'Not Set', should run once on a book
- qof_event_suspend();
- xaccAccountScrubColorNotSet (gnc_get_current_book());
- qof_event_resume();
+ run_post_load_scrubs (parent, new_book);
return TRUE;
}
commit 73822f97a958dd2b2a732e4453cc5747450e09f7
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Fri Aug 27 20:37:50 2021 +0800
[1/2][Scrubbudget.c] use heuristics to scrub budget signs
If book has budgets, and GNC_FEATURE_BUDGET_UNREVERSED isn't set,
check and fix budget amount signs. Previously budgets were created
with assumption that sign reversal was set to credit amounts. A
heuristic approach is used:
- if budgeted expense is negative, conclude sign reversal is
"Income and Expense"
- if budgeted liability is positive, conclude sign reversal is
"None"
- otherwise conclude sign reversal is "Credit Accounts"
The above is calibrated to (hopefully) prefer sign reversal of Credit
Accounts.
diff --git a/libgnucash/engine/CMakeLists.txt b/libgnucash/engine/CMakeLists.txt
index d860bd436..559d53919 100644
--- a/libgnucash/engine/CMakeLists.txt
+++ b/libgnucash/engine/CMakeLists.txt
@@ -37,6 +37,7 @@ set (engine_HEADERS
Scrub2.h
ScrubBusiness.h
Scrub3.h
+ ScrubBudget.h
Split.h
TransLog.h
Transaction.h
@@ -133,6 +134,7 @@ set (engine_SOURCES
Scrub2.c
Scrub3.c
ScrubBusiness.c
+ ScrubBudget.c
Split.c
TransLog.c
Transaction.c
diff --git a/libgnucash/engine/ScrubBudget.c b/libgnucash/engine/ScrubBudget.c
new file mode 100644
index 000000000..614f946f7
--- /dev/null
+++ b/libgnucash/engine/ScrubBudget.c
@@ -0,0 +1,211 @@
+/********************************************************************\
+ * ScrubBudget.c -- fix budget amount signs *
+ * Copyright (c) 2020 Christoher Lam *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+
+#include <config.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "gnc-prefs.h"
+#include "gnc-budget.h"
+#include "gnc-features.h"
+#include "ScrubBudget.h"
+
+static QofLogModule log_module = "gnc.engine.scrub";
+
+typedef enum
+{
+ HEURISTICS_INC_EXP,
+ HEURISTICS_CREDIT_ACC,
+ HEURISTICS_NONE
+} SignReversals;
+
+typedef struct
+{
+ GncBudget* budget;
+ SignReversals policy;
+} ReversalType;
+
+typedef struct
+{
+ gint asset,liability,equity,income,expense;
+ gint num_periods;
+ GncBudget* budget;
+} ProcessData;
+
+static void
+process_heuristics_acct (Account * account, gpointer user_data)
+{
+ /* each account- check type. sum budget period amounts. if sum<0,
+ decrease type tally by 1. if sum>0, increase type tally by 1. */
+ ProcessData *heuristics = (ProcessData*) user_data;
+ gnc_numeric total = gnc_numeric_zero(), val;
+ gint sign;
+ gchar *totalstr;
+
+ for (gint i = 0; i < heuristics->num_periods; ++i)
+ {
+ if (!gnc_budget_is_account_period_value_set (heuristics->budget, account, i))
+ continue;
+ val = gnc_budget_get_account_period_value (heuristics->budget, account, i);
+ total = gnc_numeric_add_fixed (total, val);
+ }
+
+ sign = gnc_numeric_compare (total, gnc_numeric_zero ());
+ totalstr = gnc_numeric_to_string (total);
+ PINFO ("acct=%s, total=%s, sign=%d",
+ xaccAccountGetName (account), totalstr, sign);
+ g_free (totalstr);
+
+ switch (xaccAccountTypeGetFundamental (xaccAccountGetType (account)))
+ {
+ case ACCT_TYPE_ASSET:
+ heuristics->asset += sign;
+ break;
+ case ACCT_TYPE_LIABILITY:
+ heuristics->liability += sign;
+ break;
+ case ACCT_TYPE_EXPENSE:
+ heuristics->expense += sign;
+ break;
+ case ACCT_TYPE_INCOME:
+ heuristics->income += sign;
+ break;
+ case ACCT_TYPE_EQUITY:
+ heuristics->equity += sign;
+ break;
+ default:
+ break;
+ }
+}
+
+static SignReversals
+heuristics_on_budget (GncBudget * budget, Account *root)
+{
+ ProcessData heuristics = {0, 0, 0, 0, 0, gnc_budget_get_num_periods (budget),
+ budget};
+ SignReversals result;
+
+ gnc_account_foreach_descendant (root, process_heuristics_acct, &heuristics);
+
+ result =
+ heuristics.expense < 0 ? HEURISTICS_INC_EXP :
+ heuristics.liability > 0 ? HEURISTICS_NONE :
+ HEURISTICS_CREDIT_ACC;
+
+ LEAVE ("heuristics_on_budget %s: A(%d) L(%d) Inc(%d) Exp(%d) Eq(%d) = %d",
+ gnc_budget_get_name (budget),
+ heuristics.asset, heuristics.liability, heuristics.income,
+ heuristics.expense, heuristics.equity, result);
+
+ return result;
+}
+
+static void
+fix_budget_acc_sign (Account *acc, gpointer user_data)
+{
+ ReversalType* reversal = (ReversalType*) user_data;
+ GncBudget* budget = reversal->budget;
+ guint numperiods = gnc_budget_get_num_periods (budget);
+ int type = xaccAccountTypeGetFundamental (xaccAccountGetType (acc));
+
+ ENTER ("budget account reversal [%s] starting", xaccAccountGetName(acc));
+
+ switch (reversal->policy)
+ {
+ case HEURISTICS_INC_EXP:
+ if ((type != ACCT_TYPE_INCOME) && (type != ACCT_TYPE_EXPENSE))
+ return;
+ PINFO ("budget account [%s] is inc/exp. reverse!",
+ xaccAccountGetName(acc));
+ break;
+ case HEURISTICS_CREDIT_ACC:
+ if ((type != ACCT_TYPE_LIABILITY) &&
+ (type != ACCT_TYPE_EQUITY) &&
+ (type != ACCT_TYPE_INCOME))
+ return;
+ PINFO ("budget account [%s] is credit-account. reverse!",
+ xaccAccountGetName(acc));
+ break;
+ default:
+ /* shouldn't happen. */
+ return;
+ }
+
+ for (guint i=0; i < numperiods; ++i)
+ {
+ gnc_numeric amt;
+ if (!gnc_budget_is_account_period_value_set (budget, acc, i))
+ continue;
+
+ amt = gnc_budget_get_account_period_value (budget, acc, i);
+ amt = gnc_numeric_neg (amt);
+ gnc_budget_set_account_period_value (budget, acc, i, amt);
+ }
+
+ LEAVE ("budget account reversal [%s] completed!", xaccAccountGetName(acc));
+}
+
+static void
+maybe_scrub_budget (QofInstance* data, gpointer user_data)
+{
+ GncBudget* budget = GNC_BUDGET(data);
+ Account *root = (Account*) user_data;
+ ReversalType reversal;
+
+ reversal.policy = heuristics_on_budget (budget, root);
+ if (reversal.policy == HEURISTICS_NONE)
+ {
+ PWARN ("budget [%s] doesn't need reversing", gnc_budget_get_name (budget));
+ return;
+ }
+
+ reversal.budget = budget;
+
+ ENTER ("processing budget [%s] for reversal", gnc_budget_get_name (budget));
+ gnc_account_foreach_descendant (root, fix_budget_acc_sign, &reversal);
+ LEAVE ("completed budget [%s] for reversal", gnc_budget_get_name (budget));
+}
+
+gboolean
+gnc_maybe_scrub_all_budget_signs (QofBook *book)
+{
+ Account* root = gnc_book_get_root_account (book);
+ gchar *retval = NULL;
+
+ if (gnc_features_check_used (book, GNC_FEATURE_BUDGET_UNREVERSED))
+ return FALSE;
+
+ if (!gnc_budget_get_default (book))
+ return FALSE;
+
+ qof_collection_foreach (qof_book_get_collection (book, GNC_ID_BUDGET),
+ maybe_scrub_budget, root);
+
+ gnc_features_set_used (book, GNC_FEATURE_BUDGET_UNREVERSED);
+ return TRUE;
+}
+/* ==================== END OF FILE ==================== */
diff --git a/libgnucash/engine/ScrubBudget.h b/libgnucash/engine/ScrubBudget.h
new file mode 100644
index 000000000..9efc42b79
--- /dev/null
+++ b/libgnucash/engine/ScrubBudget.h
@@ -0,0 +1,43 @@
+/********************************************************************\
+ * ScrubBudget.h -- fix budget amount signs *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+
+#ifndef _GNC_SCRUBBUDGET_H_
+#define _GNC_SCRUBBUDGET_H_
+
+#include <glib.h>
+#include <qofbook.h>
+
+/* ================================================================ */
+
+/** Fix budget signs
+ * For GnuCash 5.0 onwards - fix budget signs
+ * A feature is set if we have completed reversal.
+ *
+ * @param book The book to scrub
+ *
+ * returns TRUE if budgets were scrubbed
+ * returns FALSE if feature already set, or no budgets.
+ */
+gboolean gnc_maybe_scrub_all_budget_signs (QofBook *book);
+
+
+#endif // _GNC_SCRUBBUDGET_H_
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 52dd27261..da7ec590e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -673,6 +673,7 @@ libgnucash/engine/Recurrence.c
libgnucash/engine/SchedXaction.c
libgnucash/engine/Scrub2.c
libgnucash/engine/Scrub3.c
+libgnucash/engine/ScrubBudget.c
libgnucash/engine/ScrubBusiness.c
libgnucash/engine/Scrub.c
libgnucash/engine/Split.c
commit 99c2c82c98220fd1f95add33b0d1201cbf5191f0
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Sat Mar 6 18:14:25 2021 +0800
[3/3][gnc-plugin-budget.c] set/unset feature creating/deleting budget
If creating budget, and unfeatured, set feature.
If deleting budget, and num(budgets) == 0 afterwards, unset feature
diff --git a/gnucash/gnome/gnc-plugin-budget.c b/gnucash/gnome/gnc-plugin-budget.c
index 6632a8d11..351290195 100644
--- a/gnucash/gnome/gnc-plugin-budget.c
+++ b/gnucash/gnome/gnc-plugin-budget.c
@@ -32,6 +32,7 @@
#include "gnc-tree-model-budget.h"
#include "qof.h"
+#include "gnc-features.h"
#include "gnc-ui-util.h"
#include "gnc-ui.h"
#include "gnc-component-manager.h"
@@ -158,9 +159,17 @@ gnc_plugin_budget_cmd_new_budget (GtkAction *action,
GncBudget *budget;
GncPluginPage *page;
gchar *description, *date;
+ QofBook *book = gnc_get_current_book();
g_return_if_fail (user_data != NULL);
+ if (!gnc_features_check_used (book, GNC_FEATURE_BUDGET_UNREVERSED))
+ {
+ gnc_features_set_used (book, GNC_FEATURE_BUDGET_UNREVERSED);
+ PWARN ("Setting feature BUDGET_UNREVERSED. This book now requires \
+GnuCash 3.8 or later.");
+ }
+
budget = gnc_budget_new (gnc_get_current_book());
page = gnc_plugin_page_budget_new (budget);
@@ -259,6 +268,14 @@ gnc_plugin_budget_cmd_delete_budget (GtkAction *action,
if (!bgt) return;
gnc_budget_gui_delete_budget (bgt);
+
+ if (qof_collection_count (qof_book_get_collection (book, GNC_ID_BUDGET)) == 0)
+ {
+ gnc_features_set_unused (book, GNC_FEATURE_BUDGET_UNREVERSED);
+ PWARN ("Removing feature BUDGET_UNREVERSED. No budgets left.");
+ }
+
+
}
/************************************************************
commit 6070aecd69785c8f51727aea4df1d7c8b5fcc3e3
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Thu Dec 2 22:12:29 2021 +0800
[2/3][gnc-features.c] add & expose gnc_features_set_unused
same as gnc_features_set_used but removes feature
diff --git a/libgnucash/engine/gnc-features.c b/libgnucash/engine/gnc-features.c
index f710677d2..e6622712c 100644
--- a/libgnucash/engine/gnc-features.c
+++ b/libgnucash/engine/gnc-features.c
@@ -152,6 +152,27 @@ void gnc_features_set_used (QofBook *book, const gchar *feature)
qof_book_set_feature (book, feature, description);
}
+
+void gnc_features_set_unused (QofBook *book, const gchar *feature)
+{
+ const gchar *description;
+
+ g_return_if_fail (book);
+ g_return_if_fail (feature);
+
+ gnc_features_init();
+
+ /* Can't unset an unknown feature */
+ description = g_hash_table_lookup (features_table, feature);
+ if (!description)
+ {
+ PWARN("Tried to set unknown feature as unused.");
+ return;
+ }
+
+ qof_book_unset_feature (book, feature, description);
+}
+
struct CheckFeature
{
gchar const * checked_feature;
diff --git a/libgnucash/engine/gnc-features.h b/libgnucash/engine/gnc-features.h
index 030c02531..b5960ac7a 100644
--- a/libgnucash/engine/gnc-features.h
+++ b/libgnucash/engine/gnc-features.h
@@ -67,6 +67,13 @@ extern "C" {
*/
gchar *gnc_features_test_unknown (QofBook *book);
+/**
+ * Indicate that the current book does not use the given feature. This
+ * will allow older versions of GnuCash that don't support this
+ * feature to load this book.
+ */
+void gnc_features_set_unused (QofBook *book, const gchar *feature);
+
/**
* Indicate that the current book uses the given feature. This will prevent
* older versions of GnuCash that don't support this feature to refuse to load
commit 5dab33694fbbe82f4aa46ad148584ec105385372
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Thu Dec 2 22:12:12 2021 +0800
[1/3][qofbook.cpp] add & expose qof_book_unset_feature
same as qof_book_set_feature but removes feature item
diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index ab2b01231..1cbc673eb 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -1255,6 +1255,27 @@ qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr)
}
}
+
+void
+qof_book_unset_feature (QofBook *book, const gchar *key, const gchar *descr)
+{
+ KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
+ KvpValue* feature = nullptr;
+ auto feature_slot = frame->get_slot({GNC_FEATURES});
+ if (feature_slot)
+ {
+ auto feature_frame = feature_slot->get<KvpFrame*>();
+ feature = feature_frame->get_slot({key});
+ }
+ if (feature == nullptr || g_strcmp0 (feature->get<const char*>(), descr))
+ {
+ qof_book_begin_edit (book);
+ delete frame->set_path({GNC_FEATURES, key}, nullptr);
+ qof_instance_set_dirty (QOF_INSTANCE (book));
+ qof_book_commit_edit (book);
+ }
+}
+
void
qof_book_load_options (QofBook *book, GNCOptionLoad load_cb, GNCOptionDB *odb)
{
diff --git a/libgnucash/engine/qofbook.h b/libgnucash/engine/qofbook.h
index f48ed9400..a26229938 100644
--- a/libgnucash/engine/qofbook.h
+++ b/libgnucash/engine/qofbook.h
@@ -382,6 +382,7 @@ void qof_book_option_frame_delete (QofBook *book, const char* opt_name);
/** Access functions for reading and setting the used-features on this book.
*/
GHashTable *qof_book_get_features (QofBook *book);
+void qof_book_unset_feature (QofBook *book, const gchar *key, const gchar *descr);
void qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr);
void qof_book_begin_edit(QofBook *book);
Summary of changes:
gnucash/gnome-utils/gnc-file.c | 26 ++-
gnucash/gnome/gnc-budget-view.c | 97 +++-------
gnucash/gnome/gnc-plugin-budget.c | 17 ++
gnucash/gnome/gnc-plugin-page-budget.c | 9 +-
.../reports/standard/budget-balance-sheet.scm | 2 +-
.../reports/standard/budget-income-statement.scm | 2 +-
gnucash/report/reports/standard/budget.scm | 43 +----
.../report/reports/standard/test/test-budget.scm | 4 +-
libgnucash/app-utils/app-utils.i | 2 -
libgnucash/app-utils/gnc-ui-util.c | 17 --
libgnucash/app-utils/gnc-ui-util.h | 10 -
libgnucash/engine/CMakeLists.txt | 2 +
libgnucash/engine/ScrubBudget.c | 211 +++++++++++++++++++++
.../engine/ScrubBudget.h | 42 ++--
libgnucash/engine/gnc-features.c | 21 ++
libgnucash/engine/gnc-features.h | 7 +
libgnucash/engine/qofbook.cpp | 21 ++
libgnucash/engine/qofbook.h | 1 +
po/POTFILES.in | 1 +
19 files changed, 355 insertions(+), 180 deletions(-)
create mode 100644 libgnucash/engine/ScrubBudget.c
copy gnucash/register/register-core/table-control.c => libgnucash/engine/ScrubBudget.h (71%)
More information about the gnucash-changes
mailing list