mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-22 08:57:17 -06:00
[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.
This commit is contained in:
parent
99c2c82c98
commit
73822f97a9
@ -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
|
||||
|
211
libgnucash/engine/ScrubBudget.c
Normal file
211
libgnucash/engine/ScrubBudget.c
Normal file
@ -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@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 ==================== */
|
43
libgnucash/engine/ScrubBudget.h
Normal file
43
libgnucash/engine/ScrubBudget.h
Normal file
@ -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@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_
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user