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