lib: Make sure automatic postings generated from postings with more than one commodity match on commodity symbol (#1582).

This commit is contained in:
Stephen Morgan 2021-06-28 21:51:25 +10:00
parent fc62cebd10
commit 8ab29f84b3
2 changed files with 32 additions and 11 deletions

View File

@ -13,16 +13,17 @@ module Hledger.Data.TransactionModifier (
where
import Control.Applicative ((<|>))
import Data.Maybe
import Data.Maybe (catMaybes)
import qualified Data.Text as T
import Data.Time.Calendar
import Data.Time.Calendar (Day)
import Hledger.Data.Types
import Hledger.Data.Dates
import Hledger.Data.Amount
import Hledger.Data.Transaction
import Hledger.Query
import Hledger.Data.Transaction (txnTieKnot)
import Hledger.Query (Query, filterQuery, matchesAmount, matchesPosting,
parseQuery, queryIsSym, simplifyQuery)
import Hledger.Data.Posting (commentJoin, commentAddTag)
import Hledger.Utils
import Hledger.Utils (dbg6, wrap)
-- $setup
-- >>> :set -XOverloadedStrings
@ -57,8 +58,8 @@ modifyTransactions d tmods ts = do
-- Currently the only kind of modification possible is adding automated
-- postings when certain other postings are present.
--
-- >>> t = nulltransaction{tpostings=["ping" `post` usd 1]}
-- >>> import qualified Data.Text.IO as T
-- >>> t = nulltransaction{tpostings=["ping" `post` usd 1]}
-- >>> test = either putStr (T.putStr.showTransaction) . fmap ($ t) . transactionModifierToFunction nulldate
-- >>> test $ TransactionModifier "" ["pong" `post` usd 2]
-- 0000-01-01
@ -79,7 +80,7 @@ transactionModifierToFunction :: Day -> TransactionModifier -> Either String (Tr
transactionModifierToFunction refdate TransactionModifier{tmquerytxt, tmpostingrules} = do
q <- simplifyQuery . fst <$> parseQuery refdate tmquerytxt
let
fs = map (tmPostingRuleToFunction tmquerytxt) tmpostingrules
fs = map (tmPostingRuleToFunction q tmquerytxt) tmpostingrules
generatePostings ps = [p' | p <- ps
, p' <- if q `matchesPosting` p then p:[f p | f <- fs] else [p]]
Right $ \t@(tpostings -> ps) -> txnTieKnot t{tpostings=generatePostings ps}
@ -92,8 +93,8 @@ transactionModifierToFunction refdate TransactionModifier{tmquerytxt, tmpostingr
-- and a hidden _generated-posting: tag which does not.
-- The TransactionModifier's query text is also provided, and saved
-- as the tags' value.
tmPostingRuleToFunction :: T.Text -> TMPostingRule -> (Posting -> Posting)
tmPostingRuleToFunction querytxt pr =
tmPostingRuleToFunction :: Query -> T.Text -> TMPostingRule -> (Posting -> Posting)
tmPostingRuleToFunction query querytxt pr =
\p -> renderPostingCommentDates $ pr
{ pdate = pdate pr <|> pdate p
, pdate2 = pdate2 pr <|> pdate2 p
@ -105,13 +106,14 @@ tmPostingRuleToFunction querytxt pr =
}
where
qry = "= " <> querytxt
symq = filterQuery queryIsSym query
amount' = case postingRuleMultiplier pr of
Nothing -> const $ pamount pr
Nothing -> const . filterMixedAmount (symq `matchesAmount`) $ pamount pr
Just n -> \p ->
-- Multiply the old posting's amount by the posting rule's multiplier.
let
pramount = dbg6 "pramount" . head . amountsRaw $ pamount pr
matchedamount = dbg6 "matchedamount" $ pamount p
matchedamount = dbg6 "matchedamount" . filterMixedAmount (symq `matchesAmount`) $ pamount p
-- Handle a matched amount with a total price carefully so as to keep the transaction balanced (#928).
-- Approach 1: convert to a unit price and increase the display precision slightly
-- Mixed as = dbg6 "multipliedamount" $ n `multiplyMixedAmount` mixedAmountTotalPriceToUnitPrice matchedamount

View File

@ -342,3 +342,22 @@ $ hledger -f- print --auto
(b) 1.5 B ; generated-posting: =
>=0
# 18. Auto-generated postings with currency matching only matches amounts with that currency in an auto posting (#1582)
<
= assets cur:USD
(b:USD) *1
2017-12-14
revenue:job -10 EUR
revenue:job -10 USD
assets
$ hledger -f- print --auto
2017-12-14 ; modified:
revenue:job -10 EUR
revenue:job -10 USD
assets
(b:USD) 10 USD ; generated-posting: = assets cur:USD
>=0