summaryrefslogtreecommitdiff
path: root/parse.cc
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2003-10-01 21:55:40 +0000
committerJohn Wiegley <johnw@newartisans.com>2003-10-01 21:55:40 +0000
commit7ce12f8cfe0beaecea3de7e073aa3c9751742a5d (patch)
treea2681c82ede5e0edc1dc7c0e39f40239762244c9 /parse.cc
parentc7e1cf34b393d98cda4d270cc3e431b9a7909fa7 (diff)
downloadfork-ledger-7ce12f8cfe0beaecea3de7e073aa3c9751742a5d.tar.gz
fork-ledger-7ce12f8cfe0beaecea3de7e073aa3c9751742a5d.tar.bz2
fork-ledger-7ce12f8cfe0beaecea3de7e073aa3c9751742a5d.zip
*** empty log message ***
Diffstat (limited to 'parse.cc')
-rw-r--r--parse.cc170
1 files changed, 102 insertions, 68 deletions
diff --git a/parse.cc b/parse.cc
index 7a4c5b07..1c2cb556 100644
--- a/parse.cc
+++ b/parse.cc
@@ -36,95 +36,129 @@ static void finalize_entry(entry * curr, bool compute_balances)
{
assert(curr);
- // Certain shorcuts are allowed in the case of exactly two
- // transactions.
+ // If there were no transactions, it's definitely an error!
- if (! curr->xacts.empty() && curr->xacts.size() == 2) {
- transaction * first = curr->xacts.front();
- transaction * second = curr->xacts.back();
+ if (curr->xacts.empty()) {
+ std::cerr << "Error, line " << (linenum - 1)
+ << ": Entry has no transactions!" << std::endl;
+ return;
+ }
- // If one transaction gives no value at all, then its value is
- // the inverse of the computed value of the other.
+ // Scan through and compute the total balance for the entry.
- if (! first->cost && second->cost) {
- first->cost = second->cost->value();
- first->cost->negate();
+ totals balance;
- if (compute_balances)
- first->acct->balance.credit(first->cost);
- }
- else if (! second->cost && first->cost) {
- second->cost = first->cost->value();
- second->cost->negate();
+ for (std::list<transaction *>::iterator x = curr->xacts.begin();
+ x != curr->xacts.end();
+ x++)
+ if ((*x)->cost)
+ balance.credit((*x)->cost->value());
- if (compute_balances)
- second->acct->balance.credit(second->cost);
- }
- else if (first->cost && second->cost) {
- // If one transaction is of a different commodity than the
- // other, and it has no per-unit price, and its not of the
- // default commodity, then determine its price by dividing the
- // unit count into the total, to balance the transaction.
-
- if (first->cost->comm() != second->cost->comm()) {
- if (! second->cost->has_price() &&
- second->cost->comm_symbol() != DEFAULT_COMMODITY) {
- second->cost->set_value(first->cost);
- }
- else if (! first->cost->has_price() &&
- first->cost->comm_symbol() != DEFAULT_COMMODITY) {
- first->cost->set_value(second->cost);
+ // If one transaction is of a different commodity than the others,
+ // and it has no per-unit price, determine its price by dividing
+ // the unit count into the value of the balance.
+ //
+ // NOTE: We don't do this for prefix-style or joined-symbol
+ // commodities. Also, do it for the last eligible commodity first,
+ // if it meets the criteria.
+
+ if (! balance.amounts.empty() && balance.amounts.size() == 2) {
+ for (std::list<transaction *>::iterator x = curr->xacts.begin();
+ x != curr->xacts.end();
+ x++) {
+ if (! (*x)->cost->has_price() &&
+ ! (*x)->cost->comm()->prefix &&
+ (*x)->cost->comm()->separate) {
+ for (totals::iterator i = balance.amounts.begin();
+ i != balance.amounts.end();
+ i++) {
+ if ((*i).second->comm() != (*x)->cost->comm()) {
+ (*x)->cost->set_value((*i).second);
+ break;
+ }
}
+ break;
}
}
}
- if (! curr->validate()) {
- std::cerr << "Error, line " << (linenum - 1)
- << ": Failed to balance the following transaction:"
- << std::endl;
- curr->print(std::cerr);
- curr->validate(true);
- return;
- }
+ // Walk through each of the transactions, fixing up any that we
+ // can, and performing any on-the-fly calculations.
+
+ bool empty_allowed = true;
+
+ for (std::list<transaction *>::iterator x = curr->xacts.begin();
+ x != curr->xacts.end();
+ x++) {
+ if (! (*x)->cost) {
+ if (empty_allowed && ! balance.amounts.empty() &&
+ balance.amounts.size() == 1) {
+ empty_allowed = false;
+
+ // If one transaction gives no value at all -- and all the
+ // rest are of the same commodity -- then its value is the
+ // inverse of the computed value of the others.
+
+ totals::iterator i = balance.amounts.begin();
+ (*x)->cost = (*i).second->value();
+ (*x)->cost->negate();
+
+ if (compute_balances)
+ (*x)->acct->balance.credit((*x)->cost);
+ } else {
+ std::cerr << "Error, line " << (linenum - 1)
+ << ": Transaction entry is lacking an amount."
+ << std::endl;
+ return;
+ }
+ }
#ifdef HUQUQULLAH
- if (main_ledger.compute_huquq) {
- for (std::list<transaction *>::iterator x = curr->xacts.begin();
- x != curr->xacts.end();
- x++) {
- if (! (*x)->exempt_or_necessary || ! (*x)->cost)
- continue;
+ if (! main_ledger.compute_huquq || ! (*x)->exempt_or_necessary)
+ continue;
- // Reflect the exempt or necessary transaction in the
- // Huququ'llah account, using the H commodity, which is 19% of
- // whichever DEFAULT_COMMODITY ledger was compiled with.
+ // Reflect 19% of the exempt or necessary transaction in the
+ // Huququ'llah account.
- amount * temp = (*x)->cost->value();
+ amount * divisor = create_amount("0.19");
+ amount * temp = (*x)->cost->value();
- transaction * t
- = new transaction(main_ledger.huquq_account,
- temp->value(main_ledger.huquq));
- curr->xacts.push_back(t);
+ transaction * t = new transaction(main_ledger.huquq_account,
+ temp->value(divisor));
+ curr->xacts.push_back(t);
- if (compute_balances)
- t->acct->balance.credit(t->cost);
+ if (compute_balances)
+ t->acct->balance.credit(t->cost);
- // Balance the above transaction by recording the inverse in
- // Expenses:Huququ'llah.
+ // Balance the above transaction by recording the inverse in
+ // Expenses:Huququ'llah.
- t = new transaction(main_ledger.huquq_expenses_account,
- temp->value(main_ledger.huquq));
- t->cost->negate();
- curr->xacts.push_back(t);
+ t = new transaction(main_ledger.huquq_expenses_account,
+ temp->value(divisor));
+ t->cost->negate();
+ curr->xacts.push_back(t);
- if (compute_balances)
- t->acct->balance.credit(t->cost);
+ if (compute_balances)
+ t->acct->balance.credit(t->cost);
- delete temp;
- }
- }
+ delete temp;
+ delete divisor;
#endif
+ }
+
+ // Compute the balances again, just to make sure it all comes out
+ // right (i.e., to zero for every commodity).
+
+ if (! curr->validate()) {
+ std::cerr << "Error, line " << (linenum - 1)
+ << ": Failed to balance the following transaction:"
+ << std::endl;
+ curr->print(std::cerr);
+ curr->validate(true);
+ return;
+ }
+
+ // If it's OK, add it to the general ledger's list of entries.
main_ledger.entries.push_back(curr);
}