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