GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-ui-balances.cpp
1/********************************************************************\
2 * gnc-ui-balances.c -- utility functions for calculating *
3 * account and owner balances used in the *
4 * the GnuCash UI *
5 * Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
6 * Copyright (C) 2011 Geert Janssens <geert@kobaltwit.be> *
7 * *
8 * This program is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License as *
10 * published by the Free Software Foundation; either version 2 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License*
19 * along with this program; if not, contact: *
20 * *
21 * Free Software Foundation Voice: +1-617-542-5942 *
22 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23 * Boston, MA 02110-1301, USA gnu@gnu.org *
24\********************************************************************/
25
26#include <config.h>
27
28#include "gnc-ui-balances.h"
29#include "gnc-ui-util.h"
30
31#include <glib.h>
32#include <glib/gi18n.h>
33
34#include "Account.h"
35#include "Split.h"
36#include "gncOwner.h"
37#include "qof.h"
38
39G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_GUI;
40
41/********************************************************************
42 * Balance calculations related to accounts
43 ********************************************************************/
44
45/*
46 * This is a wrapper routine around an xaccGetBalanceInCurrency
47 * function that handles additional needs of the gui.
48 *
49 * @param fn The underlying function in Account.c to call to retrieve
50 * a specific balance from the account.
51 * @param account The account to retrieve data about.
52 * @param recurse Include all sub-accounts of this account.
53 * @param negative An indication of whether or not the returned value
54 * is negative. This can be used by the caller to
55 * easily decode whether or not to color the output.
56 * @param commodity The commodity in which the account balance should
57 * be returned. If NULL, the value will be returned in
58 * the commodity of the account. This is normally used
59 * to specify a currency, which forces the conversion
60 * of things like stock account values from share
61 * values to an amount the requested currency.
62 */
63gnc_numeric
64gnc_ui_account_get_balance_full (xaccGetBalanceInCurrencyFn fn,
65 const Account *account,
66 gboolean recurse,
67 gboolean *negative,
68 const gnc_commodity *commodity)
69{
70 gnc_numeric balance;
71
72 balance = fn(account, commodity, recurse);
73
74 /* reverse sign if needed */
75 if (gnc_reverse_balance (account))
76 balance = gnc_numeric_neg (balance);
77
78 /* Record whether the balance is negative. */
79 if (negative)
80 *negative = gnc_numeric_negative_p(balance);
81
82 return balance;
83}
84
85/*
86 * This routine retrieves the total balance in an account, possibly
87 * including all sub-accounts under the specified account.
88 */
89gnc_numeric
90gnc_ui_account_get_balance (const Account *account, gboolean recurse)
91{
92 return gnc_ui_account_get_balance_full (xaccAccountGetBalanceInCurrency,
93 account, recurse, NULL, NULL);
94}
95
96/*
97 * This routine retrieves the total balance in an account converted to
98 * a given currency, possibly including all sub-accounts under the
99 * specified account.
100 *
101gnc_numeric
102gnc_ui_account_get_balance_in_currency (const Account *account,
103 const gnc_commodity *currency,
104 gboolean recurse)
105{
106 return gnc_ui_account_get_balance_full (xaccAccountGetBalanceInCurrency,
107 account, recurse, NULL, currency);
108}
109*/
110/*
111 * This routine retrieves the reconciled balance in an account,
112 * possibly including all sub-accounts under the specified account.
113 */
114gnc_numeric
115gnc_ui_account_get_reconciled_balance (const Account *account,
116 gboolean recurse)
117{
118 return gnc_ui_account_get_balance_full (xaccAccountGetReconciledBalanceInCurrency,
119 account, recurse, NULL, NULL);
120}
121
122
137gchar *
138gnc_ui_account_get_print_balance (xaccGetBalanceInCurrencyFn fn,
139 const Account *account,
140 gboolean recurse,
141 gboolean *negative)
142{
143 GNCPrintAmountInfo print_info;
144 gnc_numeric balance;
145
146 balance = gnc_ui_account_get_balance_full(fn, account, recurse,
147 negative, NULL);
148 print_info = gnc_account_print_info(account, TRUE);
149
150 return g_strdup (gnc_print_amount_with_bidi_ltr_isolate (balance, print_info));
151}
152
153
168gchar *
169gnc_ui_account_get_print_report_balance (xaccGetBalanceInCurrencyFn fn,
170 const Account *account,
171 gboolean recurse,
172 gboolean *negative)
173{
174 GNCPrintAmountInfo print_info;
175 gnc_numeric balance;
176 gnc_commodity *report_commodity;
177
178 report_commodity = gnc_default_report_currency();
179 balance = gnc_ui_account_get_balance_full(fn, account, recurse,
180 negative, report_commodity);
181 print_info = gnc_commodity_print_info(report_commodity, TRUE);
182
183 return g_strdup (gnc_print_amount_with_bidi_ltr_isolate (balance, print_info));
184}
185
186static gnc_numeric
187account_get_balance_as_of_date (Account *account,
188 time64 date,
189 gboolean include_children,
190 xaccGetBalanceAsOfDateFn fn)
191{
192 QofBook *book = gnc_account_get_book (account);
193 GNCPriceDB *pdb = gnc_pricedb_get_db (book);
194 gnc_numeric balance;
195 gnc_commodity *currency;
196
197 if (account == NULL)
198 return gnc_numeric_zero ();
199
200 currency = xaccAccountGetCommodity (account);
201 balance = fn (account, date);
202
203 if (include_children)
204 {
205 GList *children, *node;
206
207 children = gnc_account_get_descendants(account);
208
209 for (node = children; node; node = node->next)
210 {
211 Account *child;
212 gnc_commodity *child_currency;
213 gnc_numeric child_balance;
214
215 child = static_cast<Account*>(node->data);
216 child_currency = xaccAccountGetCommodity (child);
217 child_balance = fn (child, date);
218 child_balance =
220 child_currency,
221 currency);
222 balance = gnc_numeric_add_fixed (balance, child_balance);
223 }
224
225 g_list_free(children);
226 }
227
228 /* reverse sign if needed */
229 if (gnc_reverse_balance (account))
230 balance = gnc_numeric_neg (balance);
231
232 return balance;
233}
234
235gnc_numeric
236gnc_ui_account_get_balance_as_of_date (Account *account,
237 time64 date,
238 gboolean include_children)
239{
240 return account_get_balance_as_of_date (account, date, include_children,
242}
243
244gnc_numeric
245gnc_ui_account_get_reconciled_balance_as_of_date (Account *account,
246 time64 date,
247 gboolean include_children)
248{
249 return account_get_balance_as_of_date (account, date, include_children,
251}
252
253// retrieve account's balance to compare against the limit.
254// we use today's date because account may have future dated splits
255static gnc_numeric
256account_balance_for_limit (const Account *account)
257{
258 return gnc_ui_account_get_balance_as_of_date
259 ((Account*)account, gnc_time64_get_day_end (gnc_time (NULL)),
261}
262
263static gint
264account_balance_limit_reached (const Account *account, gnc_numeric balance_limit)
265{
266 gnc_numeric balance = account_balance_for_limit (account);
267
268 if (gnc_numeric_zero_p (balance))
269 return 0;
270
271 if (gnc_reverse_balance (account))
272 balance_limit = gnc_numeric_neg (balance_limit);
273
274 // Returns 1 if a>b, -1 if b>a, 0 if a == b
275 return gnc_numeric_compare (balance, balance_limit);
276}
277
278static gboolean
279get_limit_info (const Account *account, gnc_numeric *limit, gboolean higher)
280{
281 gboolean reverse = gnc_reverse_balance (account);
282 if ((higher && reverse) || (!higher && !reverse))
283 return xaccAccountGetLowerBalanceLimit (account, limit);
284 else
285 return xaccAccountGetHigherBalanceLimit (account, limit);
286}
287
288gboolean
289gnc_ui_account_is_higher_balance_limit_reached (const Account *account,
290 gboolean *is_zero)
291{
292 gnc_numeric balance_limit;
293 gboolean limit_valid = FALSE;
294 gboolean retval = FALSE;
295
296 g_return_val_if_fail (GNC_IS_ACCOUNT(account), FALSE);
297
298 limit_valid = get_limit_info (account, &balance_limit, TRUE);
299
300 if (!limit_valid)
301 return retval;
302
303 if (gnc_numeric_zero_p (balance_limit))
304 *is_zero = TRUE;
305
306 if (account_balance_limit_reached (account, balance_limit) == 1)
307 retval = TRUE;
308
309 return retval;
310}
311
312gboolean
313gnc_ui_account_is_lower_balance_limit_reached (const Account *account,
314 gboolean *is_zero)
315{
316 gnc_numeric balance_limit;
317 gboolean limit_valid = FALSE;
318 gboolean retval = FALSE;
319
320 g_return_val_if_fail (GNC_IS_ACCOUNT(account), FALSE);
321
322 limit_valid = get_limit_info (account, &balance_limit, FALSE);
323
324 if (!limit_valid)
325 return retval;
326
327 if (gnc_numeric_zero_p (balance_limit))
328 *is_zero = TRUE;
329
330 if (account_balance_limit_reached (account, balance_limit) == -1)
331 retval = TRUE;
332
333 return retval;
334}
335
336static gchar *
337make_limit_explanation (const Account *account, const char* template_str,
338 gboolean zero, gboolean higher)
339{
340 gnc_commodity *currency = xaccAccountGetCommodity (account);
341 GNCPrintAmountInfo pinfo = gnc_commodity_print_info (currency, TRUE);
342 gnc_numeric acct_bal = account_balance_for_limit (account);
343 char *fullname = gnc_account_get_full_name (account);
344 char *bal_str = g_strdup (xaccPrintAmount (acct_bal, pinfo));
345 char *rv;
346 if (zero)
347 rv = g_strdup_printf (_(template_str), fullname, bal_str);
348 else
349 {
350 gnc_numeric limit;
351 get_limit_info (account, &limit, higher);
352 if (gnc_reverse_balance (account))
353 limit = gnc_numeric_neg (limit);
354 char *lim_str = g_strdup (xaccPrintAmount (limit, pinfo));
355 rv = g_strdup_printf (_(template_str), fullname, bal_str, lim_str);
356 g_free (lim_str);
357 }
358 g_free (bal_str);
359 g_free (fullname);
360 return rv;
361}
362
363static gchar *
364get_balance_limit_info (const Account *account, gboolean icon)
365{
366 gboolean lower_limit_reached, higher_limit_reached;
367 gboolean lower_is_zero = FALSE;
368 gboolean higher_is_zero = FALSE;
369 const char *higher_template = N_("%s balance of %s is above the upper limit %s.");
370 const char *lower_template = N_("%s balance of %s is below the lower limit %s.");
371 const char *zero_template = N_("%s balance of %s should be zero.");
372
373 g_return_val_if_fail (GNC_IS_ACCOUNT(account), NULL);
374
375 higher_limit_reached = gnc_ui_account_is_higher_balance_limit_reached (account, &higher_is_zero);
376
377 // assume the higher value will be set mostly so test that first
378 if (higher_limit_reached && !higher_is_zero)
379 return icon ? g_strdup ("go-top") : make_limit_explanation (account, higher_template, FALSE, TRUE);
380
381 lower_limit_reached = gnc_ui_account_is_lower_balance_limit_reached (account, &lower_is_zero);
382
383 if (lower_limit_reached && (!lower_is_zero || !higher_is_zero))
384 return icon ? g_strdup ("go-bottom") : make_limit_explanation (account, lower_template, FALSE, FALSE);
385
386 if (higher_limit_reached && !lower_is_zero)
387 return icon ? g_strdup ("go-top") : make_limit_explanation (account, higher_template, FALSE, TRUE);
388
389 if ((lower_limit_reached || higher_limit_reached ) && lower_is_zero && higher_is_zero)
390 return icon ? g_strdup ("dialog-warning") : make_limit_explanation (account, zero_template, TRUE, FALSE);
391
392 return NULL;
393}
394
395gchar *
396gnc_ui_account_get_balance_limit_icon_name (const Account *account)
397{
398 char *icon = get_balance_limit_info (account, TRUE);
399 return icon ? icon : g_strdup ("");
400}
401
402gchar *
403gnc_ui_account_get_balance_limit_explanation (const Account *account)
404{
405 return get_balance_limit_info (account, FALSE);
406}
407
408/********************************************************************
409 * Balance calculations related to owners
410 ********************************************************************/
411
412/*
413 * This is a wrapper routine around an gncOwnerGetBalanceInCurrency
414 * function that handles additional needs of the gui.
415 *
416 * @param owner The owner to retrieve data about.
417 * @param negative An indication of whether or not the returned value
418 * is negative. This can be used by the caller to
419 * easily decode whether or not to color the output.
420 * @param commodity The commodity in which the account balance should
421 * be returned. If NULL, the value will be returned in
422 * the commodity of the owner. This is normally used
423 * to specify a currency, which forces the conversion
424 * of things like stock account values from share
425 * values to an amount the requested currency.
426 */
427gnc_numeric
428gnc_ui_owner_get_balance_full (GncOwner *owner,
429 gboolean *negative,
430 const gnc_commodity *commodity)
431{
432 gnc_numeric balance;
433
434 if (!owner)
435 return gnc_numeric_zero ();
436
437 balance = gncOwnerGetBalanceInCurrency (owner, commodity);
438
439 /* reverse sign if needed */
440 if ((gncOwnerGetType (owner) != GNC_OWNER_CUSTOMER))
441 balance = gnc_numeric_neg (balance);
442
443 /* Record whether the balance is negative. */
444 if (negative)
445 *negative = gnc_numeric_negative_p (balance);
446
447 return balance;
448}
449
450
462gchar *
463gnc_ui_owner_get_print_balance (GncOwner *owner,
464 gboolean *negative)
465{
466 gnc_numeric balance;
467 GNCPrintAmountInfo print_info;
468
469 balance = gnc_ui_owner_get_balance_full (owner, negative, NULL);
470 print_info = gnc_commodity_print_info (gncOwnerGetCurrency (owner), TRUE);
471
472 return g_strdup (gnc_print_amount_with_bidi_ltr_isolate (balance, print_info));
473}
474
486gchar *
487gnc_ui_owner_get_print_report_balance (GncOwner *owner,
488 gboolean *negative)
489{
490 GNCPrintAmountInfo print_info;
491 gnc_numeric balance;
492 gnc_commodity *report_commodity;
493
494 report_commodity = gnc_default_report_currency ();
495 balance = gnc_ui_owner_get_balance_full (owner, negative,
496 report_commodity);
497 print_info = gnc_commodity_print_info (report_commodity, TRUE);
498
499 return g_strdup (gnc_print_amount_with_bidi_ltr_isolate (balance, print_info));
500}
501
Account handling public routines.
API for Transactions and Splits (journal entries)
utility functions for the GnuCash UI
Business Interface: Object OWNERs.
gnc_numeric xaccAccountGetReconciledBalanceAsOfDate(Account *acc, time64 date)
Get the reconciled balance of the account at the end of the day of the date specified.
Definition Account.cpp:3545
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition Account.cpp:3305
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition Account.cpp:3044
gnc_numeric xaccAccountGetBalanceAsOfDate(Account *acc, time64 date)
Get the balance of the account at the end of the day before the date specified.
Definition Account.cpp:3533
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gnc_time64_get_day_end(time64 time_val)
The gnc_time64_get_day_end() routine will take the given time in seconds and adjust it to the last se...
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
gboolean xaccAccountGetLowerBalanceLimit(const Account *acc, gnc_numeric *balance)
Get the lower balance limit for the account.
Definition Account.cpp:4726
gboolean xaccAccountGetHigherBalanceLimit(const Account *acc, gnc_numeric *balance)
Get the higher balance limit for the account.
Definition Account.cpp:4719
gboolean xaccAccountGetIncludeSubAccountBalances(const Account *acc)
Get whether to include balances of sub accounts.
Definition Account.cpp:4757
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
const char * gnc_print_amount_with_bidi_ltr_isolate(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
gnc_commodity * gnc_default_report_currency(void)
Return the default currency for use in reports, as set by the user.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
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.
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition gncOwner.c:200
gnc_numeric gncOwnerGetBalanceInCurrency(const GncOwner *owner, const gnc_commodity *report_currency)
Given an owner, extract the open balance from the owner and then convert it to the desired currency.
Definition gncOwner.c:1478
gnc_numeric gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb, gnc_numeric balance, const gnc_commodity *balance_currency, const gnc_commodity *new_currency)
Convert a balance from one currency to another using the most recent price between the two.
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
STRUCTS.
QofBook reference.
Definition qofbook-p.hpp:47