1+ {-# LANGUAGE NamedFieldPuns #-}
12{-|
23
34A 'Transaction' represents a movement of some commodity(ies) between two
@@ -83,6 +84,7 @@ import Hledger.Data.Valuation
8384import Text.Tabular
8485import Text.Tabular.AsciiWide
8586import Control.Applicative ((<|>) )
87+ import Text.Printf (printf )
8688
8789sourceFilePath :: GenericSourcePos -> FilePath
8890sourceFilePath = \ case
@@ -378,10 +380,41 @@ transactionCheckBalanced mglobalstyles t = errs
378380 -- of decimal places specified by its display style, from either the
379381 -- provided global display styles, or local styles inferred from just
380382 -- this transaction.
383+
384+ -- Which local styles (& thence, precisions) exactly should we
385+ -- infer from this transaction ? Since amounts are going to be
386+ -- converted to cost, we may end up with the commodity of
387+ -- transaction prices, so we'll need to pick a style for those too.
388+ --
389+ -- Option 1: also infer styles from the price amounts, which normally isn't done.
390+ -- canonicalise = maybe id canonicaliseMixedAmount (mglobalstyles <|> mtxnstyles)
391+ -- where
392+ -- mtxnstyles = dbg0 "transactionCheckBalanced mtxnstyles" $
393+ -- either (const Nothing) Just $ -- shouldn't get any error here, but if so just.. carry on, comparing uncanonicalised amounts XXX
394+ -- commodityStylesFromAmounts $ concatMap postingAllAmounts $ rps ++ bvps
395+ -- where
396+ -- -- | Get all the individual Amounts from a posting's MixedAmount,
397+ -- -- and all their price Amounts as well.
398+ -- postingAllAmounts :: Posting -> [Amount]
399+ -- postingAllAmounts p = catMaybes $ concat [[Just a, priceamount a] | a <- amounts $ pamount p]
400+ -- where
401+ -- priceamount Amount{aprice} =
402+ -- case aprice of
403+ -- Just (UnitPrice a) -> Just a
404+ -- Just (TotalPrice a) -> Just a
405+ -- Nothing -> Nothing
406+ --
407+ -- Option 2, for amounts converted to cost, where the new commodity appears only in prices,
408+ -- use the precision of their original commodity (by using mixedAmountCostPreservingPrecision).
409+ (tocost,costlabel) = case mglobalstyles of
410+ Just _ -> (mixedAmountCost," " ) -- --balancing=styled
411+ Nothing -> (mixedAmountCostPreservingPrecision," withorigprecision" ) -- --balancing=exact
381412 canonicalise = maybe id canonicaliseMixedAmount (mglobalstyles <|> mtxnstyles)
382413 where
383- mtxnstyles = either (const Nothing ) Just $ -- shouldn't get any error here, but if so just.. carry on, comparing uncanonicalised amounts XXX
384- commodityStylesFromAmounts $ concatMap (amounts. pamount) $ rps ++ bvps
414+ mtxnstyles = dbg9 " transactionCheckBalanced mtxnstyles" $
415+ either (const Nothing ) Just $ -- shouldn't get an error here, but if so just don't canonicalise
416+ commodityStylesFromAmounts $ concatMap (amounts. pamount) $ rps ++ bvps
417+
385418
386419 -- check for mixed signs, detecting nonzeros at display precision
387420 signsOk ps =
@@ -392,22 +425,28 @@ transactionCheckBalanced mglobalstyles t = errs
392425 (rsignsok, bvsignsok) = (signsOk rps, signsOk bvps)
393426
394427 -- check for zero sum, at display precision
395- (rsum, bvsum) = (sumPostings rps, sumPostings bvps)
396- (rsumcost, bvsumcost) = (mixedAmountCost rsum, mixedAmountCost bvsum)
397- (rsumdisplay, bvsumdisplay ) = (canonicalise rsumcost, canonicalise bvsumcost)
398- (rsumok, bvsumok) = (mixedAmountLooksZero rsumdisplay , mixedAmountLooksZero bvsumdisplay )
428+ (rsum, bvsum) = (dbg9 " transactionCheckBalanced rsum " $ sumPostings rps, sumPostings bvps)
429+ (rsumcost, bvsumcost) = (dbg9 ( " transactionCheckBalanced rsumcost " ++ costlabel) $ tocost rsum, tocost bvsum)
430+ (rsumstyled, bvsumstyled ) = (dbg9 " transactionCheckBalanced rsumstyled " $ canonicalise rsumcost, canonicalise bvsumcost)
431+ (rsumok, bvsumok) = (mixedAmountLooksZero rsumstyled , mixedAmountLooksZero bvsumstyled )
399432
400- -- generate error messages, showing amounts with their original precision
433+ -- generate error messages
401434 errs = filter (not . null ) [rmsg, bvmsg]
402435 where
403436 rmsg
404437 | not rsignsok = " real postings all have the same sign"
405- | not rsumok = " real postings' sum should be 0 but is: " ++ showMixedAmount (mixedAmountSetFullPrecision rsumcost)
438+ | not rsumok = printf " real postings' sum should be %s but is %s (rounded from %s) " rsumexpected rsumactual rsumfull
406439 | otherwise = " "
407440 bvmsg
408441 | not bvsignsok = " balanced virtual postings all have the same sign"
409- | not bvsumok = " balanced virtual postings' sum should be 0 but is: " ++ showMixedAmount (mixedAmountSetFullPrecision bvsumcost)
442+ | not bvsumok = printf " balanced virtual postings' sum should be %s but is %s (rounded from %s) " bvsumexpected bvsumactual bvsumfull
410443 | otherwise = " "
444+ rsumexpected = showMixedAmountWithZeroCommodity $ mapMixedAmount (\ a -> a{aquantity= 0 }) rsumstyled
445+ rsumactual = showMixedAmount rsumstyled
446+ rsumfull = showMixedAmount (mixedAmountSetFullPrecision rsumcost)
447+ bvsumexpected = showMixedAmountWithZeroCommodity $ mapMixedAmount (\ a -> a{aquantity= 0 }) rsumstyled
448+ bvsumactual = showMixedAmount bvsumstyled
449+ bvsumfull = showMixedAmount (mixedAmountSetFullPrecision bvsumcost)
411450
412451-- | Legacy form of transactionCheckBalanced.
413452isTransactionBalanced :: Maybe (M. Map CommoditySymbol AmountStyle ) -> Transaction -> Bool
0 commit comments