diff options
author | John Wiegley <johnw@newartisans.com> | 2009-03-06 00:26:30 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-03-06 00:27:29 -0400 |
commit | 2728e4d55e1c9e84ee5aae4ee8e9c380198d1c99 (patch) | |
tree | 5b5e8207db2a37684b2527acad7bccdd770fc1a4 /src | |
parent | dd23edd5cee8e712e13a3b5eefffcc3c57bf9e10 (diff) | |
download | fork-ledger-2728e4d55e1c9e84ee5aae4ee8e9c380198d1c99.tar.gz fork-ledger-2728e4d55e1c9e84ee5aae4ee8e9c380198d1c99.tar.bz2 fork-ledger-2728e4d55e1c9e84ee5aae4ee8e9c380198d1c99.zip |
Changed the way that account balances are computed
Diffstat (limited to 'src')
-rw-r--r-- | src/account.cc | 157 | ||||
-rw-r--r-- | src/account.h | 79 | ||||
-rw-r--r-- | src/filters.cc | 24 | ||||
-rw-r--r-- | src/output.cc | 16 | ||||
-rw-r--r-- | src/post.cc | 5 | ||||
-rw-r--r-- | src/session.cc | 7 | ||||
-rw-r--r-- | src/textual.cc | 13 | ||||
-rw-r--r-- | src/xact.cc | 16 |
8 files changed, 234 insertions, 83 deletions
diff --git a/src/account.cc b/src/account.cc index 56555d61..b9955120 100644 --- a/src/account.cc +++ b/src/account.cc @@ -30,6 +30,8 @@ */ #include "account.h" +#include "post.h" +#include "xact.h" #include "interactive.h" namespace ledger { @@ -166,33 +168,20 @@ namespace { return string_value(account.name); } - value_t get_total(account_t& account) { - if (! account.xdata_ || account.xdata_->family_details.total.is_null()) - return 0L; - else - return account.xdata_->family_details.total; + value_t get_amount(account_t& account) { + return VALUE_OR_ZERO(account.self_total()); } - value_t get_count(account_t& account) { - if (account.xdata_) - return long(account.xdata_->family_details.posts_count); - else - return 0L; + value_t get_total(account_t& account) { + return VALUE_OR_ZERO(account.family_total()); } value_t get_subcount(account_t& account) { - if (account.xdata_) - return long(account.xdata_->self_details.posts_count); - else - return 0L; + return long(account.self_details().posts_count); } - value_t get_amount(account_t& account) { - if (! account.xdata_ || - account.xdata_->self_details.total.is_null()) - return 0L; - else - return account.xdata_->self_details.total; + value_t get_count(account_t& account) { + return long(account.family_details().posts_count); } value_t get_depth(account_t& account) { @@ -317,4 +306,132 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const return count; } +account_t::xdata_t::details_t& +account_t::xdata_t::details_t::operator+=(const details_t& other) +{ + // jww (2009-03-05): NYI + return *this; +} + +value_t account_t::self_total(const optional<expr_t&>& expr) const +{ + if (xdata_ && xdata_->has_flags(ACCOUNT_EXT_VISITED)) { + if (! xdata_) xdata_ = xdata_t(); + + posts_deque::const_iterator i = + posts.begin() + xdata_->self_details.last_size; + + for (; i != posts.end(); i++) { + if ((*i)->xdata().has_flags(POST_EXT_VISITED) && + ! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) { + (*i)->add_to_value(xdata_->self_details.total, expr); + (*i)->xdata().add_flags(POST_EXT_CONSIDERED); + } + } + + xdata_->self_details.last_size = posts.size(); + + return xdata_->self_details.total; + } else { + return NULL_VALUE; + } +} + +value_t account_t::family_total(const optional<expr_t&>& expr) const +{ + if (! (xdata_ && xdata_->family_details.calculated)) { + const_cast<account_t&>(*this).xdata().family_details.calculated = true; + + value_t temp; + foreach (const accounts_map::value_type& pair, accounts) { + temp = pair.second->family_total(expr); + if (! temp.is_null()) + add_or_set_value(xdata_->family_details.total, temp); + } + + temp = self_total(expr); + if (! temp.is_null()) + add_or_set_value(xdata_->family_details.total, temp); + } + return xdata_->family_details.total; +} + +const account_t::xdata_t::details_t& +account_t::self_details(bool gather_all) const +{ + if (! (xdata_ && xdata_->self_details.gathered)) { + const_cast<account_t&>(*this).xdata().self_details.gathered = true; + + foreach (const post_t * post, posts) + xdata_->self_details.update(const_cast<post_t&>(*post), gather_all); + } + return xdata_->self_details; +} + +const account_t::xdata_t::details_t& +account_t::family_details(bool gather_all) const +{ + if (! (xdata_ && xdata_->family_details.gathered)) { + const_cast<account_t&>(*this).xdata().family_details.gathered = true; + + foreach (const accounts_map::value_type& pair, accounts) + xdata_->family_details += pair.second->family_details(gather_all); + + xdata_->self_details += self_details(gather_all); + } + return xdata_->family_details; +} + +void account_t::xdata_t::details_t::update(post_t& post, + bool gather_all) +{ + if (last_xact != post.xact) { + xacts_count++; + last_xact = post.xact; + } + if (last_post == &post) + return; + + last_post = &post; + + posts_count++; + if (post.has_flags(POST_VIRTUAL)) + posts_virtuals_count++; + + if (gather_all) + filenames.insert(post.pathname); + + date_t date = post.date(); + + if (date.year() == CURRENT_DATE().year() && + date.month() == CURRENT_DATE().month()) + posts_this_month_count++; + + if ((CURRENT_DATE() - date).days() <= 30) + posts_last_30_count++; + if ((CURRENT_DATE() - date).days() <= 7) + posts_last_7_count++; + + if (! is_valid(earliest_post) || post.date() < earliest_post) + earliest_post = post.date(); + if (! is_valid(latest_post) || post.date() > latest_post) + latest_post = post.date(); + + if (post.state() == item_t::CLEARED) { + posts_cleared_count++; + + if (! is_valid(earliest_cleared_post) || + post.date() < earliest_cleared_post) + earliest_cleared_post = post.date(); + if (! is_valid(latest_cleared_post) || + post.date() > latest_cleared_post) + latest_cleared_post = post.date(); + } + + if (gather_all) { + accounts_referenced.insert(post.account->fullname()); + payees_referenced.insert(post.xact->payee); + } +} + } // namespace ledger diff --git a/src/account.h b/src/account.h index dd7ac3d6..f161a11f 100644 --- a/src/account.h +++ b/src/account.h @@ -50,9 +50,12 @@ namespace ledger { -class account_t; class session_t; +class account_t; +class xact_t; +class post_t; +typedef std::deque<post_t *> posts_deque; typedef std::map<const string, account_t *> accounts_map; /** @@ -68,14 +71,15 @@ class account_t : public scope_t optional<string> note; unsigned short depth; accounts_map accounts; + posts_deque posts; bool known; mutable void * data; mutable string _fullname; - account_t(account_t * _parent = NULL, - const string& _name = "", - const optional<string>& _note = none) + account_t(account_t * _parent = NULL, + const string& _name = "", + const optional<string>& _note = none) : scope_t(), parent(_parent), name(_name), note(_note), depth(static_cast<unsigned short>(parent ? parent->depth + 1 : 0)), known(false), data(NULL) { @@ -112,6 +116,10 @@ class account_t : public scope_t account_t * find_account(const string& name, bool auto_create = true); account_t * find_account_re(const string& regexp); + void add_post(post_t * post) { + posts.push_back(post); + } + virtual expr_t::ptr_op_t lookup(const string& name); bool valid() const; @@ -130,14 +138,61 @@ class account_t : public scope_t struct details_t { - value_t total; + value_t total; + bool calculated; + bool gathered; + + // The following are only calculated if --totals is enabled + std::size_t xacts_count; + + std::size_t posts_count; + std::size_t posts_virtuals_count; + std::size_t posts_cleared_count; + std::size_t posts_last_7_count; + std::size_t posts_last_30_count; + std::size_t posts_this_month_count; + + date_t earliest_post; + date_t earliest_cleared_post; + date_t latest_post; + date_t latest_cleared_post; + + xact_t * last_xact; + post_t * last_post; + + std::size_t last_size; - std::size_t posts_count; - std::size_t posts_virtuals_count; + // The following are only calculated if --gather is enabled + std::set<path> filenames; + std::set<string> accounts_referenced; + std::set<string> payees_referenced; details_t() - : posts_count(0), - posts_virtuals_count(0) {} + : calculated(false), + gathered(false), + + xacts_count(0), + + posts_count(0), + posts_virtuals_count(0), + posts_cleared_count(0), + posts_last_7_count(0), + posts_last_30_count(0), + posts_this_month_count(0), + + earliest_post(0), + earliest_cleared_post(0), + latest_post(0), + latest_cleared_post(0), + + last_xact(NULL), + last_post(NULL), + + last_size(0) {} + + details_t& operator+=(const details_t& other); + + void update(post_t& post, bool gather_all = false); }; details_t self_details; @@ -185,6 +240,12 @@ class account_t : public scope_t return *xdata_; } + value_t self_total(const optional<expr_t&>& expr = none) const; + value_t family_total(const optional<expr_t&>& expr = none) const; + + const xdata_t::details_t& self_details(bool gather_all = true) const; + const xdata_t::details_t& family_details(bool gather_all = true) const; + bool has_flags(xdata_t::flags_t flags) const { return xdata_ && xdata_->has_flags(flags); } diff --git a/src/filters.cc b/src/filters.cc index 2895bf7f..f8736667 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -207,30 +207,8 @@ void calc_posts::operator()(post_t& post) account_t * acct = post.reported_account(); acct->xdata().add_flags(ACCOUNT_EXT_VISITED); - if (! account_wise) { + if (! account_wise) add_or_set_value(xdata.total, xdata.visited_value); - } else { - account_t::xdata_t * acct_xdata = &acct->xdata(); - - add_or_set_value(acct_xdata->self_details.total, xdata.visited_value); - - acct_xdata->self_details.posts_count++; - acct_xdata->self_details.posts_virtuals_count++; - - while (true) { - add_or_set_value(acct_xdata->family_details.total, xdata.visited_value); - - acct_xdata->family_details.posts_count++; - if (post.has_flags(POST_VIRTUAL)) - acct_xdata->family_details.posts_virtuals_count++; - - acct = acct->parent; - if (acct) - acct_xdata = &acct->xdata(); - else - break; - } - } item_handler<post_t>::operator()(post); diff --git a/src/output.cc b/src/output.cc index f10de042..975d8077 100644 --- a/src/output.cc +++ b/src/output.cc @@ -297,17 +297,11 @@ void format_accounts::flush() } } - if (report.session.master->has_xdata()) { - account_t::xdata_t& xdata(report.session.master->xdata()); - - if (! report.HANDLED(no_total) && top_displayed > 1 && - xdata.family_details.total) { - xdata.self_details.total = xdata.family_details.total; - - bind_scope_t bound_scope(report, *report.session.master); - separator_format.format(out, bound_scope); - total_line_format.format(out, bound_scope); - } + if (! report.HANDLED(no_total) && top_displayed > 1 && + report.session.master->family_total()) { + bind_scope_t bound_scope(report, *report.session.master); + separator_format.format(out, bound_scope); + total_line_format.format(out, bound_scope); } out.flush(); diff --git a/src/post.cc b/src/post.cc index 42e81159..2c303a87 100644 --- a/src/post.cc +++ b/src/post.cc @@ -231,10 +231,11 @@ namespace { DEBUG("post.account_amount", "Found account: " << account->fullname()); - if (account->xdata().self_details.total.is_null()) + value_t total = account->self_total(); + if (total.is_null()) return 0L; else - return account->xdata().self_details.total.simplified(); + return total.simplified(); } value_t get_account_depth(post_t& post) { diff --git a/src/session.cc b/src/session.cc index ff23719b..e171ff4d 100644 --- a/src/session.cc +++ b/src/session.cc @@ -87,9 +87,14 @@ std::size_t session_t::read_journal(std::istream& in, { if (! master) master = journal->master; + std::size_t count = journal->parse(in, *this, master, &pathname, HANDLED(strict)); - clean_accounts(); // remove calculated totals + + // remove calculated totals and flags + clean_posts(); + clean_accounts(); + return count; } diff --git a/src/textual.cc b/src/textual.cc index 1c3bcb02..3652176a 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -1013,25 +1013,24 @@ post_t * instance_t::parse_post(char * line, DEBUG("textual.parse", "line " << linenum << ": " << "POST assign: parsed amt = " << *post->assigned_amount); - account_t::xdata_t& xdata(post->account->xdata()); - amount_t& amt(*post->assigned_amount); + amount_t& amt(*post->assigned_amount); + value_t account_total(post->account->self_total(false)); DEBUG("post.assign", "line " << linenum << ": " - "account balance = " << xdata.self_details.total); + "account balance = " << account_total); DEBUG("post.assign", "line " << linenum << ": " "post amount = " << amt); amount_t diff; - switch (xdata.self_details.total.type()) { + switch (account_total.type()) { case value_t::AMOUNT: - diff = amt - xdata.self_details.total.as_amount(); + diff = amt - account_total.as_amount(); break; case value_t::BALANCE: if (optional<amount_t> comm_bal = - xdata.self_details.total.as_balance() - .commodity_amount(amt.commodity())) + account_total.as_balance().commodity_amount(amt.commodity())) diff = amt - *comm_bal; else diff = amt; diff --git a/src/xact.cc b/src/xact.cc index 8fb1d14c..0ad223a1 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -306,7 +306,7 @@ bool xact_base_t::finalize() throw_(balance_error, _("Transaction does not balance")); } - // Add the final calculated totals each to their related account + // Add a pointer to each posting to their related accounts if (dynamic_cast<xact_t *>(this)) { bool all_null = true; @@ -314,19 +314,15 @@ bool xact_base_t::finalize() foreach (post_t * post, posts) { if (! post->amount.is_null()) { all_null = false; - post->amount.in_place_reduce(); - - add_or_set_value(post->account->xdata().self_details.total, - post->amount); - - DEBUG("xact.finalize.totals", - "Total for " << post->account->fullname() << " + " - << post->amount << ": " - << post->account->xdata().self_details.total); } else { some_null = true; } + + post->account->add_post(post); + + post->xdata().add_flags(POST_EXT_VISITED); + post->account->xdata().add_flags(ACCOUNT_EXT_VISITED); } if (all_null) return false; // ignore this xact completely |