mirror of
https://github.com/simonmichael/hledger.git
synced 2024-11-08 07:09:28 +03:00
clarify that amount arithmetic does not handle multiple commodities
This commit is contained in:
parent
137cc8292e
commit
091ec4e51f
@ -131,7 +131,7 @@ sameSignNonZero is | null nzs = ([], 1)
|
||||
|
||||
-- | Convert all quantities of MixedAccount to a single commodity
|
||||
amountValue :: MixedAmount -> Double
|
||||
amountValue = quantity . convertMixedAmountTo unknown
|
||||
amountValue = quantity . convertMixedAmountToSimilarCommodity unknown
|
||||
|
||||
-- | Generate a tree of account names together with their balances.
|
||||
-- The balance of account is decremented by the balance of its subaccounts
|
||||
|
@ -38,11 +38,13 @@ price-discarding arithmetic which ignores and discards prices.
|
||||
|
||||
-}
|
||||
|
||||
-- XXX due for review/rewrite
|
||||
|
||||
module Hledger.Data.Amount (
|
||||
amounts,
|
||||
canonicaliseAmount,
|
||||
canonicaliseMixedAmount,
|
||||
convertMixedAmountTo,
|
||||
convertMixedAmountToSimilarCommodity,
|
||||
costOfAmount,
|
||||
costOfMixedAmount,
|
||||
divideAmount,
|
||||
@ -58,6 +60,7 @@ module Hledger.Data.Amount (
|
||||
punctuatethousands,
|
||||
setAmountPrecision,
|
||||
setMixedAmountPrecision,
|
||||
showAmountDebug,
|
||||
showMixedAmount,
|
||||
showMixedAmountDebug,
|
||||
showMixedAmountOrZero,
|
||||
@ -85,41 +88,42 @@ instance Num Amount where
|
||||
abs (Amount c q p) = Amount c (abs q) p
|
||||
signum (Amount c q p) = Amount c (signum q) p
|
||||
fromInteger i = Amount (comm "") (fromInteger i) Nothing
|
||||
(+) = amountop (+)
|
||||
(-) = amountop (-)
|
||||
(*) = amountop (*)
|
||||
(+) = similarAmountsOp (+)
|
||||
(-) = similarAmountsOp (-)
|
||||
(*) = similarAmountsOp (*)
|
||||
|
||||
instance Num MixedAmount where
|
||||
fromInteger i = Mixed [Amount (comm "") (fromInteger i) Nothing]
|
||||
negate (Mixed as) = Mixed $ map negateAmountPreservingPrice as
|
||||
where negateAmountPreservingPrice a = (-a){price=price a}
|
||||
(+) (Mixed as) (Mixed bs) = normaliseMixedAmount $ Mixed $ as ++ bs
|
||||
(*) = error' "programming error, mixed amounts do not support multiplication"
|
||||
abs = error' "programming error, mixed amounts do not support abs"
|
||||
signum = error' "programming error, mixed amounts do not support signum"
|
||||
|
||||
negateAmountPreservingPrice a = (-a){price=price a}
|
||||
-- | Apply a binary arithmetic operator to two amounts, after converting
|
||||
-- the first to the commodity (and display precision) of the second in a
|
||||
-- simplistic way. This should be used only for two amounts in the same
|
||||
-- commodity, since the conversion rate is assumed to be 1.
|
||||
-- NB preserving the second commodity is preferred since sum and other
|
||||
-- folds start with the no-commodity zero amount.
|
||||
similarAmountsOp :: (Double -> Double -> Double) -> Amount -> Amount -> Amount
|
||||
similarAmountsOp op a (Amount bc bq _) =
|
||||
Amount bc (quantity (convertAmountToSimilarCommodity bc a) `op` bq) Nothing
|
||||
|
||||
-- | Apply a binary arithmetic operator to two amounts, converting to the
|
||||
-- second one's commodity (and display precision), discarding any price
|
||||
-- information. (Using the second commodity is best since sum and other
|
||||
-- folds start with a no-commodity amount.)
|
||||
amountop :: (Double -> Double -> Double) -> Amount -> Amount -> Amount
|
||||
amountop op a@(Amount _ _ _) (Amount bc bq _) =
|
||||
Amount bc (quantity (convertAmountTo bc a) `op` bq) Nothing
|
||||
-- | Convert an amount to the specified commodity, assuming an exchange rate of 1.
|
||||
convertAmountToSimilarCommodity :: Commodity -> Amount -> Amount
|
||||
convertAmountToSimilarCommodity c (Amount _ q _) = Amount c q Nothing
|
||||
|
||||
-- | Convert an amount to the specified commodity using the appropriate
|
||||
-- exchange rate (which is currently always 1).
|
||||
convertAmountTo :: Commodity -> Amount -> Amount
|
||||
convertAmountTo c2 (Amount c1 q _) = Amount c2 (q * conversionRate c1 c2) Nothing
|
||||
|
||||
-- | Convert mixed amount to the specified commodity
|
||||
convertMixedAmountTo :: Commodity -> MixedAmount -> Amount
|
||||
convertMixedAmountTo c2 (Mixed ams) = Amount c2 total Nothing
|
||||
-- | Convert a mixed amount to the specified commodity, assuming an exchange rate of 1.
|
||||
convertMixedAmountToSimilarCommodity :: Commodity -> MixedAmount -> Amount
|
||||
convertMixedAmountToSimilarCommodity c (Mixed as) = Amount c total Nothing
|
||||
where
|
||||
total = sum . map (quantity . convertAmountTo c2) $ ams
|
||||
total = sum $ map (quantity . convertAmountToSimilarCommodity c) as
|
||||
|
||||
-- | Convert an amount to the commodity of its saved price, if any. Note
|
||||
-- that although the price is a MixedAmount, only its first Amount is used.
|
||||
-- | Convert an amount to the commodity of its saved price, if any. Notes:
|
||||
-- - price amounts must be MixedAmounts with exactly one component Amount (or there will be a runtime error)
|
||||
-- - price amounts should be positive, though this is not currently enforced
|
||||
costOfAmount :: Amount -> Amount
|
||||
costOfAmount a@(Amount _ q price)
|
||||
| isNothing price = a
|
||||
@ -397,7 +401,7 @@ amountopPreservingHighestPrecision :: (Double -> Double -> Double) -> Amount ->
|
||||
amountopPreservingHighestPrecision op a@(Amount ac@Commodity{precision=ap} _ _) (Amount bc@Commodity{precision=bp} bq _) =
|
||||
Amount c q Nothing
|
||||
where
|
||||
q = quantity (convertAmountTo bc a) `op` bq
|
||||
q = quantity (convertAmountToSimilarCommodity bc a) `op` bq
|
||||
c = if ap > bp then ac else bc
|
||||
--
|
||||
|
||||
@ -450,6 +454,10 @@ tests_Hledger_Data_Amount = TestList [
|
||||
(a1 + a3) `is` Amount (comm "$") 0 Nothing
|
||||
(a2 + a3) `is` Amount (comm "$") (-2.46) Nothing
|
||||
(a3 + a3) `is` Amount (comm "$") (-2.46) Nothing
|
||||
-- arithmetic with different commodities currently assumes conversion rate 1:
|
||||
let a4 = euros (-1.23)
|
||||
assertBool "" $ isZeroAmount (a1 + a4)
|
||||
|
||||
sum [a2,a3] `is` Amount (comm "$") (-2.46) Nothing
|
||||
sum [a3,a3] `is` Amount (comm "$") (-2.46) Nothing
|
||||
sum [a1,a2,a3,-a3] `is` Amount (comm "$") 0 Nothing
|
||||
|
Loading…
Reference in New Issue
Block a user