Bug 797390 - xaccAccountRecomputeBalance also tallies no-closing balances

Add a few API, enough for fixing bug 797326 easily.
This commit is contained in:
Christopher Lam
2019-09-04 21:11:10 +08:00
parent d881130a19
commit 198570d8c8
6 changed files with 156 additions and 4 deletions

View File

@@ -63,6 +63,8 @@ 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 gnc_numeric GetBalanceAsOfDate (Account *acc, time64 date, gboolean ignclosing);
using FinalProbabilityVec=std::vector<std::pair<std::string, int32_t>>;
using ProbabilityVec=std::vector<std::pair<std::string, struct AccountProbability>>;
using FlatKvpEntry=std::pair<std::string, KvpValue*>;
@@ -88,6 +90,7 @@ enum
PROP_COMMODITY_SCU, /* Table */
PROP_NON_STD_SCU, /* Table */
PROP_END_BALANCE, /* Constructed */
PROP_END_NOCLOSING_BALANCE, /* Constructed */
PROP_END_CLEARED_BALANCE, /* Constructed */
PROP_END_RECONCILED_BALANCE, /* Constructed */
@@ -116,6 +119,7 @@ enum
PROP_SORT_DIRTY, /* Runtime Value */
PROP_BALANCE_DIRTY, /* Runtime Value */
PROP_START_BALANCE, /* Runtime Value */
PROP_START_NOCLOSING_BALANCE, /* Runtime Value */
PROP_START_CLEARED_BALANCE, /* Runtime Value */
PROP_START_RECONCILED_BALANCE, /* Runtime Value */
};
@@ -279,9 +283,11 @@ gnc_account_init(Account* acc)
priv->non_standard_scu = FALSE;
priv->balance = gnc_numeric_zero();
priv->noclosing_balance = gnc_numeric_zero();
priv->cleared_balance = gnc_numeric_zero();
priv->reconciled_balance = gnc_numeric_zero();
priv->starting_balance = gnc_numeric_zero();
priv->starting_noclosing_balance = gnc_numeric_zero();
priv->starting_cleared_balance = gnc_numeric_zero();
priv->starting_reconciled_balance = gnc_numeric_zero();
priv->balance_dirty = FALSE;
@@ -364,6 +370,9 @@ gnc_account_get_property (GObject *object,
case PROP_START_BALANCE:
g_value_set_boxed(value, &priv->starting_balance);
break;
case PROP_START_NOCLOSING_BALANCE:
g_value_set_boxed(value, &priv->starting_noclosing_balance);
break;
case PROP_START_CLEARED_BALANCE:
g_value_set_boxed(value, &priv->starting_cleared_balance);
break;
@@ -373,6 +382,9 @@ gnc_account_get_property (GObject *object,
case PROP_END_BALANCE:
g_value_set_boxed(value, &priv->balance);
break;
case PROP_END_NOCLOSING_BALANCE:
g_value_set_boxed(value, &priv->noclosing_balance);
break;
case PROP_END_CLEARED_BALANCE:
g_value_set_boxed(value, &priv->cleared_balance);
break;
@@ -746,6 +758,23 @@ gnc_account_class_init (AccountClass *klass)
GNC_TYPE_NUMERIC,
static_cast<GParamFlags>(G_PARAM_READWRITE)));
g_object_class_install_property
(gobject_class,
PROP_START_NOCLOSING_BALANCE,
g_param_spec_boxed("start-noclosing-balance",
"Starting No-closing Balance",
"The starting balance for the account, ignoring closing."
"This parameter is intended for use with backends "
"that do not return the complete list of splits "
"for an account, but rather return a partial "
"list. In such a case, the backend will "
"typically return all of the splits after "
"some certain date, and the 'starting noclosing "
"balance' will represent the summation of the "
"splits up to that date, ignoring closing splits.",
GNC_TYPE_NUMERIC,
static_cast<GParamFlags>(G_PARAM_READWRITE)));
g_object_class_install_property
(gobject_class,
PROP_START_CLEARED_BALANCE,
@@ -791,6 +820,18 @@ gnc_account_class_init (AccountClass *klass)
GNC_TYPE_NUMERIC,
G_PARAM_READABLE));
g_object_class_install_property
(gobject_class,
PROP_END_NOCLOSING_BALANCE,
g_param_spec_boxed("end-noclosing-balance",
"Ending Account Noclosing Balance",
"This is the current ending no-closing balance for "
"the account. It is computed from the sum of the "
"starting balance and all cleared splits in the "
"account.",
GNC_TYPE_NUMERIC,
G_PARAM_READABLE));
g_object_class_install_property
(gobject_class,
PROP_END_CLEARED_BALANCE,
@@ -1269,6 +1310,7 @@ xaccFreeAccount (Account *acc)
priv->children = nullptr;
priv->balance = gnc_numeric_zero();
priv->noclosing_balance = gnc_numeric_zero();
priv->cleared_balance = gnc_numeric_zero();
priv->reconciled_balance = gnc_numeric_zero();
@@ -1565,6 +1607,22 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE;
}
if (!gnc_numeric_equal(priv_aa->starting_noclosing_balance,
priv_ab->starting_noclosing_balance))
{
char *str_a;
char *str_b;
str_a = gnc_numeric_to_string(priv_aa->starting_noclosing_balance);
str_b = gnc_numeric_to_string(priv_ab->starting_noclosing_balance);
PWARN ("starting noclosing balances differ: %s vs %s", str_a, str_b);
g_free (str_a);
g_free (str_b);
return FALSE;
}
if (!gnc_numeric_equal(priv_aa->starting_cleared_balance,
priv_ab->starting_cleared_balance))
{
@@ -1615,6 +1673,21 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE;
}
if (!gnc_numeric_equal(priv_aa->noclosing_balance, priv_ab->noclosing_balance))
{
char *str_a;
char *str_b;
str_a = gnc_numeric_to_string(priv_aa->noclosing_balance);
str_b = gnc_numeric_to_string(priv_ab->noclosing_balance);
PWARN ("noclosing balances differ: %s vs %s", str_a, str_b);
g_free (str_a);
g_free (str_b);
return FALSE;
}
if (!gnc_numeric_equal(priv_aa->cleared_balance, priv_ab->cleared_balance))
{
char *str_a;
@@ -2070,6 +2143,7 @@ xaccAccountRecomputeBalance (Account * acc)
{
AccountPrivate *priv;
gnc_numeric balance;
gnc_numeric noclosing_balance;
gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;
GList *lp;
@@ -2083,6 +2157,7 @@ xaccAccountRecomputeBalance (Account * acc)
if (qof_book_shutting_down(qof_instance_get_book(acc))) return;
balance = priv->starting_balance;
noclosing_balance = priv->starting_noclosing_balance;
cleared_balance = priv->starting_cleared_balance;
reconciled_balance = priv->starting_reconciled_balance;
@@ -2107,13 +2182,18 @@ xaccAccountRecomputeBalance (Account * acc)
gnc_numeric_add_fixed(reconciled_balance, amt);
}
if (!(xaccTransGetIsClosingTxn (split->parent)))
noclosing_balance = gnc_numeric_add_fixed(noclosing_balance, amt);
split->balance = balance;
split->noclosing_balance = noclosing_balance;
split->cleared_balance = cleared_balance;
split->reconciled_balance = reconciled_balance;
}
priv->balance = balance;
priv->noclosing_balance = noclosing_balance;
priv->cleared_balance = cleared_balance;
priv->reconciled_balance = reconciled_balance;
priv->balance_dirty = FALSE;
@@ -3287,8 +3367,8 @@ xaccAccountGetProjectedMinimumBalance (const Account *acc)
/********************************************************************\
\********************************************************************/
gnc_numeric
xaccAccountGetBalanceAsOfDate (Account *acc, time64 date)
static gnc_numeric
GetBalanceAsOfDate (Account *acc, time64 date, gboolean ignclosing)
{
/* Ideally this could use xaccAccountForEachSplit, but
* it doesn't exist yet and I'm uncertain of exactly how
@@ -3307,7 +3387,10 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time64 date)
xaccAccountRecomputeBalance (acc); /* just in case, normally a noop */
priv = GET_PRIVATE(acc);
balance = priv->balance;
if (ignclosing)
balance = priv->noclosing_balance;
else
balance = priv->balance;
lp = priv->splits;
while ( lp && !found )
@@ -3326,7 +3409,10 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time64 date)
/* Since lp is now pointing to a split which was past the reconcile
* date, get the running balance of the previous split.
*/
balance = xaccSplitGetBalance( (Split *)lp->prev->data );
if (ignclosing)
balance = xaccSplitGetNoclosingBalance( (Split *)lp->prev->data );
else
balance = xaccSplitGetBalance( (Split *)lp->prev->data );
}
else
{
@@ -3342,6 +3428,18 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time64 date)
return( balance );
}
gnc_numeric
xaccAccountGetBalanceAsOfDate (Account *acc, time64 date)
{
return GetBalanceAsOfDate (acc, date, FALSE);
}
static gnc_numeric
xaccAccountGetNoclosingBalanceAsOfDate (Account *acc, time64 date)
{
return GetBalanceAsOfDate (acc, date, TRUE);
}
/*
* Originally gsr_account_present_balance in gnc-split-reg.c
*
@@ -3669,6 +3767,16 @@ xaccAccountGetBalanceAsOfDateInCurrency(
include_children);
}
gnc_numeric
xaccAccountGetNoclosingBalanceAsOfDateInCurrency(
Account *acc, time64 date, gnc_commodity *report_commodity,
gboolean include_children)
{
return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive
(acc, date, xaccAccountGetNoclosingBalanceAsOfDate,
report_commodity, include_children);
}
gnc_numeric
xaccAccountGetBalanceChangeForPeriod (Account *acc, time64 t1, time64 t2,
gboolean recurse)
@@ -3680,6 +3788,17 @@ xaccAccountGetBalanceChangeForPeriod (Account *acc, time64 t1, time64 t2,
return gnc_numeric_sub(b2, b1, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
}
gnc_numeric
xaccAccountGetNoclosingBalanceChangeForPeriod (Account *acc, time64 t1,
time64 t2, gboolean recurse)
{
gnc_numeric b1, b2;
b1 = xaccAccountGetNoclosingBalanceAsOfDateInCurrency(acc, t1, NULL, recurse);
b2 = xaccAccountGetNoclosingBalanceAsOfDateInCurrency(acc, t2, NULL, recurse);
return gnc_numeric_sub(b2, b1, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
}
/********************************************************************\
\********************************************************************/

View File

@@ -595,12 +595,19 @@ gnc_numeric xaccAccountGetProjectedMinimumBalanceInCurrency (
const Account *account, const gnc_commodity *report_commodity,
gboolean include_children);
/* This function gets the balance as of the given date, ignoring
closing entries, in the desired commodity. */
gnc_numeric xaccAccountGetNoclosingBalanceAsOfDateInCurrency(
Account *acc, time64 date, gnc_commodity *report_commodity,
gboolean include_children);
/* This function gets the balance as of the given date in the desired
commodity. */
gnc_numeric xaccAccountGetBalanceAsOfDateInCurrency(
Account *account, time64 date, gnc_commodity *report_commodity,
gboolean include_children);
gnc_numeric xaccAccountGetNoclosingBalanceChangeForPeriod (
Account *acc, time64 date1, time64 date2, gboolean recurse);
gnc_numeric xaccAccountGetBalanceChangeForPeriod (
Account *acc, time64 date1, time64 date2, gboolean recurse);
@@ -1504,6 +1511,7 @@ const char * dxaccAccountGetQuoteTZ (const Account *account);
#define ACCOUNT_SORT_REVERSED_ "sort-reversed"
#define ACCOUNT_NOTES_ "notes"
#define ACCOUNT_BALANCE_ "balance"
#define ACCOUNT_NOCLOSING_ "noclosing"
#define ACCOUNT_CLEARED_ "cleared"
#define ACCOUNT_RECONCILED_ "reconciled"
#define ACCOUNT_PRESENT_ "present"

View File

@@ -104,11 +104,13 @@ typedef struct AccountPrivate
/* protected data - should only be set by backends */
gnc_numeric starting_balance;
gnc_numeric starting_noclosing_balance;
gnc_numeric starting_cleared_balance;
gnc_numeric starting_reconciled_balance;
/* cached parameters */
gnc_numeric balance;
gnc_numeric noclosing_balance;
gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;

View File

@@ -120,6 +120,7 @@ gnc_split_init(Split* split)
split->balance = gnc_numeric_zero();
split->cleared_balance = gnc_numeric_zero();
split->reconciled_balance = gnc_numeric_zero();
split->noclosing_balance = gnc_numeric_zero();
split->gains = GAINS_STATUS_UNKNOWN;
split->gains_split = NULL;
@@ -513,6 +514,7 @@ xaccSplitReinit(Split * split)
split->balance = gnc_numeric_zero();
split->cleared_balance = gnc_numeric_zero();
split->reconciled_balance = gnc_numeric_zero();
split->noclosing_balance = gnc_numeric_zero();
qof_instance_set_idata(split, 0);
@@ -597,6 +599,7 @@ xaccSplitCloneNoKvp (const Split *s)
split->balance = s->balance;
split->cleared_balance = s->cleared_balance;
split->reconciled_balance = s->reconciled_balance;
split->noclosing_balance = s->noclosing_balance;
split->gains = GAINS_STATUS_UNKNOWN;
split->gains_split = NULL;
@@ -679,6 +682,7 @@ xaccSplitDump (const Split *split, const char *tag)
printf(" CBalance: %s\n", gnc_numeric_to_string(split->cleared_balance));
printf(" RBalance: %s\n",
gnc_numeric_to_string(split->reconciled_balance));
printf(" NoClose: %s\n", gnc_numeric_to_string(split->noclosing_balance));
printf(" idata: %x\n", qof_instance_get_idata(split));
}
#endif
@@ -868,6 +872,9 @@ xaccSplitEqual(const Split *sa, const Split *sb,
if (!xaccSplitEqualCheckBal ("reconciled ", sa->reconciled_balance,
sb->reconciled_balance))
return FALSE;
if (!xaccSplitEqualCheckBal ("noclosing ", sa->noclosing_balance,
sb->noclosing_balance))
return FALSE;
}
if (!xaccTransEqual(sa->parent, sb->parent, check_guids, check_txn_splits,
@@ -1272,6 +1279,12 @@ xaccSplitGetBalance (const Split *s)
return s ? s->balance : gnc_numeric_zero();
}
gnc_numeric
xaccSplitGetNoclosingBalance (const Split *s)
{
return s ? s->noclosing_balance : gnc_numeric_zero();
}
gnc_numeric
xaccSplitGetClearedBalance (const Split *s)
{

View File

@@ -296,6 +296,15 @@ gnc_numeric xaccSplitGetBaseValue (const Split *split,
*/
gnc_numeric xaccSplitGetBalance (const Split *split);
/**
* The noclosing-balance is the currency-denominated balance of all
* transactions except 'closing' transactions. It is correctly
* adjusted for price fluctuations.
*
* Returns the running balance up to & including the indicated split.
*/
gnc_numeric xaccSplitGetNoclosingBalance (const Split *split);
/**
* The cleared-balance is the currency-denominated balance
* of all transactions that have been marked as cleared or reconciled.

View File

@@ -123,6 +123,7 @@ struct split_s
* These balances apply to a sorting order by date posted
* (not by date entered). */
gnc_numeric balance;
gnc_numeric noclosing_balance;
gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;
};