Fixed interaction with -V/X and grouped postings

With -s, -M/Y/D, -n, and a few other flags, postings get "grouped" into
meta-transactions that contain more postings than before.  In all these
cases, -V use the date of the *earliest* posting in that group, which
makes little sense and caused breakages with -J.  It now uses the latest
date.

Fixes #197 / 68EAF363-D0FE-4127-866E-A5AEBACB65D6
This commit is contained in:
John Wiegley 2010-06-09 01:23:38 -04:00
parent 524c98244e
commit fc09b69fb7
6 changed files with 102 additions and 55 deletions

View file

@ -289,18 +289,16 @@ void calc_posts::operator()(post_t& post)
}
namespace {
typedef function<void (post_t&)> post_functor_t;
void handle_value(const value_t& value,
account_t * account,
xact_t * xact,
temporaries_t& temps,
post_handler_ptr handler,
const date_t& date = date_t(),
const value_t& total = value_t(),
const bool direct_amount = false,
const bool mark_visited = false,
const optional<post_functor_t>& functor = none)
void handle_value(const value_t& value,
account_t * account,
xact_t * xact,
temporaries_t& temps,
post_handler_ptr handler,
const date_t& date = date_t(),
const bool act_date_p = true,
const value_t& total = value_t(),
const bool direct_amount = false,
const bool mark_visited = false)
{
post_t& post = temps.create_post(*xact, account);
post.add_flags(ITEM_GENERATED);
@ -319,8 +317,12 @@ namespace {
post_t::xdata_t& xdata(post.xdata());
if (is_valid(date))
xdata.date = date;
if (is_valid(date)) {
if (act_date_p)
xdata.date = date;
else
xdata.value_date = date;
}
value_t temp(value);
@ -353,9 +355,6 @@ namespace {
if (direct_amount)
xdata.add_flags(POST_EXT_DIRECT_AMT);
if (functor)
(*functor)(post);
DEBUG("filters.changed_value.rounding", "post.amount = " << post.amount);
(*handler)(post);
@ -388,12 +387,15 @@ void collapse_posts::report_subtotal()
}
else {
date_t earliest_date;
date_t latest_date;
foreach (post_t * post, component_posts) {
date_t reported = post->date();
if (! is_valid(earliest_date) ||
reported < earliest_date)
earliest_date = reported;
date_t date = post->date();
date_t value_date = post->value_date();
if (! is_valid(earliest_date) || date < earliest_date)
earliest_date = date;
if (! is_valid(latest_date) || value_date > latest_date)
latest_date = value_date;
}
xact_t& xact = temps.create_xact();
@ -401,12 +403,16 @@ void collapse_posts::report_subtotal()
xact._date = (is_valid(earliest_date) ?
earliest_date : last_xact->_date);
DEBUG("filters.collapse", "Pseudo-xact date = " << *xact._date);
DEBUG("filters.collapse", "earliest date = " << earliest_date);
DEBUG("filters.collapse", "latest date = " << latest_date);
handle_value(/* value= */ subtotal,
/* account= */ &totals_account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler);
handle_value(/* value= */ subtotal,
/* account= */ &totals_account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler,
/* date= */ latest_date,
/* act_date_p= */ false);
}
component_posts.clear();
@ -526,6 +532,7 @@ bool display_filter_posts::output_rounding(post_t& post)
/* temps= */ temps,
/* handler= */ handler,
/* date= */ *xact._date,
/* act_date_p= */ true,
/* total= */ precise_display_total,
/* direct_amount= */ true);
}
@ -627,7 +634,7 @@ void changed_value_posts::output_revaluation(post_t& post, const date_t& date)
xact_t& xact = temps.create_xact();
xact.payee = _("Commodities revalued");
xact._date = is_valid(date) ? date : post.date();
xact._date = is_valid(date) ? date : post.value_date();
if (! for_accounts_report) {
handle_value
@ -637,6 +644,7 @@ void changed_value_posts::output_revaluation(post_t& post, const date_t& date)
/* temps= */ temps,
/* handler= */ handler,
/* date= */ *xact._date,
/* act_date_p= */ true,
/* total= */ repriced_total);
}
else if (show_unrealized) {
@ -649,6 +657,7 @@ void changed_value_posts::output_revaluation(post_t& post, const date_t& date)
/* temps= */ temps,
/* handler= */ handler,
/* date= */ *xact._date,
/* act_date_p= */ true,
/* total= */ value_t(),
/* direct_amount= */ false,
/* mark_visited= */ true);
@ -672,7 +681,7 @@ void changed_value_posts::output_intermediate_prices(post_t& post,
xact_t& xact(temps.create_xact());
xact.payee = _("Commodities revalued");
xact._date = is_valid(current) ? current : post.date();
xact._date = is_valid(current) ? current : post.value_date();
post_t& temp(temps.copy_post(post, xact));
temp.add_flags(ITEM_GENERATED);
@ -734,9 +743,9 @@ void changed_value_posts::output_intermediate_prices(post_t& post,
hist->histories) {
foreach (const commodity_t::history_map::value_type& price,
comm_hist.second.prices) {
if (price.first.date() > post.date() &&
if (price.first.date() > post.value_date() &&
price.first.date() < current) {
DEBUG("filters.revalued", post.date() << " < "
DEBUG("filters.revalued", post.value_date() << " < "
<< price.first.date() << " < " << current);
DEBUG("filters.revalued", "inserting "
<< price.second << " at " << price.first.date());
@ -778,8 +787,8 @@ void changed_value_posts::operator()(post_t& post)
{
if (last_post) {
if (! for_accounts_report)
output_intermediate_prices(*last_post, post.date());
output_revaluation(*last_post, post.date());
output_intermediate_prices(*last_post, post.value_date());
output_revaluation(*last_post, post.value_date());
}
if (changed_values_only)
@ -803,11 +812,12 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
if (! range_start || ! range_finish) {
foreach (post_t * post, component_posts) {
date_t date = post->date();
date_t date = post->date();
date_t value_date = post->value_date();
if (! range_start || date < *range_start)
range_start = date;
if (! range_finish || date > *range_finish)
range_finish = date;
if (! range_finish || value_date > *range_finish)
range_finish = value_date;
}
}
component_posts.clear();
@ -829,11 +839,13 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
xact._date = *range_start;
foreach (values_map::value_type& pair, values)
handle_value(/* value= */ pair.second.value,
/* account= */ pair.second.account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler);
handle_value(/* value= */ pair.second.value,
/* account= */ pair.second.account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler,
/* date= */ *range_finish,
/* act_date_p= */ false);
values.clear();
}
@ -942,17 +954,21 @@ void posts_as_equity::report_subtotal()
if (pair.second.value.is_balance()) {
foreach (const balance_t::amounts_map::value_type& amount_pair,
pair.second.value.as_balance().amounts)
handle_value(/* value= */ amount_pair.second,
/* account= */ pair.second.account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler);
handle_value(/* value= */ amount_pair.second,
/* account= */ pair.second.account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler,
/* date= */ finish,
/* act_date_p= */ false);
} else {
handle_value(/* value= */ pair.second.value,
/* account= */ pair.second.account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler);
handle_value(/* value= */ pair.second.value,
/* account= */ pair.second.account,
/* xact= */ &xact,
/* temps= */ temps,
/* handler= */ handler,
/* date= */ finish,
/* act_date_p= */ false);
}
total += pair.second.value;
}

View file

@ -465,6 +465,11 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind,
return WRAP_FUNCTOR(get_wrapper<&get_uncleared>);
break;
case 'v':
if (name == "value_date")
return WRAP_FUNCTOR(get_wrapper<&get_date>);
break;
case 'L':
if (name[1] == '\0')
return WRAP_FUNCTOR(get_wrapper<&get_actual>);

View file

@ -78,6 +78,13 @@ optional<string> post_t::get_tag(const mask_t& tag_mask,
return none;
}
date_t post_t::value_date() const
{
if (xdata_ && is_valid(xdata_->value_date))
return xdata_->value_date;
return date();
}
date_t post_t::date() const
{
if (xdata_ && is_valid(xdata_->date))
@ -319,6 +326,14 @@ namespace {
return long(post.reported_account()->depth);
}
value_t get_value_date(post_t& post) {
if (post.has_xdata()) {
post_t::xdata_t& xdata(post.xdata());
if (! xdata.value_date.is_not_a_date())
return xdata.value_date;
}
return post.date();
}
value_t get_datetime(post_t& post) {
return post.xdata().datetime;
}
@ -479,6 +494,8 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind,
case 'v':
if (name == "virtual")
return WRAP_FUNCTOR(get_wrapper<&get_virtual>);
else if (name == "value_date")
return WRAP_FUNCTOR(get_wrapper<&get_value_date>);
break;
case 'x':

View file

@ -106,6 +106,7 @@ public:
virtual optional<string> get_tag(const mask_t& tag_mask,
const optional<mask_t>& value_mask = none) const;
virtual date_t value_date() const;
virtual date_t date() const;
virtual date_t actual_date() const;
virtual optional<date_t> effective_date() const;
@ -141,6 +142,7 @@ public:
value_t total;
std::size_t count;
date_t date;
date_t value_date;
datetime_t datetime;
account_t * account;

View file

@ -1308,6 +1308,11 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
return MAKE_FUNCTOR(report_t::fn_unrounded);
break;
case 'v':
if (is_eq(p, "value_date"))
return MAKE_FUNCTOR(report_t::fn_now);
break;
case 'w':
if (is_eq(p, "white"))
return WRAP_FUNCTOR(fn_white);

View file

@ -586,16 +586,16 @@ public:
"use_direct_amount ? amount :"
" (is_seq(get_at(amount_expr, 0)) ?"
" get_at(get_at(amount_expr, 0), 0) :"
" market(get_at(amount_expr, 0), date, exchange)"
" market(get_at(amount_expr, 0), value_date, exchange)"
" - get_at(amount_expr, 1))");
parent->HANDLER(revalued_total_)
.set_expr(string("--gain"),
"(market(get_at(total_expr, 0), date, exchange), "
"(market(get_at(total_expr, 0), value_date, exchange), "
"get_at(total_expr, 1))");
parent->HANDLER(display_total_)
.set_expr(string("--gain"),
"use_direct_amount ? total_expr :"
" market(get_at(total_expr, 0), date, exchange)"
" market(get_at(total_expr, 0), value_date, exchange)"
" - get_at(total_expr, 1)");
});
@ -642,9 +642,11 @@ public:
OPTION_(report_t, market, DO() { // -V
parent->HANDLER(revalued).on_only(string("--market"));
parent->HANDLER(display_amount_)
.set_expr(string("--market"), "market(amount_expr, date, exchange)");
.set_expr(string("--market"),
"market(amount_expr, value_date, exchange)");
parent->HANDLER(display_total_)
.set_expr(string("--market"), "market(total_expr, date, exchange)");
.set_expr(string("--market"),
"market(total_expr, value_date, exchange)");
});
OPTION(report_t, meta_);