csv: undo failed #1192 fix, causing "_unknown_" accounts; refactor
Restore the old logic, while also trying to clarify this transaction-generating code, and add some tests. See also #1198.
This commit is contained in:
		
							parent
							
								
									fb788a64e8
								
							
						
					
					
						commit
						58bb0df5ab
					
				| @ -798,46 +798,46 @@ transactionFromCsvRecord sourcepos rules record = t | ||||
|       ] | ||||
| 
 | ||||
|     -- Default account names to use when one is not set. | ||||
|     -- The first one is chosen by default, and sometimes gets replaced later | ||||
|     -- by the other when appropriate. | ||||
|     unknownExpenseAccount = "expenses:unknown" | ||||
|     unknownIncomeAccount  = "income:unknown" | ||||
|     -- A temporary placeholder for the unknown account name, which | ||||
|     -- gets replaced by one of the above based on the amount's sign. | ||||
|     -- This is a value hopefully never chosen by users (cf #1192). | ||||
|     unknownPlaceholderAccount = "_unknown_" | ||||
| 
 | ||||
|     parsePosting' :: String -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> Maybe (String, Posting) | ||||
|     parsePosting' number accountFld amountFld amountInFld amountOutFld balanceFld commentFld = | ||||
|       let currency = maybe (fromMaybe "" mdefaultcurrency) render $ | ||||
|                       (mfieldtemplate ("currency"++number) `or `mfieldtemplate "currency") | ||||
|           amount = chooseAmount rules record currency amountFld amountInFld amountOutFld                       | ||||
|           account' = ((T.pack . render) <$> (mfieldtemplate accountFld | ||||
|                                            `or` mdirective ("default-account" ++ number))) | ||||
|           balance = (parsebalance currency number.render) =<< mfieldtemplate balanceFld | ||||
|           mamount = chooseAmount rules record currency amountFld amountInFld amountOutFld | ||||
|           maccount' = ((T.pack . render) <$> | ||||
|                         (mfieldtemplate accountFld `or` mdirective ("default-account" ++ number))) | ||||
|           mbalance = (parsebalance currency number.render) =<< mfieldtemplate balanceFld | ||||
|           comment = T.pack $ maybe "" render $ mfieldtemplate commentFld | ||||
|           account = | ||||
|             case account' of | ||||
|               -- account is set to "" - suppress posting | ||||
|           maccount :: Maybe AccountName = | ||||
|             case maccount' of | ||||
|               -- accountN is set to the empty string - this posting will be suppressed | ||||
|               Just "" -> Nothing | ||||
|               -- account is set | ||||
|               Just account -> Just account | ||||
|               -- accountN is set | ||||
|               Just a  -> Just a | ||||
|               -- accountN is unset | ||||
|               Nothing -> | ||||
|                 case (amount, balance) of | ||||
|                   -- account is not set, but an amount is set (or implied by | ||||
|                   -- balance assignment) - use "unknown" account. | ||||
|                   (Just _, _ ) -> Just unknownPlaceholderAccount | ||||
|                   (_, Just _)  -> Just unknownPlaceholderAccount | ||||
|                   -- no account, no amount | ||||
|                 case (mamount, mbalance) of | ||||
|                   -- amountN is set, or implied by balanceN - accountN will be | ||||
|                   -- set to the unknown account (expenses:unknown, for now) | ||||
|                   (Just _, _) -> Just unknownExpenseAccount | ||||
|                   (_, Just _) -> Just unknownExpenseAccount | ||||
|                   -- amountN is also unset, this posting will be suppressed | ||||
|                   (Nothing, Nothing) -> Nothing | ||||
|       in | ||||
|         -- if there's an account N, make a posting N | ||||
|         case account of | ||||
|           Nothing -> Nothing | ||||
|           Just account ->  | ||||
|             Just $ (number, posting {paccount=accountNameWithoutPostingType account | ||||
|                                     , pamount=fromMaybe missingmixedamt amount | ||||
|                                     , ptransaction=Just t | ||||
|                                     , pbalanceassertion=toAssertion <$> balance | ||||
|                                     , pcomment = comment | ||||
|                                     , ptype = accountNamePostingType account}) | ||||
|         case maccount of | ||||
|           Nothing   -> Nothing | ||||
|           Just acct -> | ||||
|             Just (number, posting{paccount          = accountNameWithoutPostingType acct | ||||
|                                  ,pamount           = fromMaybe missingmixedamt mamount | ||||
|                                  ,ptransaction      = Just t | ||||
|                                  ,pbalanceassertion = toAssertion <$> mbalance | ||||
|                                  ,pcomment          = comment | ||||
|                                  ,ptype             = accountNamePostingType acct}) | ||||
| 
 | ||||
|     parsePosting number =               | ||||
|       parsePosting' number | ||||
| @ -870,31 +870,36 @@ transactionFromCsvRecord sourcepos rules record = t | ||||
| 
 | ||||
|     postings = | ||||
|       case postings' of | ||||
|         -- To be compatible with the behavior of the old code which allowed two postings only, we enforce | ||||
|         -- second posting when rules generated just first of them, and posting is of type that should be balanced. | ||||
|         [("1",posting1)] -> | ||||
|           case ptype posting1 of | ||||
|             VirtualPosting -> [posting1] | ||||
|             _ -> | ||||
|               [posting1,improveUnknownAccountName (posting{paccount=unknownPlaceholderAccount, pamount=costOfMixedAmount(-(pamount posting1)), ptransaction=Just t})] | ||||
|         -- When we have strictly first and second posting, but second posting does not have amount, we fill it in. | ||||
|         [("1",posting1),("2",posting2)] -> | ||||
|           case (pamount posting1 == missingmixedamt , pamount posting2 == missingmixedamt) of | ||||
|             (False, True) -> [posting1, improveUnknownAccountName (posting2{pamount=costOfMixedAmount(-(pamount posting1))})] | ||||
|             _  -> [posting1, posting2] | ||||
|         -- pre-1.16 compatibility: when rules generate just one posting, and | ||||
|         -- it's a type that needs to be balanced, generate the second posting | ||||
|         -- to balance it, with appropriate unknown account name | ||||
|         [("1",p1)] -> | ||||
|           if ptype p1 == VirtualPosting | ||||
|           then [p1] | ||||
|           else [p1, p2] | ||||
|             where | ||||
|               p2 = improveUnknownAccountName $ | ||||
|                    nullposting{paccount=unknownExpenseAccount | ||||
|                               ,pamount=costOfMixedAmount (-pamount p1) | ||||
|                               ,ptransaction=Just t} | ||||
| 
 | ||||
|         -- pre-1.16 compatibility: when rules generate exactly two postings, | ||||
|         -- and the second has no amount, give it the balancing amount, and | ||||
|         -- refine the account name if it's unknown | ||||
|         [("1",p1), ("2",p2)] -> | ||||
|           case (pamount p1 == missingmixedamt , pamount p2 == missingmixedamt) of | ||||
|             (False, True) -> [p1, improveUnknownAccountName $ p2{pamount=costOfMixedAmount(-(pamount p1))}] | ||||
|             _  -> [p1, p2] | ||||
| 
 | ||||
|         -- otherwise, refine any unknown account names in all postings | ||||
|         _ -> map (improveUnknownAccountName . snd) postings' | ||||
|       where | ||||
|         improveUnknownAccountName p = | ||||
|           if paccount p == unknownPlaceholderAccount | ||||
|           then case isNegativeMixedAmount (pamount p) of | ||||
|             -- amount is negative, call it an income | ||||
|             Just True  -> p{paccount = unknownIncomeAccount} | ||||
|             -- amount is positive, or in multiple commodities so we | ||||
|             -- can't tell, call it an expense | ||||
|             _          -> p{paccount = unknownExpenseAccount} | ||||
|           else p | ||||
|          | ||||
|         -- If this posting has the "expenses:unknown" account name, maybe | ||||
|         -- replace that with "income:unknown" now that we know the amount's sign. | ||||
|         improveUnknownAccountName p@Posting{..} | ||||
|           | paccount == unknownExpenseAccount | ||||
|             && fromMaybe False (isNegativeMixedAmount pamount) = p{paccount=unknownIncomeAccount} | ||||
|           | otherwise = p | ||||
|          | ||||
|     -- build the transaction | ||||
|     t = nulltransaction{ | ||||
|  | ||||
| @ -574,6 +574,45 @@ $  ./hledger-csv desc:one | ||||
| 
 | ||||
| >=0 | ||||
| 
 | ||||
| # 28. choose unknown account names correctly when no account name is set | ||||
| # and backwards-compatibly generating two postings. | ||||
| < | ||||
| 2020-01-01, 1, | ||||
| RULES | ||||
| fields date, amount,  | ||||
| $  ./hledger-csv | ||||
| 2020-01-01 | ||||
|     expenses:unknown               1 | ||||
|     income:unknown                -1 | ||||
| 
 | ||||
| >=0 | ||||
| 
 | ||||
| # 29. choose unknown account name correctly when only account1 is set | ||||
| # and backwards-compatibly generating second posting. | ||||
| < | ||||
| 2020-01-01, 1, a | ||||
| RULES | ||||
| fields date, amount, account1 | ||||
| $  ./hledger-csv | ||||
| 2020-01-01 | ||||
|     a                            1 | ||||
|     income:unknown              -1 | ||||
| 
 | ||||
| >=0 | ||||
| 
 | ||||
| # 30. leave unknown account name as-is when explicitly set by user (#1192). | ||||
| < | ||||
| 2020-01-01, 1, a | ||||
| RULES | ||||
| fields date, amount, account1 | ||||
| account2 expenses:unknown | ||||
| $  ./hledger-csv | ||||
| 2020-01-01 | ||||
|     a                             1 | ||||
|     expenses:unknown             -1 | ||||
| 
 | ||||
| >=0 | ||||
| 
 | ||||
| ## .  | ||||
| #< | ||||
| #$  ./hledger-csv | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user