dev: Amount: aprice -> acost
Acked-by: Simon Michael <simon@joyful.com>
This commit is contained in:
parent
8102bd9c2b
commit
323f87b3e9
@ -206,7 +206,7 @@ main = do
|
|||||||
-- the final balance portion to move
|
-- the final balance portion to move
|
||||||
finalamt = dbgamt "final amt to move" $
|
finalamt = dbgamt "final amt to move" $
|
||||||
(balincommsinglecost + stilltomovenext)
|
(balincommsinglecost + stilltomovenext)
|
||||||
{aprice=aprice balincommsinglecost} -- + discards cost, need to restore it
|
{acost=acost balincommsinglecost} -- + discards cost, need to restore it
|
||||||
in (0, reverse $ (acct, mixed [finalamt]) : balscollected)
|
in (0, reverse $ (acct, mixed [finalamt]) : balscollected)
|
||||||
where
|
where
|
||||||
-- how much of the requested commodity is in this account
|
-- how much of the requested commodity is in this account
|
||||||
@ -228,7 +228,7 @@ main = do
|
|||||||
fromps = [
|
fromps = [
|
||||||
posting{paccount = a
|
posting{paccount = a
|
||||||
,pamount = mixedAmount $ negate b
|
,pamount = mixedAmount $ negate b
|
||||||
-- ,pbalanceassertion = Just nullassertion{baamount=precise b{aquantity=0, aprice=Nothing}}
|
-- ,pbalanceassertion = Just nullassertion{baamount=precise b{aquantity=0, acost=Nothing}}
|
||||||
}
|
}
|
||||||
|
|
||||||
| -- get the balances for each commodity and transaction price
|
| -- get the balances for each commodity and transaction price
|
||||||
|
|||||||
@ -279,7 +279,7 @@ instance Num Amount where
|
|||||||
-- | The empty simple amount - a zero with no commodity symbol or cost
|
-- | The empty simple amount - a zero with no commodity symbol or cost
|
||||||
-- and the default amount display style.
|
-- and the default amount display style.
|
||||||
nullamt :: Amount
|
nullamt :: Amount
|
||||||
nullamt = Amount{acommodity="", aquantity=0, aprice=Nothing, astyle=amountstyle}
|
nullamt = Amount{acommodity="", aquantity=0, acost=Nothing, astyle=amountstyle}
|
||||||
|
|
||||||
-- | A special amount used as a marker, meaning
|
-- | A special amount used as a marker, meaning
|
||||||
-- "no explicit amount provided here, infer it when needed".
|
-- "no explicit amount provided here, infer it when needed".
|
||||||
@ -296,8 +296,8 @@ usd n = nullamt{acommodity="$", aquantity=roundTo 2 n, astyle=amountstyle{asprec
|
|||||||
eur n = nullamt{acommodity="€", aquantity=roundTo 2 n, astyle=amountstyle{asprecision=Precision 2}}
|
eur n = nullamt{acommodity="€", aquantity=roundTo 2 n, astyle=amountstyle{asprecision=Precision 2}}
|
||||||
gbp n = nullamt{acommodity="£", aquantity=roundTo 2 n, astyle=amountstyle{asprecision=Precision 2}}
|
gbp n = nullamt{acommodity="£", aquantity=roundTo 2 n, astyle=amountstyle{asprecision=Precision 2}}
|
||||||
per n = nullamt{acommodity="%", aquantity=n, astyle=amountstyle{asprecision=Precision 1, ascommodityside=R, ascommodityspaced=True}}
|
per n = nullamt{acommodity="%", aquantity=n, astyle=amountstyle{asprecision=Precision 1, ascommodityside=R, ascommodityspaced=True}}
|
||||||
amt `at` costamt = amt{aprice=Just $ UnitCost costamt}
|
amt `at` costamt = amt{acost=Just $ UnitCost costamt}
|
||||||
amt @@ costamt = amt{aprice=Just $ TotalCost costamt}
|
amt @@ costamt = amt{acost=Just $ TotalCost costamt}
|
||||||
|
|
||||||
-- | Apply a binary arithmetic operator to two amounts, which should
|
-- | Apply a binary arithmetic operator to two amounts, which should
|
||||||
-- be in the same commodity if non-zero (warning, this is not checked).
|
-- be in the same commodity if non-zero (warning, this is not checked).
|
||||||
@ -317,7 +317,7 @@ similarAmountsOp op Amount{acommodity=_, aquantity=q1, astyle=AmountStyle{aspre
|
|||||||
-- | Convert an amount to the specified commodity, ignoring and discarding
|
-- | Convert an amount to the specified commodity, ignoring and discarding
|
||||||
-- any costs and assuming an exchange rate of 1.
|
-- any costs and assuming an exchange rate of 1.
|
||||||
amountWithCommodity :: CommoditySymbol -> Amount -> Amount
|
amountWithCommodity :: CommoditySymbol -> Amount -> Amount
|
||||||
amountWithCommodity c a = a{acommodity=c, aprice=Nothing}
|
amountWithCommodity c a = a{acommodity=c, acost=Nothing}
|
||||||
|
|
||||||
-- | Convert a amount to its "cost" or "selling price" in another commodity,
|
-- | Convert a amount to its "cost" or "selling price" in another commodity,
|
||||||
-- using its attached cost if it has one. Notes:
|
-- using its attached cost if it has one. Notes:
|
||||||
@ -328,7 +328,7 @@ amountWithCommodity c a = a{acommodity=c, aprice=Nothing}
|
|||||||
-- - cost amounts should be positive in the Journal
|
-- - cost amounts should be positive in the Journal
|
||||||
-- (though this is currently not enforced)
|
-- (though this is currently not enforced)
|
||||||
amountCost :: Amount -> Amount
|
amountCost :: Amount -> Amount
|
||||||
amountCost a@Amount{aquantity=q, aprice=mp} =
|
amountCost a@Amount{aquantity=q, acost=mp} =
|
||||||
case mp of
|
case mp of
|
||||||
Nothing -> a
|
Nothing -> a
|
||||||
Just (UnitCost p@Amount{aquantity=pq}) -> p{aquantity=pq * q}
|
Just (UnitCost p@Amount{aquantity=pq}) -> p{aquantity=pq * q}
|
||||||
@ -336,11 +336,11 @@ amountCost a@Amount{aquantity=q, aprice=mp} =
|
|||||||
|
|
||||||
-- | Strip all costs from an Amount
|
-- | Strip all costs from an Amount
|
||||||
amountStripCost :: Amount -> Amount
|
amountStripCost :: Amount -> Amount
|
||||||
amountStripCost a = a{aprice=Nothing}
|
amountStripCost a = a{acost=Nothing}
|
||||||
|
|
||||||
-- | Apply a function to an amount's quantity (and its total cost, if it has one).
|
-- | Apply a function to an amount's quantity (and its total cost, if it has one).
|
||||||
transformAmount :: (Quantity -> Quantity) -> Amount -> Amount
|
transformAmount :: (Quantity -> Quantity) -> Amount -> Amount
|
||||||
transformAmount f a@Amount{aquantity=q,aprice=p} = a{aquantity=f q, aprice=f' <$> p}
|
transformAmount f a@Amount{aquantity=q,acost=p} = a{aquantity=f q, acost=f' <$> p}
|
||||||
where
|
where
|
||||||
f' (TotalCost a1@Amount{aquantity=pq}) = TotalCost a1{aquantity = f pq}
|
f' (TotalCost a1@Amount{aquantity=pq}) = TotalCost a1{aquantity = f pq}
|
||||||
f' p' = p'
|
f' p' = p'
|
||||||
@ -371,7 +371,7 @@ amountRoundedQuantity Amount{aquantity=q, astyle=AmountStyle{asprecision=mp}} =
|
|||||||
|
|
||||||
-- | Apply a test to both an Amount and its total cost, if it has one.
|
-- | Apply a test to both an Amount and its total cost, if it has one.
|
||||||
testAmountAndTotalCost :: (Amount -> Bool) -> Amount -> Bool
|
testAmountAndTotalCost :: (Amount -> Bool) -> Amount -> Bool
|
||||||
testAmountAndTotalCost f amt = case aprice amt of
|
testAmountAndTotalCost f amt = case acost amt of
|
||||||
Just (TotalCost cost) -> f amt && f cost
|
Just (TotalCost cost) -> f amt && f cost
|
||||||
_ -> f amt
|
_ -> f amt
|
||||||
|
|
||||||
@ -514,8 +514,8 @@ instance HasAmounts Amount where
|
|||||||
-- except that costs' precision is never changed (costs are often recorded inexactly,
|
-- except that costs' precision is never changed (costs are often recorded inexactly,
|
||||||
-- so we don't want to imply greater precision than they were recorded with).
|
-- so we don't want to imply greater precision than they were recorded with).
|
||||||
-- If no style is found for an amount, it is left unchanged.
|
-- If no style is found for an amount, it is left unchanged.
|
||||||
styleAmounts styles a@Amount{aquantity=qty, acommodity=comm, astyle=oldstyle, aprice=mcost0} =
|
styleAmounts styles a@Amount{aquantity=qty, acommodity=comm, astyle=oldstyle, acost=mcost0} =
|
||||||
a{astyle=newstyle, aprice=mcost1}
|
a{astyle=newstyle, acost=mcost1}
|
||||||
where
|
where
|
||||||
newstyle = mknewstyle False qty oldstyle comm
|
newstyle = mknewstyle False qty oldstyle comm
|
||||||
|
|
||||||
@ -617,7 +617,7 @@ withDecimalPoint = flip setAmountDecimalPoint
|
|||||||
-- Amount rendering
|
-- Amount rendering
|
||||||
|
|
||||||
showAmountCostB :: Amount -> WideBuilder
|
showAmountCostB :: Amount -> WideBuilder
|
||||||
showAmountCostB amt = case aprice amt of
|
showAmountCostB amt = case acost amt of
|
||||||
Nothing -> mempty
|
Nothing -> mempty
|
||||||
Just (UnitCost pa) -> WideBuilder (TB.fromString " @ ") 3 <> showAmountB noColour{displayZeroCommodity=True} pa
|
Just (UnitCost pa) -> WideBuilder (TB.fromString " @ ") 3 <> showAmountB noColour{displayZeroCommodity=True} pa
|
||||||
Just (TotalCost pa) -> WideBuilder (TB.fromString " @@ ") 4 <> showAmountB noColour{displayZeroCommodity=True} (sign pa)
|
Just (TotalCost pa) -> WideBuilder (TB.fromString " @@ ") 4 <> showAmountB noColour{displayZeroCommodity=True} (sign pa)
|
||||||
@ -693,7 +693,7 @@ showAmountDebug :: Amount -> String
|
|||||||
showAmountDebug Amount{acommodity="AUTO"} = "(missing)"
|
showAmountDebug Amount{acommodity="AUTO"} = "(missing)"
|
||||||
showAmountDebug Amount{..} =
|
showAmountDebug Amount{..} =
|
||||||
"Amount {acommodity=" ++ show acommodity ++ ", aquantity=" ++ show aquantity
|
"Amount {acommodity=" ++ show acommodity ++ ", aquantity=" ++ show aquantity
|
||||||
++ ", aprice=" ++ showAmountCostDebug aprice ++ ", astyle=" ++ show astyle ++ "}"
|
++ ", acost=" ++ showAmountCostDebug acost ++ ", astyle=" ++ show astyle ++ "}"
|
||||||
|
|
||||||
-- | Get a Text Builder for the string representation of the number part of of an amount,
|
-- | Get a Text Builder for the string representation of the number part of of an amount,
|
||||||
-- using the display settings from its commodity. Also returns the width of the number.
|
-- using the display settings from its commodity. Also returns the width of the number.
|
||||||
@ -758,7 +758,7 @@ instance Num MixedAmount where
|
|||||||
|
|
||||||
-- | Calculate the key used to store an Amount within a MixedAmount.
|
-- | Calculate the key used to store an Amount within a MixedAmount.
|
||||||
amountKey :: Amount -> MixedAmountKey
|
amountKey :: Amount -> MixedAmountKey
|
||||||
amountKey amt@Amount{acommodity=c} = case aprice amt of
|
amountKey amt@Amount{acommodity=c} = case acost amt of
|
||||||
Nothing -> MixedAmountKeyNoCost c
|
Nothing -> MixedAmountKeyNoCost c
|
||||||
Just (TotalCost p) -> MixedAmountKeyTotalCost c (acommodity p)
|
Just (TotalCost p) -> MixedAmountKeyTotalCost c (acommodity p)
|
||||||
Just (UnitCost p) -> MixedAmountKeyUnitCost c (acommodity p) (aquantity p)
|
Just (UnitCost p) -> MixedAmountKeyUnitCost c (acommodity p) (aquantity p)
|
||||||
@ -942,12 +942,12 @@ unifyMixedAmount = foldM combine 0 . amounts
|
|||||||
-- cost to the result and discarding any other costs. Only used as a
|
-- cost to the result and discarding any other costs. Only used as a
|
||||||
-- rendering helper.
|
-- rendering helper.
|
||||||
sumSimilarAmountsUsingFirstPrice :: Amount -> Amount -> Amount
|
sumSimilarAmountsUsingFirstPrice :: Amount -> Amount -> Amount
|
||||||
sumSimilarAmountsUsingFirstPrice a b = (a + b){aprice=p}
|
sumSimilarAmountsUsingFirstPrice a b = (a + b){acost=p}
|
||||||
where
|
where
|
||||||
p = case (aprice a, aprice b) of
|
p = case (acost a, acost b) of
|
||||||
(Just (TotalCost ap), Just (TotalCost bp))
|
(Just (TotalCost ap), Just (TotalCost bp))
|
||||||
-> Just . TotalCost $ ap{aquantity = aquantity ap + aquantity bp }
|
-> Just . TotalCost $ ap{aquantity = aquantity ap + aquantity bp }
|
||||||
_ -> aprice a
|
_ -> acost a
|
||||||
|
|
||||||
-- -- | Sum same-commodity amounts. If there were different costs, set
|
-- -- | Sum same-commodity amounts. If there were different costs, set
|
||||||
-- -- the cost to a special marker indicating "various". Only used as a
|
-- -- the cost to a special marker indicating "various". Only used as a
|
||||||
@ -985,7 +985,7 @@ mapMixedAmountUnsafe f (Mixed ma) = Mixed $ M.map f ma -- Use M.map instead of
|
|||||||
mixedAmountCost :: MixedAmount -> MixedAmount
|
mixedAmountCost :: MixedAmount -> MixedAmount
|
||||||
mixedAmountCost (Mixed ma) =
|
mixedAmountCost (Mixed ma) =
|
||||||
foldl' (\m a -> maAddAmount m (amountCost a)) (Mixed noCosts) withCosts
|
foldl' (\m a -> maAddAmount m (amountCost a)) (Mixed noCosts) withCosts
|
||||||
where (noCosts, withCosts) = M.partition (isNothing . aprice) ma
|
where (noCosts, withCosts) = M.partition (isNothing . acost) ma
|
||||||
|
|
||||||
-- -- | MixedAmount derived Eq instance in Types.hs doesn't know that we
|
-- -- | MixedAmount derived Eq instance in Types.hs doesn't know that we
|
||||||
-- -- want $0 = EUR0 = 0. Yet we don't want to drag all this code over there.
|
-- -- want $0 = EUR0 = 0. Yet we don't want to drag all this code over there.
|
||||||
@ -1227,8 +1227,8 @@ mixedAmountSetPrecisionMax p = mapMixedAmountUnsafe (amountSetPrecisionMax p)
|
|||||||
-- | Remove all costs from a MixedAmount.
|
-- | Remove all costs from a MixedAmount.
|
||||||
mixedAmountStripPrices :: MixedAmount -> MixedAmount
|
mixedAmountStripPrices :: MixedAmount -> MixedAmount
|
||||||
mixedAmountStripPrices (Mixed ma) =
|
mixedAmountStripPrices (Mixed ma) =
|
||||||
foldl' (\m a -> maAddAmount m a{aprice=Nothing}) (Mixed noPrices) withPrices
|
foldl' (\m a -> maAddAmount m a{acost=Nothing}) (Mixed noPrices) withPrices
|
||||||
where (noPrices, withPrices) = M.partition (isNothing . aprice) ma
|
where (noPrices, withPrices) = M.partition (isNothing . acost) ma
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@ -1239,9 +1239,9 @@ tests_Amount = testGroup "Amount" [
|
|||||||
|
|
||||||
testCase "amountCost" $ do
|
testCase "amountCost" $ do
|
||||||
amountCost (eur 1) @?= eur 1
|
amountCost (eur 1) @?= eur 1
|
||||||
amountCost (eur 2){aprice=Just $ UnitCost $ usd 2} @?= usd 4
|
amountCost (eur 2){acost=Just $ UnitCost $ usd 2} @?= usd 4
|
||||||
amountCost (eur 1){aprice=Just $ TotalCost $ usd 2} @?= usd 2
|
amountCost (eur 1){acost=Just $ TotalCost $ usd 2} @?= usd 2
|
||||||
amountCost (eur (-1)){aprice=Just $ TotalCost $ usd (-2)} @?= usd (-2)
|
amountCost (eur (-1)){acost=Just $ TotalCost $ usd (-2)} @?= usd (-2)
|
||||||
|
|
||||||
,testCase "amountLooksZero" $ do
|
,testCase "amountLooksZero" $ do
|
||||||
assertBool "" $ amountLooksZero nullamt
|
assertBool "" $ amountLooksZero nullamt
|
||||||
@ -1249,7 +1249,7 @@ tests_Amount = testGroup "Amount" [
|
|||||||
|
|
||||||
,testCase "negating amounts" $ do
|
,testCase "negating amounts" $ do
|
||||||
negate (usd 1) @?= (usd 1){aquantity= -1}
|
negate (usd 1) @?= (usd 1){aquantity= -1}
|
||||||
let b = (usd 1){aprice=Just $ UnitCost $ eur 2} in negate b @?= b{aquantity= -1}
|
let b = (usd 1){acost=Just $ UnitCost $ eur 2} in negate b @?= b{aquantity= -1}
|
||||||
|
|
||||||
,testCase "adding amounts without costs" $ do
|
,testCase "adding amounts without costs" $ do
|
||||||
(usd 1.23 + usd (-1.23)) @?= usd 0
|
(usd 1.23 + usd (-1.23)) @?= usd 0
|
||||||
|
|||||||
@ -340,7 +340,7 @@ costInferrerFor t pt = maybe id infercost inferFromAndTo
|
|||||||
inferFromAndTo = case sumamounts of
|
inferFromAndTo = case sumamounts of
|
||||||
[a,b] | noprices, oppositesigns -> asum $ map orderIfMatches pcommodities
|
[a,b] | noprices, oppositesigns -> asum $ map orderIfMatches pcommodities
|
||||||
where
|
where
|
||||||
noprices = all (isNothing . aprice) sumamounts
|
noprices = all (isNothing . acost) sumamounts
|
||||||
oppositesigns = signum (aquantity a) /= signum (aquantity b)
|
oppositesigns = signum (aquantity a) /= signum (aquantity b)
|
||||||
orderIfMatches x | x == acommodity a = Just (a,b)
|
orderIfMatches x | x == acommodity a = Just (a,b)
|
||||||
| x == acommodity b = Just (b,a)
|
| x == acommodity b = Just (b,a)
|
||||||
@ -352,7 +352,7 @@ costInferrerFor t pt = maybe id infercost inferFromAndTo
|
|||||||
-- then set its cost based on the ratio between fromamount and toamount.
|
-- then set its cost based on the ratio between fromamount and toamount.
|
||||||
infercost (fromamount, toamount) p
|
infercost (fromamount, toamount) p
|
||||||
| [a] <- amounts (pamount p), ptype p == pt, acommodity a == acommodity fromamount
|
| [a] <- amounts (pamount p), ptype p == pt, acommodity a == acommodity fromamount
|
||||||
= p{ pamount = mixedAmount a{aprice=Just conversionprice}
|
= p{ pamount = mixedAmount a{acost=Just conversionprice}
|
||||||
& dbg9With (lbl "inferred cost".showMixedAmountOneLine)
|
& dbg9With (lbl "inferred cost".showMixedAmountOneLine)
|
||||||
, poriginal = Just $ originalPosting p }
|
, poriginal = Just $ originalPosting p }
|
||||||
| otherwise = p
|
| otherwise = p
|
||||||
|
|||||||
@ -970,7 +970,7 @@ journalMarkRedundantCosts j = do
|
|||||||
|
|
||||||
-- -- | Get this amount's commodity and any commodities referenced in its price.
|
-- -- | Get this amount's commodity and any commodities referenced in its price.
|
||||||
-- amountCommodities :: Amount -> [CommoditySymbol]
|
-- amountCommodities :: Amount -> [CommoditySymbol]
|
||||||
-- amountCommodities Amount{acommodity=c,aprice=p} =
|
-- amountCommodities Amount{acommodity=c,acost=p} =
|
||||||
-- case p of Nothing -> [c]
|
-- case p of Nothing -> [c]
|
||||||
-- Just (UnitCost ma) -> c:(concatMap amountCommodities $ amounts ma)
|
-- Just (UnitCost ma) -> c:(concatMap amountCommodities $ amounts ma)
|
||||||
-- Just (TotalCost ma) -> c:(concatMap amountCommodities $ amounts ma)
|
-- Just (TotalCost ma) -> c:(concatMap amountCommodities $ amounts ma)
|
||||||
@ -983,7 +983,7 @@ journalMarkRedundantCosts j = do
|
|||||||
-- * posting amounts in transactions (in parse order)
|
-- * posting amounts in transactions (in parse order)
|
||||||
-- * the amount in the final default commodity (D) directive
|
-- * the amount in the final default commodity (D) directive
|
||||||
--
|
--
|
||||||
-- Transaction price amounts (posting amounts' aprice field) are not included.
|
-- Transaction price amounts (posting amounts' acost field) are not included.
|
||||||
--
|
--
|
||||||
journalStyleInfluencingAmounts :: Journal -> [Amount]
|
journalStyleInfluencingAmounts :: Journal -> [Amount]
|
||||||
journalStyleInfluencingAmounts j =
|
journalStyleInfluencingAmounts j =
|
||||||
@ -1023,7 +1023,7 @@ journalStyleInfluencingAmounts j =
|
|||||||
-- * posting amounts in transactions (in parse order)
|
-- * posting amounts in transactions (in parse order)
|
||||||
--
|
--
|
||||||
-- Transaction price amounts, which may be embedded in posting amounts
|
-- Transaction price amounts, which may be embedded in posting amounts
|
||||||
-- (the aprice field), are left intact but not traversed/processed.
|
-- (the acost field), are left intact but not traversed/processed.
|
||||||
--
|
--
|
||||||
-- traverseJournalAmounts :: Applicative f => (Amount -> f Amount) -> Journal -> f Journal
|
-- traverseJournalAmounts :: Applicative f => (Amount -> f Amount) -> Journal -> f Journal
|
||||||
-- traverseJournalAmounts f j =
|
-- traverseJournalAmounts f j =
|
||||||
|
|||||||
@ -386,7 +386,7 @@ type BeancountAmount = Amount
|
|||||||
-- in a way that Beancount can read: forces the commodity symbol to the right,
|
-- in a way that Beancount can read: forces the commodity symbol to the right,
|
||||||
-- converts a few currency symbols to names, capitalises all letters.
|
-- converts a few currency symbols to names, capitalises all letters.
|
||||||
amountToBeancount :: Amount -> BeancountAmount
|
amountToBeancount :: Amount -> BeancountAmount
|
||||||
amountToBeancount a@Amount{acommodity=c,astyle=s,aprice=mp} = a{acommodity=c', astyle=s', aprice=mp'}
|
amountToBeancount a@Amount{acommodity=c,astyle=s,acost=mp} = a{acommodity=c', astyle=s', acost=mp'}
|
||||||
-- https://beancount.github.io/docs/beancount_language_syntax.html#commodities-currencies
|
-- https://beancount.github.io/docs/beancount_language_syntax.html#commodities-currencies
|
||||||
where
|
where
|
||||||
c' = T.toUpper $
|
c' = T.toUpper $
|
||||||
@ -543,7 +543,7 @@ postingToCost ToCost p
|
|||||||
| "_conversion-matched" `elem` map fst (ptags p) && nocosts = Nothing
|
| "_conversion-matched" `elem` map fst (ptags p) && nocosts = Nothing
|
||||||
| otherwise = Just $ postingTransformAmount mixedAmountCost p
|
| otherwise = Just $ postingTransformAmount mixedAmountCost p
|
||||||
where
|
where
|
||||||
nocosts = (not . any (isJust . aprice) . amountsRaw) $ pamount p
|
nocosts = (not . any (isJust . acost) . amountsRaw) $ pamount p
|
||||||
|
|
||||||
-- | Generate inferred equity postings from a 'Posting' using transaction prices.
|
-- | Generate inferred equity postings from a 'Posting' using transaction prices.
|
||||||
-- Make sure not to generate equity postings when there are already matched
|
-- Make sure not to generate equity postings when there are already matched
|
||||||
@ -556,7 +556,7 @@ postingAddInferredEquityPostings verbosetags equityAcct p
|
|||||||
taggedPosting
|
taggedPosting
|
||||||
| null priceAmounts = p
|
| null priceAmounts = p
|
||||||
| otherwise = p{ ptags = ("_price-matched","") : ptags p }
|
| otherwise = p{ ptags = ("_price-matched","") : ptags p }
|
||||||
conversionPostings amt = case aprice amt of
|
conversionPostings amt = case acost amt of
|
||||||
Nothing -> []
|
Nothing -> []
|
||||||
Just _ -> [ cp{ paccount = accountPrefix <> amtCommodity
|
Just _ -> [ cp{ paccount = accountPrefix <> amtCommodity
|
||||||
, pamount = mixedAmount . negate $ amountStripCost amt
|
, pamount = mixedAmount . negate $ amountStripCost amt
|
||||||
@ -581,7 +581,7 @@ postingAddInferredEquityPostings verbosetags equityAcct p
|
|||||||
-- Take the commodity of an amount and collapse consecutive spaces to a single space
|
-- Take the commodity of an amount and collapse consecutive spaces to a single space
|
||||||
commodity = T.unwords . filter (not . T.null) . T.words . acommodity
|
commodity = T.unwords . filter (not . T.null) . T.words . acommodity
|
||||||
|
|
||||||
priceAmounts = filter (isJust . aprice) . amountsRaw $ pamount p
|
priceAmounts = filter (isJust . acost) . amountsRaw $ pamount p
|
||||||
|
|
||||||
-- | Make a market price equivalent to this posting's amount's unit
|
-- | Make a market price equivalent to this posting's amount's unit
|
||||||
-- price, if any.
|
-- price, if any.
|
||||||
|
|||||||
@ -386,7 +386,7 @@ transactionInferCostsFromEquity dryrun acctTypes t = first (annotateErrorWithTra
|
|||||||
-- with the matching amount which must be present in another non-conversion posting.
|
-- with the matching amount which must be present in another non-conversion posting.
|
||||||
costfulPostingIfMatchesBothAmounts :: Amount -> Amount -> Posting -> Maybe Posting
|
costfulPostingIfMatchesBothAmounts :: Amount -> Amount -> Posting -> Maybe Posting
|
||||||
costfulPostingIfMatchesBothAmounts a1 a2 costfulp = do
|
costfulPostingIfMatchesBothAmounts a1 a2 costfulp = do
|
||||||
a@Amount{aprice=Just _} <- postingSingleAmount costfulp
|
a@Amount{acost=Just _} <- postingSingleAmount costfulp
|
||||||
if
|
if
|
||||||
| dbgamtmatch 1 a1 a (amountsMatch (-a1) a) && dbgcostmatch 2 a2 a (amountsMatch a2 (amountCost a)) -> Just costfulp
|
| dbgamtmatch 1 a1 a (amountsMatch (-a1) a) && dbgcostmatch 2 a2 a (amountsMatch a2 (amountCost a)) -> Just costfulp
|
||||||
| dbgamtmatch 2 a2 a (amountsMatch (-a2) a) && dbgcostmatch 1 a1 a (amountsMatch a1 (amountCost a)) -> Just costfulp
|
| dbgamtmatch 2 a2 a (amountsMatch (-a2) a) && dbgcostmatch 1 a1 a (amountsMatch a1 (amountCost a)) -> Just costfulp
|
||||||
@ -400,7 +400,7 @@ transactionInferCostsFromEquity dryrun acctTypes t = first (annotateErrorWithTra
|
|||||||
addCostIfMatchesOneAmount :: Amount -> Amount -> Posting -> Maybe (Posting, Amount)
|
addCostIfMatchesOneAmount :: Amount -> Amount -> Posting -> Maybe (Posting, Amount)
|
||||||
addCostIfMatchesOneAmount a1 a2 p = do
|
addCostIfMatchesOneAmount a1 a2 p = do
|
||||||
a <- postingSingleAmount p
|
a <- postingSingleAmount p
|
||||||
let newp cost = p{pamount = mixedAmount a{aprice = Just $ TotalCost cost}}
|
let newp cost = p{pamount = mixedAmount a{acost = Just $ TotalCost cost}}
|
||||||
if
|
if
|
||||||
| amountsMatch (-a1) a -> Just (newp a2, a2)
|
| amountsMatch (-a1) a -> Just (newp a2, a2)
|
||||||
| amountsMatch (-a2) a -> Just (newp a1, a1)
|
| amountsMatch (-a2) a -> Just (newp a1, a1)
|
||||||
@ -408,8 +408,8 @@ transactionInferCostsFromEquity dryrun acctTypes t = first (annotateErrorWithTra
|
|||||||
|
|
||||||
-- Get the single-commodity costless amount from a conversion posting, or raise an error.
|
-- Get the single-commodity costless amount from a conversion posting, or raise an error.
|
||||||
conversionPostingAmountNoCost p = case postingSingleAmount p of
|
conversionPostingAmountNoCost p = case postingSingleAmount p of
|
||||||
Just a@Amount{aprice=Nothing} -> Right a
|
Just a@Amount{acost=Nothing} -> Right a
|
||||||
Just Amount{aprice=Just _} -> Left $ annotateWithPostings [p] "Conversion postings must not have a cost:"
|
Just Amount{acost=Just _} -> Left $ annotateWithPostings [p] "Conversion postings must not have a cost:"
|
||||||
Nothing -> Left $ annotateWithPostings [p] "Conversion postings must have a single-commodity amount:"
|
Nothing -> Left $ annotateWithPostings [p] "Conversion postings must have a single-commodity amount:"
|
||||||
|
|
||||||
-- Do these amounts look the same when compared at the first's display precision ?
|
-- Do these amounts look the same when compared at the first's display precision ?
|
||||||
@ -456,7 +456,7 @@ partitionAndCheckConversionPostings check acctTypes =
|
|||||||
| check = Left "Conversion postings must occur in adjacent pairs"
|
| check = Left "Conversion postings must occur in adjacent pairs"
|
||||||
| otherwise = Right ((cs, (ps, np:os)), Nothing)
|
| otherwise = Right ((cs, (ps, np:os)), Nothing)
|
||||||
isConversion p = M.lookup (paccount p) acctTypes == Just Conversion
|
isConversion p = M.lookup (paccount p) acctTypes == Just Conversion
|
||||||
hasCost p = isJust $ aprice =<< postingSingleAmount p
|
hasCost p = isJust $ acost =<< postingSingleAmount p
|
||||||
|
|
||||||
-- | Get a posting's amount if it is single-commodity.
|
-- | Get a posting's amount if it is single-commodity.
|
||||||
postingSingleAmount :: Posting -> Maybe Amount
|
postingSingleAmount :: Posting -> Maybe Amount
|
||||||
|
|||||||
@ -140,7 +140,7 @@ tmPostingRuleToFunction verbosetags styles query querytxt tmpr =
|
|||||||
-- TODO multipliers with commodity symbols are not yet a documented feature.
|
-- TODO multipliers with commodity symbols are not yet a documented feature.
|
||||||
-- For now: in addition to multiplying the quantity, it also replaces the
|
-- For now: in addition to multiplying the quantity, it also replaces the
|
||||||
-- matched amount's commodity, display style, and price with those of the posting rule.
|
-- matched amount's commodity, display style, and price with those of the posting rule.
|
||||||
c -> mapMixedAmount (\a -> a{acommodity = c, astyle = astyle pramount, aprice = aprice pramount}) as
|
c -> mapMixedAmount (\a -> a{acommodity = c, astyle = astyle pramount, acost = acost pramount}) as
|
||||||
|
|
||||||
postingRuleMultiplier :: TMPostingRule -> Maybe Quantity
|
postingRuleMultiplier :: TMPostingRule -> Maybe Quantity
|
||||||
postingRuleMultiplier tmpr = case amountsRaw . pamount $ tmprPosting tmpr of
|
postingRuleMultiplier tmpr = case amountsRaw . pamount $ tmprPosting tmpr of
|
||||||
|
|||||||
@ -312,7 +312,7 @@ data Amount = Amount {
|
|||||||
acommodity :: !CommoditySymbol, -- commodity symbol, or special value "AUTO"
|
acommodity :: !CommoditySymbol, -- commodity symbol, or special value "AUTO"
|
||||||
aquantity :: !Quantity, -- numeric quantity, or zero in case of "AUTO"
|
aquantity :: !Quantity, -- numeric quantity, or zero in case of "AUTO"
|
||||||
astyle :: !AmountStyle,
|
astyle :: !AmountStyle,
|
||||||
aprice :: !(Maybe AmountCost) -- ^ the (fixed, transaction-specific) cost in another commodity of this amount, if any
|
acost :: !(Maybe AmountCost) -- ^ the (fixed, transaction-specific) cost in another commodity of this amount, if any
|
||||||
} deriving (Eq,Ord,Generic,Show)
|
} deriving (Eq,Ord,Generic,Show)
|
||||||
|
|
||||||
-- | Types with this class have one or more amounts,
|
-- | Types with this class have one or more amounts,
|
||||||
@ -351,7 +351,7 @@ maCompare (Mixed a) (Mixed b) = go (M.toList a) (M.toList b)
|
|||||||
go [] ((_,y):ys) = compareQuantities Nothing (Just y) <> go [] ys
|
go [] ((_,y):ys) = compareQuantities Nothing (Just y) <> go [] ys
|
||||||
go [] [] = EQ
|
go [] [] = EQ
|
||||||
compareQuantities = comparing (maybe 0 aquantity) <> comparing (maybe 0 totalcost)
|
compareQuantities = comparing (maybe 0 aquantity) <> comparing (maybe 0 totalcost)
|
||||||
totalcost x = case aprice x of
|
totalcost x = case acost x of
|
||||||
Just (TotalCost p) -> aquantity p
|
Just (TotalCost p) -> aquantity p
|
||||||
_ -> 0
|
_ -> 0
|
||||||
|
|
||||||
|
|||||||
@ -112,7 +112,7 @@ priceDirectiveToMarketPrice PriceDirective{..} =
|
|||||||
-- The price's display precision will be set to show all significant
|
-- The price's display precision will be set to show all significant
|
||||||
-- decimal digits; or if they seem to be infinite, defaultPrecisionLimit.
|
-- decimal digits; or if they seem to be infinite, defaultPrecisionLimit.
|
||||||
amountPriceDirectiveFromCost :: Day -> Amount -> Maybe PriceDirective
|
amountPriceDirectiveFromCost :: Day -> Amount -> Maybe PriceDirective
|
||||||
amountPriceDirectiveFromCost d amt@Amount{acommodity=fromcomm, aquantity=n} = case aprice amt of
|
amountPriceDirectiveFromCost d amt@Amount{acommodity=fromcomm, aquantity=n} = case acost amt of
|
||||||
Just (UnitCost u) -> Just $ pd{pdamount=u}
|
Just (UnitCost u) -> Just $ pd{pdamount=u}
|
||||||
Just (TotalCost t) | n /= 0 -> Just $ pd{pdamount=u}
|
Just (TotalCost t) | n /= 0 -> Just $ pd{pdamount=u}
|
||||||
where u = amountSetFullPrecisionOr Nothing $ divideAmount n t
|
where u = amountSetFullPrecisionOr Nothing $ divideAmount n t
|
||||||
|
|||||||
@ -774,7 +774,7 @@ amountp' mult =
|
|||||||
<*> toPermutationWithDefault Nothing (Just <$> lotcostp <* spaces)
|
<*> toPermutationWithDefault Nothing (Just <$> lotcostp <* spaces)
|
||||||
<*> toPermutationWithDefault Nothing (Just <$> lotdatep <* spaces)
|
<*> toPermutationWithDefault Nothing (Just <$> lotdatep <* spaces)
|
||||||
<*> toPermutationWithDefault Nothing (Just <$> lotnotep <* spaces)
|
<*> toPermutationWithDefault Nothing (Just <$> lotnotep <* spaces)
|
||||||
pure $ amt { aprice = mcost }
|
pure $ amt { acost = mcost }
|
||||||
|
|
||||||
-- An amount with optional cost, but no cost basis.
|
-- An amount with optional cost, but no cost basis.
|
||||||
amountnobasisp :: JournalParser m Amount
|
amountnobasisp :: JournalParser m Amount
|
||||||
@ -785,7 +785,7 @@ amountnobasisp =
|
|||||||
amt <- simpleamountp False
|
amt <- simpleamountp False
|
||||||
spaces
|
spaces
|
||||||
mprice <- optional $ costp amt <* spaces
|
mprice <- optional $ costp amt <* spaces
|
||||||
pure $ amt { aprice = mprice }
|
pure $ amt { acost = mprice }
|
||||||
|
|
||||||
-- An amount with no cost or cost basis.
|
-- An amount with no cost or cost basis.
|
||||||
-- A flag indicates whether we are parsing a multiplier amount;
|
-- A flag indicates whether we are parsing a multiplier amount;
|
||||||
@ -815,7 +815,7 @@ simpleamountp mult =
|
|||||||
let numRegion = (offBeforeNum, offAfterNum)
|
let numRegion = (offBeforeNum, offAfterNum)
|
||||||
(q,prec,mdec,mgrps) <- lift $ interpretNumber numRegion suggestedStyle ambiguousRawNum mExponent
|
(q,prec,mdec,mgrps) <- lift $ interpretNumber numRegion suggestedStyle ambiguousRawNum mExponent
|
||||||
let s = amountstyle{ascommodityside=L, ascommodityspaced=commodityspaced, asprecision=prec, asdecimalmark=mdec, asdigitgroups=mgrps}
|
let s = amountstyle{ascommodityside=L, ascommodityspaced=commodityspaced, asprecision=prec, asdecimalmark=mdec, asdigitgroups=mgrps}
|
||||||
return nullamt{acommodity=c, aquantity=sign (sign2 q), astyle=s, aprice=Nothing}
|
return nullamt{acommodity=c, aquantity=sign (sign2 q), astyle=s, acost=Nothing}
|
||||||
|
|
||||||
-- An amount with commodity symbol on the right or no commodity symbol.
|
-- An amount with commodity symbol on the right or no commodity symbol.
|
||||||
-- A no-symbol amount will have the default commodity applied to it
|
-- A no-symbol amount will have the default commodity applied to it
|
||||||
@ -837,7 +837,7 @@ simpleamountp mult =
|
|||||||
let msuggestedStyle = mdecmarkStyle <|> mcommodityStyle
|
let msuggestedStyle = mdecmarkStyle <|> mcommodityStyle
|
||||||
(q,prec,mdec,mgrps) <- lift $ interpretNumber numRegion msuggestedStyle ambiguousRawNum mExponent
|
(q,prec,mdec,mgrps) <- lift $ interpretNumber numRegion msuggestedStyle ambiguousRawNum mExponent
|
||||||
let s = amountstyle{ascommodityside=R, ascommodityspaced=commodityspaced, asprecision=prec, asdecimalmark=mdec, asdigitgroups=mgrps}
|
let s = amountstyle{ascommodityside=R, ascommodityspaced=commodityspaced, asprecision=prec, asdecimalmark=mdec, asdigitgroups=mgrps}
|
||||||
return nullamt{acommodity=c, aquantity=sign q, astyle=s, aprice=Nothing}
|
return nullamt{acommodity=c, aquantity=sign q, astyle=s, acost=Nothing}
|
||||||
-- no symbol amount
|
-- no symbol amount
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
-- look for a number style to use when parsing, based on
|
-- look for a number style to use when parsing, based on
|
||||||
@ -854,7 +854,7 @@ simpleamountp mult =
|
|||||||
let (c,s) = case (mult, defcs) of
|
let (c,s) = case (mult, defcs) of
|
||||||
(False, Just (defc,defs)) -> (defc, defs{asprecision=max (asprecision defs) prec})
|
(False, Just (defc,defs)) -> (defc, defs{asprecision=max (asprecision defs) prec})
|
||||||
_ -> ("", amountstyle{asprecision=prec, asdecimalmark=mdec, asdigitgroups=mgrps})
|
_ -> ("", amountstyle{asprecision=prec, asdecimalmark=mdec, asdigitgroups=mgrps})
|
||||||
return nullamt{acommodity=c, aquantity=sign q, astyle=s, aprice=Nothing}
|
return nullamt{acommodity=c, aquantity=sign q, astyle=s, acost=Nothing}
|
||||||
|
|
||||||
-- For reducing code duplication. Doesn't parse anything. Has the type
|
-- For reducing code duplication. Doesn't parse anything. Has the type
|
||||||
-- of a parser only in order to throw parse errors (for convenience).
|
-- of a parser only in order to throw parse errors (for convenience).
|
||||||
@ -1586,7 +1586,7 @@ tests_Common = testGroup "Common" [
|
|||||||
acommodity="$"
|
acommodity="$"
|
||||||
,aquantity=10 -- need to test internal precision with roundTo ? I think not
|
,aquantity=10 -- need to test internal precision with roundTo ? I think not
|
||||||
,astyle=amountstyle{asprecision=Precision 0, asdecimalmark=Nothing}
|
,astyle=amountstyle{asprecision=Precision 0, asdecimalmark=Nothing}
|
||||||
,aprice=Just $ UnitCost $
|
,acost=Just $ UnitCost $
|
||||||
nullamt{
|
nullamt{
|
||||||
acommodity="€"
|
acommodity="€"
|
||||||
,aquantity=0.5
|
,aquantity=0.5
|
||||||
@ -1598,7 +1598,7 @@ tests_Common = testGroup "Common" [
|
|||||||
acommodity="$"
|
acommodity="$"
|
||||||
,aquantity=10
|
,aquantity=10
|
||||||
,astyle=amountstyle{asprecision=Precision 0, asdecimalmark=Nothing}
|
,astyle=amountstyle{asprecision=Precision 0, asdecimalmark=Nothing}
|
||||||
,aprice=Just $ TotalCost $
|
,acost=Just $ TotalCost $
|
||||||
nullamt{
|
nullamt{
|
||||||
acommodity="€"
|
acommodity="€"
|
||||||
,aquantity=5
|
,aquantity=5
|
||||||
|
|||||||
@ -617,7 +617,7 @@ balanceReportTableAsText ReportOpts{..} =
|
|||||||
tests_MultiBalanceReport = testGroup "MultiBalanceReport" [
|
tests_MultiBalanceReport = testGroup "MultiBalanceReport" [
|
||||||
|
|
||||||
let
|
let
|
||||||
amt0 = Amount {acommodity="$", aquantity=0, aprice=Nothing,
|
amt0 = Amount {acommodity="$", aquantity=0, acost=Nothing,
|
||||||
astyle=AmountStyle {ascommodityside = L, ascommodityspaced = False, asdigitgroups = Nothing,
|
astyle=AmountStyle {ascommodityside = L, ascommodityspaced = False, asdigitgroups = Nothing,
|
||||||
asdecimalmark = Just '.', asprecision = Precision 2, asrounding = NoRounding}}
|
asdecimalmark = Just '.', asprecision = Precision 2, asrounding = NoRounding}}
|
||||||
(rspec,journal) `gives` r = do
|
(rspec,journal) `gives` r = do
|
||||||
|
|||||||
@ -154,7 +154,7 @@ close copts@CliOpts{rawopts_=rawopts, reportspec_=rspec0} j = do
|
|||||||
| mode_ == Assert =
|
| mode_ == Assert =
|
||||||
[ posting{
|
[ posting{
|
||||||
paccount = a
|
paccount = a
|
||||||
,pamount = mixedAmount $ precise b{aquantity=0, aprice=Nothing}
|
,pamount = mixedAmount $ precise b{aquantity=0, acost=Nothing}
|
||||||
-- after each commodity's last posting, assert 0 balance (#1035)
|
-- after each commodity's last posting, assert 0 balance (#1035)
|
||||||
-- balance assertion amounts are unpriced (#824)
|
-- balance assertion amounts are unpriced (#824)
|
||||||
,pbalanceassertion =
|
,pbalanceassertion =
|
||||||
@ -179,7 +179,7 @@ close copts@CliOpts{rawopts_=rawopts, reportspec_=rspec0} j = do
|
|||||||
-- balance assertion amounts are unpriced (#824)
|
-- balance assertion amounts are unpriced (#824)
|
||||||
,pbalanceassertion =
|
,pbalanceassertion =
|
||||||
if islast
|
if islast
|
||||||
then Just nullassertion{baamount=precise b{aquantity=0, aprice=Nothing}}
|
then Just nullassertion{baamount=precise b{aquantity=0, acost=Nothing}}
|
||||||
else Nothing
|
else Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ close copts@CliOpts{rawopts_=rawopts, reportspec_=rspec0} j = do
|
|||||||
,pamount = mixedAmount $ precise b
|
,pamount = mixedAmount $ precise b
|
||||||
,pbalanceassertion =
|
,pbalanceassertion =
|
||||||
case mcommoditysum of
|
case mcommoditysum of
|
||||||
Just s -> Just nullassertion{baamount=precise s{aprice=Nothing}}
|
Just s -> Just nullassertion{baamount=precise s{acost=Nothing}}
|
||||||
Nothing -> Nothing
|
Nothing -> Nothing
|
||||||
}
|
}
|
||||||
: [posting{paccount=openacct, pamount=mixedAmount . precise $ negate b} | interleaved]
|
: [posting{paccount=openacct, pamount=mixedAmount . precise $ negate b} | interleaved]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user