Many fixes to both --market and --exchange

This commit is contained in:
John Wiegley 2009-02-23 01:51:23 -04:00
parent de6de07bac
commit 9f53efbf5f
11 changed files with 106 additions and 71 deletions

View file

@ -163,18 +163,19 @@ balance_t::value(const bool primary_only,
const optional<datetime_t>& moment, const optional<datetime_t>& moment,
const optional<commodity_t&>& in_terms_of) const const optional<commodity_t&>& in_terms_of) const
{ {
optional<balance_t> temp; balance_t temp;
bool resolved = false;
foreach (const amounts_map::value_type& pair, amounts) { foreach (const amounts_map::value_type& pair, amounts) {
if (! temp)
temp = balance_t();
if (optional<amount_t> val = pair.second.value(primary_only, moment, if (optional<amount_t> val = pair.second.value(primary_only, moment,
in_terms_of)) in_terms_of)) {
*temp += *val; temp += *val;
else resolved = true;
*temp += pair.second; } else {
temp += pair.second;
} }
return temp; }
return resolved ? temp : optional<balance_t>();
} }
optional<amount_t> optional<amount_t>

View file

@ -74,6 +74,15 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
handler.reset(new filter_xacts(handler, display_predicate, report)); handler.reset(new filter_xacts(handler, display_predicate, report));
} }
// changed_value_xacts adds virtual xacts to the list to account for
// changes in market value of commodities, which otherwise would affect
// the running total unpredictably.
if (report.HANDLED(revalued))
handler.reset(new changed_value_xacts(handler,
report.HANDLER(display_total_).expr,
report,
report.HANDLED(revalued_only)));
// calc_xacts computes the running total. When this appears will // calc_xacts computes the running total. When this appears will
// determine, for example, whether filtered xacts are included or excluded // determine, for example, whether filtered xacts are included or excluded
// from the running total. // from the running total.
@ -98,14 +107,6 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
handler.reset(new sort_xacts(handler, report.HANDLER(sort_).str())); handler.reset(new sort_xacts(handler, report.HANDLER(sort_).str()));
} }
// changed_value_xacts adds virtual xacts to the list to account for
// changes in market value of commodities, which otherwise would affect
// the running total unpredictably.
if (report.HANDLED(revalued))
handler.reset(new changed_value_xacts(handler,
report.HANDLER(total_).expr,
report.HANDLED(revalued_only)));
// collapse_xacts causes entries with multiple xacts to appear as entries // collapse_xacts causes entries with multiple xacts to appear as entries
// with a subtotaled xact for each commodity used. // with a subtotaled xact for each commodity used.
if (report.HANDLED(collapse)) if (report.HANDLED(collapse))
@ -137,7 +138,6 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
if (report.HANDLED(period_)) { if (report.HANDLED(period_)) {
handler.reset(new interval_xacts(handler, expr, handler.reset(new interval_xacts(handler, expr,
report.HANDLER(period_).str(), report.HANDLER(period_).str(),
report.session.master.get(),
report.HANDLED(exact), report.HANDLED(exact),
report.HANDLED(empty))); report.HANDLED(empty)));
handler.reset(new sort_xacts(handler, "date")); handler.reset(new sort_xacts(handler, "date"));

View file

@ -33,6 +33,7 @@
#include "iterators.h" #include "iterators.h"
#include "compare.h" #include "compare.h"
#include "format.h" #include "format.h"
#include "report.h"
namespace ledger { namespace ledger {
@ -218,7 +219,8 @@ namespace {
unsigned int flags, unsigned int flags,
std::list<xact_t>& temps, std::list<xact_t>& temps,
item_handler<xact_t>& handler, item_handler<xact_t>& handler,
const date_t& date = date_t()) const date_t& date = date_t(),
const value_t& total = value_t())
{ {
temps.push_back(xact_t(account)); temps.push_back(xact_t(account));
xact_t& xact(temps.back()); xact_t& xact(temps.back());
@ -266,6 +268,9 @@ namespace {
break; break;
} }
if (! total.is_null())
xdata.total = total;
if (flags) if (flags)
xdata.add_flags(flags); xdata.add_flags(flags);
@ -294,7 +299,7 @@ void collapse_xacts::report_subtotal()
date_t earliest_date; date_t earliest_date;
foreach (xact_t * xact, component_xacts) { foreach (xact_t * xact, component_xacts) {
date_t reported = xact->reported_date(); date_t reported = xact->date();
if (! is_valid(earliest_date) || if (! is_valid(earliest_date) ||
reported < earliest_date) reported < earliest_date)
earliest_date = reported; earliest_date = reported;
@ -367,35 +372,54 @@ void related_xacts::flush()
item_handler<xact_t>::flush(); item_handler<xact_t>::flush();
} }
void changed_value_xacts::output_diff(const date_t& date) void changed_value_xacts::output_diff(xact_t * xact, const date_t& date)
{ {
value_t cur_bal; if (is_valid(date))
xact->xdata().date = date;
last_xact->xdata().date = date; value_t repriced_total;
cur_bal = total_expr.calc(*last_xact).rounded(); try {
bind_scope_t bound_scope(report, *xact);
repriced_total = total_expr.calc(bound_scope);
}
catch (...) {
xact->xdata().date = date_t();
throw;
}
xact->xdata().date = date_t();
DEBUG("filter.changed_value",
"output_diff(last_balance) = " << last_balance);
DEBUG("filter.changed_value",
"output_diff(repriced_total) = " << repriced_total);
if (value_t diff = repriced_total - last_balance) {
DEBUG("filter.changed_value", "output_diff(strip(diff)) = "
<< diff.strip_annotations(report.what_to_keep()));
if (value_t diff = cur_bal - last_balance) {
entry_temps.push_back(entry_t()); entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back(); entry_t& entry = entry_temps.back();
entry.payee = "Commodities revalued"; entry.payee = "Commodities revalued";
entry._date = date; entry._date = is_valid(date) ? date : xact->date();
handle_value(diff, NULL, &entry, XACT_EXT_NO_TOTAL, xact_temps, handle_value(diff, &revalued_account, &entry, XACT_EXT_NO_TOTAL,
*handler); xact_temps, *handler, *entry._date, repriced_total);
} }
} }
void changed_value_xacts::operator()(xact_t& xact) void changed_value_xacts::operator()(xact_t& xact)
{ {
if (last_xact) if (last_xact)
output_diff(last_xact->reported_date()); output_diff(last_xact, xact.date());
if (changed_values_only) if (changed_values_only)
xact.xdata().add_flags(XACT_EXT_DISPLAYED); xact.xdata().add_flags(XACT_EXT_DISPLAYED);
item_handler<xact_t>::operator()(xact); item_handler<xact_t>::operator()(xact);
last_balance = total_expr.calc(xact).rounded(); bind_scope_t bound_scope(report, xact);
last_balance = total_expr.calc(bound_scope);
last_xact = &xact; last_xact = &xact;
} }
@ -409,7 +433,7 @@ void subtotal_xacts::report_subtotal(const char * spec_fmt,
date_t range_start = start; date_t range_start = start;
date_t range_finish = finish; date_t range_finish = finish;
foreach (xact_t * xact, component_xacts) { foreach (xact_t * xact, component_xacts) {
date_t date = xact->reported_date(); date_t date = xact->date();
if (! is_valid(range_start) || date < range_start) if (! is_valid(range_start) || date < range_start)
range_start = date; range_start = date;
if (! is_valid(range_finish) || date > range_finish) if (! is_valid(range_finish) || date > range_finish)
@ -437,7 +461,7 @@ void subtotal_xacts::report_subtotal(const char * spec_fmt,
foreach (values_map::value_type& pair, values) foreach (values_map::value_type& pair, values)
handle_value(pair.second.value, pair.second.account, &entry, 0, handle_value(pair.second.value, pair.second.account, &entry, 0,
xact_temps, *handler, range_finish); xact_temps, *handler);
values.clear(); values.clear();
} }
@ -484,7 +508,7 @@ void interval_xacts::report_subtotal(const date_t& finish)
void interval_xacts::operator()(xact_t& xact) void interval_xacts::operator()(xact_t& xact)
{ {
date_t date = xact.reported_date(); date_t date = xact.date();
if ((is_valid(interval.begin) && date < interval.begin) || if ((is_valid(interval.begin) && date < interval.begin) ||
(is_valid(interval.end) && date >= interval.end)) (is_valid(interval.end) && date >= interval.end))
@ -542,7 +566,7 @@ void xacts_as_equity::report_subtotal()
{ {
date_t finish; date_t finish;
foreach (xact_t * xact, component_xacts) { foreach (xact_t * xact, component_xacts) {
date_t date = xact->reported_date(); date_t date = xact->date();
if (! is_valid(finish) || date > finish) if (! is_valid(finish) || date > finish)
finish = date; finish = date;
} }
@ -614,7 +638,7 @@ void transfer_details::operator()(xact_t& xact)
{ {
entry_temps.push_back(*xact.entry); entry_temps.push_back(*xact.entry);
entry_t& entry = entry_temps.back(); entry_t& entry = entry_temps.back();
entry._date = xact.reported_date(); entry._date = xact.date();
xact_temps.push_back(xact); xact_temps.push_back(xact);
xact_t& temp = xact_temps.back(); xact_t& temp = xact_temps.back();

View file

@ -450,9 +450,11 @@ class changed_value_xacts : public item_handler<xact_t>
// later in the chain. // later in the chain.
expr_t total_expr; expr_t total_expr;
report_t& report;
bool changed_values_only; bool changed_values_only;
xact_t * last_xact; xact_t * last_xact;
value_t last_balance; value_t last_balance;
account_t revalued_account;
std::list<entry_t> entry_temps; std::list<entry_t> entry_temps;
std::list<xact_t> xact_temps; std::list<xact_t> xact_temps;
@ -462,11 +464,13 @@ class changed_value_xacts : public item_handler<xact_t>
public: public:
changed_value_xacts(xact_handler_ptr handler, changed_value_xacts(xact_handler_ptr handler,
const expr_t& _total_expr, const expr_t& _total_expr,
report_t& _report,
bool _changed_values_only) bool _changed_values_only)
: item_handler<xact_t>(handler), total_expr(_total_expr), : item_handler<xact_t>(handler), total_expr(_total_expr),
changed_values_only(_changed_values_only), last_xact(NULL) { report(_report), changed_values_only(_changed_values_only),
last_xact(NULL), revalued_account(NULL, "<Revalued>") {
TRACE_CTOR(changed_value_xacts, TRACE_CTOR(changed_value_xacts,
"xact_handler_ptr, bool"); "xact_handler_ptr, const expr_t&, report_t&, bool");
} }
virtual ~changed_value_xacts() { virtual ~changed_value_xacts() {
TRACE_DTOR(changed_value_xacts); TRACE_DTOR(changed_value_xacts);
@ -474,14 +478,14 @@ public:
} }
virtual void flush() { virtual void flush() {
if (last_xact) { if (last_xact && last_xact->date() <= CURRENT_DATE()) {
output_diff(CURRENT_DATE()); output_diff(last_xact, CURRENT_DATE());
last_xact = NULL; last_xact = NULL;
} }
item_handler<xact_t>::flush(); item_handler<xact_t>::flush();
} }
void output_diff(const date_t& current); void output_diff(xact_t * xact, const date_t& current);
virtual void operator()(xact_t& xact); virtual void operator()(xact_t& xact);
}; };
@ -576,11 +580,10 @@ public:
interval_xacts(xact_handler_ptr _handler, interval_xacts(xact_handler_ptr _handler,
expr_t& amount_expr, expr_t& amount_expr,
const interval_t& _interval, const interval_t& _interval,
account_t * master = NULL,
bool _exact_periods = false, bool _exact_periods = false,
bool _generate_empty_xacts = false) bool _generate_empty_xacts = false)
: subtotal_xacts(_handler, amount_expr), interval(_interval), : subtotal_xacts(_handler, amount_expr), interval(_interval),
last_xact(NULL), empty_account(master, "<None>"), last_xact(NULL), empty_account(NULL, "<None>"),
exact_periods(_exact_periods), exact_periods(_exact_periods),
generate_empty_xacts(_generate_empty_xacts) { generate_empty_xacts(_generate_empty_xacts) {
TRACE_CTOR(interval_xacts, TRACE_CTOR(interval_xacts,

View file

@ -170,7 +170,7 @@ void gather_statistics::operator()(xact_t& xact)
statistics.filenames.insert(xact.pathname); statistics.filenames.insert(xact.pathname);
date_t date = xact.reported_date(); date_t date = xact.date();
if (date.year() == CURRENT_DATE().year() && if (date.year() == CURRENT_DATE().year() &&
date.month() == CURRENT_DATE().month()) date.month() == CURRENT_DATE().month())
@ -185,11 +185,11 @@ void gather_statistics::operator()(xact_t& xact)
statistics.total_uncleared_xacts++; statistics.total_uncleared_xacts++;
if (! is_valid(statistics.earliest_xact) || if (! is_valid(statistics.earliest_xact) ||
xact.reported_date() < statistics.earliest_xact) xact.date() < statistics.earliest_xact)
statistics.earliest_xact = xact.reported_date(); statistics.earliest_xact = xact.date();
if (! is_valid(statistics.latest_xact) || if (! is_valid(statistics.latest_xact) ||
xact.reported_date() > statistics.latest_xact) xact.date() > statistics.latest_xact)
statistics.latest_xact = xact.reported_date(); statistics.latest_xact = xact.date();
statistics.accounts_referenced.insert(xact.account->fullname()); statistics.accounts_referenced.insert(xact.account->fullname());
statistics.payees_referenced.insert(xact.entry->payee); statistics.payees_referenced.insert(xact.entry->payee);

View file

@ -120,7 +120,7 @@ value_t report_t::fn_display_total(call_scope_t& scope)
return HANDLER(display_total_).expr.calc(scope); return HANDLER(display_total_).expr.calc(scope);
} }
value_t report_t::fn_market_value(call_scope_t& scope) value_t report_t::fn_market(call_scope_t& scope)
{ {
interactive_t args(scope, "a&ts"); interactive_t args(scope, "a&ts");
@ -132,14 +132,18 @@ value_t report_t::fn_market_value(call_scope_t& scope)
p; p;
p = std::strtok(NULL, ",")) { p = std::strtok(NULL, ",")) {
if (commodity_t * commodity = amount_t::current_pool->find(trim_ws(p))) { if (commodity_t * commodity = amount_t::current_pool->find(trim_ws(p))) {
DEBUG("report.market", "Searching for value of " << args.value_at(0)
<< " in terms of commodity " << commodity->symbol());
value_t result = value_t result =
args.value_at(0).value(false, args.has(1) ? args.value_at(0).value(false, args.has(1) ?
args.get<datetime_t>(1) : args.get<datetime_t>(1) :
optional<datetime_t>(), *commodity); optional<datetime_t>(), *commodity);
if (! result.is_null()) if (! result.is_null()) {
DEBUG("report.market", "Market value is = " << result);
return result; return result;
} }
} }
}
} else { } else {
value_t result = value_t result =
args.value_at(0).value(true, args.has(1) ? args.value_at(0).value(true, args.has(1) ?
@ -621,7 +625,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
case 'm': case 'm':
if (is_eq(p, "market")) if (is_eq(p, "market"))
return MAKE_FUNCTOR(report_t::fn_market_value); return MAKE_FUNCTOR(report_t::fn_market);
break; break;
case 'o': case 'o':

View file

@ -132,7 +132,7 @@ public:
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);
value_t fn_display_total(call_scope_t& scope); value_t fn_display_total(call_scope_t& scope);
value_t fn_market_value(call_scope_t& scope); value_t fn_market(call_scope_t& scope);
value_t fn_strip(call_scope_t& scope); value_t fn_strip(call_scope_t& scope);
value_t fn_scrub(call_scope_t& scope); value_t fn_scrub(call_scope_t& scope);
value_t fn_quantity(call_scope_t& scope); value_t fn_quantity(call_scope_t& scope);

View file

@ -77,6 +77,9 @@ optional<string> xact_t::get_tag(const mask_t& tag_mask,
date_t xact_t::date() const date_t xact_t::date() const
{ {
if (xdata_ && is_valid(xdata_->date))
return xdata_->date;
if (item_t::use_effective_date) { if (item_t::use_effective_date) {
if (_date_eff) if (_date_eff)
return *_date_eff; return *_date_eff;

View file

@ -189,12 +189,6 @@ public:
void add_to_value(value_t& value, expr_t& expr); void add_to_value(value_t& value, expr_t& expr);
date_t reported_date() const {
if (xdata_ && is_valid(xdata_->date))
return xdata_->date;
return date();
}
account_t * reported_account() { account_t * reported_account() {
if (xdata_) if (xdata_)
if (account_t * acct = xdata_->account) if (account_t * acct = xdata_->account)

View file

@ -49,16 +49,12 @@ reg --exchange=' C, A '
Assets:Brokerage -155 A [2009/01/06] Assets:Brokerage -155 A [2009/01/06]
>>>1 >>>1
09-Jan-01 January 1st, 2009 (1) Assets:Brokerage 100 A 100 A 09-Jan-01 January 1st, 2009 (1) Assets:Brokerage 100 A 100 A
Assets:Brokerage -50 A 100 A Assets:Brokerage -50 A 50 A
-200 B 09-Jan-01 January 1st, 2009 (2) Assets:Brokerage 100 A 150 A
09-Jan-01 January 1st, 2009 (2) Assets:Brokerage 100 A 200 A Assets:Brokerage -75 A 75 A
-200 B 09-Jan-01 January 1st, 2009 (3) Assets:Brokerage 100 A 175 A
Assets:Brokerage -75 A 200 A Assets:Brokerage -100 A 75 A
-500 B 09-Jan-02 Commodities revalued <Revalued> 0 600 C
09-Jan-01 January 1st, 2009 (3) Assets:Brokerage 100 A 300 A
-500 B
Assets:Brokerage -100 A 300 A
-900 B
09-Jan-02 January 2nd, 2009 Assets:Brokerage 500 C 1100 C 09-Jan-02 January 2nd, 2009 Assets:Brokerage 500 C 1100 C
Assets:Brokerage -500 C 600 C Assets:Brokerage -500 C 600 C
09-Jan-03 January 3rd, 2009 Assets:Brokerage 600 C 1200 C 09-Jan-03 January 3rd, 2009 Assets:Brokerage 600 C 1200 C
@ -67,12 +63,16 @@ reg --exchange=' C, A '
Assets:Brokerage -2400 C 600 C Assets:Brokerage -2400 C 600 C
09-Jan-05 January 5th, 2009 Assets:Brokerage 1280 C 1880 C 09-Jan-05 January 5th, 2009 Assets:Brokerage 1280 C 1880 C
Assets:Brokerage -1280 C 600 C Assets:Brokerage -1280 C 600 C
09-Jan-06 Commodities revalued <Revalued> -2040 C -1440 C
09-Jan-06 January 6th, 2009 Assets:Brokerage 186 C -1254 C 09-Jan-06 January 6th, 2009 Assets:Brokerage 186 C -1254 C
Assets:Brokerage -186 C -1440 C Assets:Brokerage -186 C -1440 C
09-Jan-07 Commodities revalued <Revalued> -18 C -1458 C
09-Jan-07 January 7th, 2009 Assets:Brokerage 200 C -1258 C 09-Jan-07 January 7th, 2009 Assets:Brokerage 200 C -1258 C
Assets:Brokerage -200 C -1458 C Assets:Brokerage -200 C -1458 C
09-Jan-08 Commodities revalued <Revalued> -5613 C -7071 C
09-Jan-08 January 8th, 2009 Assets:Brokerage 200 C -6871 C 09-Jan-08 January 8th, 2009 Assets:Brokerage 200 C -6871 C
Assets:Brokerage -200 C -7071 C Assets:Brokerage -200 C -7071 C
09-Jan-09 Commodities revalued <Revalued> -2800 C -9871 C
09-Jan-09 January 9th, 2009 Assets:Brokerage 200 C -9671 C 09-Jan-09 January 9th, 2009 Assets:Brokerage 200 C -9671 C
Assets:Brokerage -200 C -9871 C Assets:Brokerage -200 C -9871 C
09-Jan-10 January 10th, 2009 Assets:Brokerage 200 C -9671 C 09-Jan-10 January 10th, 2009 Assets:Brokerage 200 C -9671 C

View file

@ -50,11 +50,17 @@ P 2010/03/01 00:00:00 S 8 P
P 2010/04/01 00:00:00 S 16 P P 2010/04/01 00:00:00 S 16 P
>>>1 >>>1
09-Jan-01 Sample 1a As:Brokerage:Stocks 200 P 200 P 09-Jan-01 Sample 1a As:Brokerage:Stocks 200 P 200 P
09-Feb-01 Commodities revalued <Revalued> 200 P 400 P
09-Feb-01 Sample 2a As:Brokerage:Stocks 400 P 800 P 09-Feb-01 Sample 2a As:Brokerage:Stocks 400 P 800 P
09-Mar-01 Commodities revalued <Revalued> 800 P 1600 P
09-Mar-01 Sample 3a As:Brokerage:Stocks 800 P 2400 P 09-Mar-01 Sample 3a As:Brokerage:Stocks 800 P 2400 P
09-Apr-01 Commodities revalued <Revalued> 2400 P 4800 P
09-Apr-01 Sample 4a As:Brokerage:Stocks -1600 P 3200 P 09-Apr-01 Sample 4a As:Brokerage:Stocks -1600 P 3200 P
10-Feb-01 Commodities revalued <Revalued> -2400 P 800 P
10-Feb-01 Sample 2b As:Brokerage:Stocks 400 P 1200 P 10-Feb-01 Sample 2b As:Brokerage:Stocks 400 P 1200 P
10-Mar-01 Commodities revalued <Revalued> 1200 P 2400 P
10-Mar-01 Sample 3b As:Brokerage:Stocks 800 P 3200 P 10-Mar-01 Sample 3b As:Brokerage:Stocks 800 P 3200 P
10-Apr-01 Commodities revalued <Revalued> 3200 P 6400 P
10-Apr-01 Sample 4b As:Brokerage:Stocks -1600 P 4800 P 10-Apr-01 Sample 4b As:Brokerage:Stocks -1600 P 4800 P
>>>2 >>>2
=== 0 === 0