Transactional assignments (i.e., confirmed balances) are working now.

This commit is contained in:
John Wiegley 2008-09-14 19:38:44 -04:00
parent 0135c28049
commit 7d1809cb15
4 changed files with 66 additions and 50 deletions

View file

@ -130,7 +130,7 @@ bool entry_base_t::finalize()
// :generatedp t)) // :generatedp t))
// (add-xact entry null-xact))) // (add-xact entry null-xact)))
if (journal && journal->basket && xacts.size() == 1) { 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 // jww (2008-07-24): Need to make the rest of the code aware of what to do
// when it sees a generated xact. // when it sees a generated xact.
null_xact = new xact_t(journal->basket, XACT_GENERATED); null_xact = new xact_t(journal->basket, XACT_GENERATED);
@ -173,10 +173,14 @@ bool entry_base_t::finalize()
XACT_GENERATED)); XACT_GENERATED));
} }
} }
} else { }
else if (balance.is_amount()) {
null_xact->amount = balance.as_amount().negate(); null_xact->amount = balance.as_amount().negate();
null_xact->add_flags(XACT_CALCULATED); null_xact->add_flags(XACT_CALCULATED);
} }
else if (! balance.is_null() && ! balance.is_realzero()) {
throw_(balance_error, "Entry does not balance");
}
balance = NULL_VALUE; balance = NULL_VALUE;
} }
@ -300,28 +304,37 @@ bool entry_base_t::finalize()
// (format-value balance :width 20))) // (format-value balance :width 20)))
if (! balance.is_null()) { if (! balance.is_null()) {
balance.round(); balance.in_place_round();
if (! balance.is_zero()) { if (! balance.is_zero()) {
#if 0 #if 0
error * err = new entry_context(*this, "While balancing entry:");
new balance_error("Entry does not balance",
new entry_context(*this, "While balancing entry:"));
err->context.push_front
(new value_context(balance, "Unbalanced remainder is:"));
throw err;
#endif #endif
add_error_context("Unbalanced remainder is: ");
add_error_context(value_context(balance));
throw_(balance_error, "Entry does not balance");
} }
} }
// Add the final calculated totals each to their related account // Add the final calculated totals each to their related account
if (dynamic_cast<entry_t *>(this)) { if (dynamic_cast<entry_t *>(this)) {
bool all_null = true;
foreach (xact_t * xact, xacts) { foreach (xact_t * xact, xacts) {
// jww (2008-08-09): For now, this feature only works for if (! xact->amount.is_null()) {
// non-specific commodities. all_null = false;
add_or_set_value(xact->account->xdata().value,
xact->amount.strip_annotations()); // 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",
"Total for " << xact->account->fullname() << " + "
<< xact->amount.strip_annotations() << ": "
<< xact->account->xdata().value.strip_annotations());
}
} }
if (all_null)
return false; // ignore this entry completely
} }
return true; return true;

View file

@ -313,71 +313,78 @@ xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"Found a balance assignment indicator"); "Found a balance assignment indicator");
if (in.good() && ! in.eof()) { if (in.good() && ! in.eof()) {
amount_t amt; xact->assigned_amount = amount_t();
try { try {
istream_pos_type beg = in.tellg(); istream_pos_type beg = in.tellg();
optional<expr_t> total_expr = xact->assigned_amount_expr =
parse_amount_expr(in, amt, xact.get(), EXPR_PARSE_NO_MIGRATE); parse_amount_expr(in, *xact->assigned_amount, xact.get(),
EXPR_PARSE_NO_MIGRATE);
if (amt.is_null()) if (xact->assigned_amount->is_null())
throw parse_error throw parse_error
("An assigned balance must evaluate to a constant value"); ("An assigned balance must evaluate to a constant value");
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"XACT assign: parsed amt = " << amt); "XACT assign: parsed amt = " << *xact->assigned_amount);
if (total_expr) { if (xact->assigned_amount_expr) {
istream_pos_type end = in.tellg(); istream_pos_type end = in.tellg();
total_expr->set_text(string("=") + xact->assigned_amount_expr->set_text
string(line, long(beg), long(end - beg))); (string("=") + string(line, long(beg), long(end - beg)));
} }
// jww (2008-08-02): Save total_expr somewhere!
account_t::xdata_t& xdata(xact->account->xdata()); account_t::xdata_t& xdata(xact->account->xdata());
amount_t& amt(*xact->assigned_amount);
DEBUG("ledger.xact.assign", "account balance = " << xdata.value); DEBUG("xact.assign",
DEBUG("ledger.xact.assign", "xact amount = " << amt); "account balance = " << xdata.value.strip_annotations());
DEBUG("xact.assign",
"xact amount = " << amt.strip_annotations());
amount_t diff; amount_t diff;
if (xdata.value.is_amount()) { if (xdata.value.is_amount()) {
diff = amt - xdata.value.as_amount(); diff = amt - xdata.value.as_amount();
} }
else if (xdata.value.is_balance()) { else if (xdata.value.is_balance()) {
optional<amount_t> comm_bal = if (optional<amount_t> comm_bal =
xdata.value.as_balance().commodity_amount(amt.commodity()); xdata.value.as_balance().commodity_amount(amt.commodity()))
diff = amt - (comm_bal ? *comm_bal : amount_t(0L)); diff = amt - *comm_bal;
else
diff = amt;
} }
else if (xdata.value.is_balance_pair()) { else if (xdata.value.is_balance_pair()) {
optional<amount_t> comm_bal = if (optional<amount_t> comm_bal =
xdata.value.as_balance_pair().commodity_amount(amt.commodity()); xdata.value.as_balance_pair().commodity_amount(amt.commodity()))
diff = amt - (comm_bal ? *comm_bal : amount_t(0L)); diff = amt - *comm_bal;
else
diff = amt;
} }
else { else {
diff = amt; diff = amt;
} }
DEBUG("ledger.xact.assign", "diff = " << diff); DEBUG("xact.assign", "diff = " << diff.strip_annotations());
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"XACT assign: diff = " << diff); "XACT assign: diff = " << diff.strip_annotations());
if (! diff.is_realzero()) { if (! diff.is_zero()) {
if (! xact->amount.is_null()) { if (! xact->amount.is_null()) {
xact_t * temp = diff -= xact->amount;
new xact_t(xact->account, diff, if (! diff.is_zero()) {
XACT_GENERATED | XACT_CALCULATED); xact_t * temp = new xact_t(xact->account, diff,
entry->add_xact(temp); XACT_GENERATED | XACT_CALCULATED);
entry->add_xact(temp);
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"Created balancing transaction"); "Created balancing transaction");
}
} else { } else {
xact->amount = diff; xact->amount = diff;
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"Overwrite null transaction"); "Overwrite null transaction");
} }
xdata.value = amt;
} }
} }
catch (const std::exception& err) { catch (const std::exception& err) {

View file

@ -1263,11 +1263,8 @@ bool value_t::is_realzero() const
return as_any_pointer().empty(); return as_any_pointer().empty();
default: default:
assert(false); throw_(value_error, "Cannot determine if " << label() << " is really zero");
break;
} }
assert(false);
return true;
} }
bool value_t::is_zero() const bool value_t::is_zero() const
@ -1296,11 +1293,8 @@ bool value_t::is_zero() const
return as_any_pointer().empty(); return as_any_pointer().empty();
default: default:
assert(false); throw_(value_error, "Cannot determine if " << label() << " is zero");
break;
} }
assert(false);
return true;
} }
value_t value_t::value(const optional<datetime_t>& moment) const value_t value_t::value(const optional<datetime_t>& moment) const

View file

@ -69,6 +69,8 @@ public:
optional<expr_t> amount_expr; optional<expr_t> amount_expr;
optional<amount_t> cost; optional<amount_t> cost;
optional<expr_t> cost_expr; optional<expr_t> cost_expr;
optional<amount_t> assigned_amount;
optional<expr_t> assigned_amount_expr;
istream_pos_type beg_pos; istream_pos_type beg_pos;
unsigned long beg_line; unsigned long beg_line;
@ -84,7 +86,7 @@ public:
{ {
TRACE_CTOR(xact_t, "account_t *, flags_t"); TRACE_CTOR(xact_t, "account_t *, flags_t");
} }
xact_t(account_t * _account, xact_t(account_t * _account,
const amount_t& _amount, const amount_t& _amount,
flags_t _flags = XACT_NORMAL, flags_t _flags = XACT_NORMAL,
const optional<string>& _note = none) const optional<string>& _note = none)