Fixed bugs relating to sign and rounding of costs
This commit is contained in:
parent
501949a364
commit
f1795e628b
6 changed files with 39 additions and 15 deletions
|
|
@ -413,20 +413,21 @@ commodity_t::exchange(const amount_t& amount,
|
||||||
if (commodity.annotated)
|
if (commodity.annotated)
|
||||||
current_annotation = &as_annotated_commodity(commodity).details;
|
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);
|
DEBUG("commodity.prices.add", "exchange: per-unit-cost = " << per_unit_cost);
|
||||||
|
|
||||||
exchange(commodity, per_unit_cost, moment ? *moment : CURRENT_TIME());
|
exchange(commodity, per_unit_cost, moment ? *moment : CURRENT_TIME());
|
||||||
|
|
||||||
cost_breakdown_t breakdown;
|
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",
|
DEBUG("commodity.prices.add",
|
||||||
"exchange: final-cost = " << breakdown.final_cost);
|
"exchange: final-cost = " << breakdown.final_cost);
|
||||||
|
|
||||||
if (current_annotation && current_annotation->price)
|
if (current_annotation && current_annotation->price)
|
||||||
breakdown.basis_cost = (*current_annotation->price * amount).unrounded();
|
breakdown.basis_cost
|
||||||
|
= (*current_annotation->price * amount).unrounded();
|
||||||
else
|
else
|
||||||
breakdown.basis_cost = breakdown.final_cost;
|
breakdown.basis_cost = breakdown.final_cost;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -319,10 +319,16 @@ bool post_t::valid() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cost && ! cost->valid()) {
|
if (cost) {
|
||||||
|
if (! cost->valid()) {
|
||||||
DEBUG("ledger.validate", "post_t: cost && ! cost->valid()");
|
DEBUG("ledger.validate", "post_t: cost && ! cost->valid()");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (! cost->keep_precision()) {
|
||||||
|
DEBUG("ledger.validate", "post_t: ! cost->keep_precision()");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,12 @@ value_t report_t::fn_quantity(call_scope_t& scope)
|
||||||
return args.get<amount_t>(0).number();
|
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)
|
value_t report_t::fn_truncated(call_scope_t& scope)
|
||||||
{
|
{
|
||||||
interactive_t args(scope, "v&ll");
|
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);
|
return MAKE_FUNCTOR(report_t::fn_amount_expr);
|
||||||
else if (is_eq(p, "ansify_if"))
|
else if (is_eq(p, "ansify_if"))
|
||||||
return MAKE_FUNCTOR(report_t::fn_ansify_if);
|
return MAKE_FUNCTOR(report_t::fn_ansify_if);
|
||||||
|
else if (is_eq(p, "abs"))
|
||||||
|
return MAKE_FUNCTOR(report_t::fn_abs);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,7 @@ public:
|
||||||
value_t fn_quantity(call_scope_t& scope);
|
value_t fn_quantity(call_scope_t& scope);
|
||||||
value_t fn_rounded(call_scope_t& scope);
|
value_t fn_rounded(call_scope_t& scope);
|
||||||
value_t fn_truncated(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_justify(call_scope_t& scope);
|
||||||
value_t fn_quoted(call_scope_t& scope);
|
value_t fn_quoted(call_scope_t& scope);
|
||||||
value_t fn_join(call_scope_t& scope);
|
value_t fn_join(call_scope_t& scope);
|
||||||
|
|
@ -514,12 +515,12 @@ public:
|
||||||
" %(xact.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")"
|
" %(xact.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")"
|
||||||
"%-34(account)"
|
"%-34(account)"
|
||||||
" %12(calculated ? \"\" : justify(scrub(amount), 12, -1, true))"
|
" %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%/"
|
"%(comment | \"\")\n%/"
|
||||||
" %(xact.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")"
|
" %(xact.uncleared ? (cleared ? \"* \" : (pending ? \"! \" : \"\")) : \"\")"
|
||||||
"%-34(account)"
|
"%-34(account)"
|
||||||
" %12(calculated ? \"\" : justify(scrub(amount), 12, -1, true))"
|
" %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");
|
"%(comment | \"\")\n%/\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -954,6 +954,8 @@ post_t * instance_t::parse_post(char * line,
|
||||||
if (post->cost->sign() < 0)
|
if (post->cost->sign() < 0)
|
||||||
throw parse_error(_("A posting's cost may not be negative"));
|
throw parse_error(_("A posting's cost may not be negative"));
|
||||||
|
|
||||||
|
post->cost->in_place_unround();
|
||||||
|
|
||||||
if (per_unit)
|
if (per_unit)
|
||||||
*post->cost *= post->amount;
|
*post->cost *= post->amount;
|
||||||
|
|
||||||
|
|
|
||||||
18
src/xact.cc
18
src/xact.cc
|
|
@ -80,13 +80,14 @@ bool xact_base_t::finalize()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
amount_t& p(post->cost ? *post->cost : post->amount);
|
amount_t& p(post->cost ? *post->cost : post->amount);
|
||||||
DEBUG("xact.finalize", "post must balance = " << p.reduced());
|
|
||||||
if (! p.is_null()) {
|
if (! p.is_null()) {
|
||||||
|
DEBUG("xact.finalize", "post must balance = " << p.reduced());
|
||||||
if (! post->cost && post->amount.is_annotated() &&
|
if (! post->cost && post->amount.is_annotated() &&
|
||||||
post->amount.annotation().price) {
|
post->amount.annotation().price) {
|
||||||
// If the amount has no cost, but is annotated with a per-unit
|
// If the amount has no cost, but is annotated with a per-unit
|
||||||
// price, use the price times the amount as the cost
|
// 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",
|
DEBUG("xact.finalize",
|
||||||
"annotation price = " << *post->amount.annotation().price);
|
"annotation price = " << *post->amount.annotation().price);
|
||||||
DEBUG("xact.finalize", "amount = " << post->amount);
|
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) {
|
foreach (const balance_t::amounts_map::value_type& pair, bal.amounts) {
|
||||||
if (first) {
|
if (first) {
|
||||||
null_post->amount = pair.second.negated();
|
null_post->amount = pair.second.negated();
|
||||||
|
null_post->add_flags(POST_CALCULATED);
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
post_t * p = new post_t(null_post->account, pair.second.negated(),
|
post_t * p = new post_t(null_post->account, pair.second.negated(),
|
||||||
ITEM_GENERATED);
|
ITEM_GENERATED | POST_CALCULATED);
|
||||||
p->set_state(null_post->state());
|
p->set_state(null_post->state());
|
||||||
add_post(p);
|
add_post(p);
|
||||||
}
|
}
|
||||||
|
|
@ -228,7 +230,7 @@ bool xact_base_t::finalize()
|
||||||
DEBUG("xact.finalize", "total_cost = " << total_cost);
|
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);
|
DEBUG("xact.finalize", "per_unit_cost = " << per_unit_cost);
|
||||||
|
|
||||||
|
|
@ -254,7 +256,9 @@ bool xact_base_t::finalize()
|
||||||
|
|
||||||
DEBUG("xact.finalize", "resolved balance = " << balance);
|
DEBUG("xact.finalize", "resolved balance = " << balance);
|
||||||
|
|
||||||
foreach (post_t * post, posts) {
|
posts_list copy(posts);
|
||||||
|
|
||||||
|
foreach (post_t * post, copy) {
|
||||||
if (! post->cost)
|
if (! post->cost)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -281,7 +285,7 @@ bool xact_base_t::finalize()
|
||||||
else
|
else
|
||||||
account = journal->find_account(_("Equity:Capital Losses"));
|
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());
|
p->set_state(post->state());
|
||||||
add_post(p);
|
add_post(p);
|
||||||
DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
|
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"));
|
_("There cannot be null amounts after balancing a transaction"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VERIFY(valid());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue