imp:balance assertion error message: make it clearer, show diff again

This commit is contained in:
Simon Michael 2024-01-21 13:50:15 -10:00
parent 6091f583dc
commit ac47ea4a0e
3 changed files with 77 additions and 40 deletions

View File

@ -527,6 +527,8 @@ journalBalanceTransactions bopts' j' =
ts' <- lift $ getElems balancedtxns ts' <- lift $ getElems balancedtxns
return j{jtxns=ts'} return j{jtxns=ts'}
-- Before #2039: "Costs are removed, which helps eg balance-assertions.test: 15. Mix different commodities and assignments."
-- | This function is called statefully on each of a date-ordered sequence of -- | This function is called statefully on each of a date-ordered sequence of
-- 1. fully explicit postings from already-balanced transactions and -- 1. fully explicit postings from already-balanced transactions and
-- 2. not-yet-balanced transactions containing balance assignments. -- 2. not-yet-balanced transactions containing balance assignments.
@ -534,7 +536,6 @@ journalBalanceTransactions bopts' j' =
-- and checks balance assertions on each posting as it goes. -- and checks balance assertions on each posting as it goes.
-- An error will be thrown if a transaction can't be balanced -- An error will be thrown if a transaction can't be balanced
-- or if an illegal balance assignment is found (cf checkIllegalBalanceAssignment). -- or if an illegal balance assignment is found (cf checkIllegalBalanceAssignment).
-- Transaction prices are removed, which helps eg balance-assertions.test: 15. Mix different commodities and assignments.
-- This stores the balanced transactions in case 2 but not in case 1. -- This stores the balanced transactions in case 2 but not in case 1.
balanceTransactionAndCheckAssertionsB :: Either Posting Transaction -> Balancing s () balanceTransactionAndCheckAssertionsB :: Either Posting Transaction -> Balancing s ()
balanceTransactionAndCheckAssertionsB (Left p@Posting{}) = balanceTransactionAndCheckAssertionsB (Left p@Posting{}) =
@ -630,7 +631,7 @@ checkBalanceAssertionB _ _ = return ()
-- If the assertion is inclusive, the expected amount is compared with the account's -- If the assertion is inclusive, the expected amount is compared with the account's
-- subaccount-inclusive balance; otherwise, with the subaccount-exclusive balance. -- subaccount-inclusive balance; otherwise, with the subaccount-exclusive balance.
checkBalanceAssertionOneCommodityB :: Posting -> Amount -> MixedAmount -> Balancing s () checkBalanceAssertionOneCommodityB :: Posting -> Amount -> MixedAmount -> Balancing s ()
checkBalanceAssertionOneCommodityB p@Posting{paccount=assertedacct} assertedamt actualbal = do checkBalanceAssertionOneCommodityB p@Posting{paccount=assertedacct} assertedcommbal actualbal = do
let isinclusive = maybe False bainclusive $ pbalanceassertion p let isinclusive = maybe False bainclusive $ pbalanceassertion p
let istotal = maybe False batotal $ pbalanceassertion p let istotal = maybe False batotal $ pbalanceassertion p
actualbal' <- actualbal' <-
@ -645,49 +646,84 @@ checkBalanceAssertionOneCommodityB p@Posting{paccount=assertedacct} assertedamt
bsBalances bsBalances
else return actualbal else return actualbal
let let
assertedcomm = acommodity assertedamt assertedcomm = acommodity assertedcommbal
actualbalincomm = headDef nullamt . amountsRaw . filterMixedAmountByCommodity assertedcomm $ actualbal' assertedcommbalcostless = amountStripPrices assertedcommbal
actualcommbalcostless = amountStripPrices . headDef nullamt . amountsRaw . filterMixedAmountByCommodity assertedcomm $ actualbal'
-- test the assertion. Costs are ignored currently.
pass = pass =
aquantity aquantity (
-- traceWith (("asserted:"++).showAmountDebug) -- traceWith (("asserted:"++).showAmountDebug)
assertedamt == assertedcommbalcostless)
aquantity ==
aquantity (
-- traceWith (("actual:"++).showAmountDebug) -- traceWith (("actual:"++).showAmountDebug)
actualbalincomm actualcommbalcostless)
errmsg = chomp $ printf (unlines errmsg = chomp $ printf (unlines
[ "%s:", [ "%s:",
"%s\n", "%s\n",
"This balance assertion failed.", "Balance assertion failed in %s",
-- "date: %s", "%s at this point, %s, ignoring costs,",
"In account: %s", "the expected balance is: %s", -- (at display precision: %s)",
"and commodity: %s", "but the calculated balance is: %s", -- (at display precision: %s)",
-- "display precision: %d", "(difference: %s)",
"this balance was asserted: %s", -- (at display precision: %s)", "To troubleshoot, check this account's running balance with assertions disabled, eg:",
"but the calculated balance is: %s", -- (at display precision: %s)", "hledger reg -I '%s'%s"
"",
"To troubleshoot, you can view this account's running balance. Eg:",
"",
"hledger reg '%s'%s -I # -f FILE"
]) ])
(sourcePosPretty pos)
(textChomp ex) (sourcePosPretty pos) -- position
-- (showDate $ postingDate p) (textChomp ex) -- journal excerpt
(if isinclusive then printf "%-30s (including subaccounts)" acct else acct) acct -- asserted account
(if istotal then printf "%-30s (no other commodities allowed)" (T.unpack assertedcomm) else (T.unpack assertedcomm)) (if istotal then "Across all commodities" else "In commodity " <> assertedcommstr) -- asserted commodity (partial assertion) or all commodities (total assertion)
-- (asprecision $ astyle actualbalincommodity) -- should be the standard display precision I think (if isinclusive then "including subaccounts" else "excluding subaccounts" :: String) -- inclusive or exclusive balance asserted ?
(show $ aquantity assertedamt) assertedcommbalstrpadded
-- (showAmount assertedamt) actualcommbalstrpadded
(show $ aquantity actualbalincomm) diffstr -- diff
-- (showAmount actualbalincommodity) (acct ++ if isinclusive then "" else "$") -- query matching the account(s) postings
-- (show $ aquantity assertedamt - aquantity actualbalincomm) (if istotal then "" else (" cur:" ++ quoteForCommandLine (T.unpack assertedcomm))) -- query matching the commodity(ies)
(acct ++ if isinclusive then "" else "$")
(if istotal then "" else (" cur:" ++ quoteForCommandLine (T.unpack assertedcomm)))
where where
acct = T.unpack $ paccount p acct = T.unpack $ paccount p
ass = fromJust $ pbalanceassertion p -- PARTIAL: fromJust won't fail, there is a balance assertion ass = fromJust $ pbalanceassertion p -- PARTIAL: fromJust won't fail, there is a balance assertion
pos = baposition ass pos = baposition ass
(_,_,_,ex) = makeBalanceAssertionErrorExcerpt p (_,_,_,ex) = makeBalanceAssertionErrorExcerpt p
assertedcommstr = if T.null assertedcomm then "\"\"" else assertedcomm
showamt = showAmountWithZeroCommodity
assertedcommbalstr = showamt assertedcommbalcostless
actualcommbalstr = showamt actualcommbalcostless
amtswidth = max (length assertedcommbalstr) (length actualcommbalstr)
assertedcommbalstrpadded = fitText (Just amtswidth) Nothing False False $ T.pack assertedcommbalstr
actualcommbalstrpadded = fitText (Just amtswidth) Nothing False False $ T.pack actualcommbalstr
-- diffstr = show $ aquantity assertedcommbal - aquantity actualcommbalcostless
diffstr = showamt $ assertedcommbal - actualcommbalcostless
-- (showDate $ postingDate p)
-- (asprecision $ astyle actualcommbalodity) -- should be the standard display precision I think
unless pass $ throwError errmsg unless pass $ throwError errmsg
{- XXX
When the posting amount has a cost, the highlight region expands to the full line:
*** Exception: Error: /Users/simon/src/hledger/2024-01-21.j:12:69:
| 2023-12-31 closing balances
12 | assets:cash:petty:saved:rent -4.00 EUR @ 2 UAH == 0.00 EUR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| equity:opening/closing balances 8 UAH
Maybe it's better than the normal region ?
*** Exception: Error: /Users/simon/src/hledger/2024-01-21.j:12:61:
| 2023-12-31 closing balances
12 | assets:cash:petty:saved:rent -4.00 EUR == 0.00 EUR @ 3 UAH
| ^^^^^^^^^^^^^^^^^^^
| equity:opening/closing balances 4.00 EUR
If changed also check flycheck-hledger, which currently highlights the equals:
assets:cash:petty:saved:rent -4.00 EUR @ 2 UAH == 0.00 EUR @ 3 UAH
--
-}
-- | Throw an error if this posting is trying to do an illegal balance assignment. -- | Throw an error if this posting is trying to do an illegal balance assignment.
checkIllegalBalanceAssignmentB :: Posting -> Balancing s () checkIllegalBalanceAssignmentB :: Posting -> Balancing s ()

View File

@ -2,14 +2,15 @@
# ** 1. # ** 1.
$ hledger check -f assertions.j $ hledger check -f assertions.j
>2 /hledger: Error: .*assertions.j:4:8: >2 /hledger: Error: .*assertions.j:4:8:
\| 2022-01-01 .*
4 \| a 0 = 1 4 \| a 0 = 1
\| \^\^\^ \| \^\^\^
This balance assertion failed. Balance assertion failed in a
In account: a In commodity "" at this point, excluding subaccounts, ignoring costs,
and commodity: the expected balance is: 1
this balance was asserted: 1 but the calculated balance is: 0
but the calculated balance is: 0 \(difference: 1\)
/ /
>= 1 >= 1

View File

@ -398,7 +398,7 @@ commodity $1000.00
(a) $1.00 = $1.01 (a) $1.00 = $1.01
$ hledger -f- print $ hledger -f- print
>2 /balance assertion failed/ >2 /Balance assertion failed/
>=1 >=1
# ** 25. This fails # ** 25. This fails
@ -412,7 +412,7 @@ commodity $1000.00
(a) $1.00 = $1.0061 (a) $1.00 = $1.0061
$ hledger -f- print $ hledger -f- print
>2 /balance assertion failed/ >2 /Balance assertion failed/
>=1 >=1
# ** 26. Inclusive assertions include balances from subaccounts. # ** 26. Inclusive assertions include balances from subaccounts.