GnuCash c935c2f+
Loading...
Searching...
No Matches
ScrubBudget.c
1/********************************************************************\
2 * ScrubBudget.c -- fix budget amount signs *
3 * Copyright (c) 2020 Christoher Lam *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation; either version 2 of *
8 * the License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License*
16 * along with this program; if not, contact: *
17 * *
18 * Free Software Foundation Voice: +1-617-542-5942 *
19 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20 * Boston, MA 02110-1301, USA gnu@gnu.org *
21 * *
22\********************************************************************/
23
24#include <config.h>
25
26#include <glib.h>
27#include <glib/gi18n.h>
28#include <stdio.h>
29#include <string.h>
30#include <stdint.h>
31
32#include "gnc-prefs.h"
33#include "gnc-budget.h"
34#include "gnc-features.h"
35#include "ScrubBudget.h"
36
37static QofLogModule log_module = "gnc.engine.scrub";
38
39typedef enum
40{
41 HEURISTICS_INC_EXP,
42 HEURISTICS_CREDIT_ACC,
43 HEURISTICS_NONE
44} SignReversals;
45
46typedef struct
47{
48 GncBudget* budget;
49 SignReversals policy;
51
52typedef struct
53{
54 gint asset,liability,equity,income,expense;
55 gint num_periods;
56 GncBudget* budget;
58
59static void
60process_heuristics_acct (Account * account, gpointer user_data)
61{
62 /* each account- check type. sum budget period amounts. if sum<0,
63 decrease type tally by 1. if sum>0, increase type tally by 1. */
64 ProcessData *heuristics = (ProcessData*) user_data;
65 gnc_numeric total = gnc_numeric_zero(), val;
66 gint sign;
67 gchar *totalstr;
68
69 for (gint i = 0; i < heuristics->num_periods; ++i)
70 {
71 if (!gnc_budget_is_account_period_value_set (heuristics->budget, account, i))
72 continue;
73 val = gnc_budget_get_account_period_value (heuristics->budget, account, i);
74 total = gnc_numeric_add_fixed (total, val);
75 }
76
77 sign = gnc_numeric_compare (total, gnc_numeric_zero ());
78 totalstr = gnc_numeric_to_string (total);
79 PINFO ("acct=%s, total=%s, sign=%d",
80 xaccAccountGetName (account), totalstr, sign);
81 g_free (totalstr);
82
84 {
85 case ACCT_TYPE_ASSET:
86 heuristics->asset += sign;
87 break;
89 heuristics->liability += sign;
90 break;
92 heuristics->expense += sign;
93 break;
95 heuristics->income += sign;
96 break;
98 heuristics->equity += sign;
99 break;
100 default:
101 break;
102 }
103}
104
105static SignReversals
106heuristics_on_budget (GncBudget * budget, Account *root)
107{
108 ProcessData heuristics = {0, 0, 0, 0, 0, gnc_budget_get_num_periods (budget),
109 budget};
110 SignReversals result;
111
112 gnc_account_foreach_descendant (root, process_heuristics_acct, &heuristics);
113
114 result =
115 heuristics.expense < 0 ? HEURISTICS_INC_EXP :
116 heuristics.income < 0 ? HEURISTICS_NONE :
117 HEURISTICS_CREDIT_ACC;
118
119 LEAVE ("heuristics_on_budget %s: A(%d) L(%d) Inc(%d) Exp(%d) Eq(%d) = %d",
120 gnc_budget_get_name (budget),
121 heuristics.asset, heuristics.liability, heuristics.income,
122 heuristics.expense, heuristics.equity, result);
123
124 return result;
125}
126
127static void
128fix_budget_acc_sign (Account *acc, gpointer user_data)
129{
130 ReversalType* reversal = (ReversalType*) user_data;
131 GncBudget* budget = reversal->budget;
132 guint numperiods = gnc_budget_get_num_periods (budget);
134
135 ENTER ("budget account reversal [%s] starting", xaccAccountGetName(acc));
136
137 switch (reversal->policy)
138 {
139 case HEURISTICS_INC_EXP:
140 if ((type != ACCT_TYPE_INCOME) && (type != ACCT_TYPE_EXPENSE))
141 return;
142 PINFO ("budget account [%s] is inc/exp. reverse!",
143 xaccAccountGetName(acc));
144 break;
145 case HEURISTICS_CREDIT_ACC:
146 if ((type != ACCT_TYPE_LIABILITY) &&
147 (type != ACCT_TYPE_EQUITY) &&
148 (type != ACCT_TYPE_INCOME))
149 return;
150 PINFO ("budget account [%s] is credit-account. reverse!",
151 xaccAccountGetName(acc));
152 break;
153 default:
154 /* shouldn't happen. */
155 return;
156 }
157
158 for (guint i=0; i < numperiods; ++i)
159 {
160 gnc_numeric amt;
161 if (!gnc_budget_is_account_period_value_set (budget, acc, i))
162 continue;
163
164 amt = gnc_budget_get_account_period_value (budget, acc, i);
165 amt = gnc_numeric_neg (amt);
166 gnc_budget_set_account_period_value (budget, acc, i, amt);
167 }
168
169 LEAVE ("budget account reversal [%s] completed!", xaccAccountGetName(acc));
170}
171
172static void
173maybe_scrub_budget (QofInstance* data, gpointer user_data)
174{
175 GncBudget* budget = GNC_BUDGET(data);
176 Account *root = (Account*) user_data;
177 ReversalType reversal;
178
179 reversal.policy = heuristics_on_budget (budget, root);
180 if (reversal.policy == HEURISTICS_NONE)
181 {
182 PWARN ("budget [%s] doesn't need reversing", gnc_budget_get_name (budget));
183 return;
184 }
185
186 reversal.budget = budget;
187
188 ENTER ("processing budget [%s] for reversal", gnc_budget_get_name (budget));
189 gnc_account_foreach_descendant (root, fix_budget_acc_sign, &reversal);
190 LEAVE ("completed budget [%s] for reversal", gnc_budget_get_name (budget));
191}
192
193gboolean
194gnc_maybe_scrub_all_budget_signs (QofBook *book)
195{
196 QofCollection* collection = qof_book_get_collection (book, GNC_ID_BUDGET);
197 gboolean has_no_budgets = (qof_collection_count (collection) == 0);
198 gboolean featured = gnc_features_check_used (book, GNC_FEATURE_BUDGET_UNREVERSED);
199
200 /* If there are no budgets, there shouldn't be feature! */
201 if (has_no_budgets && featured)
202 {
203 gnc_features_set_unused (book, GNC_FEATURE_BUDGET_UNREVERSED);
204 PWARN ("There are no budgets, removing feature BUDGET_UNREVERSED");
205 }
206
207 if (has_no_budgets || featured)
208 return FALSE;
209
210 /* There are budgets and feature is not set. Scrub, and set
211 feature. Return TRUE to show budget fix warning. */
212 qof_collection_foreach (collection, maybe_scrub_budget,
213 gnc_book_get_root_account (book));
214 gnc_features_set_used (book, GNC_FEATURE_BUDGET_UNREVERSED);
215 return TRUE;
216}
217/* ==================== END OF FILE ==================== */
GnuCash Budgets.
Utility functions for file access.
Generic api to store and retrieve preferences.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
Definition Account.cpp:3289
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3267
@ ACCT_TYPE_INCOME
Income accounts are used to denote income.
Definition Account.h:140
@ ACCT_TYPE_EXPENSE
Expense accounts are used to denote expenses.
Definition Account.h:143
@ ACCT_TYPE_ASSET
asset (and liability) accounts indicate generic, generalized accounts that are none of the above.
Definition Account.h:116
@ ACCT_TYPE_LIABILITY
liability (and asset) accounts indicate generic, generalized accounts that are none of the above.
Definition Account.h:119
@ ACCT_TYPE_EQUITY
Equity account is used to balance the balance sheet.
Definition Account.h:146
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition qofbook.cpp:521
GNCAccountType xaccAccountTypeGetFundamental(GNCAccountType t)
Convenience function to return the fundamental type asset/liability/income/expense/equity given an ac...
Definition Account.cpp:4495
guint qof_collection_count(const QofCollection *col)
return the number of entities in the collection.
Definition qofid.cpp:221
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
void gnc_features_set_unused(QofBook *book, const gchar *feature)
Indicate that the current book does not use the given feature.
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
STRUCTS.
QofBook reference.
Definition qofbook-p.hpp:47