lib: Distinguish between an Amount having quantity (or rounded quantity 0), and having both quantity and totalprice 0 (or rounded to 0).
This commit is contained in:
parent
81b778a389
commit
ecca7f4e0c
@ -63,6 +63,8 @@ module Hledger.Data.Amount (
|
|||||||
amountCost,
|
amountCost,
|
||||||
amountIsZero,
|
amountIsZero,
|
||||||
amountLooksZero,
|
amountLooksZero,
|
||||||
|
amountAndPriceIsZero,
|
||||||
|
amountAndPriceLooksZero,
|
||||||
divideAmount,
|
divideAmount,
|
||||||
multiplyAmount,
|
multiplyAmount,
|
||||||
divideAmountAndPrice,
|
divideAmountAndPrice,
|
||||||
@ -114,6 +116,8 @@ module Hledger.Data.Amount (
|
|||||||
isNegativeMixedAmount,
|
isNegativeMixedAmount,
|
||||||
mixedAmountIsZero,
|
mixedAmountIsZero,
|
||||||
mixedAmountLooksZero,
|
mixedAmountLooksZero,
|
||||||
|
mixedAmountAndPriceIsZero,
|
||||||
|
mixedAmountAndPriceLooksZero,
|
||||||
mixedAmountTotalPriceToUnitPrice,
|
mixedAmountTotalPriceToUnitPrice,
|
||||||
-- ** rendering
|
-- ** rendering
|
||||||
styleMixedAmount,
|
styleMixedAmount,
|
||||||
@ -324,10 +328,27 @@ amountRoundedQuantity Amount{aquantity=q, astyle=AmountStyle{asprecision=p}} = c
|
|||||||
amountLooksZero :: Amount -> Bool
|
amountLooksZero :: Amount -> Bool
|
||||||
amountLooksZero = (0==) . amountRoundedQuantity
|
amountLooksZero = (0==) . amountRoundedQuantity
|
||||||
|
|
||||||
|
-- | Does mixed amount and its price appear to be zero when rendered with its
|
||||||
|
-- display precision ?
|
||||||
|
amountAndPriceLooksZero :: Amount -> Bool
|
||||||
|
amountAndPriceLooksZero amt = amountLooksZero amt && priceLooksZero
|
||||||
|
where
|
||||||
|
priceLooksZero = case aprice amt of
|
||||||
|
Just (TotalPrice p) -> amountLooksZero p
|
||||||
|
_ -> True
|
||||||
|
|
||||||
-- | Is this amount exactly zero, ignoring its display precision ?
|
-- | Is this amount exactly zero, ignoring its display precision ?
|
||||||
amountIsZero :: Amount -> Bool
|
amountIsZero :: Amount -> Bool
|
||||||
amountIsZero Amount{aquantity=q} = q == 0
|
amountIsZero Amount{aquantity=q} = q == 0
|
||||||
|
|
||||||
|
-- | Are this amount and its price exactly zero, ignoring its display precision ?
|
||||||
|
amountAndPriceIsZero :: Amount -> Bool
|
||||||
|
amountAndPriceIsZero amt@Amount{aquantity=q} = q == 0 && priceIsZero
|
||||||
|
where
|
||||||
|
priceIsZero = case aprice amt of
|
||||||
|
Just (TotalPrice p) -> amountIsZero p
|
||||||
|
_ -> True
|
||||||
|
|
||||||
-- | Set an amount's display precision, flipped.
|
-- | Set an amount's display precision, flipped.
|
||||||
withPrecision :: Amount -> AmountPrecision -> Amount
|
withPrecision :: Amount -> AmountPrecision -> Amount
|
||||||
withPrecision = flip amountSetPrecision
|
withPrecision = flip amountSetPrecision
|
||||||
@ -496,8 +517,7 @@ applyDigitGroupStyle (Just (DigitGroups c (g:gs))) l s = addseps (g:|gs) (toInte
|
|||||||
-- | Canonicalise an amount's display style using the provided commodity style map.
|
-- | Canonicalise an amount's display style using the provided commodity style map.
|
||||||
canonicaliseAmount :: M.Map CommoditySymbol AmountStyle -> Amount -> Amount
|
canonicaliseAmount :: M.Map CommoditySymbol AmountStyle -> Amount -> Amount
|
||||||
canonicaliseAmount styles a@Amount{acommodity=c, astyle=s} = a{astyle=s'}
|
canonicaliseAmount styles a@Amount{acommodity=c, astyle=s} = a{astyle=s'}
|
||||||
where
|
where s' = M.findWithDefault s c styles
|
||||||
s' = findWithDefault s c styles
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- MixedAmount
|
-- MixedAmount
|
||||||
@ -658,10 +678,19 @@ isNegativeMixedAmount m =
|
|||||||
mixedAmountLooksZero :: MixedAmount -> Bool
|
mixedAmountLooksZero :: MixedAmount -> Bool
|
||||||
mixedAmountLooksZero = all amountLooksZero . amounts . normaliseMixedAmountSquashPricesForDisplay
|
mixedAmountLooksZero = all amountLooksZero . amounts . normaliseMixedAmountSquashPricesForDisplay
|
||||||
|
|
||||||
|
-- | Does this mixed amount and its price appear to be zero when rendered with its
|
||||||
|
-- display precision ?
|
||||||
|
mixedAmountAndPriceLooksZero :: MixedAmount -> Bool
|
||||||
|
mixedAmountAndPriceLooksZero = all amountAndPriceLooksZero . amounts . normaliseMixedAmountSquashPricesForDisplay
|
||||||
|
|
||||||
-- | Is this mixed amount exactly zero, ignoring display precisions ?
|
-- | Is this mixed amount exactly zero, ignoring display precisions ?
|
||||||
mixedAmountIsZero :: MixedAmount -> Bool
|
mixedAmountIsZero :: MixedAmount -> Bool
|
||||||
mixedAmountIsZero = all amountIsZero . amounts . normaliseMixedAmountSquashPricesForDisplay
|
mixedAmountIsZero = all amountIsZero . amounts . normaliseMixedAmountSquashPricesForDisplay
|
||||||
|
|
||||||
|
-- | Is this mixed amount exactly zero, ignoring display precisions ?
|
||||||
|
mixedAmountAndPriceIsZero :: MixedAmount -> Bool
|
||||||
|
mixedAmountAndPriceIsZero = all amountAndPriceIsZero . amounts . normaliseMixedAmountSquashPricesForDisplay
|
||||||
|
|
||||||
-- -- | MixedAmount derived Eq instance in Types.hs doesn't know that we
|
-- -- | MixedAmount derived Eq instance in Types.hs doesn't know that we
|
||||||
-- -- want $0 = EUR0 = 0. Yet we don't want to drag all this code over there.
|
-- -- want $0 = EUR0 = 0. Yet we don't want to drag all this code over there.
|
||||||
-- -- For now, use this when cross-commodity zero equality is important.
|
-- -- For now, use this when cross-commodity zero equality is important.
|
||||||
|
|||||||
@ -257,7 +257,7 @@ isPostingInDateSpan' PrimaryDate s = spanContainsDate s . postingDate
|
|||||||
isPostingInDateSpan' SecondaryDate s = spanContainsDate s . postingDate2
|
isPostingInDateSpan' SecondaryDate s = spanContainsDate s . postingDate2
|
||||||
|
|
||||||
isEmptyPosting :: Posting -> Bool
|
isEmptyPosting :: Posting -> Bool
|
||||||
isEmptyPosting = mixedAmountLooksZero . pamount
|
isEmptyPosting = mixedAmountAndPriceLooksZero . pamount
|
||||||
|
|
||||||
-- AccountName stuff that depends on PostingType
|
-- AccountName stuff that depends on PostingType
|
||||||
|
|
||||||
|
|||||||
@ -368,7 +368,7 @@ transactionCheckBalanced mstyles t = errs
|
|||||||
-- check for mixed signs, detecting nonzeros at display precision
|
-- check for mixed signs, detecting nonzeros at display precision
|
||||||
canonicalise = maybe id canonicaliseMixedAmount mstyles
|
canonicalise = maybe id canonicaliseMixedAmount mstyles
|
||||||
signsOk ps =
|
signsOk ps =
|
||||||
case filter (not.mixedAmountLooksZero) $ map (canonicalise.mixedAmountCost.pamount) ps of
|
case filter (not.mixedAmountAndPriceLooksZero) $ map (canonicalise.mixedAmountCost.pamount) ps of
|
||||||
nonzeros | length nonzeros >= 2
|
nonzeros | length nonzeros >= 2
|
||||||
-> length (nubSort $ mapMaybe isNegativeMixedAmount nonzeros) > 1
|
-> length (nubSort $ mapMaybe isNegativeMixedAmount nonzeros) > 1
|
||||||
_ -> True
|
_ -> True
|
||||||
@ -378,7 +378,7 @@ transactionCheckBalanced mstyles t = errs
|
|||||||
(rsum, bvsum) = (sumPostings rps, sumPostings bvps)
|
(rsum, bvsum) = (sumPostings rps, sumPostings bvps)
|
||||||
(rsumcost, bvsumcost) = (mixedAmountCost rsum, mixedAmountCost bvsum)
|
(rsumcost, bvsumcost) = (mixedAmountCost rsum, mixedAmountCost bvsum)
|
||||||
(rsumdisplay, bvsumdisplay) = (canonicalise rsumcost, canonicalise bvsumcost)
|
(rsumdisplay, bvsumdisplay) = (canonicalise rsumcost, canonicalise bvsumcost)
|
||||||
(rsumok, bvsumok) = (mixedAmountLooksZero rsumdisplay, mixedAmountLooksZero bvsumdisplay)
|
(rsumok, bvsumok) = (mixedAmountAndPriceLooksZero rsumdisplay, mixedAmountAndPriceLooksZero bvsumdisplay)
|
||||||
|
|
||||||
-- generate error messages, showing amounts with their original precision
|
-- generate error messages, showing amounts with their original precision
|
||||||
errs = filter (not.null) [rmsg, bvmsg]
|
errs = filter (not.null) [rmsg, bvmsg]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user