Normalized how account totals are calculated
This commit is contained in:
parent
cf2548c29c
commit
eb45a0a4f4
10 changed files with 68 additions and 128 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
if (account.xdata_)
|
||||
return long(account.xdata_->total_count);
|
||||
else
|
||||
return 0L;
|
||||
}
|
||||
|
||||
value_t get_subcount(account_t& account) {
|
||||
assert(account.xdata_);
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
10
src/chain.cc
10
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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ void format_accounts::flush()
|
|||
}
|
||||
}
|
||||
|
||||
assert(report.session.master->has_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) {
|
||||
|
|
@ -296,6 +296,7 @@ void format_accounts::flush()
|
|||
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)) {
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
|
|
|
|||
19
src/report.h
19
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);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue