summaryrefslogtreecommitdiff
path: root/src/xact.cc
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-24 03:03:04 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-24 03:03:04 -0400
commiteb364f4183d2549540c92d3e58246fad4f45dda2 (patch)
tree78fef87bef1ba02749eb53a51cc5dfe473fe2005 /src/xact.cc
parent267b2ba5d80f2d4f9897fb5ad633716d5a8a6752 (diff)
downloadfork-ledger-eb364f4183d2549540c92d3e58246fad4f45dda2.tar.gz
fork-ledger-eb364f4183d2549540c92d3e58246fad4f45dda2.tar.bz2
fork-ledger-eb364f4183d2549540c92d3e58246fad4f45dda2.zip
Improved the way that entries are balanced
Diffstat (limited to 'src/xact.cc')
-rw-r--r--src/xact.cc83
1 files changed, 59 insertions, 24 deletions
diff --git a/src/xact.cc b/src/xact.cc
index c67ecf12..8a7cbb46 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -93,15 +93,24 @@ bool xact_base_t::finalize()
amount_t& p(post->cost ? *post->cost : post->amount);
DEBUG("xact.finalize", "post must balance = " << p);
if (! p.is_null()) {
- if (p.keep_precision()) {
+ 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;
+ DEBUG("xact.finalize",
+ "annotation price = " << *post->amount.annotation().price);
+ DEBUG("xact.finalize", "amount = " << post->amount);
+ DEBUG("xact.finalize", "priced cost = " << *post->cost);
+ post->add_flags(POST_PRICED);
+ add_or_set_value(balance, post->cost->rounded());
+ } else {
// If the amount was a cost, it very likely has the "keep_precision"
// flag set, meaning commodity display precision is ignored when
// displaying the amount. We never want this set for the balance,
// so we must clear the flag in a temporary to avoid it propagating
// into the balance.
- add_or_set_value(balance, p.rounded());
- } else {
- add_or_set_value(balance, p);
+ add_or_set_value(balance, p.keep_precision() ? p.rounded() : p);
}
} else {
if (null_post)
@@ -114,7 +123,13 @@ bool xact_base_t::finalize()
}
assert(balance.valid());
+#if defined(DEBUG_ON)
DEBUG("xact.finalize", "initial balance = " << balance);
+ DEBUG("xact.finalize", "balance is " << balance.label());
+ if (balance.is_balance())
+ DEBUG("xact.finalize", "balance commodity count = "
+ << balance.as_balance().amounts.size());
+#endif
// If there is only one post, balance against the default account if one has
// been set.
@@ -132,6 +147,8 @@ bool xact_base_t::finalize()
// the rest. If multiple commodities are involved, multiple posts are
// generated to balance them all.
+ DEBUG("xact.finalize", "there was a null posting");
+
if (balance.is_balance()) {
bool first = true;
const balance_t& bal(balance.as_balance());
@@ -174,7 +191,7 @@ bool xact_base_t::finalize()
else if (! top_post)
top_post = post;
- if (post->cost) {
+ if (post->cost && ! post->has_flags(POST_PRICED)) {
saw_cost = true;
break;
}
@@ -196,8 +213,8 @@ bool xact_base_t::finalize()
y = t;
}
- DEBUG("xact.finalize", "primary amount = " << *y);
- DEBUG("xact.finalize", "secondary amount = " << *x);
+ DEBUG("xact.finalize", "primary amount = " << *x);
+ DEBUG("xact.finalize", "secondary amount = " << *y);
commodity_t& comm(x->commodity());
amount_t per_unit_cost;
@@ -228,36 +245,54 @@ bool xact_base_t::finalize()
if (post->must_balance() && amt.commodity() == comm) {
balance -= amt;
post->cost = per_unit_cost * amt;
+ post->add_flags(POST_PRICED);
balance += *post->cost;
DEBUG("xact.finalize", "set post->cost to = " << *post->cost);
}
}
}
-
- DEBUG("xact.finalize", "resolved balance = " << balance);
}
// Now that the post list has its final form, calculate the balance once
// more in terms of total cost, accounting for any possible gain/loss
// amounts.
+ DEBUG("xact.finalize", "resolved balance = " << balance);
+
foreach (post_t * post, posts) {
- if (post->cost) {
- if (post->amount.commodity() == post->cost->commodity())
- throw_(balance_error, "Posting's cost must be of a different commodity");
-
- commodity_t::cost_breakdown_t breakdown =
- commodity_t::exchange(post->amount, *post->cost, false,
- datetime_t(date(), time_duration(0, 0, 0, 0)));
-
- if (post->amount.is_annotated() &&
- breakdown.basis_cost.commodity() ==
- breakdown.final_cost.commodity())
- add_or_set_value(balance, (breakdown.basis_cost -
- breakdown.final_cost).rounded());
- else
- post->amount = breakdown.amount;
+ if (! post->cost)
+ continue;
+
+ if (post->amount.commodity() == post->cost->commodity())
+ throw_(balance_error,
+ "A posting's cost must be of a different commodity than its amount");
+
+ commodity_t::cost_breakdown_t breakdown =
+ commodity_t::exchange(post->amount, *post->cost, false,
+ datetime_t(date(), time_duration(0, 0, 0, 0)));
+
+ if (post->amount.is_annotated() &&
+ breakdown.basis_cost.commodity() ==
+ breakdown.final_cost.commodity()) {
+ if (amount_t gain_loss = (breakdown.basis_cost -
+ breakdown.final_cost).rounded()) {
+ DEBUG("xact.finalize", "gain_loss = " << gain_loss);
+
+ add_or_set_value(balance, gain_loss);
+
+ account_t * account;
+ if (gain_loss.sign() > 0)
+ account = journal->find_account(_("Equity:Capital Gains"));
+ else
+ account = journal->find_account(_("Equity:Capital Losses"));
+
+ add_post(new post_t(account, gain_loss.rounded(), ITEM_GENERATED));
+ DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
+ }
+ } else {
+ post->amount = breakdown.amount;
+ DEBUG("xact.finalize", "added breakdown, balance = " << balance);
}
}