diff --git a/hledger-lib/Hledger/Data/Amount.hs b/hledger-lib/Hledger/Data/Amount.hs index 8e8110293..a64876a1a 100644 --- a/hledger-lib/Hledger/Data/Amount.hs +++ b/hledger-lib/Hledger/Data/Amount.hs @@ -59,6 +59,8 @@ module Hledger.Data.Amount ( costOfAmount, divideAmount, multiplyAmount, + divideAmountAndPrice, + multiplyAmountAndPrice, amountValue, amountTotalPriceToUnitPrice, -- ** rendering @@ -91,6 +93,8 @@ module Hledger.Data.Amount ( costOfMixedAmount, divideMixedAmount, multiplyMixedAmount, + divideMixedAmountAndPrice, + multiplyMixedAmountAndPrice, averageMixedAmounts, isNegativeAmount, 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. -- Has no effect on amounts without one. -- 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. amountTotalPriceToUnitPrice :: Amount -> Amount amountTotalPriceToUnitPrice @@ -230,6 +234,22 @@ divideAmount n a@Amount{aquantity=q} = a{aquantity=q/n} multiplyAmount :: Quantity -> Amount -> Amount 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. isNegativeAmount :: Amount -> Bool isNegativeAmount Amount{aquantity=q} = q < 0 @@ -553,6 +573,16 @@ divideMixedAmount n = mapMixedAmount (divideAmount n) multiplyMixedAmount :: Quantity -> MixedAmount -> MixedAmount 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. averageMixedAmounts :: [MixedAmount] -> MixedAmount averageMixedAmounts [] = 0 diff --git a/hledger-lib/Hledger/Data/Types.hs b/hledger-lib/Hledger/Data/Types.hs index 4e1ac28d8..be2899255 100644 --- a/hledger-lib/Hledger/Data/Types.hs +++ b/hledger-lib/Hledger/Data/Types.hs @@ -154,7 +154,7 @@ instance ToMarkup Quantity toMarkup = toMarkup . show -- | 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 deriving (Eq,Ord,Typeable,Data,Generic,Show)