Fixed bugs relating to sign and rounding of costs

This commit is contained in:
John Wiegley 2009-02-27 03:28:14 -04:00
parent 501949a364
commit f1795e628b
6 changed files with 39 additions and 15 deletions

View file

@ -413,20 +413,21 @@ commodity_t::exchange(const amount_t& amount,
if (commodity.annotated)
current_annotation = &as_annotated_commodity(commodity).details;
amount_t per_unit_cost(is_per_unit ? cost : (cost / amount).unrounded());
amount_t per_unit_cost = (is_per_unit ? cost : cost / amount).abs();
DEBUG("commodity.prices.add", "exchange: per-unit-cost = " << per_unit_cost);
exchange(commodity, per_unit_cost, moment ? *moment : CURRENT_TIME());
cost_breakdown_t breakdown;
breakdown.final_cost = ! is_per_unit ? cost : (cost * amount).unrounded();
breakdown.final_cost = ! is_per_unit ? cost : cost * amount;
DEBUG("commodity.prices.add",
"exchange: final-cost = " << breakdown.final_cost);
if (current_annotation && current_annotation->price)
breakdown.basis_cost = (*current_annotation->price * amount).unrounded();
breakdown.basis_cost
= (*current_annotation->price * amount).unrounded();
else
breakdown.basis_cost = breakdown.final_cost;

View file

@ -319,9 +319,15 @@ bool post_t::valid() const
return false;
}
if (cost && ! cost->valid()) {
DEBUG("ledger.validate", "post_t: cost && ! cost->valid()");
return false;
if (cost) {
if (! cost->valid()) {
DEBUG("ledger.validate", "post_t: cost && ! cost->valid()");
return false;
}
if (! cost->keep_precision()) {
DEBUG("ledger.validate", "post_t: ! cost->keep_precision()");
return false;
}
}
return true;

View file

@ -203,6 +203,12 @@ value_t report_t::fn_quantity(call_scope_t& scope)
return args.get<amount_t>(0).number();
}
value_t report_t::fn_abs(call_scope_t& scope)
{
interactive_t args(scope, "v");
return args.value_at(0).abs();
}
value_t report_t::fn_truncated(call_scope_t& scope)
{
interactive_t args(scope, "v&ll");
@ -568,6 +574,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
return MAKE_FUNCTOR(report_t::fn_amount_expr);
else if (is_eq(p, "ansify_if"))
return MAKE_FUNCTOR(report_t::fn_ansify_if);
else if (is_eq(p, "abs"))
return MAKE_FUNCTOR(report_t::fn_abs);
break;
case 'c':

View file

@ -140,6 +140,7 @@ public:
value_t fn_quantity(call_scope_t& scope);
value_t fn_rounded(call_scope_t& scope);
value_t fn_truncated(call_scope_t& scope);
value_t fn_abs(call_scope_t& scope);
value_t fn_justify(call_scope_t& scope);
value_t fn_quoted(call_scope_t& scope);
value_t fn_join(call_scope_t& scope);
@ -514,12 +515,12 @@ public:
" %(xact.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")"
"%-34(account)"
" %12(calculated ? \"\" : justify(scrub(amount), 12, -1, true))"
"%(has_cost & !priced ? \" @ \" + justify(scrub(cost / amount), 0) : \"\")"
"%(has_cost & !priced ? \" @ \" + justify(scrub(abs(cost / amount)), 0) : \"\")"
"%(comment | \"\")\n%/"
" %(xact.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")"
"%-34(account)"
" %12(calculated ? \"\" : justify(scrub(amount), 12, -1, true))"
"%(has_cost & !priced ? \" @ \" + justify(scrub(cost / amount), 0) : \"\")"
"%(has_cost & !priced ? \" @ \" + justify(scrub(abs(cost / amount)), 0) : \"\")"
"%(comment | \"\")\n%/\n");
});

View file

@ -954,6 +954,8 @@ post_t * instance_t::parse_post(char * line,
if (post->cost->sign() < 0)
throw parse_error(_("A posting's cost may not be negative"));
post->cost->in_place_unround();
if (per_unit)
*post->cost *= post->amount;

View file

@ -78,15 +78,16 @@ bool xact_base_t::finalize()
foreach (post_t * post, posts) {
if (! post->must_balance())
continue;
amount_t& p(post->cost ? *post->cost : post->amount);
DEBUG("xact.finalize", "post must balance = " << p.reduced());
if (! p.is_null()) {
DEBUG("xact.finalize", "post must balance = " << p.reduced());
if (! post->cost && post->amount.is_annotated() &&
post->amount.annotation().price) {
// If the amount has no cost, but is annotated with a per-unit
// price, use the price times the amount as the cost
post->cost = *post->amount.annotation().price * post->amount;
post->cost = (*post->amount.annotation().price *
post->amount).unrounded();
DEBUG("xact.finalize",
"annotation price = " << *post->amount.annotation().price);
DEBUG("xact.finalize", "amount = " << post->amount);
@ -145,10 +146,11 @@ bool xact_base_t::finalize()
foreach (const balance_t::amounts_map::value_type& pair, bal.amounts) {
if (first) {
null_post->amount = pair.second.negated();
null_post->add_flags(POST_CALCULATED);
first = false;
} else {
post_t * p = new post_t(null_post->account, pair.second.negated(),
ITEM_GENERATED);
ITEM_GENERATED | POST_CALCULATED);
p->set_state(null_post->state());
add_post(p);
}
@ -228,7 +230,7 @@ bool xact_base_t::finalize()
DEBUG("xact.finalize", "total_cost = " << total_cost);
}
}
per_unit_cost = (*y / *x).abs();
per_unit_cost = (*y / *x).abs().unrounded();
DEBUG("xact.finalize", "per_unit_cost = " << per_unit_cost);
@ -254,7 +256,9 @@ bool xact_base_t::finalize()
DEBUG("xact.finalize", "resolved balance = " << balance);
foreach (post_t * post, posts) {
posts_list copy(posts);
foreach (post_t * post, copy) {
if (! post->cost)
continue;
@ -281,7 +285,7 @@ bool xact_base_t::finalize()
else
account = journal->find_account(_("Equity:Capital Losses"));
post_t * p = new post_t(account, gain_loss.rounded(), ITEM_GENERATED);
post_t * p = new post_t(account, gain_loss, ITEM_GENERATED);
p->set_state(post->state());
add_post(p);
DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
@ -328,6 +332,8 @@ bool xact_base_t::finalize()
_("There cannot be null amounts after balancing a transaction"));
}
VERIFY(valid());
return true;
}