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 Ar EXPR
|
||||||
.It Fl \-total-data Pq Fl J
|
.It Fl \-total-data Pq Fl J
|
||||||
.It Fl \-total-width Ar INT
|
.It Fl \-total-width Ar INT
|
||||||
|
.It Fl \-totals
|
||||||
.It Fl \-trace Ar INT
|
.It Fl \-trace Ar INT
|
||||||
.It Fl \-truncate
|
.It Fl \-truncate
|
||||||
.It Fl \-unbudgeted
|
.It Fl \-unbudgeted
|
||||||
|
|
|
||||||
|
|
@ -167,26 +167,29 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t get_total(account_t& account) {
|
value_t get_total(account_t& account) {
|
||||||
assert(account.xdata_);
|
if (! account.xdata_ || account.xdata_->total.is_null())
|
||||||
if (account.xdata_->total.is_null())
|
|
||||||
return 0L;
|
return 0L;
|
||||||
else
|
else
|
||||||
return account.xdata_->total;
|
return account.xdata_->total;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t get_count(account_t& account) {
|
value_t get_count(account_t& account) {
|
||||||
assert(account.xdata_);
|
if (account.xdata_)
|
||||||
return long(account.xdata_->total_count);
|
return long(account.xdata_->total_count);
|
||||||
|
else
|
||||||
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t get_subcount(account_t& account) {
|
value_t get_subcount(account_t& account) {
|
||||||
assert(account.xdata_);
|
if (account.xdata_)
|
||||||
return long(account.xdata_->count);
|
return long(account.xdata_->count);
|
||||||
|
else
|
||||||
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t get_amount(account_t& account) {
|
value_t get_amount(account_t& account) {
|
||||||
assert(account.xdata_);
|
if (! account.xdata_ ||
|
||||||
if (account.xdata_->value.is_null())
|
account.xdata_->value.is_null())
|
||||||
return 0L;
|
return 0L;
|
||||||
else
|
else
|
||||||
return account.xdata_->value;
|
return account.xdata_->value;
|
||||||
|
|
@ -314,33 +317,4 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const
|
||||||
return count;
|
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
|
} // namespace ledger
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ class account_t : public scope_t
|
||||||
std::size_t count; // posts counted toward amount
|
std::size_t count; // posts counted toward amount
|
||||||
std::size_t total_count; // posts counted toward total
|
std::size_t total_count; // posts counted toward total
|
||||||
std::size_t virtuals;
|
std::size_t virtuals;
|
||||||
|
std::size_t total_virtuals;
|
||||||
|
|
||||||
std::list<sort_value_t> sort_values;
|
std::list<sort_value_t> sort_values;
|
||||||
|
|
||||||
|
|
@ -183,8 +184,6 @@ class account_t : public scope_t
|
||||||
return xdata_ && xdata_->has_flags(flags);
|
return xdata_ && xdata_->has_flags(flags);
|
||||||
}
|
}
|
||||||
std::size_t children_with_flags(xdata_t::flags_t flags) const;
|
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);
|
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.HANDLER(display_total_).expr,
|
report.HANDLER(display_total_).expr,
|
||||||
report, report.HANDLED(revalued_only)));
|
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
|
// unround_posts will unround the amounts in all postings
|
||||||
if (report.HANDLED(unround))
|
if (report.HANDLED(unround))
|
||||||
handler.reset(new unround_posts(handler));
|
handler.reset(new unround_posts(handler));
|
||||||
|
|
|
||||||
|
|
@ -118,26 +118,6 @@ void truncate_xacts::operator()(post_t& post)
|
||||||
posts.push_back(&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()
|
void sort_posts::post_accumulated_posts()
|
||||||
{
|
{
|
||||||
std::stable_sort(posts.begin(), posts.end(),
|
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);
|
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);
|
item_handler<post_t>::operator()(post);
|
||||||
|
|
||||||
last_post = &post;
|
last_post = &post;
|
||||||
|
|
|
||||||
|
|
@ -180,22 +180,6 @@ public:
|
||||||
virtual void operator()(post_t& post);
|
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
|
* @brief Brief
|
||||||
*
|
*
|
||||||
|
|
@ -359,15 +343,17 @@ class calc_posts : public item_handler<post_t>
|
||||||
{
|
{
|
||||||
post_t * last_post;
|
post_t * last_post;
|
||||||
expr_t& amount_expr;
|
expr_t& amount_expr;
|
||||||
|
bool calc_totals;
|
||||||
|
|
||||||
calc_posts();
|
calc_posts();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
calc_posts(post_handler_ptr handler,
|
calc_posts(post_handler_ptr handler,
|
||||||
expr_t& _amount_expr)
|
expr_t& _amount_expr,
|
||||||
: item_handler<post_t>(handler),
|
bool _calc_totals = false)
|
||||||
last_post(NULL), amount_expr(_amount_expr) {
|
: item_handler<post_t>(handler), last_post(NULL),
|
||||||
TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&");
|
amount_expr(_amount_expr), calc_totals(_calc_totals) {
|
||||||
|
TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&, bool");
|
||||||
}
|
}
|
||||||
virtual ~calc_posts() {
|
virtual ~calc_posts() {
|
||||||
TRACE_DTOR(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')
|
if (verb[0] != 'b' && verb[0] != 'r')
|
||||||
rep.HANDLER(base).on_only();
|
rep.HANDLER(base).on_only();
|
||||||
|
|
||||||
|
if (verb[0] == 'b' || verb == "equity")
|
||||||
|
rep.HANDLER(totals).on_only();
|
||||||
|
|
||||||
if (rep.HANDLED(period_) && ! rep.HANDLED(sort_all_))
|
if (rep.HANDLED(period_) && ! rep.HANDLED(sort_all_))
|
||||||
rep.HANDLER(sort_xacts_).on_only();
|
rep.HANDLER(sort_xacts_).on_only();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -287,14 +287,15 @@ 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());
|
account_t::xdata_t& xdata(report.session.master->xdata());
|
||||||
|
|
||||||
if (! report.HANDLED(no_total) && top_displayed > 1 && xdata.total) {
|
if (! report.HANDLED(no_total) && top_displayed > 1 && xdata.total) {
|
||||||
xdata.value = xdata.total;
|
xdata.value = xdata.total;
|
||||||
bind_scope_t bound_scope(report, *report.session.master);
|
bind_scope_t bound_scope(report, *report.session.master);
|
||||||
separator_format.format(out, bound_scope);
|
separator_format.format(out, bound_scope);
|
||||||
total_line_format.format(out, bound_scope);
|
total_line_format.format(out, bound_scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
@ -306,8 +307,7 @@ void format_accounts::operator()(account_t& account)
|
||||||
"Proposing to format account: " << account.fullname());
|
"Proposing to format account: " << account.fullname());
|
||||||
|
|
||||||
if (account.has_flags(ACCOUNT_EXT_VISITED)) {
|
if (account.has_flags(ACCOUNT_EXT_VISITED)) {
|
||||||
DEBUG("account.display",
|
DEBUG("account.display", " Account or its children was visited");
|
||||||
" Account or its children visited by sum_all_accounts");
|
|
||||||
|
|
||||||
bind_scope_t bound_scope(report, account);
|
bind_scope_t bound_scope(report, account);
|
||||||
if (disp_pred(bound_scope)) {
|
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);
|
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)
|
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;
|
scoped_ptr<accounts_iterator> iter;
|
||||||
|
|
||||||
if (! HANDLED(sort_))
|
if (! HANDLED(sort_))
|
||||||
iter.reset(new basic_accounts_iterator(*session.master));
|
iter.reset(new basic_accounts_iterator(*session.master));
|
||||||
else
|
else
|
||||||
|
|
@ -477,7 +463,6 @@ option_t<report_t> * report_t::lookup_option(const char * p)
|
||||||
case 'a':
|
case 'a':
|
||||||
OPT(abbrev_len_);
|
OPT(abbrev_len_);
|
||||||
else OPT(account_);
|
else OPT(account_);
|
||||||
else OPT(account_amount_);
|
|
||||||
else OPT(actual);
|
else OPT(actual);
|
||||||
else OPT(add_budget);
|
else OPT(add_budget);
|
||||||
else OPT(amount_);
|
else OPT(amount_);
|
||||||
|
|
@ -613,6 +598,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
|
||||||
OPT_CH(amount_);
|
OPT_CH(amount_);
|
||||||
else OPT(tail_);
|
else OPT(tail_);
|
||||||
else OPT(total_);
|
else OPT(total_);
|
||||||
|
else OPT(totals);
|
||||||
else OPT(total_data);
|
else OPT(total_data);
|
||||||
else OPT(truncate_);
|
else OPT(truncate_);
|
||||||
else OPT(total_width_);
|
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 accounts_report(acct_handler_ptr handler);
|
||||||
void commodities_report(post_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_amount_expr(call_scope_t& scope);
|
||||||
value_t fn_total_expr(call_scope_t& scope);
|
value_t fn_total_expr(call_scope_t& scope);
|
||||||
value_t fn_display_amount(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); });
|
CTOR(report_t, abbrev_len_) { on_with(2L); });
|
||||||
OPTION(report_t, account_);
|
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
|
OPTION_(report_t, actual, DO() { // -L
|
||||||
parent->HANDLER(limit_).on("actual");
|
parent->HANDLER(limit_).on("actual");
|
||||||
});
|
});
|
||||||
|
|
@ -399,7 +383,6 @@ public:
|
||||||
|
|
||||||
OPTION_(report_t, gain, DO() { // -G
|
OPTION_(report_t, gain, DO() { // -G
|
||||||
parent->HANDLER(revalued).on_only();
|
parent->HANDLER(revalued).on_only();
|
||||||
parent->HANDLER(account_amount_).set_expr("amount | (0, 0)");
|
|
||||||
parent->HANDLER(amount_).set_expr("(amount, cost)");
|
parent->HANDLER(amount_).set_expr("(amount, cost)");
|
||||||
// Since we are displaying the amounts of revalued postings, they
|
// Since we are displaying the amounts of revalued postings, they
|
||||||
// will end up being composite totals, and hence a pair of pairs.
|
// will end up being composite totals, and hence a pair of pairs.
|
||||||
|
|
@ -629,6 +612,8 @@ public:
|
||||||
set_expr(args[0].to_string());
|
set_expr(args[0].to_string());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OPTION(report_t, totals);
|
||||||
|
|
||||||
OPTION_(report_t, total_data, DO() { // -J
|
OPTION_(report_t, total_data, DO() { // -J
|
||||||
parent->HANDLER(format_).on_with(parent->HANDLER(plot_total_format_).value);
|
parent->HANDLER(format_).on_with(parent->HANDLER(plot_total_format_).value);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue