lib: better inference for unknown account names in csv parser
This commit is contained in:
parent
b5d4918c16
commit
32cbe4c7b3
@ -738,19 +738,12 @@ transactionFromCsvRecord sourcepos rules record = t
|
|||||||
,"the parse error is: "++customErrorBundlePretty err
|
,"the parse error is: "++customErrorBundlePretty err
|
||||||
]
|
]
|
||||||
|
|
||||||
unknownAccountForAmount amt =
|
parsePosting' number accountFld amountFld amountInFld amountOutFld balanceFld commentFld =
|
||||||
case isNegativeMixedAmount amt of
|
|
||||||
Just True -> "income:unknown"
|
|
||||||
Just False -> "expense:unknown"
|
|
||||||
_ -> "unknown"
|
|
||||||
|
|
||||||
parsePosting' number accountFld amtForUnknownAccount 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")
|
||||||
amount = chooseAmountStr rules record currency amountFld amountInFld amountOutFld
|
amount = chooseAmount rules record currency amountFld amountInFld amountOutFld
|
||||||
account' = ((T.pack . render) <$> (mfieldtemplate accountFld
|
account' = ((T.pack . render) <$> (mfieldtemplate accountFld
|
||||||
`or` mdirective ("default-account" ++ number)))
|
`or` mdirective ("default-account" ++ number)))
|
||||||
`or` (unknownAccountForAmount <$> amtForUnknownAccount)
|
|
||||||
balance = (parsebalance currency number.render) =<< mfieldtemplate balanceFld
|
balance = (parsebalance currency number.render) =<< mfieldtemplate balanceFld
|
||||||
comment = T.pack $ maybe "" render $ mfieldtemplate commentFld
|
comment = T.pack $ maybe "" render $ mfieldtemplate commentFld
|
||||||
account =
|
account =
|
||||||
@ -759,29 +752,26 @@ transactionFromCsvRecord sourcepos rules record = t
|
|||||||
Nothing ->
|
Nothing ->
|
||||||
-- If we have amount or balance assertion (which implies potential amount change),
|
-- If we have amount or balance assertion (which implies potential amount change),
|
||||||
-- but no account name, lets generate "unknown" account name.
|
-- but no account name, lets generate "unknown" account name.
|
||||||
-- If we can figure out whether this is income or expense based on amount, do that
|
|
||||||
-- otherwise stick to "unknown"
|
|
||||||
case (amount, balance) of
|
case (amount, balance) of
|
||||||
(Just amt, _ ) -> Just $ unknownAccountForAmount amt
|
(Just _, _ ) -> Just "unknown"
|
||||||
(_, Just _) -> Just "unknown"
|
(_, Just _) -> Just "unknown"
|
||||||
(Nothing, Nothing) -> Nothing
|
(Nothing, Nothing) -> Nothing
|
||||||
in
|
in
|
||||||
case account of
|
case account of
|
||||||
Nothing -> Nothing
|
Nothing -> Nothing
|
||||||
Just account ->
|
Just account ->
|
||||||
Just $ posting {paccount=account, pamount=fromMaybe nullmixedamt amount, ptransaction=Just t, pbalanceassertion=toAssertion <$> balance, pcomment = comment}
|
Just $ posting {paccount=account, pamount=fromMaybe missingmixedamt amount, ptransaction=Just t', pbalanceassertion=toAssertion <$> balance, pcomment = comment}
|
||||||
|
|
||||||
parsePosting number =
|
parsePosting number =
|
||||||
parsePosting' number
|
parsePosting' number
|
||||||
("account"++number)
|
("account"++number)
|
||||||
Nothing
|
|
||||||
("amount"++number)
|
("amount"++number)
|
||||||
("amount"++number++"-in")
|
("amount"++number++"-in")
|
||||||
("amount"++number++"-out")
|
("amount"++number++"-out")
|
||||||
("balance"++number)
|
("balance"++number)
|
||||||
("comment" ++ number)
|
("comment" ++ number)
|
||||||
|
|
||||||
postingLegacy = parsePosting' "" "account1" Nothing "amount" "amount-in" "amount-out" "balance" "comment1"
|
postingLegacy = parsePosting' "" "account1" "amount" "amount-in" "amount-out" "balance" "comment1"
|
||||||
posting1' = parsePosting "1"
|
posting1' = parsePosting "1"
|
||||||
posting1 =
|
posting1 =
|
||||||
case (postingLegacy,posting1') of
|
case (postingLegacy,posting1') of
|
||||||
@ -807,28 +797,37 @@ transactionFromCsvRecord sourcepos rules record = t
|
|||||||
, "amount/amount-in/amount-out is " ++ showMixedAmount al
|
, "amount/amount-in/amount-out is " ++ showMixedAmount al
|
||||||
, "amount1/amount1-in/amount1-out is " ++ showMixedAmount a1
|
, "amount1/amount1-in/amount1-out is " ++ showMixedAmount a1
|
||||||
]
|
]
|
||||||
in posting {paccount=paccount posting1, pamount=amount, ptransaction=Just t, pbalanceassertion=balanceassertion, pcomment = pcomment posting1}
|
in posting {paccount=paccount posting1, pamount=amount, ptransaction=Just t', pbalanceassertion=balanceassertion, pcomment = pcomment posting1}
|
||||||
(Nothing, Nothing) -> error' $ unlines [ "sadly, no posting was generated for account1"
|
(Nothing, Nothing) -> error' $ unlines [ "sadly, no posting was generated for account1, cannot generate transaction"
|
||||||
, showRecord record
|
, showRecord record
|
||||||
, showRules rules record
|
, showRules rules record
|
||||||
]
|
]
|
||||||
-- Posting 2 is special -- if there are no postings 3-9, we want to preserve legacy behaviour and
|
postings2to9 = catMaybes $ [ parsePosting i | x<-[2..9], let i = show x]
|
||||||
-- we want account to be income:unknown or expense:unknown if it is not specified,
|
|
||||||
-- based on the amount from posting 1
|
|
||||||
postings3to9 = catMaybes $ [ parsePosting i | x<-[3..9], let i = show x]
|
|
||||||
postings =
|
postings =
|
||||||
if postings3to9 == []
|
if postings2to9 == []
|
||||||
then [fromMaybe justOnePostingError $ parsePosting' "2" "account2" (Just $ negate $ pamount posting1) "amount2" "amount2-in" "amount2-out" "balance2" "comment2"]
|
then [posting1,posting{paccount="unknown", pamount=missingmixedamt, ptransaction=Just t'}]
|
||||||
else case parsePosting "2" of
|
else posting1:postings2to9
|
||||||
Just posting2 -> posting2:postings3to9
|
|
||||||
Nothing -> postings3to9
|
|
||||||
|
|
||||||
justOnePostingError = error' $ unlines [ "Found single posting, cannot generate transaction"
|
balanced = balanceTransaction Nothing t'
|
||||||
, showRecord record
|
t =
|
||||||
, showRules rules record
|
case balanced of
|
||||||
]
|
Left _ -> t'
|
||||||
|
Right balanced ->
|
||||||
|
-- If we managed to balance transaction, lets infer better names for all "unknown" accounts
|
||||||
|
t' {tpostings =
|
||||||
|
[ originalPosting {paccount=newAccount}
|
||||||
|
| (originalPosting,p) <- zip postings (tpostings balanced)
|
||||||
|
, let account = paccount p
|
||||||
|
, let newAccount =
|
||||||
|
if account/="unknown"
|
||||||
|
then account
|
||||||
|
else case isNegativeMixedAmount (pamount p) of
|
||||||
|
Just True -> "income:unknown"
|
||||||
|
Just False -> "expense:unknown"
|
||||||
|
_ -> "unknown"
|
||||||
|
]}
|
||||||
-- build the transaction
|
-- build the transaction
|
||||||
t = nulltransaction{
|
t' = nulltransaction{
|
||||||
tsourcepos = genericSourcePos sourcepos,
|
tsourcepos = genericSourcePos sourcepos,
|
||||||
tdate = date',
|
tdate = date',
|
||||||
tdate2 = mdate2',
|
tdate2 = mdate2',
|
||||||
@ -837,15 +836,15 @@ transactionFromCsvRecord sourcepos rules record = t
|
|||||||
tdescription = T.pack description,
|
tdescription = T.pack description,
|
||||||
tcomment = T.pack comment,
|
tcomment = T.pack comment,
|
||||||
tprecedingcomment = T.pack precomment,
|
tprecedingcomment = T.pack precomment,
|
||||||
tpostings = posting1:postings
|
tpostings = postings
|
||||||
}
|
}
|
||||||
toAssertion (a, b) = assertion{
|
toAssertion (a, b) = assertion{
|
||||||
baamount = a,
|
baamount = a,
|
||||||
baposition = b
|
baposition = b
|
||||||
}
|
}
|
||||||
|
|
||||||
chooseAmountStr :: CsvRules -> CsvRecord -> String -> String -> String -> String -> Maybe MixedAmount
|
chooseAmount :: CsvRules -> CsvRecord -> String -> String -> String -> String -> Maybe MixedAmount
|
||||||
chooseAmountStr rules record currency amountFld amountInFld amountOutFld =
|
chooseAmount rules record currency amountFld amountInFld amountOutFld =
|
||||||
let
|
let
|
||||||
mamount = getEffectiveAssignment rules record amountFld
|
mamount = getEffectiveAssignment rules record amountFld
|
||||||
mamountin = getEffectiveAssignment rules record amountInFld
|
mamountin = getEffectiveAssignment rules record amountInFld
|
||||||
|
|||||||
@ -217,9 +217,9 @@ account3 expenses:tax
|
|||||||
|
|
||||||
$ ./hledger-csv
|
$ ./hledger-csv
|
||||||
2009/09/10 Flubber Co
|
2009/09/10 Flubber Co
|
||||||
assets:myacct $50 = $321
|
assets:myacct $50 = $321
|
||||||
unknown = $123
|
income:unknown = $123
|
||||||
expenses:tax $0.234 ; VAT
|
expenses:tax $0.234 ; VAT
|
||||||
|
|
||||||
>=0
|
>=0
|
||||||
|
|
||||||
@ -346,8 +346,8 @@ amount %2
|
|||||||
date %1
|
date %1
|
||||||
date-format %Y/%m/%d
|
date-format %Y/%m/%d
|
||||||
$ ./hledger-csv | hledger balance -f - --no-total
|
$ ./hledger-csv | hledger balance -f - --no-total
|
||||||
|
$1,001.00 expense:unknown
|
||||||
$-1,001.00 income:unknown
|
$-1,001.00 income:unknown
|
||||||
$1,001.00 unknown
|
|
||||||
>=0
|
>=0
|
||||||
|
|
||||||
# 18. Conditional skips
|
# 18. Conditional skips
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user