summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-20 02:53:54 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-20 02:53:54 -0400
commitc1b25fcf8629eca326fe6dd586e4896eeb5f2d45 (patch)
treef7c59ce215ee66513db2f9eb142cdf9e7095c465 /src
parentf2f52066d2a9c82619ffea0f3972e48417a90b5b (diff)
downloadfork-ledger-c1b25fcf8629eca326fe6dd586e4896eeb5f2d45.tar.gz
fork-ledger-c1b25fcf8629eca326fe6dd586e4896eeb5f2d45.tar.bz2
fork-ledger-c1b25fcf8629eca326fe6dd586e4896eeb5f2d45.zip
Rewrote the equity command, which is working again
The old implementation used an account formatter, and was very specialized. The new is done as a transaction filter, and works along with everything else, eliminating bugs special to the equity report.
Diffstat (limited to 'src')
-rw-r--r--src/chain.cc4
-rw-r--r--src/filters.cc45
-rw-r--r--src/filters.h28
-rw-r--r--src/global.cc13
-rw-r--r--src/output.cc78
-rw-r--r--src/output.h23
-rw-r--r--src/report.cc54
-rw-r--r--src/report.h5
8 files changed, 110 insertions, 140 deletions
diff --git a/src/chain.cc b/src/chain.cc
index 30a6793c..c67de108 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -113,7 +113,9 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
//
// dow_xacts is like period_xacts, except that it reports all the xacts
// that fall on each subsequent day of the week.
- if (report.HANDLED(subtotal))
+ if (report.HANDLED(equity))
+ handler.reset(new xacts_as_equity(handler, expr));
+ else if (report.HANDLED(subtotal))
handler.reset(new subtotal_xacts(handler, expr));
}
diff --git a/src/filters.cc b/src/filters.cc
index c5116b6c..651bc762 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -516,7 +516,7 @@ void interval_xacts::operator()(xact_t& xact)
xact_temps.push_back(xact_t(&empty_account));
xact_t& null_xact = xact_temps.back();
- null_xact.add_flags(ITEM_TEMP);
+ null_xact.add_flags(ITEM_TEMP | XACT_CALCULATED);
null_xact.amount = 0L;
null_entry.add_xact(&null_xact);
@@ -536,6 +536,49 @@ void interval_xacts::operator()(xact_t& xact)
last_xact = &xact;
}
+void xacts_as_equity::report_subtotal()
+{
+ date_t finish;
+ foreach (xact_t * xact, component_xacts) {
+ date_t date = xact->reported_date();
+ if (! is_valid(finish) || date > finish)
+ finish = date;
+ }
+ component_xacts.clear();
+
+ entry_temps.push_back(entry_t());
+ entry_t& entry = entry_temps.back();
+ entry.payee = "Opening Balances";
+ entry._date = finish;
+
+ value_t total = 0L;
+ foreach (values_map::value_type& pair, values) {
+ handle_value(pair.second.value, pair.second.account, &entry, 0,
+ xact_temps, *handler);
+ total += pair.second.value;
+ }
+ values.clear();
+
+ if (total.is_balance()) {
+ foreach (balance_t::amounts_map::value_type pair,
+ total.as_balance().amounts) {
+ xact_temps.push_back(xact_t(balance_account));
+ xact_t& balance_xact = xact_temps.back();
+ balance_xact.add_flags(ITEM_TEMP);
+ balance_xact.amount = - pair.second;
+ entry.add_xact(&balance_xact);
+ (*handler)(balance_xact);
+ }
+ } else {
+ xact_temps.push_back(xact_t(balance_account));
+ xact_t& balance_xact = xact_temps.back();
+ balance_xact.add_flags(ITEM_TEMP);
+ balance_xact.amount = - total.to_amount();
+ entry.add_xact(&balance_xact);
+ (*handler)(balance_xact);
+ }
+}
+
by_payee_xacts::~by_payee_xacts()
{
TRACE_DTOR(by_payee_xacts);
diff --git a/src/filters.h b/src/filters.h
index d5636796..985fbf94 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -611,6 +611,34 @@ public:
virtual void operator()(xact_t& xact);
};
+class xacts_as_equity : public subtotal_xacts
+{
+ interval_t interval;
+ xact_t * last_xact;
+ account_t equity_account;
+ account_t * balance_account;
+
+ xacts_as_equity();
+
+public:
+ xacts_as_equity(xact_handler_ptr _handler, expr_t& amount_expr)
+ : subtotal_xacts(_handler, amount_expr),
+ equity_account(NULL, "Equity") {
+ TRACE_CTOR(xacts_as_equity, "xact_handler_ptr, expr_t&");
+ balance_account = equity_account.find_account("Opening Balances");
+ }
+ virtual ~xacts_as_equity() throw() {
+ TRACE_DTOR(xacts_as_equity);
+ }
+
+ void report_subtotal();
+
+ virtual void flush() {
+ report_subtotal();
+ subtotal_xacts::flush();
+ }
+};
+
/**
* @brief Brief
*
diff --git a/src/global.cc b/src/global.cc
index 0ecd1fb8..f967d3e9 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -339,7 +339,7 @@ void global_scope_t::normalize_session_options()
function_t global_scope_t::look_for_precommand(scope_t& scope,
const string& verb)
{
- if (expr_t::ptr_op_t def = scope.lookup(string("precmd_") + verb))
+ if (expr_t::ptr_op_t def = scope.lookup(string(PRECMD_PREFIX) + verb))
return def->as_function();
else
return function_t();
@@ -348,7 +348,7 @@ function_t global_scope_t::look_for_precommand(scope_t& scope,
function_t global_scope_t::look_for_command(scope_t& scope,
const string& verb)
{
- if (expr_t::ptr_op_t def = scope.lookup(string("cmd_") + verb))
+ if (expr_t::ptr_op_t def = scope.lookup(string(CMD_PREFIX) + verb))
return def->as_function();
else
return function_t();
@@ -361,7 +361,7 @@ void global_scope_t::normalize_report_options(const string& verb)
report_t& rep(report());
- // jww (2009-02-09): These global are a hack, but hard to avoid
+ // jww (2009-02-09): These global are a hack, but hard to avoid.
item_t::use_effective_date = rep.HANDLED(effective);
if (rep.HANDLED(date_format_)) {
@@ -369,14 +369,15 @@ void global_scope_t::normalize_report_options(const string& verb)
output_date_format = rep.HANDLER(date_format_).str();
}
- // jww (2008-08-14): This code really needs to be rationalized away
- // for 3.0.
+ // jww (2008-08-14): This code really needs to be rationalized away for 3.0.
+ // I might be able to do it with command objects, like register_t, which
+ // each know how to adjust the report based on its current option settings.
if (verb == "print" || verb == "entry" || verb == "dump") {
rep.HANDLER(related).on_only();
rep.HANDLER(related_all).on_only();
}
else if (verb == "equity") {
- rep.HANDLER(subtotal).on_only();
+ rep.HANDLER(equity).on_only();
}
else if (rep.HANDLED(related)) {
if (verb[0] == 'r') {
diff --git a/src/output.cc b/src/output.cc
index bd55fe99..2cc075eb 100644
--- a/src/output.cc
+++ b/src/output.cc
@@ -304,82 +304,4 @@ void format_accounts::operator()(account_t& account)
posted_accounts.push_back(&account);
}
-format_equity::format_equity(report_t& _report, const string& _format)
- : format_accounts(_report)
-{
- const char * f = _format.c_str();
-
- if (const char * p = std::strstr(f, "%/")) {
- first_line_format.parse(string(f, 0, p - f));
- next_lines_format.parse(string(p + 2));
- } else {
- first_line_format.parse(_format);
- next_lines_format.parse(_format);
- }
-
- entry_t header_entry;
- header_entry.payee = "Opening Balances";
- header_entry._date = CURRENT_DATE();
- bind_scope_t bound_scope(report, header_entry);
- first_line_format.format(report.output_stream, bound_scope);
-}
-
-void format_equity::flush()
-{
- account_t summary(NULL, "Equity:Opening Balances");
-
- account_t::xdata_t& xdata(summary.xdata());
- std::ostream& out(report.output_stream);
-
- xdata.value = total.negate();
-
- if (total.type() >= value_t::BALANCE) {
- const balance_t * bal;
- if (total.is_type(value_t::BALANCE))
- bal = &(total.as_balance());
- else
- assert(false);
-
- foreach (balance_t::amounts_map::value_type pair, bal->amounts) {
- xdata.value = pair.second;
- xdata.value.negate();
- bind_scope_t bound_scope(report, summary);
- next_lines_format.format(out, bound_scope);
- }
- } else {
- bind_scope_t bound_scope(report, summary);
- next_lines_format.format(out, bound_scope);
- }
- out.flush();
-}
-
-void format_equity::post_account(account_t& account)
-{
- std::ostream& out(report.output_stream);
-
- if (! account.has_flags(ACCOUNT_EXT_MATCHING))
- return;
-
- value_t val = account.xdata().value;
-
- if (val.type() >= value_t::BALANCE) {
- const balance_t * bal;
- if (val.is_type(value_t::BALANCE))
- bal = &(val.as_balance());
- else
- assert(false);
-
- foreach (balance_t::amounts_map::value_type pair, bal->amounts) {
- account.xdata().value = pair.second;
- bind_scope_t bound_scope(report, account);
- next_lines_format.format(out, bound_scope);
- }
- account.xdata().value = val;
- } else {
- bind_scope_t bound_scope(report, account);
- next_lines_format.format(out, bound_scope);
- }
- total += val;
-}
-
} // namespace ledger
diff --git a/src/output.h b/src/output.h
index 7019b7b2..f638f4de 100644
--- a/src/output.h
+++ b/src/output.h
@@ -192,29 +192,6 @@ public:
virtual void operator()(account_t& account);
};
-/**
- * @brief Brief
- *
- * Long.
- */
-class format_equity : public format_accounts
-{
- format_t first_line_format;
- format_t next_lines_format;
-
- mutable value_t total;
-
- public:
- format_equity(report_t& _report,
- const string& _format);
- virtual ~format_equity() {
- TRACE_DTOR(format_equity);
- }
-
- virtual void post_account(account_t& account);
- virtual void flush();
-};
-
} // namespace ledger
#endif // _OUTPUT_H
diff --git a/src/report.cc b/src/report.cc
index d9e88634..da56e141 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -356,7 +356,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
OPT(effective);
else OPT(empty);
else OPT_(end_);
- else OPT(equity_format_);
+ else OPT(equity);
break;
case 'f':
OPT(flat);
@@ -475,10 +475,10 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'c':
- if (WANT_CMD()) { p += CMD_PREFIX_LEN;
- switch (*p) {
+ if (WANT_CMD()) { const char * q = p + CMD_PREFIX_LEN;
+ switch (*q) {
case 'b':
- if (*(p + 1) == '\0' || is_eq(p, "bal") || is_eq(p, "balance"))
+ if (*(q + 1) == '\0' || is_eq(q, "bal") || is_eq(q, "balance"))
return expr_t::op_t::wrap_functor
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
(new format_accounts(*this, report_format(HANDLER(balance_format_)),
@@ -486,7 +486,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'c':
- if (is_eq(p, "csv"))
+ if (is_eq(q, "csv"))
return WRAP_FUNCTOR
(reporter<>
(new format_xacts(*this, report_format(HANDLER(csv_format_))),
@@ -494,30 +494,30 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'e':
- if (is_eq(p, "equity"))
- return expr_t::op_t::wrap_functor
- (reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
- (new format_equity(*this, report_format(HANDLER(print_format_))),
+ if (is_eq(q, "equity"))
+ return WRAP_FUNCTOR
+ (reporter<>
+ (new format_xacts(*this, report_format(HANDLER(print_format_))),
*this));
- else if (is_eq(p, "entry"))
+ else if (is_eq(q, "entry"))
return WRAP_FUNCTOR(entry_command);
- else if (is_eq(p, "emacs"))
+ else if (is_eq(q, "emacs"))
return WRAP_FUNCTOR
(reporter<>(new format_emacs_xacts(output_stream), *this));
break;
case 'p':
- if (*(p + 1) == '\0' || is_eq(p, "print"))
+ if (*(q + 1) == '\0' || is_eq(q, "print"))
return WRAP_FUNCTOR
(reporter<>
(new format_xacts(*this, report_format(HANDLER(print_format_))),
*this));
- else if (is_eq(p, "prices"))
+ else if (is_eq(q, "prices"))
return expr_t::op_t::wrap_functor
(reporter<xact_t, xact_handler_ptr, &report_t::commodities_report>
(new format_xacts(*this, report_format(HANDLER(prices_format_))),
*this));
- else if (is_eq(p, "pricesdb"))
+ else if (is_eq(q, "pricesdb"))
return expr_t::op_t::wrap_functor
(reporter<xact_t, xact_handler_ptr, &report_t::commodities_report>
(new format_xacts(*this, report_format(HANDLER(pricesdb_format_))),
@@ -525,17 +525,17 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'r':
- if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register"))
+ if (*(q + 1) == '\0' || is_eq(q, "reg") || is_eq(q, "register"))
return WRAP_FUNCTOR
(reporter<>
(new format_xacts(*this, report_format(HANDLER(register_format_))),
*this));
- else if (is_eq(p, "reload"))
+ else if (is_eq(q, "reload"))
return MAKE_FUNCTOR(report_t::reload_command);
break;
case 's':
- if (is_eq(p, "stats") || is_eq(p, "stat"))
+ if (is_eq(q, "stats") || is_eq(q, "stat"))
return WRAP_FUNCTOR(reporter<>(new gather_statistics(*this), *this));
break;
}
@@ -565,8 +565,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'o':
- if (WANT_OPT()) { p += OPT_PREFIX_LEN;
- if (option_t<report_t> * handler = lookup_option(p))
+ if (WANT_OPT()) { const char * q = p + OPT_PREFIX_LEN;
+ if (option_t<report_t> * handler = lookup_option(q))
return MAKE_OPT_HANDLER(report_t, handler);
}
else if (is_eq(p, "options")) {
@@ -575,28 +575,28 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'p':
- if (WANT_PRECMD()) { p += PRECMD_PREFIX_LEN;
- switch (*p) {
+ if (WANT_PRECMD()) { const char * q = p + PRECMD_PREFIX_LEN;
+ switch (*q) {
case 'a':
- if (is_eq(p, "args"))
+ if (is_eq(q, "args"))
return WRAP_FUNCTOR(args_command);
break;
case 'e':
- if (is_eq(p, "eval"))
+ if (is_eq(q, "eval"))
return WRAP_FUNCTOR(eval_command);
break;
case 'f':
- if (is_eq(p, "format"))
+ if (is_eq(q, "format"))
return WRAP_FUNCTOR(format_command);
break;
case 'p':
- if (is_eq(p, "parse"))
+ if (is_eq(q, "parse"))
return WRAP_FUNCTOR(parse_command);
- else if (is_eq(p, "period"))
+ else if (is_eq(q, "period"))
return WRAP_FUNCTOR(period_command);
break;
case 't':
- if (is_eq(p, "template"))
+ if (is_eq(q, "template"))
return WRAP_FUNCTOR(template_command);
break;
}
diff --git a/src/report.h b/src/report.h
index 0e66ec75..47a073d1 100644
--- a/src/report.h
+++ b/src/report.h
@@ -354,10 +354,7 @@ public:
#endif
});
- OPTION__(report_t, equity_format_, CTOR(report_t, equity_format_) {
- on("\n%D %Y%C%P\n%/ %-34W %12t\n");
- });
-
+ OPTION(report_t, equity);
OPTION(report_t, flat);
OPTION(report_t, forecast_);
OPTION(report_t, format_); // -F