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