lib: Make sure automatic postings generated from postings with more than one commodity match on commodity symbol (#1582).
This commit is contained in:
		
							parent
							
								
									bb7d04c031
								
							
						
					
					
						commit
						2a9d358627
					
				| @ -13,16 +13,17 @@ module Hledger.Data.TransactionModifier ( | |||||||
| where | where | ||||||
| 
 | 
 | ||||||
| import Control.Applicative ((<|>)) | import Control.Applicative ((<|>)) | ||||||
| import Data.Maybe | import Data.Maybe (catMaybes) | ||||||
| import qualified Data.Text as T | import qualified Data.Text as T | ||||||
| import Data.Time.Calendar | import Data.Time.Calendar (Day) | ||||||
| import Hledger.Data.Types | import Hledger.Data.Types | ||||||
| import Hledger.Data.Dates | import Hledger.Data.Dates | ||||||
| import Hledger.Data.Amount | import Hledger.Data.Amount | ||||||
| import Hledger.Data.Transaction | import Hledger.Data.Transaction (txnTieKnot) | ||||||
| import Hledger.Query | import Hledger.Query (Query, filterQuery, matchesAmount, matchesPosting, | ||||||
|  |                       parseQuery, queryIsSym, simplifyQuery) | ||||||
| import Hledger.Data.Posting (commentJoin, commentAddTag) | import Hledger.Data.Posting (commentJoin, commentAddTag) | ||||||
| import Hledger.Utils | import Hledger.Utils (dbg6, wrap) | ||||||
| 
 | 
 | ||||||
| -- $setup | -- $setup | ||||||
| -- >>> :set -XOverloadedStrings | -- >>> :set -XOverloadedStrings | ||||||
| @ -57,8 +58,8 @@ modifyTransactions d tmods ts = do | |||||||
| -- Currently the only kind of modification possible is adding automated | -- Currently the only kind of modification possible is adding automated | ||||||
| -- postings when certain other postings are present. | -- postings when certain other postings are present. | ||||||
| -- | -- | ||||||
| -- >>> t = nulltransaction{tpostings=["ping" `post` usd 1]} |  | ||||||
| -- >>> import qualified Data.Text.IO as T | -- >>> 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 = either putStr (T.putStr.showTransaction) . fmap ($ t) . transactionModifierToFunction nulldate | ||||||
| -- >>> test $ TransactionModifier "" ["pong" `post` usd 2] | -- >>> test $ TransactionModifier "" ["pong" `post` usd 2] | ||||||
| -- 0000-01-01 | -- 0000-01-01 | ||||||
| @ -79,7 +80,7 @@ transactionModifierToFunction :: Day -> TransactionModifier -> Either String (Tr | |||||||
| transactionModifierToFunction refdate TransactionModifier{tmquerytxt, tmpostingrules} = do | transactionModifierToFunction refdate TransactionModifier{tmquerytxt, tmpostingrules} = do | ||||||
|   q <- simplifyQuery . fst <$> parseQuery refdate tmquerytxt |   q <- simplifyQuery . fst <$> parseQuery refdate tmquerytxt | ||||||
|   let |   let | ||||||
|     fs = map (tmPostingRuleToFunction tmquerytxt) tmpostingrules |     fs = map (tmPostingRuleToFunction q tmquerytxt) tmpostingrules | ||||||
|     generatePostings ps = [p' | p <- ps |     generatePostings ps = [p' | p <- ps | ||||||
|                               , p' <- if q `matchesPosting` p then p:[f p | f <- fs] else [p]] |                               , p' <- if q `matchesPosting` p then p:[f p | f <- fs] else [p]] | ||||||
|   Right $ \t@(tpostings -> ps) -> txnTieKnot t{tpostings=generatePostings ps} |   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. | -- and a hidden _generated-posting: tag which does not. | ||||||
| -- The TransactionModifier's query text is also provided, and saved | -- The TransactionModifier's query text is also provided, and saved | ||||||
| -- as the tags' value. | -- as the tags' value. | ||||||
| tmPostingRuleToFunction :: T.Text -> TMPostingRule -> (Posting -> Posting) | tmPostingRuleToFunction :: Query -> T.Text -> TMPostingRule -> (Posting -> Posting) | ||||||
| tmPostingRuleToFunction querytxt pr = | tmPostingRuleToFunction query querytxt pr = | ||||||
|   \p -> renderPostingCommentDates $ pr |   \p -> renderPostingCommentDates $ pr | ||||||
|       { pdate    = pdate  pr <|> pdate  p |       { pdate    = pdate  pr <|> pdate  p | ||||||
|       , pdate2   = pdate2 pr <|> pdate2 p |       , pdate2   = pdate2 pr <|> pdate2 p | ||||||
| @ -105,13 +106,14 @@ tmPostingRuleToFunction querytxt pr = | |||||||
|       } |       } | ||||||
|   where |   where | ||||||
|     qry = "= " <> querytxt |     qry = "= " <> querytxt | ||||||
|  |     symq = filterQuery queryIsSym query | ||||||
|     amount' = case postingRuleMultiplier pr of |     amount' = case postingRuleMultiplier pr of | ||||||
|         Nothing -> const $ pamount pr |         Nothing -> const . filterMixedAmount (symq `matchesAmount`) $ pamount pr | ||||||
|         Just n  -> \p -> |         Just n  -> \p -> | ||||||
|           -- Multiply the old posting's amount by the posting rule's multiplier. |           -- Multiply the old posting's amount by the posting rule's multiplier. | ||||||
|           let |           let | ||||||
|             pramount = dbg6 "pramount" . head . amountsRaw $ pamount pr |             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). |             -- 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 |             -- Approach 1: convert to a unit price and increase the display precision slightly | ||||||
|             -- Mixed as = dbg6 "multipliedamount" $ n `multiplyMixedAmount` mixedAmountTotalPriceToUnitPrice matchedamount |             -- Mixed as = dbg6 "multipliedamount" $ n `multiplyMixedAmount` mixedAmountTotalPriceToUnitPrice matchedamount | ||||||
|  | |||||||
| @ -342,3 +342,22 @@ $ hledger -f- print --auto | |||||||
|     (b)           1.5 B  ; generated-posting: = |     (b)           1.5 B  ; generated-posting: = | ||||||
| 
 | 
 | ||||||
| >=0 | >=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 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user