LCOV - code coverage report
Current view: top level - libgnucash/app-utils - gnc-ui-balances.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 0.0 % 144 0
Test Date: 2026-11-02 18:19:43 Functions: 0.0 % 20 0
Legend: Lines:     hit not hit

            Line data    Source code
       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              : 
      39              : G_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              :  */
      63              : gnc_numeric
      64            0 : gnc_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            0 :     balance = fn(account, commodity, recurse);
      73              : 
      74              :     /* reverse sign if needed */
      75            0 :     if (gnc_reverse_balance (account))
      76            0 :         balance = gnc_numeric_neg (balance);
      77              : 
      78              :     /* Record whether the balance is negative. */
      79            0 :     if (negative)
      80            0 :         *negative = gnc_numeric_negative_p(balance);
      81              : 
      82            0 :     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              :  */
      89              : gnc_numeric
      90            0 : gnc_ui_account_get_balance (const Account *account, gboolean recurse)
      91              : {
      92            0 :     return gnc_ui_account_get_balance_full (xaccAccountGetBalanceInCurrency,
      93            0 :                                             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              :  *
     101              : gnc_numeric
     102              : gnc_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              :  */
     114              : gnc_numeric
     115            0 : gnc_ui_account_get_reconciled_balance (const Account *account,
     116              :                                        gboolean recurse)
     117              : {
     118            0 :     return gnc_ui_account_get_balance_full (xaccAccountGetReconciledBalanceInCurrency,
     119            0 :                                             account, recurse, NULL, NULL);
     120              : }
     121              : 
     122              : 
     123              : /**
     124              :  * Wrapper around gnc_ui_account_get_balance_full that converts
     125              :  * the resulting number to a character string.  The number is
     126              :  * formatted according to the specification of the account currency.
     127              :  * The caller is responsible for g_free'ing the returned memory.
     128              :  *
     129              :  * @param fn        The underlying function in Account.c to call to retrieve
     130              :  *                  a specific balance from the account.
     131              :  * @param account   The account to retrieve data about.
     132              :  * @param recurse   Include all sub-accounts of this account.
     133              :  * @param negative  An indication of whether or not the returned value
     134              :  *                  is negative.  This can be used by the caller to
     135              :  *                  easily decode whether or not to color the output.
     136              :  */
     137              : gchar *
     138            0 : gnc_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            0 :     balance = gnc_ui_account_get_balance_full(fn, account, recurse,
     147              :               negative, NULL);
     148            0 :     print_info = gnc_account_print_info(account, TRUE);
     149              : 
     150            0 :     return g_strdup (gnc_print_amount_with_bidi_ltr_isolate (balance, print_info));
     151              : }
     152              : 
     153              : 
     154              : /**
     155              :  * Wrapper around gnc_ui_account_get_balance_full that converts
     156              :  * the resulting number to a character string.  The number is
     157              :  * formatted according to the specification of the default reporting
     158              :  * currency.
     159              :  *
     160              :  * @param fn        The underlying function in Account.c to call to retrieve
     161              :  *                  a specific balance from the account.
     162              :  * @param account   The account to retrieve data about.
     163              :  * @param recurse   Include all sub-accounts of this account.
     164              :  * @param negative  An indication of whether or not the returned value
     165              :  *                  is negative.  This can be used by the caller to
     166              :  *                  easily decode whether or not to color the output.
     167              :  */
     168              : gchar *
     169            0 : gnc_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            0 :     report_commodity = gnc_default_report_currency();
     179            0 :     balance = gnc_ui_account_get_balance_full(fn, account, recurse,
     180              :               negative, report_commodity);
     181            0 :     print_info = gnc_commodity_print_info(report_commodity, TRUE);
     182              : 
     183            0 :     return g_strdup (gnc_print_amount_with_bidi_ltr_isolate (balance, print_info));
     184              : }
     185              : 
     186              : static gnc_numeric
     187            0 : account_get_balance_as_of_date (Account *account,
     188              :                                 time64 date,
     189              :                                 gboolean include_children,
     190              :                                 xaccGetBalanceAsOfDateFn fn)
     191              : {
     192            0 :     QofBook *book = gnc_account_get_book (account);
     193            0 :     GNCPriceDB *pdb = gnc_pricedb_get_db (book);
     194              :     gnc_numeric balance;
     195              :     gnc_commodity *currency;
     196              : 
     197            0 :     if (account == NULL)
     198            0 :         return gnc_numeric_zero ();
     199              : 
     200            0 :     currency = xaccAccountGetCommodity (account);
     201            0 :     balance = fn (account, date);
     202              : 
     203            0 :     if (include_children)
     204              :     {
     205              :         GList *children, *node;
     206              : 
     207            0 :         children = gnc_account_get_descendants(account);
     208              : 
     209            0 :         for (node = children; node; node = node->next)
     210              :         {
     211              :             Account *child;
     212              :             gnc_commodity *child_currency;
     213              :             gnc_numeric child_balance;
     214              : 
     215            0 :             child = static_cast<Account*>(node->data);
     216            0 :             child_currency = xaccAccountGetCommodity (child);
     217            0 :             child_balance = fn (child, date);
     218              :             child_balance =
     219            0 :                 gnc_pricedb_convert_balance_latest_price (pdb, child_balance,
     220              :                                                           child_currency,
     221              :                                                           currency);
     222            0 :             balance = gnc_numeric_add_fixed (balance, child_balance);
     223              :         }
     224              : 
     225            0 :         g_list_free(children);
     226              :     }
     227              : 
     228              :     /* reverse sign if needed */
     229            0 :     if (gnc_reverse_balance (account))
     230            0 :         balance = gnc_numeric_neg (balance);
     231              : 
     232            0 :     return balance;
     233              : }
     234              : 
     235              : gnc_numeric
     236            0 : gnc_ui_account_get_balance_as_of_date (Account *account,
     237              :                                        time64 date,
     238              :                                        gboolean include_children)
     239              : {
     240            0 :     return account_get_balance_as_of_date (account, date, include_children,
     241            0 :                                            xaccAccountGetBalanceAsOfDate);
     242              : }
     243              : 
     244              : gnc_numeric
     245            0 : gnc_ui_account_get_reconciled_balance_as_of_date (Account *account,
     246              :                                                   time64 date,
     247              :                                                   gboolean include_children)
     248              : {
     249            0 :     return account_get_balance_as_of_date (account, date, include_children,
     250            0 :                                            xaccAccountGetReconciledBalanceAsOfDate);
     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
     255              : static gnc_numeric
     256            0 : account_balance_for_limit (const Account *account)
     257              : {
     258              :     return gnc_ui_account_get_balance_as_of_date
     259            0 :         ((Account*)account, gnc_time64_get_day_end (gnc_time (NULL)),
     260            0 :          xaccAccountGetIncludeSubAccountBalances (account));
     261              : }
     262              : 
     263              : static gint
     264            0 : account_balance_limit_reached (const Account *account, gnc_numeric balance_limit)
     265              : {
     266            0 :     gnc_numeric balance = account_balance_for_limit (account);
     267              : 
     268            0 :     if (gnc_numeric_zero_p (balance))
     269            0 :         return 0;
     270              : 
     271            0 :     if (gnc_reverse_balance (account))
     272            0 :         balance_limit = gnc_numeric_neg (balance_limit);
     273              : 
     274              :     // Returns 1 if a>b, -1 if b>a, 0 if a == b
     275            0 :     return gnc_numeric_compare (balance, balance_limit);
     276              : }
     277              : 
     278              : static gboolean
     279            0 : get_limit_info (const Account *account, gnc_numeric *limit, gboolean higher)
     280              : {
     281            0 :     gboolean reverse = gnc_reverse_balance (account);
     282            0 :     if ((higher && reverse) || (!higher && !reverse))
     283            0 :         return xaccAccountGetLowerBalanceLimit (account, limit);
     284              :     else
     285            0 :         return xaccAccountGetHigherBalanceLimit (account, limit);
     286              : }
     287              : 
     288              : gboolean
     289            0 : gnc_ui_account_is_higher_balance_limit_reached (const Account *account,
     290              :                                                 gboolean *is_zero)
     291              : {
     292              :     gnc_numeric balance_limit;
     293            0 :     gboolean limit_valid = FALSE;
     294            0 :     gboolean retval = FALSE;
     295              : 
     296            0 :     g_return_val_if_fail (GNC_IS_ACCOUNT(account), FALSE);
     297              : 
     298            0 :     limit_valid = get_limit_info (account, &balance_limit, TRUE);
     299              : 
     300            0 :     if (!limit_valid)
     301            0 :         return retval;
     302              : 
     303            0 :     if (gnc_numeric_zero_p (balance_limit))
     304            0 :         *is_zero = TRUE;
     305              : 
     306            0 :     if (account_balance_limit_reached (account, balance_limit) == 1)
     307            0 :         retval = TRUE;
     308              : 
     309            0 :     return retval;
     310              : }
     311              : 
     312              : gboolean
     313            0 : gnc_ui_account_is_lower_balance_limit_reached (const Account *account,
     314              :                                                gboolean *is_zero)
     315              : {
     316              :     gnc_numeric balance_limit;
     317            0 :     gboolean limit_valid = FALSE;
     318            0 :     gboolean retval = FALSE;
     319              : 
     320            0 :     g_return_val_if_fail (GNC_IS_ACCOUNT(account), FALSE);
     321              : 
     322            0 :     limit_valid = get_limit_info (account, &balance_limit, FALSE);
     323              : 
     324            0 :     if (!limit_valid)
     325            0 :         return retval;
     326              : 
     327            0 :     if (gnc_numeric_zero_p (balance_limit))
     328            0 :         *is_zero = TRUE;
     329              : 
     330            0 :     if (account_balance_limit_reached (account, balance_limit) == -1)
     331            0 :         retval = TRUE;
     332              : 
     333            0 :     return retval;
     334              : }
     335              : 
     336              : static gchar *
     337            0 : make_limit_explanation (const Account *account, const char* template_str,
     338              :                         gboolean zero, gboolean higher)
     339              : {
     340            0 :     gnc_commodity *currency = xaccAccountGetCommodity (account);
     341            0 :     GNCPrintAmountInfo pinfo = gnc_commodity_print_info (currency, TRUE);
     342            0 :     gnc_numeric acct_bal = account_balance_for_limit (account);
     343            0 :     char *fullname = gnc_account_get_full_name (account);
     344            0 :     char *bal_str = g_strdup (xaccPrintAmount (acct_bal, pinfo));
     345              :     char *rv;
     346            0 :     if (zero)
     347            0 :         rv = g_strdup_printf (_(template_str), fullname, bal_str);
     348              :     else
     349              :     {
     350              :         gnc_numeric limit;
     351            0 :         get_limit_info (account, &limit, higher);
     352            0 :         if (gnc_reverse_balance (account))
     353            0 :             limit = gnc_numeric_neg (limit);
     354            0 :         char *lim_str = g_strdup (xaccPrintAmount (limit, pinfo));
     355            0 :         rv = g_strdup_printf (_(template_str), fullname, bal_str, lim_str);
     356            0 :         g_free (lim_str);
     357              :     }
     358            0 :     g_free (bal_str);
     359            0 :     g_free (fullname);
     360            0 :     return rv;
     361              : }
     362              : 
     363              : static gchar *
     364            0 : get_balance_limit_info (const Account *account, gboolean icon)
     365              : {
     366              :     gboolean lower_limit_reached, higher_limit_reached;
     367            0 :     gboolean lower_is_zero = FALSE;
     368            0 :     gboolean higher_is_zero = FALSE;
     369            0 :     const char *higher_template = N_("%s balance of %s is above the upper limit %s.");
     370            0 :     const char *lower_template = N_("%s balance of %s is below the lower limit %s.");
     371            0 :     const char *zero_template = N_("%s balance of %s should be zero.");
     372              : 
     373            0 :     g_return_val_if_fail (GNC_IS_ACCOUNT(account), NULL);
     374              : 
     375            0 :     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            0 :     if (higher_limit_reached && !higher_is_zero)
     379            0 :         return icon ? g_strdup ("go-top") : make_limit_explanation (account, higher_template, FALSE, TRUE);
     380              : 
     381            0 :     lower_limit_reached = gnc_ui_account_is_lower_balance_limit_reached (account, &lower_is_zero);
     382              : 
     383            0 :     if (lower_limit_reached && (!lower_is_zero || !higher_is_zero))
     384            0 :         return icon ? g_strdup ("go-bottom") : make_limit_explanation (account, lower_template, FALSE, FALSE);
     385              : 
     386            0 :     if (higher_limit_reached && !lower_is_zero)
     387            0 :         return icon ? g_strdup ("go-top") : make_limit_explanation (account, higher_template, FALSE, TRUE);
     388              : 
     389            0 :     if ((lower_limit_reached || higher_limit_reached ) && lower_is_zero && higher_is_zero)
     390            0 :         return icon ? g_strdup ("dialog-warning") : make_limit_explanation (account, zero_template, TRUE, FALSE);
     391              : 
     392            0 :     return NULL;
     393              : }
     394              : 
     395              : gchar *
     396            0 : gnc_ui_account_get_balance_limit_icon_name (const Account *account)
     397              : {
     398            0 :     char *icon = get_balance_limit_info (account, TRUE);
     399            0 :     return icon ? icon : g_strdup ("");
     400              : }
     401              : 
     402              : gchar *
     403            0 : gnc_ui_account_get_balance_limit_explanation (const Account *account)
     404              : {
     405            0 :     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              :  */
     427              : gnc_numeric
     428            0 : gnc_ui_owner_get_balance_full (GncOwner *owner,
     429              :                                gboolean *negative,
     430              :                                const gnc_commodity *commodity)
     431              : {
     432              :     gnc_numeric balance;
     433              : 
     434            0 :     if (!owner)
     435            0 :         return gnc_numeric_zero ();
     436              : 
     437            0 :     balance = gncOwnerGetBalanceInCurrency (owner, commodity);
     438              : 
     439              :     /* reverse sign if needed */
     440            0 :     if ((gncOwnerGetType (owner) != GNC_OWNER_CUSTOMER))
     441            0 :         balance = gnc_numeric_neg (balance);
     442              : 
     443              :     /* Record whether the balance is negative. */
     444            0 :     if (negative)
     445            0 :         *negative = gnc_numeric_negative_p (balance);
     446              : 
     447            0 :     return balance;
     448              : }
     449              : 
     450              : 
     451              : /**
     452              :  * Wrapper around gnc_ui_owner_get_balance_full that converts
     453              :  * the resulting number to a character string.  The number is
     454              :  * formatted according to the specification of the owner currency.
     455              :  * The caller is responsible for g_free'ing the returned memory.
     456              :  *
     457              :  * @param owner   The owner to retrieve data about.
     458              :  * @param negative  An indication of whether or not the returned value
     459              :  *                  is negative.  This can be used by the caller to
     460              :  *                  easily decode whether or not to color the output.
     461              :  */
     462              : gchar *
     463            0 : gnc_ui_owner_get_print_balance (GncOwner *owner,
     464              :                                 gboolean *negative)
     465              : {
     466              :     gnc_numeric balance;
     467              :     GNCPrintAmountInfo print_info;
     468              : 
     469            0 :     balance = gnc_ui_owner_get_balance_full (owner, negative, NULL);
     470            0 :     print_info = gnc_commodity_print_info (gncOwnerGetCurrency (owner), TRUE);
     471              : 
     472            0 :     return g_strdup (gnc_print_amount_with_bidi_ltr_isolate (balance, print_info));
     473              : }
     474              : 
     475              : /**
     476              :  * Wrapper around gnc_ui_owner_get_balance_full that converts
     477              :  * the resulting number to a character string.  The number is
     478              :  * formatted according to the specification of the default reporting
     479              :  * currency.
     480              :  *
     481              :  * @param account   The owner to retrieve data about.
     482              :  * @param negative  An indication of whether or not the returned value
     483              :  *                  is negative.  This can be used by the caller to
     484              :  *                  easily decode whether or not to color the output.
     485              :  */
     486              : gchar *
     487            0 : gnc_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            0 :     report_commodity = gnc_default_report_currency ();
     495            0 :     balance = gnc_ui_owner_get_balance_full (owner, negative,
     496              :               report_commodity);
     497            0 :     print_info = gnc_commodity_print_info (report_commodity, TRUE);
     498              : 
     499            0 :     return g_strdup (gnc_print_amount_with_bidi_ltr_isolate (balance, print_info));
     500              : }
     501              : 
        

Generated by: LCOV version 2.0-1