diff options
author | John Wiegley <johnw@newartisans.com> | 2009-02-22 22:22:07 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-02-22 22:23:02 -0400 |
commit | de6de07bac1337b0dd87b41c853369dc8432c2af (patch) | |
tree | 7a03ec320c4c359d3ca16c163badb797f96b92ee /src/entry.cc | |
parent | ea418c7fbcd54d7222583914477d087fe7d6c5e8 (diff) | |
download | fork-ledger-de6de07bac1337b0dd87b41c853369dc8432c2af.tar.gz fork-ledger-de6de07bac1337b0dd87b41c853369dc8432c2af.tar.bz2 fork-ledger-de6de07bac1337b0dd87b41c853369dc8432c2af.zip |
Many fixes to --market and --exchange
Also, --exchange now accepted multiple, comma-separated commodities.
Diffstat (limited to 'src/entry.cc')
-rw-r--r-- | src/entry.cc | 103 |
1 files changed, 75 insertions, 28 deletions
diff --git a/src/entry.cc b/src/entry.cc index a07481f1..eceec5f7 100644 --- a/src/entry.cc +++ b/src/entry.cc @@ -85,9 +85,6 @@ bool entry_base_t::finalize() // for auto-calculating the value of entries with no cost, and the per-unit // price of unpriced commodities. - // (let ((balance 0) - // null-xact) - value_t balance; xact_t * null_xact = NULL; @@ -119,8 +116,8 @@ bool entry_base_t::finalize() DEBUG("entry.finalize", "initial balance = " << balance); - // If there is only one xact, balance against the default account if - // one has been set. + // If there is only one xact, balance against the default account if one has + // been set. if (journal && journal->basket && xacts.size() == 1 && ! balance.is_null()) { // jww (2008-07-24): Need to make the rest of the code aware of what to do @@ -131,9 +128,9 @@ bool entry_base_t::finalize() } if (null_xact != NULL) { - // If one xact has no value at all, its value will become the - // inverse of the rest. If multiple commodities are involved, multiple - // xacts are generated to balance them all. + // If one xact has no value at all, its value will become the inverse of + // the rest. If multiple commodities are involved, multiple xacts are + // generated to balance them all. if (balance.is_balance()) { bool first = true; @@ -161,41 +158,88 @@ bool entry_base_t::finalize() else if (balance.is_balance() && balance.as_balance().amounts.size() == 2) { // When an entry involves two different commodities (regardless of how - // many xacts there are) determine the conversion ratio by dividing - // the total value of one commodity by the total value of the other. This - // establishes the per-unit cost for this xact for both - // commodities. + // many xacts there are) determine the conversion ratio by dividing the + // total value of one commodity by the total value of the other. This + // establishes the per-unit cost for this xact for both commodities. + + DEBUG("entry.finalize", "there were exactly two commodities"); + + bool saw_cost = false; + xact_t * top_xact = NULL; + + foreach (xact_t * xact, xacts) { + if (! xact->amount.is_null()) + if (xact->amount.is_annotated()) + top_xact = xact; + else if (! top_xact) + top_xact = xact; + + if (xact->cost) { + saw_cost = true; + break; + } + } + + if (! saw_cost && top_xact) { + const balance_t& bal(balance.as_balance()); - const balance_t& bal(balance.as_balance()); + DEBUG("entry.finalize", "there were no costs, and a valid top_xact"); - balance_t::amounts_map::const_iterator a = bal.amounts.begin(); + balance_t::amounts_map::const_iterator a = bal.amounts.begin(); - const amount_t& x((*a++).second); - const amount_t& y((*a++).second); + const amount_t * x = &(*a++).second; + const amount_t * y = &(*a++).second; - if (! y.is_realzero()) { - amount_t per_unit_cost = (x / y).abs(); + if (x->commodity() != top_xact->amount.commodity()) { + const amount_t * t = x; + x = y; + y = t; + } + + DEBUG("entry.finalize", "primary amount = " << *y); + DEBUG("entry.finalize", "secondary amount = " << *x); - commodity_t& comm(x.commodity()); + commodity_t& comm(x->commodity()); + amount_t per_unit_cost; + amount_t total_cost; + + foreach (xact_t * xact, xacts) { + if (xact != top_xact && xact->must_balance() && + ! xact->amount.is_null() && + xact->amount.is_annotated() && + xact->amount.annotation().price) { + amount_t temp = *xact->amount.annotation().price * xact->amount; + if (total_cost.is_null()) { + total_cost = temp; + y = &total_cost; + } else { + total_cost += temp; + } + DEBUG("entry.finalize", "total_cost = " << total_cost); + } + } + per_unit_cost = (*y / *x).abs(); + + DEBUG("entry.finalize", "per_unit_cost = " << per_unit_cost); foreach (xact_t * xact, xacts) { const amount_t& amt(xact->amount); - if (! (xact->cost || ! xact->must_balance() || - amt.commodity() == comm)) { + if (xact->must_balance() && amt.commodity() == comm) { balance -= amt; xact->cost = per_unit_cost * amt; balance += *xact->cost; - } + DEBUG("entry.finalize", "set xact->cost to = " << *xact->cost); + } } } DEBUG("entry.finalize", "resolved balance = " << balance); } - // Now that the xact list has its final form, calculate the balance - // once more in terms of total cost, accounting for any possible gain/loss + // Now that the xact list has its final form, calculate the balance once + // more in terms of total cost, accounting for any possible gain/loss // amounts. foreach (xact_t * xact, xacts) { @@ -204,9 +248,12 @@ bool entry_base_t::finalize() throw_(balance_error, "Transaction's cost must be of a different commodity"); commodity_t::cost_breakdown_t breakdown = - commodity_t::exchange(xact->amount, *xact->cost); + commodity_t::exchange(xact->amount, *xact->cost, false, + datetime_t(date(), time_duration(0, 0, 0, 0))); - if (xact->amount.is_annotated()) + if (xact->amount.is_annotated() && + breakdown.basis_cost.commodity() == + breakdown.final_cost.commodity()) add_or_set_value(balance, (breakdown.basis_cost - breakdown.final_cost).rounded()); else @@ -231,8 +278,8 @@ bool entry_base_t::finalize() if (! xact->amount.is_null()) { all_null = false; - // jww (2008-08-09): For now, this feature only works for - // non-specific commodities. + // jww (2008-08-09): For now, this feature only works for non-specific + // commodities. add_or_set_value(xact->account->xdata().value, xact->amount); DEBUG("entry.finalize.totals", |