csv: refine unknown accounts more thoroughly, a better fix for #1192
This commit is contained in:
		
							parent
							
								
									58bb0df5ab
								
							
						
					
					
						commit
						02f2e3bd9b
					
				| @ -741,6 +741,7 @@ type CsvRecord = [String] | |||||||
| showRules rules record = | showRules rules record = | ||||||
|   unlines $ catMaybes [ (("the "++fld++" rule is: ")++) <$> getEffectiveAssignment rules record fld | fld <- journalfieldnames] |   unlines $ catMaybes [ (("the "++fld++" rule is: ")++) <$> getEffectiveAssignment rules record fld | fld <- journalfieldnames] | ||||||
| 
 | 
 | ||||||
|  | -- warning: 200 line beast ahead. How to simplify ? | ||||||
| transactionFromCsvRecord :: SourcePos -> CsvRules -> CsvRecord -> Transaction | transactionFromCsvRecord :: SourcePos -> CsvRules -> CsvRecord -> Transaction | ||||||
| transactionFromCsvRecord sourcepos rules record = t | transactionFromCsvRecord sourcepos rules record = t | ||||||
|   where |   where | ||||||
| @ -803,7 +804,7 @@ transactionFromCsvRecord sourcepos rules record = t | |||||||
|     unknownExpenseAccount = "expenses:unknown" |     unknownExpenseAccount = "expenses:unknown" | ||||||
|     unknownIncomeAccount  = "income:unknown" |     unknownIncomeAccount  = "income:unknown" | ||||||
| 
 | 
 | ||||||
|     parsePosting' :: String -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> Maybe (String, Posting) |     parsePosting' :: String -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> JournalFieldName -> Maybe (Posting, Bool) | ||||||
|     parsePosting' number accountFld amountFld amountInFld amountOutFld balanceFld commentFld = |     parsePosting' number accountFld amountFld amountInFld amountOutFld balanceFld commentFld = | ||||||
|       let currency = maybe (fromMaybe "" mdefaultcurrency) render $ |       let currency = maybe (fromMaybe "" mdefaultcurrency) render $ | ||||||
|                       (mfieldtemplate ("currency"++number) `or `mfieldtemplate "currency") |                       (mfieldtemplate ("currency"++number) `or `mfieldtemplate "currency") | ||||||
| @ -812,32 +813,39 @@ transactionFromCsvRecord sourcepos rules record = t | |||||||
|                         (mfieldtemplate accountFld `or` mdirective ("default-account" ++ number))) |                         (mfieldtemplate accountFld `or` mdirective ("default-account" ++ number))) | ||||||
|           mbalance = (parsebalance currency number.render) =<< mfieldtemplate balanceFld |           mbalance = (parsebalance currency number.render) =<< mfieldtemplate balanceFld | ||||||
|           comment = T.pack $ maybe "" render $ mfieldtemplate commentFld |           comment = T.pack $ maybe "" render $ mfieldtemplate commentFld | ||||||
|           maccount :: Maybe AccountName = | 
 | ||||||
|  |           -- figure out the account name to use for this posting, if any, and | ||||||
|  |           -- whether it is the unknown account which may be improved later, | ||||||
|  |           -- when we know the posting's final amount. | ||||||
|  |           maccountAndIsFinal :: Maybe (AccountName, Bool) = | ||||||
|             case maccount' of |             case maccount' of | ||||||
|               -- accountN is set to the empty string - this posting will be suppressed |               -- accountN is set to the empty string - no posting will be generated | ||||||
|               Just "" -> Nothing |               Just "" -> Nothing | ||||||
|               -- accountN is set |               -- accountN is set (possibly to "expenses:unknown" ! #1192) - | ||||||
|               Just a  -> Just a |               -- don't let it be changed. | ||||||
|  |               Just a  -> Just (a, True) | ||||||
|               -- accountN is unset |               -- accountN is unset | ||||||
|               Nothing -> |               Nothing -> | ||||||
|                 case (mamount, mbalance) of |                 case (mamount, mbalance) of | ||||||
|                   -- amountN is set, or implied by balanceN - accountN will be |                   -- amountN is set, or implied by balanceN - set accountN to | ||||||
|                   -- set to the unknown account (expenses:unknown, for now) |                   -- set to the default unknown account (expenses:unknown) | ||||||
|                   (Just _, _) -> Just unknownExpenseAccount |                   -- and allow it to be improved later | ||||||
|                   (_, Just _) -> Just unknownExpenseAccount |                   (Just _, _) -> Just (unknownExpenseAccount, False) | ||||||
|                   -- amountN is also unset, this posting will be suppressed |                   (_, Just _) -> Just (unknownExpenseAccount, False) | ||||||
|  |                   -- amountN is also unset - no posting will be generated | ||||||
|                   (Nothing, Nothing) -> Nothing |                   (Nothing, Nothing) -> Nothing | ||||||
|       in |       in | ||||||
|         -- if there's an account N, make a posting N |         -- if there's an account N, make a posting N | ||||||
|         case maccount of |         case maccountAndIsFinal of | ||||||
|           Nothing   -> Nothing |           Nothing            -> Nothing | ||||||
|           Just acct -> |           Just (acct, final) -> | ||||||
|             Just (number, posting{paccount          = accountNameWithoutPostingType acct |             Just (posting{paccount          = accountNameWithoutPostingType acct | ||||||
|                                  ,pamount           = fromMaybe missingmixedamt mamount |                          ,pamount           = fromMaybe missingmixedamt mamount | ||||||
|                                  ,ptransaction      = Just t |                          ,ptransaction      = Just t | ||||||
|                                  ,pbalanceassertion = toAssertion <$> mbalance |                          ,pbalanceassertion = toAssertion <$> mbalance | ||||||
|                                  ,pcomment          = comment |                          ,pcomment          = comment | ||||||
|                                  ,ptype             = accountNamePostingType acct}) |                          ,ptype             = accountNamePostingType acct} | ||||||
|  |                  ,final) | ||||||
| 
 | 
 | ||||||
|     parsePosting number =               |     parsePosting number =               | ||||||
|       parsePosting' number |       parsePosting' number | ||||||
| @ -866,33 +874,40 @@ transactionFromCsvRecord sourcepos rules record = t | |||||||
|                ("balance1" `withAlias` "balance") |                ("balance1" `withAlias` "balance") | ||||||
|                "comment1" -- comment1 does not have legacy alias |                "comment1" -- comment1 does not have legacy alias | ||||||
| 
 | 
 | ||||||
|     postings' = catMaybes $ posting1:[ parsePosting i | x<-[2..9], let i = show x] |     postings' = catMaybes $ posting1 : [parsePosting i | x<-[2..9], let i = show x] | ||||||
| 
 | 
 | ||||||
|  |     -- Handle some special cases to mimic pre-1.16 behaviour, for | ||||||
|  |     -- compatibility; and also, wherever default "unknown" accounts were used, | ||||||
|  |     -- refine these based on the sign of the final posting amount. | ||||||
|     postings = |     postings = | ||||||
|       case postings' of |       case postings' of | ||||||
|         -- pre-1.16 compatibility: when rules generate just one posting, and |         -- when rules generate just one posting, and it's a type that needs to | ||||||
|         -- it's a type that needs to be balanced, generate the second posting |         -- be balanced, generate the second posting to balance it. | ||||||
|         -- to balance it, with appropriate unknown account name |         [(p1,final)] -> | ||||||
|         [("1",p1)] -> |  | ||||||
|           if ptype p1 == VirtualPosting |           if ptype p1 == VirtualPosting | ||||||
|           then [p1] |           then [p1'] | ||||||
|           else [p1, p2] |           else [p1', p2] | ||||||
|             where |             where | ||||||
|               p2 = improveUnknownAccountName $ |               p1' = (if final then id else improveUnknownAccountName) p1 | ||||||
|  |               p2 = improveUnknownAccountName | ||||||
|                    nullposting{paccount=unknownExpenseAccount |                    nullposting{paccount=unknownExpenseAccount | ||||||
|                               ,pamount=costOfMixedAmount (-pamount p1) |                               ,pamount=costOfMixedAmount (-pamount p1) | ||||||
|                               ,ptransaction=Just t} |                               ,ptransaction=Just t} | ||||||
| 
 | 
 | ||||||
|         -- pre-1.16 compatibility: when rules generate exactly two postings, |         -- pre-1.16 compatibility: when rules generate exactly two postings, | ||||||
|         -- and the second has no amount, give it the balancing amount, and |         -- and only the second has no amount, give it the balancing amount. | ||||||
|         -- refine the account name if it's unknown |         [(p1,final1), (p2,final2)] -> | ||||||
|         [("1",p1), ("2",p2)] -> |           case (pamount p1 == missingmixedamt, pamount p2 == missingmixedamt) of | ||||||
|           case (pamount p1 == missingmixedamt , pamount p2 == missingmixedamt) of |             (False, True) -> [p1',p2'] | ||||||
|             (False, True) -> [p1, improveUnknownAccountName $ p2{pamount=costOfMixedAmount(-(pamount p1))}] |               where p2' = (if final2 then id else improveUnknownAccountName) | ||||||
|             _  -> [p1, p2] |                           p2{pamount=costOfMixedAmount(-(pamount p1))} | ||||||
|  |             _  -> [p1', p2'] | ||||||
|  |               where p2' = (if final2 then id else improveUnknownAccountName) p2 | ||||||
|  |             where | ||||||
|  |               p1' = (if final1 then id else improveUnknownAccountName) p1 | ||||||
| 
 | 
 | ||||||
|         -- otherwise, refine any unknown account names in all postings |         -- otherwise, refine an unknown account name in all postings. | ||||||
|         _ -> map (improveUnknownAccountName . snd) postings' |         ps -> [(if final then id else improveUnknownAccountName) p | (p,final) <- ps] | ||||||
|       where |       where | ||||||
|         -- If this posting has the "expenses:unknown" account name, maybe |         -- If this posting has the "expenses:unknown" account name, maybe | ||||||
|         -- replace that with "income:unknown" now that we know the amount's sign. |         -- replace that with "income:unknown" now that we know the amount's sign. | ||||||
|  | |||||||
| @ -608,8 +608,8 @@ fields date, amount, account1 | |||||||
| account2 expenses:unknown | account2 expenses:unknown | ||||||
| $  ./hledger-csv | $  ./hledger-csv | ||||||
| 2020-01-01 | 2020-01-01 | ||||||
|     a                             1 |     a                              1 | ||||||
|     expenses:unknown             -1 |     expenses:unknown              -1 | ||||||
| 
 | 
 | ||||||
| >=0 | >=0 | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user