Merge pull request #1667 from pascalfleury/improve_fix_of_issue_1187
Improve fix of issue #1187
This commit is contained in:
commit
8283abb594
3 changed files with 109 additions and 16 deletions
|
|
@ -3230,6 +3230,45 @@ A balance assertion has this general form:
|
|||
This simply asserts that after subtracting $20.00 from Assets:Cash,
|
||||
that the resulting total matches $500.00. If not, it is an error.
|
||||
|
||||
The assertion has an effect only on the specified commodity. If an account has
|
||||
multiple commodities, then only the one asserted is verified:
|
||||
|
||||
@smallexample
|
||||
2012-03-10 KFC New York
|
||||
Expenses:Food $20.00
|
||||
Assets:Cash $-20.00 = $500.00
|
||||
|
||||
2012-03-11 KFC Montreal
|
||||
Expenses:Food 15.00 CAD
|
||||
Assets:Cash -15.00 CAD = $500.00
|
||||
@end smallexample
|
||||
|
||||
In this case, the amount in USD of cash (which has not changed) is validated.
|
||||
Nothing is asserted about the current amount of Canadian dollars in @samp{Asset:Cash}.
|
||||
|
||||
@subsubsection Special assertion value 0
|
||||
|
||||
The only value that can be asserted without a commodity is @samp{0}.
|
||||
This results in a cross-commodities assertion, which makes it possible to
|
||||
assert that an account is totally empty.
|
||||
|
||||
@smallexample
|
||||
2012-03-09 Fill Wallet
|
||||
Revenue $20.00
|
||||
Revenue 15.00 CAD
|
||||
Assets:Cash
|
||||
|
||||
2012-03-10 KFC New York
|
||||
Expenses:Food $20.00
|
||||
Assets:Cash $-20.00
|
||||
|
||||
2012-03-11 KFC Montreal
|
||||
Expenses:Food 15.00 CAD
|
||||
Assets:Cash -15.00 CAD = 0
|
||||
@end smallexample
|
||||
|
||||
The last transaction will assert that we are out of cash of any sort.
|
||||
|
||||
@node Balance assignments, Resetting a balance, Balance assertions, Balance verification
|
||||
@subsection Balance assignments
|
||||
|
||||
|
|
|
|||
|
|
@ -1644,29 +1644,30 @@ post_t * instance_t::parse_post(char * line,
|
|||
}
|
||||
|
||||
DEBUG("textual.parse", "line " << context.linenum << ": "
|
||||
<< "POST assign: parsed amt = " << *post->assigned_amount);
|
||||
<< "POST assign: parsed balance amount = " << *post->assigned_amount);
|
||||
|
||||
amount_t& amt(*post->assigned_amount);
|
||||
const amount_t& amt(*post->assigned_amount);
|
||||
value_t account_total
|
||||
(post->account->amount().strip_annotations(keep_details_t()));
|
||||
|
||||
DEBUG("post.assign", "line " << context.linenum << ": "
|
||||
<< "account balance = " << account_total);
|
||||
DEBUG("post.assign",
|
||||
"line " << context.linenum << ": " << "post amount = " << amt);
|
||||
DEBUG("post.assign", "line " << context.linenum << ": "
|
||||
<< "post amount = " << amt << " (is_zero = " << amt.is_zero() << ")");
|
||||
|
||||
amount_t diff = amt;
|
||||
balance_t diff = amt;
|
||||
|
||||
switch (account_total.type()) {
|
||||
case value_t::AMOUNT:
|
||||
if (account_total.as_amount().commodity_ptr() == diff.commodity_ptr())
|
||||
diff -= account_total.as_amount();
|
||||
diff -= account_total.as_amount();
|
||||
DEBUG("textual.parse", "line " << context.linenum << ": "
|
||||
<< "Subtracting amount " << account_total.as_amount() << " from diff, yielding " << diff);
|
||||
break;
|
||||
|
||||
case value_t::BALANCE:
|
||||
if (optional<amount_t> comm_bal =
|
||||
account_total.as_balance().commodity_amount(amt.commodity()))
|
||||
diff -= *comm_bal;
|
||||
diff -= account_total.as_balance();
|
||||
DEBUG("textual.parse", "line " << context.linenum << ": "
|
||||
<< "Subtracting balance " << account_total.as_balance() << " from diff, yielding " << diff);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1680,18 +1681,34 @@ post_t * instance_t::parse_post(char * line,
|
|||
|
||||
// Subtract amounts from previous posts to this account in the xact.
|
||||
for (post_t* p : xact->posts) {
|
||||
if (p->account == post->account &&
|
||||
p->amount.commodity_ptr() == diff.commodity_ptr()) {
|
||||
if (p->account == post->account) {
|
||||
diff -= p->amount;
|
||||
DEBUG("textual.parse", "line " << context.linenum << ": "
|
||||
<< "Subtract " << p->amount << ", diff = " << diff);
|
||||
<< "Subtracting " << p->amount << ", diff = " << diff);
|
||||
}
|
||||
}
|
||||
|
||||
// If amt has a commodity, restrict balancing to that. Otherwise, it's the blanket '0' and
|
||||
// check that all of them are zero.
|
||||
if (amt.has_commodity()) {
|
||||
DEBUG("textual.parse", "line " << context.linenum << ": "
|
||||
<< "Finding commodity " << amt.commodity() << " (" << amt << ") in balance " << diff);
|
||||
optional<amount_t> wanted_commodity = diff.commodity_amount(amt.commodity());
|
||||
if (!wanted_commodity) {
|
||||
diff = amt - amt; // this is '0' with the correct commodity.
|
||||
} else {
|
||||
diff = *wanted_commodity;
|
||||
}
|
||||
DEBUG("textual.parse", "line " << context.linenum << ": "
|
||||
<< "Diff is now " << diff);
|
||||
}
|
||||
|
||||
if (post->amount.is_null()) {
|
||||
// balance assignment
|
||||
if (! diff.is_zero()) {
|
||||
post->amount = diff;
|
||||
// This will fail if there are more than 1 commodity in diff, which is wanted,
|
||||
// as amount cannot store more than 1 commodity.
|
||||
post->amount = diff.to_amount();
|
||||
DEBUG("textual.parse", "line " << context.linenum << ": "
|
||||
<< "Overwrite null posting");
|
||||
}
|
||||
|
|
@ -1699,10 +1716,11 @@ post_t * instance_t::parse_post(char * line,
|
|||
// balance assertion
|
||||
diff -= post->amount;
|
||||
if (! no_assertions && ! diff.is_zero()) {
|
||||
amount_t tot = amt - diff;
|
||||
balance_t tot = -diff + amt;
|
||||
DEBUG("textual.parse", "Balance assertion: off by " << diff << " (expected to see " << tot << ")");
|
||||
throw_(parse_error,
|
||||
_f("Balance assertion off by %1% (expected to see %2%)")
|
||||
% diff % tot);
|
||||
% diff.to_string() % tot.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
36
test/regress/1187_5.test
Normal file
36
test/regress/1187_5.test
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
2013/12/01 * Initial State
|
||||
Crédit:Viseca:MasterCard P1 -618.50 CHF
|
||||
Crédit:Viseca:MasterCard P2 -52.10 CHF
|
||||
Equity:Opening Balances
|
||||
|
||||
2013/12/15 * Buy Some Chocolate
|
||||
Dépenses:Nourriture 19.00 EUR ; #1
|
||||
Crédit:Viseca:MasterCard P1
|
||||
|
||||
2013/12/15 * Buy Some Chocolate
|
||||
Crédit:Viseca:MasterCard P1 18.00 EUR ; #2
|
||||
Recettes:Erreurs
|
||||
|
||||
2013/12/23 * Facture Viseca
|
||||
Crédit:Viseca:MasterCard P2 52.10 CHF = 0 ; #3
|
||||
Crédit:Viseca:MasterCard P1 618.50 CHF = 0 CHF ; #4
|
||||
Dépenses:Frais:Gestion Comptes 1.50 CHF
|
||||
Crédit:Viseca -672.10 CHF
|
||||
|
||||
2014/01/03 * Facture Viseca
|
||||
Crédit:Viseca 672.10 CHF = 0
|
||||
Actif:Comptes:CP courant
|
||||
|
||||
test bal
|
||||
-672.10 CHF Actif:Comptes:CP courant
|
||||
-1.00 EUR Crédit:Viseca
|
||||
-1.00 EUR MasterCard P1
|
||||
1.50 CHF
|
||||
19.00 EUR Dépenses
|
||||
1.50 CHF Frais:Gestion Comptes
|
||||
19.00 EUR Nourriture
|
||||
670.60 CHF Equity:Opening Balances
|
||||
-18.00 EUR Recettes:Erreurs
|
||||
--------------------
|
||||
0
|
||||
end test
|
||||
Loading…
Add table
Reference in a new issue