journal: make balance assertions exact again (#941)
Going with option 1b from the issue: calculated and asserted amounts are compared exactly, disregarding display precision. But now balance assertion failure messages show those exact amounts at full precision, avoiding confusion.
This commit is contained in:
parent
e120e261bd
commit
70b11ed0a4
@ -583,50 +583,53 @@ checkBalanceAssertion p@Posting{pbalanceassertion=Just (BalanceAssertion{baamoun
|
|||||||
| otherwise = []
|
| otherwise = []
|
||||||
checkBalanceAssertion _ _ = Right ()
|
checkBalanceAssertion _ _ = Right ()
|
||||||
|
|
||||||
-- | Does the difference between the asserted balance
|
-- | Are the asserted balance and the actual balance
|
||||||
-- and (the corresponding part of) the actual balance
|
-- exactly equal (disregarding display precision) ?
|
||||||
-- appear as zero, when rendered to the greater of
|
-- The posting is used for creating an error message.
|
||||||
-- 1. the standard display precision for the commodity
|
|
||||||
-- 2. the full precision of the asserted amount ?
|
|
||||||
-- The posting is used when creating an error message.
|
|
||||||
checkBalanceAssertionCommodity :: Posting -> Amount -> MixedAmount -> Either String ()
|
checkBalanceAssertionCommodity :: Posting -> Amount -> MixedAmount -> Either String ()
|
||||||
checkBalanceAssertionCommodity p assertedamt actualbal
|
checkBalanceAssertionCommodity p assertedamt actualbal
|
||||||
| isZeroAmount diff = Right ()
|
| pass = Right ()
|
||||||
| True = Left err
|
| otherwise = Left err
|
||||||
where
|
where
|
||||||
diff =
|
|
||||||
-- traceWith (("diff:"++).showAmountDebug) $
|
|
||||||
-- traceWith (("asserted:"++).showAmountDebug)
|
|
||||||
assertedamt -
|
|
||||||
-- traceWith (("actual:"++).showAmountDebug)
|
|
||||||
actualbalincommodity
|
|
||||||
assertedcomm = acommodity assertedamt
|
assertedcomm = acommodity assertedamt
|
||||||
actualbalincommodity = fromMaybe nullamt $ find ((== assertedcomm) . acommodity) (amounts actualbal)
|
actualbalincommodity = fromMaybe nullamt $ find ((== assertedcomm) . acommodity) (amounts actualbal)
|
||||||
diffplus | isNegativeAmount diff == False = "+"
|
pass =
|
||||||
| otherwise = ""
|
aquantity
|
||||||
|
-- traceWith (("asserted:"++).showAmountDebug)
|
||||||
|
assertedamt ==
|
||||||
|
aquantity
|
||||||
|
-- traceWith (("actual:"++).showAmountDebug)
|
||||||
|
actualbalincommodity
|
||||||
|
diff = aquantity assertedamt - aquantity actualbalincommodity
|
||||||
err = printf (unlines
|
err = printf (unlines
|
||||||
[ "balance assertion error%s",
|
[ "balance assertion: %s",
|
||||||
"after posting:",
|
"\nassertion details:",
|
||||||
"%s",
|
|
||||||
"balance assertion details:",
|
|
||||||
"date: %s",
|
"date: %s",
|
||||||
"account: %s",
|
"account: %s",
|
||||||
"commodity: %s",
|
"commodity: %s",
|
||||||
"calculated: %s",
|
-- "display precision: %d",
|
||||||
"asserted: %s (difference: %s)"
|
"calculated: %s", -- (at display precision: %s)",
|
||||||
|
"asserted: %s", -- (at display precision: %s)",
|
||||||
|
"difference: %s"
|
||||||
])
|
])
|
||||||
(case ptransaction p of
|
(case ptransaction p of
|
||||||
Nothing -> ":" -- shouldn't happen
|
Nothing -> "?" -- shouldn't happen
|
||||||
Just t -> printf " in %s:\nin transaction:\n%s"
|
Just t -> printf "%s\ntransaction:\n%s"
|
||||||
(showGenericSourcePos pos) (chomp $ showTransaction t) :: String
|
(showGenericSourcePos pos)
|
||||||
where pos = baposition $ fromJust $ pbalanceassertion p)
|
(chomp $ showTransaction t)
|
||||||
(showPostingLine p)
|
:: String
|
||||||
|
where
|
||||||
|
pos = baposition $ fromJust $ pbalanceassertion p
|
||||||
|
)
|
||||||
(showDate $ postingDate p)
|
(showDate $ postingDate p)
|
||||||
(T.unpack $ paccount p) -- XXX pack
|
(T.unpack $ paccount p) -- XXX pack
|
||||||
assertedcomm
|
assertedcomm
|
||||||
(showAmount actualbalincommodity)
|
-- (asprecision $ astyle actualbalincommodity) -- should be the standard display precision I think
|
||||||
(showAmount assertedamt)
|
(show $ aquantity actualbalincommodity)
|
||||||
(diffplus ++ showAmount diff)
|
-- (showAmount actualbalincommodity)
|
||||||
|
(show $ aquantity assertedamt)
|
||||||
|
-- (showAmount assertedamt)
|
||||||
|
(show diff)
|
||||||
|
|
||||||
-- | Fill in any missing amounts and check that all journal transactions
|
-- | Fill in any missing amounts and check that all journal transactions
|
||||||
-- balance and all balance assertions pass, or return an error message.
|
-- balance and all balance assertions pass, or return an error message.
|
||||||
|
|||||||
@ -35,7 +35,7 @@ module Hledger.Data.Transaction (
|
|||||||
showTransaction,
|
showTransaction,
|
||||||
showTransactionUnelided,
|
showTransactionUnelided,
|
||||||
showTransactionUnelidedOneLineAmounts,
|
showTransactionUnelidedOneLineAmounts,
|
||||||
showPostingLine,
|
-- showPostingLine,
|
||||||
showPostingLines,
|
showPostingLines,
|
||||||
-- * GenericSourcePos
|
-- * GenericSourcePos
|
||||||
sourceFilePath,
|
sourceFilePath,
|
||||||
@ -246,14 +246,17 @@ postingAsLines elideamount onelineamounts pstoalignwith p = concat [
|
|||||||
case renderCommentLines (pcomment p) of [] -> ("",[])
|
case renderCommentLines (pcomment p) of [] -> ("",[])
|
||||||
c:cs -> (c,cs)
|
c:cs -> (c,cs)
|
||||||
|
|
||||||
-- | Show a posting's status, account name and amount on one line.
|
-- | Render a posting, simply. Used in balance assertion errors.
|
||||||
-- Used in balance assertion errors.
|
-- showPostingLine p =
|
||||||
showPostingLine p =
|
-- indent $
|
||||||
indent $
|
-- if pstatus p == Cleared then "* " else "" ++ -- XXX show !
|
||||||
if pstatus p == Cleared then "* " else "" ++
|
-- showAccountName Nothing (ptype p) (paccount p) ++
|
||||||
showAccountName Nothing (ptype p) (paccount p) ++
|
-- " " ++
|
||||||
" " ++
|
-- showMixedAmountOneLine (pamount p) ++
|
||||||
showMixedAmountOneLine (pamount p)
|
-- assertion
|
||||||
|
-- where
|
||||||
|
-- -- XXX extract, handle ==
|
||||||
|
-- assertion = maybe "" ((" = " ++) . showAmountWithZeroCommodity . baamount) $ pbalanceassertion p
|
||||||
|
|
||||||
-- | Render a posting, at the appropriate width for aligning with
|
-- | Render a posting, at the appropriate width for aligning with
|
||||||
-- its siblings if any. Used by the rewrite command.
|
-- its siblings if any. Used by the rewrite command.
|
||||||
|
|||||||
@ -468,71 +468,11 @@ flag or `real:` query.
|
|||||||
|
|
||||||
### Assertions and precision
|
### Assertions and precision
|
||||||
|
|
||||||
A [commodity directive](http://hledger.org/journal.html#declaring-commodities)
|
Balance assertions compare the exactly calculated amounts,
|
||||||
which limits the display precision, can affect assertions.
|
which are not always what is shown by reports.
|
||||||
|
Eg a [commodity directive](http://hledger.org/journal.html#declaring-commodities)
|
||||||
In general, hledger balance assertions should pass or fail as you would
|
may limit the display precision, but this will not affect balance assertions.
|
||||||
expect from doing visual inspection and manual arithmetic with the amounts
|
Balance assertion failure messages show exact amounts.
|
||||||
shown in reports and error messages, ie at display precision.
|
|
||||||
|
|
||||||
More specifically, currently assertions pass if the difference between asserted
|
|
||||||
and actual amounts appears to be zero, when rendered to the greater of
|
|
||||||
the standard display precision and the asserted amount's precision.
|
|
||||||
Here are some examples of this in action.
|
|
||||||
|
|
||||||
Asserting the exact balance:
|
|
||||||
```journal
|
|
||||||
commodity $1000.00
|
|
||||||
|
|
||||||
2019/01/01
|
|
||||||
(a) $0.006
|
|
||||||
|
|
||||||
2019/01/02
|
|
||||||
(a) $1.00 = $1.006
|
|
||||||
|
|
||||||
; Actual balance: 1.006
|
|
||||||
; Asserted balence: 1.006
|
|
||||||
; Difference: 0.000
|
|
||||||
; Standard & asserted precisions: 2, 3
|
|
||||||
; Difference rendered: 0.000
|
|
||||||
; Result: pass
|
|
||||||
```
|
|
||||||
|
|
||||||
Asserting the balance rounded to fewer decimal places:
|
|
||||||
```journal
|
|
||||||
commodity $1000.00
|
|
||||||
|
|
||||||
2019/01/01
|
|
||||||
(a) $0.006
|
|
||||||
|
|
||||||
2019/01/02
|
|
||||||
(a) $1.00 = $1.01
|
|
||||||
|
|
||||||
; Actual balance: 1.006
|
|
||||||
; Asserted balence: 1.01
|
|
||||||
; Difference: 0.004
|
|
||||||
; Standard & asserted precisions: 2, 2
|
|
||||||
; Difference rendered: 0.00
|
|
||||||
; Result: pass
|
|
||||||
```
|
|
||||||
|
|
||||||
Asserting an inexact balance with too many decimal places (fails):
|
|
||||||
```journal
|
|
||||||
commodity $1000.00
|
|
||||||
|
|
||||||
2019/01/01
|
|
||||||
(a) $0.006
|
|
||||||
|
|
||||||
2019/01/02
|
|
||||||
(a) $1.00 = $1.0061
|
|
||||||
|
|
||||||
; Actual balance: 1.006
|
|
||||||
; Asserted balence: 1.0061
|
|
||||||
; Difference: 0.0001
|
|
||||||
; Standard & asserted precisions: 2, 4
|
|
||||||
; Difference rendered: 0.0001
|
|
||||||
; Result: fail
|
|
||||||
```
|
|
||||||
|
|
||||||
## Balance Assignments
|
## Balance Assignments
|
||||||
|
|
||||||
|
|||||||
@ -57,7 +57,7 @@ hledger -f - stats
|
|||||||
b $-1 = $-3
|
b $-1 = $-3
|
||||||
|
|
||||||
>>>
|
>>>
|
||||||
>>>2 /balance assertion error.*line 11, column 12/
|
>>>2 /balance assertion.*line 11, column 12/
|
||||||
>>>=1
|
>>>=1
|
||||||
|
|
||||||
# 4. should also work without commodity symbols
|
# 4. should also work without commodity symbols
|
||||||
@ -335,7 +335,7 @@ hledger -f - stats
|
|||||||
|
|
||||||
2016/1/3
|
2016/1/3
|
||||||
a 0 == $1
|
a 0 == $1
|
||||||
>>>2 /balance assertion error.*line 10, column 15/
|
>>>2 /balance assertion.*line 10, column 15/
|
||||||
>>>=1
|
>>>=1
|
||||||
|
|
||||||
# 19. Mix different commodities and exact assignments
|
# 19. Mix different commodities and exact assignments
|
||||||
@ -366,17 +366,7 @@ hledger -f- stats
|
|||||||
>>>2 /unexpected '@'/
|
>>>2 /unexpected '@'/
|
||||||
>>>=1
|
>>>=1
|
||||||
|
|
||||||
# 21. With a commodity directive limiting the display precision.
|
# 21. The exact amounts are compared; display precision does not affect assertions.
|
||||||
# Assertions pass if the difference between asserted and actual amounts
|
|
||||||
# appears to be zero, when rendered to the greater of the standard
|
|
||||||
# display precision and the asserted amount's precision.
|
|
||||||
# Here,
|
|
||||||
# Actual balance: 1.006
|
|
||||||
# Asserted balence: 1.006
|
|
||||||
# Difference: 0.000
|
|
||||||
# Standard & asserted precisions: 2, 3
|
|
||||||
# Difference rendered: 0.000
|
|
||||||
# Result: pass
|
|
||||||
hledger -f- stats
|
hledger -f- stats
|
||||||
<<<
|
<<<
|
||||||
commodity $1000.00
|
commodity $1000.00
|
||||||
@ -391,13 +381,7 @@ commodity $1000.00
|
|||||||
>>>2
|
>>>2
|
||||||
>>>=0
|
>>>=0
|
||||||
|
|
||||||
# 22. A rounded assertion amount can also pass. Here,
|
# 22. This fails
|
||||||
# Actual balance: 1.006
|
|
||||||
# Asserted balence: 1.01
|
|
||||||
# Difference: 0.004
|
|
||||||
# Standard & asserted precisions: 2, 2
|
|
||||||
# Difference rendered: 0.00
|
|
||||||
# Result: pass
|
|
||||||
hledger -f- stats
|
hledger -f- stats
|
||||||
<<<
|
<<<
|
||||||
commodity $1000.00
|
commodity $1000.00
|
||||||
@ -408,17 +392,10 @@ commodity $1000.00
|
|||||||
2019/01/02
|
2019/01/02
|
||||||
(a) $1.00 = $1.01
|
(a) $1.00 = $1.01
|
||||||
|
|
||||||
>>> /Transactions/
|
>>>2 /difference: 0\.004/
|
||||||
>>>2
|
>>>=1
|
||||||
>>>=0
|
|
||||||
|
|
||||||
# 23. A more precise assertion amount can fail. Here,
|
# 23. This fails
|
||||||
# Actual balance: 1.006
|
|
||||||
# Asserted balence: 1.0061
|
|
||||||
# Difference: 0.0001
|
|
||||||
# Standard & asserted precisions: 2, 4
|
|
||||||
# Difference rendered: 0.0001
|
|
||||||
# Result: fail
|
|
||||||
hledger -f- stats
|
hledger -f- stats
|
||||||
<<<
|
<<<
|
||||||
commodity $1000.00
|
commodity $1000.00
|
||||||
@ -429,6 +406,5 @@ commodity $1000.00
|
|||||||
2019/01/02
|
2019/01/02
|
||||||
(a) $1.00 = $1.0061
|
(a) $1.00 = $1.0061
|
||||||
|
|
||||||
>>>
|
>>>2 /difference: 0\.0001/
|
||||||
>>>2 /difference: \+\$0\.0001/
|
|
||||||
>>>=1
|
>>>=1
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user