assert only a single commodity, like Ledger (fixes #195)
This change means you can make assertions on a multi-commodity account balance (asserting one commodity at a time). On the flip side, you can no longer assert the complete balance of an account (new unexpected commodities will not be detected.) We might restore that ability later, using the == syntax.
This commit is contained in:
		
							parent
							
								
									0c3148ac7b
								
							
						
					
					
						commit
						8ae303f685
					
				| @ -74,6 +74,7 @@ module Hledger.Data.Amount ( | |||||||
|   missingmixedamt, |   missingmixedamt, | ||||||
|   mixed, |   mixed, | ||||||
|   amounts, |   amounts, | ||||||
|  |   filterMixedAmount, | ||||||
|   normaliseMixedAmountPreservingFirstPrice, |   normaliseMixedAmountPreservingFirstPrice, | ||||||
|   normaliseMixedAmountPreservingPrices, |   normaliseMixedAmountPreservingPrices, | ||||||
|   -- ** arithmetic |   -- ** arithmetic | ||||||
| @ -419,6 +420,10 @@ sumAmountsUsingFirstPrice as = (sum as){aprice=aprice $ head as} | |||||||
| amounts :: MixedAmount -> [Amount] | amounts :: MixedAmount -> [Amount] | ||||||
| amounts (Mixed as) = as | amounts (Mixed as) = as | ||||||
| 
 | 
 | ||||||
|  | -- | Filter a mixed amount's component amounts by a predicate. | ||||||
|  | filterMixedAmount :: (Amount -> Bool) -> MixedAmount -> MixedAmount | ||||||
|  | filterMixedAmount p (Mixed as) = Mixed $ filter p as | ||||||
|  | 
 | ||||||
| -- | Convert a mixed amount's component amounts to the commodity of their | -- | Convert a mixed amount's component amounts to the commodity of their | ||||||
| -- assigned price, if any. | -- assigned price, if any. | ||||||
| costOfMixedAmount :: MixedAmount -> MixedAmount | costOfMixedAmount :: MixedAmount -> MixedAmount | ||||||
|  | |||||||
| @ -59,6 +59,7 @@ import Data.List | |||||||
| -- import Data.Map (findWithDefault) | -- import Data.Map (findWithDefault) | ||||||
| import Data.Maybe | import Data.Maybe | ||||||
| import Data.Ord | import Data.Ord | ||||||
|  | import Safe (headMay) | ||||||
| import Data.Time.Calendar | import Data.Time.Calendar | ||||||
| import Data.Time.LocalTime | import Data.Time.LocalTime | ||||||
| import Data.Tree | import Data.Tree | ||||||
| @ -427,28 +428,29 @@ checkBalanceAssertionsForAccount ps | |||||||
| -- If it does, return the new balance, otherwise add an error to the | -- If it does, return the new balance, otherwise add an error to the | ||||||
| -- error list. Intended to be called from a fold. | -- error list. Intended to be called from a fold. | ||||||
| checkBalanceAssertion :: ([String],MixedAmount) -> [Posting] -> ([String],MixedAmount) | checkBalanceAssertion :: ([String],MixedAmount) -> [Posting] -> ([String],MixedAmount) | ||||||
| checkBalanceAssertion (errs,bal) ps | checkBalanceAssertion (errs,startbal) ps | ||||||
|   | null ps = (errs,bal) |   | null ps = (errs,startbal) | ||||||
|   | isNothing assertion = (errs,bal) |   | isNothing assertion = (errs,startbal) | ||||||
|   | |   | | ||||||
|     -- bal' /= assertedbal  -- MixedAmount's Eq instance currently gets confused by different precisions |     -- bal' /= assertedbal  -- MixedAmount's Eq instance currently gets confused by different precisions | ||||||
|     not $ isReallyZeroMixedAmount (bal' - assertedbal) |     not $ isReallyZeroMixedAmount (bal - assertedbal) = (errs++[err], bal) | ||||||
|     -- or, compare only the balance of that commodity, like Ledger |   | otherwise = (errs,bal) | ||||||
|     -- not $ isReallyZeroMixedAmount (filterCommodity () bal' - assertedbal) |  | ||||||
|       = (errs++[err], bal') |  | ||||||
|   | otherwise = (errs,bal') |  | ||||||
|   where |   where | ||||||
|     p = last ps |     p = last ps | ||||||
|     assertion = pbalanceassertion p |     assertion = pbalanceassertion p | ||||||
|     Just assertedbal = assertion |     Just assertedbal = dbg2 "assertedbal" assertion | ||||||
|     bal' = sum $ [bal] ++ map pamount ps |     fullbal = dbg2 "fullbal" $ sum $ [dbg2 "startbal" startbal] ++ map pamount ps | ||||||
|     err = printf "Balance assertion failed for account %s on %s\n%sAfter posting:\n   %s\nexpected balance is %s, actual balance was %s." |     singlebal = dbg2 "singlebal" $ | ||||||
|  |                 let c = maybe "" acommodity $ headMay $ amounts assertedbal | ||||||
|  |                 in filterMixedAmount (\a -> acommodity a == c) fullbal | ||||||
|  |     bal = singlebal -- check single-commodity balance like Ledger; maybe add == FULLBAL later | ||||||
|  |     err = printf "Balance assertion failed for account %s on %s\n%sAfter posting:\n   %s\nexpected commodity balance is %s, actual balance was %s." | ||||||
|                  (paccount p) |                  (paccount p) | ||||||
|                  (show $ postingDate p) |                  (show $ postingDate p) | ||||||
|                  (maybe "" (("In transaction:\n"++).show) $ ptransaction p) |                  (maybe "" (("In transaction:\n"++).show) $ ptransaction p) | ||||||
|                  (show p) |                  (show p) | ||||||
|                  (showMixedAmount assertedbal) |                  (showMixedAmount assertedbal) | ||||||
|                  (showMixedAmount bal') |                  (showMixedAmount singlebal) | ||||||
| 
 | 
 | ||||||
| -- Given a sequence of postings to a single account, split it into | -- Given a sequence of postings to a single account, split it into | ||||||
| -- sub-sequences consisting of ordinary postings followed by a single | -- sub-sequences consisting of ordinary postings followed by a single | ||||||
|  | |||||||
| @ -89,7 +89,19 @@ hledgerdev -f - stats | |||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| 
 | 
 | ||||||
| # 6. what should happen here ? Currently, | # 6. assertions currently check only a single commodity's balance, like Ledger | ||||||
|  | hledgerdev -f - stats | ||||||
|  | <<< | ||||||
|  | 1/2 | ||||||
|  |   (a)  A1 | ||||||
|  |   (a)  B1 = A1 | ||||||
|  |   (a)  0  = A1 | ||||||
|  |   (a)  C0 = D0 | ||||||
|  | >>> /Transactions/ | ||||||
|  | >>>2 | ||||||
|  | >>>=0 | ||||||
|  | 
 | ||||||
|  | # 7. what should happen here ? Currently, | ||||||
| # in a, 3.4 EUR @@ $5.6 and -3.4 EUR cancel out (wrong ?) | # in a, 3.4 EUR @@ $5.6 and -3.4 EUR cancel out (wrong ?) | ||||||
| # in b,  | # in b,  | ||||||
| #  | #  | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user