From 0018c884dbf228c54e30f0bc8b7586cc35c56b0f Mon Sep 17 00:00:00 2001 From: Daraul Date: Tue, 10 Mar 2020 13:38:43 -0400 Subject: fix: Fix #543 by tracking an account's real balance Without these changes, whether an account's balance is virtual or real is not considered when asserting it's balance. This lead to situations where the user must consider their virtual postings when attemping to assert the real balance of the account. See test/regress/543_a.test for that testcase, taken from the original issue. This commit also includes other, fringe, situations that I noticed while working on the fix. It essentially just adds a separate attribute to the account class(?) that hold's the account's "real" balance, which is only updated when the user attempts an assertion on a real account. The virtual account's balance is updated the way it always was. --- src/account.cc | 20 +++++++++++++++++--- src/account.h | 3 ++- src/py_account.cc | 3 ++- src/textual.cc | 4 ++-- test/regress/543_a.test | 26 ++++++++++++++++++++++++++ test/regress/543_b.test | 22 ++++++++++++++++++++++ test/regress/543_c.test | 24 ++++++++++++++++++++++++ test/regress/543_d.test | 32 ++++++++++++++++++++++++++++++++ 8 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 test/regress/543_a.test create mode 100644 test/regress/543_b.test create mode 100644 test/regress/543_c.test create mode 100644 test/regress/543_d.test diff --git a/src/account.cc b/src/account.cc index 29c28866..5f9f7f51 100644 --- a/src/account.cc +++ b/src/account.cc @@ -610,8 +610,10 @@ void account_t::clear_xdata() pair.second->clear_xdata(); } -value_t account_t::amount(const optional& expr) const +value_t account_t::amount(const optional real_only, const optional& expr) const { + DEBUG("account.amount", "real only: " << real_only); + if (xdata_ && xdata_->has_flags(ACCOUNT_EXT_VISITED)) { posts_list::const_iterator i; if (xdata_->self_details.last_post) @@ -622,6 +624,10 @@ value_t account_t::amount(const optional& expr) const for (; i != posts.end(); i++) { if ((*i)->xdata().has_flags(POST_EXT_VISITED)) { if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) { + if (! (*i)->has_flags(POST_VIRTUAL)) { + (*i)->add_to_value(xdata_->self_details.real_total, expr); + } + (*i)->add_to_value(xdata_->self_details.total, expr); (*i)->xdata().add_flags(POST_EXT_CONSIDERED); } @@ -637,6 +643,10 @@ value_t account_t::amount(const optional& expr) const for (; i != xdata_->reported_posts.end(); i++) { if ((*i)->xdata().has_flags(POST_EXT_VISITED)) { if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) { + if (! (*i)->has_flags(POST_VIRTUAL)) { + (*i)->add_to_value(xdata_->self_details.real_total, expr); + } + (*i)->add_to_value(xdata_->self_details.total, expr); (*i)->xdata().add_flags(POST_EXT_CONSIDERED); } @@ -644,7 +654,11 @@ value_t account_t::amount(const optional& expr) const xdata_->self_details.last_reported_post = i; } - return xdata_->self_details.total; + if (real_only == true) { + return xdata_->self_details.real_total; + } else { + return xdata_->self_details.total; + } } else { return NULL_VALUE; } @@ -662,7 +676,7 @@ value_t account_t::total(const optional& expr) const add_or_set_value(xdata_->family_details.total, temp); } - temp = amount(expr); + temp = amount(false, expr); if (! temp.is_null()) add_or_set_value(xdata_->family_details.total, temp); } diff --git a/src/account.h b/src/account.h index 0abbd87a..2db36cea 100644 --- a/src/account.h +++ b/src/account.h @@ -170,6 +170,7 @@ public: struct details_t { value_t total; + value_t real_total; bool calculated; bool gathered; @@ -277,7 +278,7 @@ public: return *xdata_; } - value_t amount(const optional& expr = none) const; + value_t amount(const optional real_only = false, const optional& expr = none) const; value_t total(const optional& expr = none) const; const xdata_t::details_t& self_details(bool gather_all = true) const; diff --git a/src/py_account.cc b/src/py_account.cc index 59680a23..295ed9d7 100644 --- a/src/py_account.cc +++ b/src/py_account.cc @@ -105,7 +105,7 @@ namespace { value_t py_amount_1(const account_t& account, const boost::optional& expr) { - return account.amount(expr); + return account.amount(false, expr); } value_t py_total_0(const account_t& account) @@ -133,6 +133,7 @@ void export_account() class_< account_t::xdata_t::details_t > ("AccountXDataDetails") .def_readonly("total", &account_t::xdata_t::details_t::total) + .def_readonly("real_total", &account_t::xdata_t::details_t::real_total) .def_readonly("calculated", &account_t::xdata_t::details_t::calculated) .def_readonly("gathered", &account_t::xdata_t::details_t::gathered) diff --git a/src/textual.cc b/src/textual.cc index 4e24fd44..16054445 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -1633,7 +1633,7 @@ post_t * instance_t::parse_post(char * line, const amount_t& amt(*post->assigned_amount); value_t account_total - (post->account->amount().strip_annotations(keep_details_t())); + (post->account->amount(!post->has_flags(POST_VIRTUAL)).strip_annotations(keep_details_t())); DEBUG("post.assign", "line " << context.linenum << ": " << "account balance = " << account_total); @@ -1666,7 +1666,7 @@ post_t * instance_t::parse_post(char * line, // Subtract amounts from previous posts to this account in the xact. for (post_t* p : xact->posts) { - if (p->account == post->account) { + if (p->account == post->account && p->has_flags(POST_VIRTUAL) == post->has_flags(POST_VIRTUAL)) { diff -= p->amount; DEBUG("textual.parse", "line " << context.linenum << ": " << "Subtracting " << p->amount << ", diff = " << diff); diff --git a/test/regress/543_a.test b/test/regress/543_a.test new file mode 100644 index 00000000..6359f0e2 --- /dev/null +++ b/test/regress/543_a.test @@ -0,0 +1,26 @@ +2018/01/01 * Opening Balance + Assets:Checking $100.00 + Equity:Opening Balances + +2018/01/01 * Budget + [Assets:Checking] -$100.00 + [Assets:Budget:Food:Groceries] $20.00 + [Assets:Budget:Food:Restaurants] $80.00 + +2018/01/02 * Assertion + [Assets:Checking] = $0.00 + +2018/01/02 * Assertion + Assets:Checking = $100.00 + +test bal Assets + $100.00 Assets:Budget:Food + $20.00 Groceries + $80.00 Restaurants +-------------------- + $100.00 +end test + +test bal Assets -R + $100.00 Assets:Checking +end test diff --git a/test/regress/543_b.test b/test/regress/543_b.test new file mode 100644 index 00000000..1a022ae4 --- /dev/null +++ b/test/regress/543_b.test @@ -0,0 +1,22 @@ +2018/01/01 * Opening Balance + Assets:Checking $100.00 + Equity:Opening Balances + +2018/01/01 * Budget + [Assets:Checking] -$100.00 + [Assets:Budget:Food:Groceries] $20.00 + [Assets:Budget:Food:Restaurants] $80.00 + +2018/01/02 * Buy Groceries + [Assets:Budget:Food:Groceries] -$20 = $0 + [Assets:Checking] $20 + Assets:Checking -$20 = $80 + Expenses:Food:Groceries $20 + +test bal Assets + $80.00 Assets:Budget:Food:Restaurants +end test + +test bal Assets -R + $80.00 Assets:Checking +end test diff --git a/test/regress/543_c.test b/test/regress/543_c.test new file mode 100644 index 00000000..0e51b119 --- /dev/null +++ b/test/regress/543_c.test @@ -0,0 +1,24 @@ +2018/01/01 * Opening Balance + Assets:Checking $100.00 + Equity:Opening Balances + +2018/01/01 * Budget + [Assets:Checking] -$100.00 + [Assets:Budget:Food:Groceries] $20.00 + [Assets:Budget:Food:Restaurants] $80.00 + +2018/01/02 * Budget Groceries + [Assets:Budget:Food:Groceries] -$20 = $0 + [Assets:Checking] $20 + +2018/01/02 * Buy Groceries + Assets:Checking -$20 = $80 + Expenses:Food:Groceries $20 + +test bal Assets + $80.00 Assets:Budget:Food:Restaurants +end test + +test bal Assets -R + $80.00 Assets:Checking +end test diff --git a/test/regress/543_d.test b/test/regress/543_d.test new file mode 100644 index 00000000..3b4e825a --- /dev/null +++ b/test/regress/543_d.test @@ -0,0 +1,32 @@ +2018/01/01 * Opening Balance + Assets:Checking $100.00 + Equity:Opening Balances + +2018/01/01 * Budget + [Assets:Checking] = 0 + [Assets:Budget:Food:Groceries] $20.00 + [Assets:Budget:Food:Restaurants] $80.00 + +2018/01/02 * Groceries + Assets:Checking = $80.00 + Expenses:Groceries + +test bal + $80.00 Assets + $100.00 Budget:Food + $20.00 Groceries + $80.00 Restaurants + $-20.00 Checking + $-100.00 Equity:Opening Balances + $20.00 Expenses:Groceries +-------------------- + 0 +end test + +test bal -R + $80.00 Assets:Checking + $-100.00 Equity:Opening Balances + $20.00 Expenses:Groceries +-------------------- + 0 +end test -- cgit v1.2.3