diff options
author | John Wiegley <johnw@newartisans.com> | 2009-03-03 17:08:11 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-03-03 17:08:11 -0400 |
commit | eb45a0a4f46577c6615695256e5f6866a27ef20e (patch) | |
tree | 7839ad1f692df20276921ec182a78a14b13c61b9 | |
parent | cf2548c29cbd10c41bd23d119394489e1ced8e2a (diff) | |
download | fork-ledger-eb45a0a4f46577c6615695256e5f6866a27ef20e.tar.gz fork-ledger-eb45a0a4f46577c6615695256e5f6866a27ef20e.tar.bz2 fork-ledger-eb45a0a4f46577c6615695256e5f6866a27ef20e.zip |
Normalized how account totals are calculated
-rw-r--r-- | doc/ledger.1 | 1 | ||||
-rw-r--r-- | src/account.cc | 48 | ||||
-rw-r--r-- | src/account.h | 3 | ||||
-rw-r--r-- | src/chain.cc | 10 | ||||
-rw-r--r-- | src/filters.cc | 46 | ||||
-rw-r--r-- | src/filters.h | 26 | ||||
-rw-r--r-- | src/global.cc | 3 | ||||
-rw-r--r-- | src/output.cc | 20 | ||||
-rw-r--r-- | src/report.cc | 22 | ||||
-rw-r--r-- | src/report.h | 19 |
10 files changed, 69 insertions, 129 deletions
diff --git a/doc/ledger.1 b/doc/ledger.1 index 551db01a..a1e84302 100644 --- a/doc/ledger.1 +++ b/doc/ledger.1 @@ -214,6 +214,7 @@ appeared in the original journal file. .It Fl \-total Ar EXPR .It Fl \-total-data Pq Fl J .It Fl \-total-width Ar INT +.It Fl \-totals .It Fl \-trace Ar INT .It Fl \-truncate .It Fl \-unbudgeted diff --git a/src/account.cc b/src/account.cc index 9bc96564..3e39045f 100644 --- a/src/account.cc +++ b/src/account.cc @@ -167,26 +167,29 @@ namespace { } value_t get_total(account_t& account) { - assert(account.xdata_); - if (account.xdata_->total.is_null()) + if (! account.xdata_ || account.xdata_->total.is_null()) return 0L; else return account.xdata_->total; } value_t get_count(account_t& account) { - assert(account.xdata_); - return long(account.xdata_->total_count); + if (account.xdata_) + return long(account.xdata_->total_count); + else + return 0L; } value_t get_subcount(account_t& account) { - assert(account.xdata_); - return long(account.xdata_->count); + if (account.xdata_) + return long(account.xdata_->count); + else + return 0L; } value_t get_amount(account_t& account) { - assert(account.xdata_); - if (account.xdata_->value.is_null()) + if (! account.xdata_ || + account.xdata_->value.is_null()) return 0L; else return account.xdata_->value; @@ -314,33 +317,4 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const return count; } -void account_t::calculate_sums(expr_t& amount_expr) -{ - xdata_t& xd(xdata()); - - foreach (accounts_map::value_type& pair, accounts) { - (*pair.second).calculate_sums(amount_expr); - - xdata_t& child_xd((*pair.second).xdata()); - if (! child_xd.total.is_null()) { - add_or_set_value(xd.total, child_xd.total); - xd.total_count += child_xd.total_count; - } else { - assert(child_xd.total_count == 0); - assert(child_xd.count == 0); - } - } - - bind_scope_t bound_scope(*amount_expr.get_context(), *this); - value_t amount(amount_expr.calc(bound_scope)); - - if (! amount.is_null()) { - DEBUG("account.sums", "Added " << amount << " to " << fullname()); - add_or_set_value(xd.total, amount); - xd.total_count += xd.count; - } else { - assert(xd.count == 0); - } -} - } // namespace ledger diff --git a/src/account.h b/src/account.h index 3bd0b9ca..79c989bc 100644 --- a/src/account.h +++ b/src/account.h @@ -133,6 +133,7 @@ class account_t : public scope_t std::size_t count; // posts counted toward amount std::size_t total_count; // posts counted toward total std::size_t virtuals; + std::size_t total_virtuals; std::list<sort_value_t> sort_values; @@ -183,8 +184,6 @@ class account_t : public scope_t return xdata_ && xdata_->has_flags(flags); } std::size_t children_with_flags(xdata_t::flags_t flags) const; - - void calculate_sums(expr_t& amount_expr); }; std::ostream& operator<<(std::ostream& out, const account_t& account); diff --git a/src/chain.cc b/src/chain.cc index 9155d4fa..5b1ba18c 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -86,13 +86,13 @@ post_handler_ptr chain_post_handlers(report_t& report, report.HANDLER(display_total_).expr, report.HANDLER(display_total_).expr, report, report.HANDLED(revalued_only))); - - // calc_posts computes the running total. When this appears will - // determine, for example, whether filtered posts are included or excluded - // from the running total. - handler.reset(new calc_posts(handler, expr)); } + // calc_posts computes the running total. When this appears will determine, + // for example, whether filtered posts are included or excluded from the + // running total. + handler.reset(new calc_posts(handler, expr, report.HANDLED(totals))); + // unround_posts will unround the amounts in all postings if (report.HANDLED(unround)) handler.reset(new unround_posts(handler)); diff --git a/src/filters.cc b/src/filters.cc index ea3ed99d..bdcd1b67 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -118,26 +118,6 @@ void truncate_xacts::operator()(post_t& post) posts.push_back(&post); } -void set_account_value::operator()(post_t& post) -{ - account_t * acct = post.reported_account(); - - account_t::xdata_t& xdata(acct->xdata()); - DEBUG("account.sums", "Account value was = " << xdata.value); - post.add_to_value(xdata.value, amount_expr); - DEBUG("account.sums", "Account value is = " << xdata.value); - - xdata.count++; - if (post.has_flags(POST_VIRTUAL)) - xdata.virtuals++; - - DEBUG("account.display", - "Visiting account: " << post.account->fullname()); - post.account->xdata().add_flags(ACCOUNT_EXT_VISITED); - - item_handler<post_t>::operator()(post); -} - void sort_posts::post_accumulated_posts() { std::stable_sort(posts.begin(), posts.end(), @@ -222,6 +202,32 @@ void calc_posts::operator()(post_t& post) post.add_to_value(xdata.total, amount_expr); + if (calc_totals) { + account_t * acct = post.reported_account(); + + account_t::xdata_t * acct_xdata = &acct->xdata(); + + post.add_to_value(acct_xdata->value, amount_expr); + + acct_xdata->count++; + acct_xdata->virtuals++; + acct_xdata->add_flags(ACCOUNT_EXT_VISITED); + + while (true) { + post.add_to_value(acct_xdata->total, amount_expr); + + acct_xdata->total_count++; + if (post.has_flags(POST_VIRTUAL)) + acct_xdata->total_virtuals++; + + acct = acct->parent; + if (acct) + acct_xdata = &acct->xdata(); + else + break; + } + } + item_handler<post_t>::operator()(post); last_post = &post; diff --git a/src/filters.h b/src/filters.h index 64b688ec..aafdf082 100644 --- a/src/filters.h +++ b/src/filters.h @@ -185,22 +185,6 @@ public: * * Long. */ -class set_account_value : public item_handler<post_t> -{ - expr_t& amount_expr; - -public: - set_account_value(expr_t& _amount_expr) - : item_handler<post_t>(), amount_expr(_amount_expr) {} - - virtual void operator()(post_t& post); -}; - -/** - * @brief Brief - * - * Long. - */ class sort_posts : public item_handler<post_t> { typedef std::deque<post_t *> posts_deque; @@ -359,15 +343,17 @@ class calc_posts : public item_handler<post_t> { post_t * last_post; expr_t& amount_expr; + bool calc_totals; calc_posts(); public: calc_posts(post_handler_ptr handler, - expr_t& _amount_expr) - : item_handler<post_t>(handler), - last_post(NULL), amount_expr(_amount_expr) { - TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&"); + expr_t& _amount_expr, + bool _calc_totals = false) + : item_handler<post_t>(handler), last_post(NULL), + amount_expr(_amount_expr), calc_totals(_calc_totals) { + TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&, bool"); } virtual ~calc_posts() { TRACE_DTOR(calc_posts); diff --git a/src/global.cc b/src/global.cc index 22bd5b7b..dc21012c 100644 --- a/src/global.cc +++ b/src/global.cc @@ -408,6 +408,9 @@ void global_scope_t::normalize_report_options(const string& verb) if (verb[0] != 'b' && verb[0] != 'r') rep.HANDLER(base).on_only(); + if (verb[0] == 'b' || verb == "equity") + rep.HANDLER(totals).on_only(); + if (rep.HANDLED(period_) && ! rep.HANDLED(sort_all_)) rep.HANDLER(sort_xacts_).on_only(); diff --git a/src/output.cc b/src/output.cc index f7f18351..e14c75dc 100644 --- a/src/output.cc +++ b/src/output.cc @@ -287,14 +287,15 @@ void format_accounts::flush() } } - assert(report.session.master->has_xdata()); - account_t::xdata_t& xdata(report.session.master->xdata()); - - if (! report.HANDLED(no_total) && top_displayed > 1 && xdata.total) { - xdata.value = xdata.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.session.master->has_xdata()) { + account_t::xdata_t& xdata(report.session.master->xdata()); + + if (! report.HANDLED(no_total) && top_displayed > 1 && xdata.total) { + xdata.value = xdata.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(); @@ -306,8 +307,7 @@ void format_accounts::operator()(account_t& account) "Proposing to format account: " << account.fullname()); if (account.has_flags(ACCOUNT_EXT_VISITED)) { - DEBUG("account.display", - " Account or its children visited by sum_all_accounts"); + DEBUG("account.display", " Account or its children was visited"); bind_scope_t bound_scope(report, account); if (disp_pred(bound_scope)) { diff --git a/src/report.cc b/src/report.cc index 2c145dc7..160cb698 100644 --- a/src/report.cc +++ b/src/report.cc @@ -67,27 +67,13 @@ void report_t::xact_report(post_handler_ptr handler, xact_t& xact) session.clean_posts(xact); } -void report_t::sum_all_accounts() -{ - expr_t& amount_expr(HANDLER(amount_).expr); - amount_expr.set_context(this); - - journal_posts_iterator walker(*session.journal.get()); - pass_down_posts(chain_post_handlers - (*this, post_handler_ptr(new set_account_value(amount_expr)), - true), walker); - - expr_t& account_amount_expr(HANDLER(account_amount_).expr); - account_amount_expr.set_context(this); - session.master->calculate_sums(account_amount_expr); -} - void report_t::accounts_report(acct_handler_ptr handler) { - sum_all_accounts(); + journal_posts_iterator walker(*session.journal.get()); + pass_down_posts(chain_post_handlers(*this, post_handler_ptr(new ignore_posts), + true), walker); scoped_ptr<accounts_iterator> iter; - if (! HANDLED(sort_)) iter.reset(new basic_accounts_iterator(*session.master)); else @@ -477,7 +463,6 @@ option_t<report_t> * report_t::lookup_option(const char * p) case 'a': OPT(abbrev_len_); else OPT(account_); - else OPT(account_amount_); else OPT(actual); else OPT(add_budget); else OPT(amount_); @@ -613,6 +598,7 @@ option_t<report_t> * report_t::lookup_option(const char * p) OPT_CH(amount_); else OPT(tail_); else OPT(total_); + else OPT(totals); else OPT(total_data); else OPT(truncate_); else OPT(total_width_); diff --git a/src/report.h b/src/report.h index 7bca98b8..f83f1745 100644 --- a/src/report.h +++ b/src/report.h @@ -127,8 +127,6 @@ public: void accounts_report(acct_handler_ptr handler); void commodities_report(post_handler_ptr handler); - void sum_all_accounts(); - value_t fn_amount_expr(call_scope_t& scope); value_t fn_total_expr(call_scope_t& scope); value_t fn_display_amount(call_scope_t& scope); @@ -190,20 +188,6 @@ public: CTOR(report_t, abbrev_len_) { on_with(2L); }); OPTION(report_t, account_); - OPTION__ - (report_t, account_amount_, - expr_t expr; - CTOR(report_t, account_amount_) { - set_expr("amount"); - } - void set_expr(const string& str) { - expr = str; - on(str); - } - DO_(args) { - set_expr(args[0].to_string()); - }); - OPTION_(report_t, actual, DO() { // -L parent->HANDLER(limit_).on("actual"); }); @@ -399,7 +383,6 @@ public: OPTION_(report_t, gain, DO() { // -G parent->HANDLER(revalued).on_only(); - parent->HANDLER(account_amount_).set_expr("amount | (0, 0)"); parent->HANDLER(amount_).set_expr("(amount, cost)"); // Since we are displaying the amounts of revalued postings, they // will end up being composite totals, and hence a pair of pairs. @@ -629,6 +612,8 @@ public: set_expr(args[0].to_string()); }); + OPTION(report_t, totals); + OPTION_(report_t, total_data, DO() { // -J parent->HANDLER(format_).on_with(parent->HANDLER(plot_total_format_).value); }); |