fix a regression balancing a transaction containing different prices
And try to clarify amount arithmetic a bit more. More to come I expect.
This commit is contained in:
parent
27e4fec943
commit
1de9cc1d80
@ -262,7 +262,7 @@ instance Show MixedAmount where show = showMixedAmount
|
|||||||
instance Num MixedAmount where
|
instance Num MixedAmount where
|
||||||
fromInteger i = Mixed [Amount (comm "") (fromInteger i) Nothing]
|
fromInteger i = Mixed [Amount (comm "") (fromInteger i) Nothing]
|
||||||
negate (Mixed as) = Mixed $ map negate as
|
negate (Mixed as) = Mixed $ map negate as
|
||||||
(+) (Mixed as) (Mixed bs) = normaliseMixedAmount $ Mixed $ as ++ bs
|
(+) (Mixed as) (Mixed bs) = normaliseMixedAmountPreservingPrice $ Mixed $ as ++ bs
|
||||||
(*) = error' "programming error, mixed amounts do not support multiplication"
|
(*) = error' "programming error, mixed amounts do not support multiplication"
|
||||||
abs = error' "programming error, mixed amounts do not support abs"
|
abs = error' "programming error, mixed amounts do not support abs"
|
||||||
signum = error' "programming error, mixed amounts do not support signum"
|
signum = error' "programming error, mixed amounts do not support signum"
|
||||||
@ -275,26 +275,36 @@ nullmixedamt = Mixed []
|
|||||||
missingamt :: MixedAmount
|
missingamt :: MixedAmount
|
||||||
missingamt = Mixed [Amount unknown{symbol="AUTO"} 0 Nothing]
|
missingamt = Mixed [Amount unknown{symbol="AUTO"} 0 Nothing]
|
||||||
|
|
||||||
-- | Simplify a mixed amount by removing redundancy in its component amounts,
|
-- | Simplify a mixed amount's component amounts: combine amounts with the
|
||||||
-- as follows:
|
-- same commodity and price, remove any zero amounts, and replace an empty
|
||||||
--
|
-- amount list with a single zero amount.
|
||||||
-- 1. combine amounts which have the same commodity, discarding all but the first's price.
|
normaliseMixedAmountPreservingPrice :: MixedAmount -> MixedAmount
|
||||||
--
|
normaliseMixedAmountPreservingPrice (Mixed as) = Mixed as''
|
||||||
-- 2. remove zero amounts
|
where
|
||||||
--
|
as'' = if null nonzeros then [nullamt] else nonzeros
|
||||||
-- 3. if there are no amounts at all, add a single zero amount
|
(_,nonzeros) = partition (\a -> isReallyZeroAmount a && Mixed [a] /= missingamt) as'
|
||||||
|
as' = map sumAmountsUsingFirstPrice $ group $ sort as
|
||||||
|
sort = sortBy (\a1 a2 -> compare (sym a1,price a1) (sym a2,price a2))
|
||||||
|
group = groupBy (\a1 a2 -> sym a1 == sym a2 && price a1 == price a2)
|
||||||
|
sym = symbol . commodity
|
||||||
|
|
||||||
|
-- | Simplify a mixed amount's component amounts: combine amounts with the
|
||||||
|
-- same commodity, remove any zero amounts, and replace an empty amount
|
||||||
|
-- list with a single zero amount. Unlike normaliseMixedAmountPreservingPrice,
|
||||||
|
-- this one discards all but the first price encountered in each commodity.
|
||||||
|
-- (This is used more for display than arithmetic, but seems a bit odd. XXX)
|
||||||
normaliseMixedAmount :: MixedAmount -> MixedAmount
|
normaliseMixedAmount :: MixedAmount -> MixedAmount
|
||||||
normaliseMixedAmount (Mixed as) = Mixed as''
|
normaliseMixedAmount (Mixed as) = Mixed as''
|
||||||
where
|
where
|
||||||
as'' = if null nonzeros then [nullamt] else nonzeros
|
as'' = if null nonzeros then [nullamt] else nonzeros
|
||||||
(_,nonzeros) = partition (\a -> isReallyZeroAmount a && Mixed [a] /= missingamt) as'
|
(_,nonzeros) = partition (\a -> isReallyZeroAmount a && Mixed [a] /= missingamt) as'
|
||||||
as' = map sumAmountsDiscardingAllButFirstPrice $ group $ sort as
|
as' = map sumAmountsUsingFirstPrice $ group $ sort as
|
||||||
sort = sortBy (\a1 a2 -> compare (sym a1) (sym a2))
|
sort = sortBy (\a1 a2 -> compare (sym a1) (sym a2))
|
||||||
group = groupBy (\a1 a2 -> sym a1 == sym a2)
|
group = groupBy (\a1 a2 -> sym a1 == sym a2)
|
||||||
sym = symbol . commodity
|
sym = symbol . commodity
|
||||||
|
|
||||||
sumAmountsDiscardingAllButFirstPrice [] = nullamt
|
sumAmountsUsingFirstPrice [] = nullamt
|
||||||
sumAmountsDiscardingAllButFirstPrice as = (sum as){price=price $ head as}
|
sumAmountsUsingFirstPrice as = (sum as){price=price $ head as}
|
||||||
|
|
||||||
-- | Get a mixed amount's component amounts.
|
-- | Get a mixed amount's component amounts.
|
||||||
amounts :: MixedAmount -> [Amount]
|
amounts :: MixedAmount -> [Amount]
|
||||||
|
|||||||
9
tests/balancing-with-prices.test
Normal file
9
tests/balancing-with-prices.test
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# this should balance
|
||||||
|
bin/hledger -f - print
|
||||||
|
<<<
|
||||||
|
2011/1/1
|
||||||
|
a 1h @ $10
|
||||||
|
b 1h @ $20
|
||||||
|
c $-30
|
||||||
|
>>>2 !/could not balance/
|
||||||
|
>>>= 0
|
||||||
Loading…
Reference in New Issue
Block a user