From ecca7f4e0cd108dc9e394d8e5f8a5619e9b73be2 Mon Sep 17 00:00:00 2001 From: Stephen Morgan Date: Sat, 16 Jan 2021 21:43:24 +1100 Subject: [PATCH] lib: Distinguish between an Amount having quantity (or rounded quantity 0), and having both quantity and totalprice 0 (or rounded to 0). --- hledger-lib/Hledger/Data/Amount.hs | 33 +++++++++++++++++++++++-- hledger-lib/Hledger/Data/Posting.hs | 2 +- hledger-lib/Hledger/Data/Transaction.hs | 6 ++--- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/hledger-lib/Hledger/Data/Amount.hs b/hledger-lib/Hledger/Data/Amount.hs index 91cf2748f..98c531348 100644 --- a/hledger-lib/Hledger/Data/Amount.hs +++ b/hledger-lib/Hledger/Data/Amount.hs @@ -63,6 +63,8 @@ module Hledger.Data.Amount ( amountCost, amountIsZero, amountLooksZero, + amountAndPriceIsZero, + amountAndPriceLooksZero, divideAmount, multiplyAmount, divideAmountAndPrice, @@ -114,6 +116,8 @@ module Hledger.Data.Amount ( isNegativeMixedAmount, mixedAmountIsZero, mixedAmountLooksZero, + mixedAmountAndPriceIsZero, + mixedAmountAndPriceLooksZero, mixedAmountTotalPriceToUnitPrice, -- ** rendering styleMixedAmount, @@ -324,10 +328,27 @@ amountRoundedQuantity Amount{aquantity=q, astyle=AmountStyle{asprecision=p}} = c amountLooksZero :: Amount -> Bool 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 ? amountIsZero :: Amount -> Bool 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. withPrecision :: Amount -> AmountPrecision -> Amount 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. canonicaliseAmount :: M.Map CommoditySymbol AmountStyle -> Amount -> Amount canonicaliseAmount styles a@Amount{acommodity=c, astyle=s} = a{astyle=s'} - where - s' = findWithDefault s c styles + where s' = M.findWithDefault s c styles ------------------------------------------------------------------------------- -- MixedAmount @@ -658,10 +678,19 @@ isNegativeMixedAmount m = mixedAmountLooksZero :: MixedAmount -> Bool 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 ? mixedAmountIsZero :: MixedAmount -> Bool 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 -- -- 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. diff --git a/hledger-lib/Hledger/Data/Posting.hs b/hledger-lib/Hledger/Data/Posting.hs index 7e2679ce8..26e6bfaf3 100644 --- a/hledger-lib/Hledger/Data/Posting.hs +++ b/hledger-lib/Hledger/Data/Posting.hs @@ -257,7 +257,7 @@ isPostingInDateSpan' PrimaryDate s = spanContainsDate s . postingDate isPostingInDateSpan' SecondaryDate s = spanContainsDate s . postingDate2 isEmptyPosting :: Posting -> Bool -isEmptyPosting = mixedAmountLooksZero . pamount +isEmptyPosting = mixedAmountAndPriceLooksZero . pamount -- AccountName stuff that depends on PostingType diff --git a/hledger-lib/Hledger/Data/Transaction.hs b/hledger-lib/Hledger/Data/Transaction.hs index 147d86841..336cbea8d 100644 --- a/hledger-lib/Hledger/Data/Transaction.hs +++ b/hledger-lib/Hledger/Data/Transaction.hs @@ -367,8 +367,8 @@ transactionCheckBalanced mstyles t = errs -- check for mixed signs, detecting nonzeros at display precision canonicalise = maybe id canonicaliseMixedAmount mstyles - signsOk ps = - case filter (not.mixedAmountLooksZero) $ map (canonicalise.mixedAmountCost.pamount) ps of + signsOk ps = + case filter (not.mixedAmountAndPriceLooksZero) $ map (canonicalise.mixedAmountCost.pamount) ps of nonzeros | length nonzeros >= 2 -> length (nubSort $ mapMaybe isNegativeMixedAmount nonzeros) > 1 _ -> True @@ -378,7 +378,7 @@ transactionCheckBalanced mstyles t = errs (rsum, bvsum) = (sumPostings rps, sumPostings bvps) (rsumcost, bvsumcost) = (mixedAmountCost rsum, mixedAmountCost bvsum) (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 errs = filter (not.null) [rmsg, bvmsg]