summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/account.cc9
-rw-r--r--src/chain.cc5
-rw-r--r--src/filters.cc112
-rw-r--r--src/filters.h24
-rw-r--r--src/post.cc12
-rw-r--r--src/post.h2
-rw-r--r--src/report.h14
7 files changed, 131 insertions, 47 deletions
diff --git a/src/account.cc b/src/account.cc
index d65b6911..9bc96564 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -196,6 +196,10 @@ namespace {
return long(account.depth);
}
+ value_t ignore(account_t&) {
+ return false;
+ }
+
value_t get_depth_spacer(account_t& account)
{
std::size_t depth = 0;
@@ -259,6 +263,11 @@ expr_t::ptr_op_t account_t::lookup(const string& name)
if (name == "total")
return WRAP_FUNCTOR(get_wrapper<&get_total>);
break;
+
+ case 'u':
+ if (name == "use_direct_amount")
+ return WRAP_FUNCTOR(get_wrapper<&ignore>);
+ break;
}
return NULL;
diff --git a/src/chain.cc b/src/chain.cc
index 0ad1709f..d33742a5 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -79,9 +79,12 @@ post_handler_ptr chain_post_handlers(report_t& report,
// the running total unpredictably.
if (report.HANDLED(revalued))
handler.reset(new changed_value_posts
- (handler, report.HANDLED(revalued_total_) ?
+ (handler,
+ report.HANDLER(display_amount_).expr,
+ report.HANDLED(revalued_total_) ?
report.HANDLER(revalued_total_).expr :
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
diff --git a/src/filters.cc b/src/filters.cc
index 7f305dd3..3071a951 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -213,14 +213,17 @@ void calc_posts::operator()(post_t& post)
}
namespace {
- void handle_value(const value_t& value,
- account_t * account,
- xact_t * xact,
- unsigned int flags,
- std::list<post_t>& temps,
- item_handler<post_t>& handler,
- const date_t& date = date_t(),
- const value_t& total = value_t())
+ typedef function<void (post_t *)> post_functor_t;
+
+ void handle_value(const value_t& value,
+ account_t * account,
+ xact_t * xact,
+ std::list<post_t>& temps,
+ item_handler<post_t>& handler,
+ const date_t& date = date_t(),
+ const value_t& total = value_t(),
+ const bool direct_amount = false,
+ const optional<post_functor_t>& functor = none)
{
temps.push_back(post_t(account));
post_t& post(temps.back());
@@ -259,7 +262,7 @@ namespace {
case value_t::BALANCE:
case value_t::SEQUENCE:
xdata.value = temp;
- flags |= POST_EXT_COMPOUND;
+ xdata.add_flags(POST_EXT_COMPOUND);
break;
case value_t::DATETIME:
@@ -272,8 +275,13 @@ namespace {
if (! total.is_null())
xdata.total = total;
- if (flags)
- xdata.add_flags(flags);
+ if (direct_amount)
+ xdata.add_flags(POST_EXT_DIRECT_AMT);
+
+ if (functor)
+ (*functor)(&post);
+
+ DEBUG("filter.changed_value.rounding", "post.amount = " << post.amount);
handler(post);
}
@@ -314,7 +322,7 @@ void collapse_posts::report_subtotal()
earliest_date : last_xact->_date);
DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date);
- handle_value(subtotal, &totals_account, &xact, 0, post_temps, *handler);
+ handle_value(subtotal, &totals_account, &xact, post_temps, *handler);
}
component_posts.clear();
@@ -374,7 +382,7 @@ void related_posts::flush()
item_handler<post_t>::flush();
}
-void changed_value_posts::output_diff(post_t * post, const date_t& date)
+void changed_value_posts::output_revaluation(post_t * post, const date_t& date)
{
if (is_valid(date))
post->xdata().date = date;
@@ -391,36 +399,80 @@ void changed_value_posts::output_diff(post_t * post, const date_t& date)
post->xdata().date = date_t();
DEBUG("filter.changed_value",
- "output_diff(last_balance) = " << last_balance);
+ "output_revaluation(last_balance) = " << last_total);
DEBUG("filter.changed_value",
- "output_diff(repriced_total) = " << repriced_total);
+ "output_revaluation(repriced_total) = " << repriced_total);
+
+ if (! last_total.is_null()) {
+ if (value_t diff = repriced_total - last_total) {
+ DEBUG("filter.changed_value", "output_revaluation(strip(diff)) = "
+ << diff.strip_annotations(report.what_to_keep()));
+
+ xact_temps.push_back(xact_t());
+ xact_t& xact = xact_temps.back();
+ xact.payee = _("Commodities revalued");
+ xact._date = is_valid(date) ? date : post->date();
+
+ handle_value(diff, &revalued_account, &xact, post_temps, *handler,
+ *xact._date, repriced_total, false,
+ optional<post_functor_t>
+ (bind(&changed_value_posts::output_rounding, this, _1)));
+ }
+ }
+}
- if (value_t diff = repriced_total - last_balance) {
- DEBUG("filter.changed_value", "output_diff(strip(diff)) = "
- << diff.strip_annotations(report.what_to_keep()));
+void changed_value_posts::output_rounding(post_t * post)
+{
+ bind_scope_t bound_scope(report, *post);
+ value_t new_display_total(display_total_expr.calc(bound_scope));
- xact_temps.push_back(xact_t());
- xact_t& xact = xact_temps.back();
- xact.payee = _("Commodities revalued");
- xact._date = is_valid(date) ? date : post->date();
+ DEBUG("filter.changed_value.rounding",
+ "rounding.new_display_total = " << new_display_total);
+
+ if (! last_display_total.is_null()) {
+ if (value_t repriced_amount = display_amount_expr.calc(bound_scope)) {
+ DEBUG("filter.changed_value.rounding",
+ "rounding.repriced_amount = " << repriced_amount);
- handle_value(diff, &revalued_account, &xact, POST_EXT_NO_TOTAL,
- post_temps, *handler, *xact._date, repriced_total);
+ value_t precise_display_total(new_display_total.truncated() -
+ repriced_amount.truncated());
+
+ DEBUG("filter.changed_value.rounding",
+ "rounding.precise_display_total = " << precise_display_total);
+ DEBUG("filter.changed_value.rounding",
+ "rounding.last_display_total = " << last_display_total);
+
+ if (value_t diff = precise_display_total - last_display_total) {
+ DEBUG("filter.changed_value.rounding",
+ "rounding.diff = " << diff);
+
+ xact_temps.push_back(xact_t());
+ xact_t& xact = xact_temps.back();
+ xact.payee = _("Commodity rounding");
+ xact._date = post->date();
+
+ handle_value(diff, &rounding_account, &xact, post_temps,
+ *handler, *xact._date, precise_display_total, true);
+ }
+ }
}
+ last_display_total = new_display_total;
}
void changed_value_posts::operator()(post_t& post)
{
if (last_post)
- output_diff(last_post, post.date());
+ output_revaluation(last_post, post.date());
if (changed_values_only)
post.xdata().add_flags(POST_EXT_DISPLAYED);
+ output_rounding(&post);
+
item_handler<post_t>::operator()(post);
bind_scope_t bound_scope(report, post);
- last_balance = total_expr.calc(bound_scope);
+ last_total = total_expr.calc(bound_scope);
last_post = &post;
}
@@ -462,8 +514,8 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
xact._date = range_start;
foreach (values_map::value_type& pair, values)
- handle_value(pair.second.value, pair.second.account, &xact, 0,
- post_temps, *handler);
+ handle_value(pair.second.value, pair.second.account, &xact, post_temps,
+ *handler);
values.clear();
}
@@ -581,8 +633,8 @@ void posts_as_equity::report_subtotal()
value_t total = 0L;
foreach (values_map::value_type& pair, values) {
- handle_value(pair.second.value, pair.second.account, &xact, 0,
- post_temps, *handler);
+ handle_value(pair.second.value, pair.second.account, &xact, post_temps,
+ *handler);
total += pair.second.value;
}
values.clear();
diff --git a/src/filters.h b/src/filters.h
index 8bc121ba..9ac2a6b9 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -449,12 +449,16 @@ class changed_value_posts : public item_handler<post_t>
// This filter requires that calc_posts be used at some point
// later in the chain.
+ expr_t display_amount_expr;
expr_t total_expr;
+ expr_t display_total_expr;
report_t& report;
bool changed_values_only;
post_t * last_post;
- value_t last_balance;
+ value_t last_total;
+ value_t last_display_total;
account_t revalued_account;
+ account_t rounding_account;
std::list<xact_t> xact_temps;
std::list<post_t> post_temps;
@@ -463,14 +467,19 @@ class changed_value_posts : public item_handler<post_t>
public:
changed_value_posts(post_handler_ptr handler,
+ const expr_t& _display_amount_expr,
const expr_t& _total_expr,
+ const expr_t& _display_total_expr,
report_t& _report,
bool _changed_values_only)
- : item_handler<post_t>(handler), total_expr(_total_expr),
- report(_report), changed_values_only(_changed_values_only),
- last_post(NULL), revalued_account(NULL, _("<Revalued>")) {
+ : item_handler<post_t>(handler),
+ display_amount_expr(_display_amount_expr), total_expr(_total_expr),
+ display_total_expr(_display_total_expr), report(_report),
+ changed_values_only(_changed_values_only), last_post(NULL),
+ revalued_account(NULL, _("<Revalued>")),
+ rounding_account(NULL, _("<Rounding>")){
TRACE_CTOR(changed_value_posts,
- "post_handler_ptr, const expr_t&, report_t&, bool");
+ "post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool");
}
virtual ~changed_value_posts() {
TRACE_DTOR(changed_value_posts);
@@ -479,13 +488,14 @@ public:
virtual void flush() {
if (last_post && last_post->date() <= CURRENT_DATE()) {
- output_diff(last_post, CURRENT_DATE());
+ output_revaluation(last_post, CURRENT_DATE());
last_post = NULL;
}
item_handler<post_t>::flush();
}
- void output_diff(post_t * post, const date_t& current);
+ void output_revaluation(post_t * post, const date_t& current);
+ void output_rounding(post_t * post);
virtual void operator()(post_t& post);
};
diff --git a/src/post.cc b/src/post.cc
index b10ab81a..8293bfe4 100644
--- a/src/post.cc
+++ b/src/post.cc
@@ -158,6 +158,10 @@ namespace {
}
}
+ value_t get_use_direct_amount(post_t& post) {
+ return post.has_xdata() && post.xdata().has_flags(POST_EXT_DIRECT_AMT);
+ }
+
value_t get_commodity(post_t& post) {
return string_value(post.amount.commodity().symbol());
}
@@ -282,6 +286,11 @@ expr_t::ptr_op_t post_t::lookup(const string& name)
return WRAP_FUNCTOR(get_wrapper<&get_total>);
break;
+ case 'u':
+ if (name == "use_direct_amount")
+ return WRAP_FUNCTOR(get_wrapper<&get_use_direct_amount>);
+ break;
+
case 'v':
if (name == "virtual")
return WRAP_FUNCTOR(get_wrapper<&get_virtual>);
@@ -333,8 +342,7 @@ void post_t::add_to_value(value_t& value, expr_t& expr)
{
if (xdata_ && xdata_->has_flags(POST_EXT_COMPOUND)) {
add_or_set_value(value, xdata_->value);
- }
- else if (! xdata_ || ! xdata_->has_flags(POST_EXT_NO_TOTAL)) {
+ } else {
bind_scope_t bound_scope(*expr.get_context(), *this);
add_or_set_value(value, expr.calc(bound_scope));
}
diff --git a/src/post.h b/src/post.h
index 0865137f..4c20fb37 100644
--- a/src/post.h
+++ b/src/post.h
@@ -134,7 +134,7 @@ public:
#define POST_EXT_HANDLED 0x02
#define POST_EXT_TO_DISPLAY 0x04
#define POST_EXT_DISPLAYED 0x08
-#define POST_EXT_NO_TOTAL 0x10
+#define POST_EXT_DIRECT_AMT 0x10
#define POST_EXT_SORT_CALC 0x20
#define POST_EXT_COMPOUND 0x40
#define POST_EXT_MATCHES 0x80
diff --git a/src/report.h b/src/report.h
index 6839de0e..1d867c68 100644
--- a/src/report.h
+++ b/src/report.h
@@ -245,7 +245,7 @@ public:
OPTION(report_t, base);
OPTION_(report_t, basis, DO() { // -B
- parent->HANDLER(revalued).off();
+ parent->HANDLER(revalued).on_only();
parent->HANDLER(amount_).set_expr("rounded(cost)");
});
@@ -401,15 +401,17 @@ public:
// Since we are displaying the amounts of revalued postings, they
// will end up being composite totals, and hence a pair of pairs.
parent->HANDLER(display_amount_)
- .set_expr("is_seq(get_at(amount_expr, 0)) ?"
- " get_at(get_at(amount_expr, 0), 0) :"
- " market(get_at(amount_expr, 0), date, exchange) -"
- " get_at(amount_expr, 1)");
+ .set_expr("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)"
+ " - get_at(amount_expr, 1))");
parent->HANDLER(revalued_total_)
.set_expr("(market(get_at(total_expr, 0), date, exchange), "
"get_at(total_expr, 1))");
parent->HANDLER(display_total_)
- .set_expr("market(get_at(total_expr, 0), date, exchange)"
+ .set_expr("use_direct_amount ? total_expr :"
+ " market(get_at(total_expr, 0), date, exchange)"
" - get_at(total_expr, 1)");
});