lib: (divide|multiply)[Mixed]AmountAndPrice (#928)
Divide/multiply amounts *and* their total price, if they have one. Helpful for keeping transactions balanced when transaction modifiers are multiplying amounts.
This commit is contained in:
		
							parent
							
								
									b053942e9b
								
							
						
					
					
						commit
						d7919003ae
					
				@ -59,6 +59,8 @@ module Hledger.Data.Amount (
 | 
				
			|||||||
  costOfAmount,
 | 
					  costOfAmount,
 | 
				
			||||||
  divideAmount,
 | 
					  divideAmount,
 | 
				
			||||||
  multiplyAmount,
 | 
					  multiplyAmount,
 | 
				
			||||||
 | 
					  divideAmountAndPrice,
 | 
				
			||||||
 | 
					  multiplyAmountAndPrice,
 | 
				
			||||||
  amountValue,
 | 
					  amountValue,
 | 
				
			||||||
  amountTotalPriceToUnitPrice,
 | 
					  amountTotalPriceToUnitPrice,
 | 
				
			||||||
  -- ** rendering
 | 
					  -- ** rendering
 | 
				
			||||||
@ -91,6 +93,8 @@ module Hledger.Data.Amount (
 | 
				
			|||||||
  costOfMixedAmount,
 | 
					  costOfMixedAmount,
 | 
				
			||||||
  divideMixedAmount,
 | 
					  divideMixedAmount,
 | 
				
			||||||
  multiplyMixedAmount,
 | 
					  multiplyMixedAmount,
 | 
				
			||||||
 | 
					  divideMixedAmountAndPrice,
 | 
				
			||||||
 | 
					  multiplyMixedAmountAndPrice,
 | 
				
			||||||
  averageMixedAmounts,
 | 
					  averageMixedAmounts,
 | 
				
			||||||
  isNegativeAmount,
 | 
					  isNegativeAmount,
 | 
				
			||||||
  isNegativeMixedAmount,
 | 
					  isNegativeMixedAmount,
 | 
				
			||||||
@ -214,7 +218,7 @@ costOfAmount a@Amount{aquantity=q, aprice=price} =
 | 
				
			|||||||
-- | Replace an amount's TotalPrice, if it has one, with an equivalent UnitPrice.
 | 
					-- | Replace an amount's TotalPrice, if it has one, with an equivalent UnitPrice.
 | 
				
			||||||
-- Has no effect on amounts without one.
 | 
					-- Has no effect on amounts without one.
 | 
				
			||||||
-- Also increases the unit price's display precision to show one extra decimal place,
 | 
					-- Also increases the unit price's display precision to show one extra decimal place,
 | 
				
			||||||
-- to help the unit-priced amounts to still balance. 
 | 
					-- to help keep transaction amounts balancing. 
 | 
				
			||||||
-- Does Decimal division, might be some rounding/irrational number issues.
 | 
					-- Does Decimal division, might be some rounding/irrational number issues.
 | 
				
			||||||
amountTotalPriceToUnitPrice :: Amount -> Amount
 | 
					amountTotalPriceToUnitPrice :: Amount -> Amount
 | 
				
			||||||
amountTotalPriceToUnitPrice 
 | 
					amountTotalPriceToUnitPrice 
 | 
				
			||||||
@ -230,6 +234,22 @@ divideAmount n a@Amount{aquantity=q} = a{aquantity=q/n}
 | 
				
			|||||||
multiplyAmount :: Quantity -> Amount -> Amount
 | 
					multiplyAmount :: Quantity -> Amount -> Amount
 | 
				
			||||||
multiplyAmount n a@Amount{aquantity=q} = a{aquantity=q*n}
 | 
					multiplyAmount n a@Amount{aquantity=q} = a{aquantity=q*n}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- | Divide an amount's quantity (and its total price, if it has one) by a constant.
 | 
				
			||||||
 | 
					-- The total price will be kept positive regardless of the multiplier's sign.
 | 
				
			||||||
 | 
					divideAmountAndPrice :: Quantity -> Amount -> Amount
 | 
				
			||||||
 | 
					divideAmountAndPrice n a@Amount{aquantity=q,aprice=p} = a{aquantity=q/n, aprice=f p}
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    f (TotalPrice a) = TotalPrice $ abs $ n `divideAmount` a
 | 
				
			||||||
 | 
					    f p = p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- | Multiply an amount's quantity (and its total price, if it has one) by a constant.
 | 
				
			||||||
 | 
					-- The total price will be kept positive regardless of the multiplier's sign.
 | 
				
			||||||
 | 
					multiplyAmountAndPrice :: Quantity -> Amount -> Amount
 | 
				
			||||||
 | 
					multiplyAmountAndPrice n a@Amount{aquantity=q,aprice=p} = a{aquantity=q*n, aprice=f p}
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    f (TotalPrice a) = TotalPrice $ abs $ n `multiplyAmount` a
 | 
				
			||||||
 | 
					    f p = p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Is this amount negative ? The price is ignored.
 | 
					-- | Is this amount negative ? The price is ignored.
 | 
				
			||||||
isNegativeAmount :: Amount -> Bool
 | 
					isNegativeAmount :: Amount -> Bool
 | 
				
			||||||
isNegativeAmount Amount{aquantity=q} = q < 0
 | 
					isNegativeAmount Amount{aquantity=q} = q < 0
 | 
				
			||||||
@ -553,6 +573,16 @@ divideMixedAmount n = mapMixedAmount (divideAmount n)
 | 
				
			|||||||
multiplyMixedAmount :: Quantity -> MixedAmount -> MixedAmount
 | 
					multiplyMixedAmount :: Quantity -> MixedAmount -> MixedAmount
 | 
				
			||||||
multiplyMixedAmount n = mapMixedAmount (multiplyAmount n)
 | 
					multiplyMixedAmount n = mapMixedAmount (multiplyAmount n)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- | Divide a mixed amount's quantities (and total prices, if any) by a constant.
 | 
				
			||||||
 | 
					-- The total prices will be kept positive regardless of the multiplier's sign.
 | 
				
			||||||
 | 
					divideMixedAmountAndPrice :: Quantity -> MixedAmount -> MixedAmount
 | 
				
			||||||
 | 
					divideMixedAmountAndPrice n = mapMixedAmount (divideAmountAndPrice n)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- | Multiply a mixed amount's quantities (and total prices, if any) by a constant.
 | 
				
			||||||
 | 
					-- The total prices will be kept positive regardless of the multiplier's sign.
 | 
				
			||||||
 | 
					multiplyMixedAmountAndPrice :: Quantity -> MixedAmount -> MixedAmount
 | 
				
			||||||
 | 
					multiplyMixedAmountAndPrice n = mapMixedAmount (multiplyAmountAndPrice n)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Calculate the average of some mixed amounts.
 | 
					-- | Calculate the average of some mixed amounts.
 | 
				
			||||||
averageMixedAmounts :: [MixedAmount] -> MixedAmount
 | 
					averageMixedAmounts :: [MixedAmount] -> MixedAmount
 | 
				
			||||||
averageMixedAmounts [] = 0
 | 
					averageMixedAmounts [] = 0
 | 
				
			||||||
 | 
				
			|||||||
@ -154,7 +154,7 @@ instance ToMarkup Quantity
 | 
				
			|||||||
   toMarkup = toMarkup . show
 | 
					   toMarkup = toMarkup . show
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | An amount's price (none, per unit, or total) in another commodity.
 | 
					-- | An amount's price (none, per unit, or total) in another commodity.
 | 
				
			||||||
-- Note the price should be a positive number, although this is not enforced.
 | 
					-- The price amount should always be positive.
 | 
				
			||||||
data Price = NoPrice | UnitPrice Amount | TotalPrice Amount 
 | 
					data Price = NoPrice | UnitPrice Amount | TotalPrice Amount 
 | 
				
			||||||
  deriving (Eq,Ord,Typeable,Data,Generic,Show)
 | 
					  deriving (Eq,Ord,Typeable,Data,Generic,Show)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user