mirror of
https://github.com/simonmichael/hledger.git
synced 2024-09-20 02:37:12 +03:00
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
|
||||
fromInteger i = Mixed [Amount (comm "") (fromInteger i) Nothing]
|
||||
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"
|
||||
abs = error' "programming error, mixed amounts do not support abs"
|
||||
signum = error' "programming error, mixed amounts do not support signum"
|
||||
@ -275,26 +275,36 @@ nullmixedamt = Mixed []
|
||||
missingamt :: MixedAmount
|
||||
missingamt = Mixed [Amount unknown{symbol="AUTO"} 0 Nothing]
|
||||
|
||||
-- | Simplify a mixed amount by removing redundancy in its component amounts,
|
||||
-- as follows:
|
||||
--
|
||||
-- 1. combine amounts which have the same commodity, discarding all but the first's price.
|
||||
--
|
||||
-- 2. remove zero amounts
|
||||
--
|
||||
-- 3. if there are no amounts at all, add a single zero amount
|
||||
-- | Simplify a mixed amount's component amounts: combine amounts with the
|
||||
-- same commodity and price, remove any zero amounts, and replace an empty
|
||||
-- amount list with a single zero amount.
|
||||
normaliseMixedAmountPreservingPrice :: MixedAmount -> MixedAmount
|
||||
normaliseMixedAmountPreservingPrice (Mixed as) = Mixed as''
|
||||
where
|
||||
as'' = if null nonzeros then [nullamt] else nonzeros
|
||||
(_,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 (Mixed as) = Mixed as''
|
||||
where
|
||||
as'' = if null nonzeros then [nullamt] else nonzeros
|
||||
(_,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))
|
||||
group = groupBy (\a1 a2 -> sym a1 == sym a2)
|
||||
sym = symbol . commodity
|
||||
|
||||
sumAmountsDiscardingAllButFirstPrice [] = nullamt
|
||||
sumAmountsDiscardingAllButFirstPrice as = (sum as){price=price $ head as}
|
||||
sumAmountsUsingFirstPrice [] = nullamt
|
||||
sumAmountsUsingFirstPrice as = (sum as){price=price $ head as}
|
||||
|
||||
-- | Get a mixed amount's component amounts.
|
||||
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