diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index d00e1aa520..f6863a0ceb 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -73,6 +73,10 @@ static const std::string AB_ACCOUNT_UID("account-uid"); static const std::string AB_BANK_CODE("bank-code"); static const std::string AB_TRANS_RETRIEVAL("trans-retrieval"); +static const std::string KEY_BALANCE_LIMIT("balance-limit"); +static const std::string KEY_BALANCE_HIGHER_LIMIT_VALUE("higher-value"); +static const std::string KEY_BALANCE_LOWER_LIMIT_VALUE("lower-value"); + static gnc_numeric GetBalanceAsOfDate (Account *acc, time64 date, gboolean ignclosing); using FinalProbabilityVec=std::vector>; @@ -328,6 +332,11 @@ gnc_account_init(Account* acc) priv->starting_reconciled_balance = gnc_numeric_zero(); priv->balance_dirty = FALSE; + priv->higher_balance_limit = gnc_numeric_create (1,0); + priv->higher_balance_cached = false; + priv->lower_balance_limit = gnc_numeric_create (1,0); + priv->lower_balance_cached = false; + priv->last_num = (char*) is_unset; priv->tax_us_code = (char*) is_unset; priv->tax_us_pns = (char*) is_unset; @@ -4930,6 +4939,211 @@ xaccAccountSetLastNum (Account *acc, const char *num) set_kvp_string_tag (acc, "last-num", priv->last_num); } + +/********************************************************************\ +\********************************************************************/ + +gboolean +xaccAccountGetHigherBalanceLimit (const Account *acc, + gnc_numeric *balance) +{ + g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false); + + if (GET_PRIVATE(acc)->higher_balance_cached) + { + *balance = GET_PRIVATE(acc)->higher_balance_limit; + + if (gnc_numeric_check (*balance) == 0) + return true; + else + return false; + } + else + { + gnc_numeric bal = gnc_numeric_create (1,0); + GValue v = G_VALUE_INIT; + gboolean retval = false; + + qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {KEY_BALANCE_LIMIT, + KEY_BALANCE_HIGHER_LIMIT_VALUE}); + if (G_VALUE_HOLDS_BOXED(&v)) + { + bal = *(gnc_numeric*)g_value_get_boxed (&v); + if (bal.denom) + { + if (balance) + *balance = bal; + retval = true; + } + } + g_value_unset (&v); + + GET_PRIVATE(acc)->higher_balance_limit = bal; + GET_PRIVATE(acc)->higher_balance_cached = true; + return retval; + } +} + +gboolean +xaccAccountGetLowerBalanceLimit (const Account *acc, + gnc_numeric *balance) +{ + g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false); + + if (GET_PRIVATE(acc)->lower_balance_cached) + { + *balance = GET_PRIVATE(acc)->lower_balance_limit; + + if (gnc_numeric_check (*balance) == 0) + return true; + else + return false; + } + else + { + gnc_numeric bal = gnc_numeric_create (1,0); + GValue v = G_VALUE_INIT; + gboolean retval = false; + + qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {KEY_BALANCE_LIMIT, + KEY_BALANCE_LOWER_LIMIT_VALUE}); + if (G_VALUE_HOLDS_BOXED(&v)) + { + bal = *(gnc_numeric*)g_value_get_boxed (&v); + if (bal.denom) + { + if (balance) + *balance = bal; + retval = true; + } + } + g_value_unset (&v); + + GET_PRIVATE(acc)->lower_balance_limit = bal; + GET_PRIVATE(acc)->lower_balance_cached = true; + return retval; + } +} + + +static void +set_balance_limits (Account *acc, gnc_numeric balance, gboolean higher) +{ + gnc_numeric balance_limit; + gboolean balance_limit_valid; + std::vector path {KEY_BALANCE_LIMIT}; + + if (higher) + { + path.push_back (KEY_BALANCE_HIGHER_LIMIT_VALUE); + balance_limit_valid = xaccAccountGetHigherBalanceLimit (acc, &balance_limit); + } + else + { + path.push_back (KEY_BALANCE_LOWER_LIMIT_VALUE); + balance_limit_valid = xaccAccountGetLowerBalanceLimit (acc, &balance_limit); + } + + if (!balance_limit_valid || gnc_numeric_compare (balance, balance_limit) != 0) + { + GValue v = G_VALUE_INIT; + g_value_init (&v, GNC_TYPE_NUMERIC); + g_value_set_boxed (&v, &balance); + xaccAccountBeginEdit (acc); + + qof_instance_set_path_kvp (QOF_INSTANCE(acc), &v, path); + if (higher) + { + GET_PRIVATE(acc)->higher_balance_limit.denom = balance.denom; + GET_PRIVATE(acc)->higher_balance_limit.num = balance.num; + GET_PRIVATE(acc)->higher_balance_cached = true; + } + else + { + GET_PRIVATE(acc)->lower_balance_limit.denom = balance.denom; + GET_PRIVATE(acc)->lower_balance_limit.num = balance.num; + GET_PRIVATE(acc)->lower_balance_cached = true; + } + mark_account (acc); + xaccAccountCommitEdit (acc); + g_value_unset (&v); + } +} + +void +xaccAccountSetHigherBalanceLimit (Account *acc, gnc_numeric balance) +{ + g_return_if_fail (GNC_IS_ACCOUNT(acc)); + + if (gnc_numeric_check (balance) != 0) + return; + + set_balance_limits (acc, balance, true); +} + +void +xaccAccountSetLowerBalanceLimit (Account *acc, gnc_numeric balance) +{ + g_return_if_fail (GNC_IS_ACCOUNT(acc)); + + if (gnc_numeric_check (balance) != 0) + return; + + set_balance_limits (acc, balance, false); +} + + +static void +clear_balance_limits (Account *acc, gboolean higher) +{ + gnc_numeric balance_limit; + gboolean balance_limit_valid; + std::vector path {KEY_BALANCE_LIMIT}; + + if (higher) + { + path.push_back (KEY_BALANCE_HIGHER_LIMIT_VALUE); + balance_limit_valid = xaccAccountGetHigherBalanceLimit (acc, &balance_limit); + } + else + { + path.push_back (KEY_BALANCE_LOWER_LIMIT_VALUE); + balance_limit_valid = xaccAccountGetLowerBalanceLimit (acc, &balance_limit); + } + + if (balance_limit_valid) + { + xaccAccountBeginEdit (acc); + qof_instance_set_path_kvp (QOF_INSTANCE(acc), nullptr, path); + qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), {KEY_BALANCE_LIMIT}); + if (higher) + GET_PRIVATE(acc)->higher_balance_cached = false; + else + GET_PRIVATE(acc)->lower_balance_cached = false; + mark_account (acc); + xaccAccountCommitEdit (acc); + } +} + +void +xaccAccountClearHigherBalanceLimit (Account *acc) +{ + g_return_if_fail (GNC_IS_ACCOUNT(acc)); + + clear_balance_limits (acc, true); +} + +void +xaccAccountClearLowerBalanceLimit (Account *acc) +{ + g_return_if_fail (GNC_IS_ACCOUNT(acc)); + + clear_balance_limits (acc, false); +} + +/********************************************************************\ +\********************************************************************/ + static Account * GetOrMakeOrphanAccount (Account *root, gnc_commodity * currency) { diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h index 3fac9bdbb7..d84176d475 100644 --- a/libgnucash/engine/Account.h +++ b/libgnucash/engine/Account.h @@ -1182,6 +1182,58 @@ typedef enum void xaccAccountClearReconcilePostpone (Account *account); /** @} */ + /** @name Account Balance Limits + @{ + */ + + /** Get the higher balance limit for the account. + * + * @param account The account whose higher limit is to be retrieved + * + * @param balance The placeholder to store the retrieved balance + * + * @return True if the limit is valid. */ + gboolean xaccAccountGetHigherBalanceLimit (const Account *account, + gnc_numeric *balance); + + /** Set the higher balance limit for the account. + * + * @param account The account whose higher limit is to be saved + * + * @param balance The balance to be saved + */ + void xaccAccountSetHigherBalanceLimit (Account *account, gnc_numeric balance); + + /** Clear the higher balance limit for the account. + * + * @param account The account to clear the limit on + */ + void xaccAccountClearHigherBalanceLimit (Account *account); + + /** Get the lower balance limit for the account. + * + * @param account The account whose lower limit is to be retrieved + * + * @param balance The placeholder to store the retrieved balance + * + * @return True if the limit is valid. */ + gboolean xaccAccountGetLowerBalanceLimit (const Account *account, + gnc_numeric *balance); + + /** Set the lower balance limit for the account. + * + * @param account The account whose lower limit is to be saved + * + * @param balance The balance to be saved + */ + void xaccAccountSetLowerBalanceLimit (Account *account, gnc_numeric balance); + + /** Clear the lower balance limit for the account. + * + * @param account The account to clear the limit on + */ + void xaccAccountClearLowerBalanceLimit (Account *account); + /** @} */ /** DOCUMENT ME! */ typedef enum diff --git a/libgnucash/engine/AccountP.h b/libgnucash/engine/AccountP.h index 14faeb6c0e..68017ba9c4 100644 --- a/libgnucash/engine/AccountP.h +++ b/libgnucash/engine/AccountP.h @@ -121,6 +121,11 @@ typedef struct AccountPrivate gnc_numeric cleared_balance; gnc_numeric reconciled_balance; + gnc_numeric higher_balance_limit; + gboolean higher_balance_cached; + gnc_numeric lower_balance_limit; + gboolean lower_balance_cached; + gboolean balance_dirty; /* balances in splits incorrect */ GList *splits; /* list of split pointers */