Skip to content

Commit

Permalink
journal: make balance assertions exact again (#941)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
simonmichael committed Jan 8, 2019
1 parent e120e26 commit 70b11ed
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 135 deletions.
61 changes: 32 additions & 29 deletions hledger-lib/Hledger/Data/Journal.hs
Expand Up @@ -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 = assertedcomm = acommodity assertedamt
-- traceWith (("diff:"++).showAmountDebug) $ actualbalincommodity = fromMaybe nullamt $ find ((== assertedcomm) . acommodity) (amounts actualbal)
pass =
aquantity
-- traceWith (("asserted:"++).showAmountDebug) -- traceWith (("asserted:"++).showAmountDebug)
assertedamt - assertedamt ==
aquantity
-- traceWith (("actual:"++).showAmountDebug) -- traceWith (("actual:"++).showAmountDebug)
actualbalincommodity actualbalincommodity
assertedcomm = acommodity assertedamt diff = aquantity assertedamt - aquantity actualbalincommodity
actualbalincommodity = fromMaybe nullamt $ find ((== assertedcomm) . acommodity) (amounts actualbal)
diffplus | isNegativeAmount diff == False = "+"
| otherwise = ""
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.
Expand Down
21 changes: 12 additions & 9 deletions hledger-lib/Hledger/Data/Transaction.hs
Expand Up @@ -35,7 +35,7 @@ module Hledger.Data.Transaction (
showTransaction, showTransaction,
showTransactionUnelided, showTransactionUnelided,
showTransactionUnelidedOneLineAmounts, showTransactionUnelidedOneLineAmounts,
showPostingLine, -- showPostingLine,
showPostingLines, showPostingLines,
-- * GenericSourcePos -- * GenericSourcePos
sourceFilePath, sourceFilePath,
Expand Down Expand Up @@ -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.
Expand Down
70 changes: 5 additions & 65 deletions hledger-lib/hledger_journal.m4.md
Expand Up @@ -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


Expand Down
40 changes: 8 additions & 32 deletions tests/journal/balance-assertions.test
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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

0 comments on commit 70b11ed

Please sign in to comment.