Normalized how account totals are calculated

This commit is contained in:
John Wiegley 2009-03-03 17:08:11 -04:00
parent cf2548c29c
commit eb45a0a4f4
10 changed files with 68 additions and 128 deletions

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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));

View file

@ -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;

View file

@ -180,22 +180,6 @@ public:
virtual void operator()(post_t& post);
};
/**
* @brief Brief
*
* 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
*
@ -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);

View file

@ -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();

View file

@ -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.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.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)) {

View file

@ -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_);

View file

@ -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);
});