refactor/fix balanced entry checking and test it properly
This commit is contained in:
parent
0cacc2a7e4
commit
89abdfa456
@ -49,7 +49,13 @@ pcommentwidth = no limit -- 22
|
||||
@
|
||||
-}
|
||||
showEntry :: Entry -> String
|
||||
showEntry e =
|
||||
showEntry = showEntry' True
|
||||
|
||||
showEntryUnelided :: Entry -> String
|
||||
showEntryUnelided = showEntry' False
|
||||
|
||||
showEntry' :: Bool -> Entry -> String
|
||||
showEntry' elide e =
|
||||
unlines $ [{-precedingcomment ++ -}description] ++ (showtxns $ etransactions e) ++ [""]
|
||||
where
|
||||
precedingcomment = epreceding_comment_lines e
|
||||
@ -59,8 +65,9 @@ showEntry e =
|
||||
code = if (length $ ecode e) > 0 then (printf " (%s)" $ ecode e) else ""
|
||||
desc = " " ++ edescription e
|
||||
comment = if (length $ ecomment e) > 0 then " ; "++(ecomment e) else ""
|
||||
showtxns (t1:t2:[]) = [showtxn t1, showtxnnoamt t2]
|
||||
showtxns ts = map showtxn ts
|
||||
showtxns ts
|
||||
| elide && length ts == 2 = [showtxn (ts !! 0), showtxnnoamt (ts !! 1)]
|
||||
| otherwise = map showtxn ts
|
||||
showtxn t = showacct t ++ " " ++ (showamount $ tamount t) ++ (showcomment $ tcomment t)
|
||||
showtxnnoamt t = showacct t ++ " " ++ (showcomment $ tcomment t)
|
||||
showacct t = " " ++ (showaccountname $ taccount t)
|
||||
@ -77,19 +84,19 @@ isEntryBalanced (Entry {etransactions=ts}) =
|
||||
-- amount first. We can auto-fill if there is just one non-virtual
|
||||
-- transaction without an amount. The auto-filled balance will be
|
||||
-- converted to cost basis if possible. If the entry can not be balanced,
|
||||
-- raise an error.
|
||||
balanceEntry :: Entry -> Entry
|
||||
balanceEntry e@Entry{etransactions=ts} = (e{etransactions=ts'})
|
||||
-- return an error message instead.
|
||||
balanceEntry :: Entry -> Either String Entry
|
||||
balanceEntry e@Entry{etransactions=ts}
|
||||
| length missingamounts > 1 = Left $ showerr "could not balance this entry, too many missing amounts"
|
||||
| not $ isEntryBalanced e' = Left $ showerr "could not balance this entry, amounts do not balance"
|
||||
| otherwise = Right e'
|
||||
where
|
||||
check e
|
||||
| isEntryBalanced e = e
|
||||
| otherwise = error $ "could not balance this entry:\n" ++ show e
|
||||
(withamounts, missingamounts) = partition hasAmount $ filter isReal ts
|
||||
ts' = case (length missingamounts) of
|
||||
0 -> ts
|
||||
1 -> map balance ts
|
||||
otherwise -> error $ "could not balance this entry, too many missing amounts:\n" ++ show e
|
||||
otherstotal = sum $ map tamount withamounts
|
||||
balance t
|
||||
| isReal t && not (hasAmount t) = t{tamount = costOfMixedAmount (-otherstotal)}
|
||||
| otherwise = t
|
||||
e' = e{etransactions=ts'}
|
||||
ts' | length missingamounts == 1 = map balance ts
|
||||
| otherwise = ts
|
||||
where
|
||||
balance t | isReal t && not (hasAmount t) = t{tamount = costOfMixedAmount (-otherstotal)}
|
||||
| otherwise = t
|
||||
where otherstotal = sum $ map tamount withamounts
|
||||
showerr s = printf "%s:\n%s" s (showEntryUnelided e)
|
||||
|
||||
@ -301,6 +301,8 @@ ledgerDefaultYear = do
|
||||
setYear y'
|
||||
return $ return id
|
||||
|
||||
-- | Try to parse a ledger entry. If we successfully parse an entry, ensure it is balanced,
|
||||
-- and if we cannot, raise an error.
|
||||
ledgerEntry :: GenParser Char LedgerFileCtx Entry
|
||||
ledgerEntry = do
|
||||
date <- ledgerdate <?> "entry"
|
||||
@ -313,7 +315,10 @@ ledgerEntry = do
|
||||
comment <- ledgercomment
|
||||
restofline
|
||||
transactions <- ledgertransactions
|
||||
return $ balanceEntry $ Entry date status code description comment transactions ""
|
||||
let e = Entry date status code description comment transactions ""
|
||||
case balanceEntry e of
|
||||
Right e' -> return e'
|
||||
Left err -> error err
|
||||
|
||||
ledgerdate :: GenParser Char LedgerFileCtx Day
|
||||
ledgerdate = try ledgerfulldate <|> ledgerpartialdate
|
||||
|
||||
@ -239,3 +239,13 @@ spacenonewline = satisfy (\c -> c `elem` " \v\f\t")
|
||||
restofline :: GenParser Char st String
|
||||
restofline = anyChar `manyTill` newline
|
||||
|
||||
|
||||
|
||||
|
||||
isLeft :: Either a b -> Bool
|
||||
isLeft (Left _) = True
|
||||
isLeft _ = False
|
||||
|
||||
isRight :: Either a b -> Bool
|
||||
isRight = not . isLeft
|
||||
|
||||
|
||||
16
NOTES
16
NOTES
@ -10,24 +10,8 @@ clever tricks like the plague." --Edsger Dijkstra
|
||||
|
||||
* to do
|
||||
** errors
|
||||
*** not catching some unbalanced entries, two ways:
|
||||
**** 1
|
||||
1/1 test1
|
||||
a $-100
|
||||
b -10h @ $10
|
||||
; $ hledger -B reg -- test1
|
||||
; 2009/01/01 test1 a $-100.00 $-100.00
|
||||
**** 2
|
||||
1/1 test2
|
||||
a $-100
|
||||
b $-100
|
||||
; $ hledger -B reg -- test2
|
||||
; 2009/01/01 test2 a $-100.00 $-100.00
|
||||
; b $-100.00 $-200.00
|
||||
|
||||
*** --depth works with reg -W but not with reg
|
||||
*** register report should sort by date
|
||||
*** too many dependencies, hard to install esp. without cabal install
|
||||
** features
|
||||
*** more ledger features
|
||||
**** rename entry -> transaction, transaction -> posting
|
||||
|
||||
22
Tests.hs
22
Tests.hs
@ -259,7 +259,27 @@ tests = [
|
||||
]
|
||||
|
||||
,"balanceEntry" ~: do
|
||||
(tamount $ last $ etransactions $ balanceEntry entry1) `is` Mixed [dollars (-47.18)]
|
||||
let fromeither (Left err) = error err
|
||||
fromeither (Right e) = e
|
||||
(tamount $ last $ etransactions $ fromeither $ balanceEntry entry1) `is` Mixed [dollars (-47.18)]
|
||||
assertBool "detect unbalanced entry, sign error"
|
||||
(isLeft $ balanceEntry
|
||||
(Entry (parsedate "2007/01/28") False "" "test" ""
|
||||
[RawTransaction False "a" (Mixed [dollars 1]) "" RegularTransaction,
|
||||
RawTransaction False "b" (Mixed [dollars 1]) "" RegularTransaction
|
||||
] ""))
|
||||
assertBool "detect unbalanced entry, multiple missing amounts"
|
||||
(isLeft $ balanceEntry
|
||||
(Entry (parsedate "2007/01/28") False "" "test" ""
|
||||
[RawTransaction False "a" missingamt "" RegularTransaction,
|
||||
RawTransaction False "b" missingamt "" RegularTransaction
|
||||
] ""))
|
||||
assertBool "one missing amount should be ok"
|
||||
(isRight $ balanceEntry
|
||||
(Entry (parsedate "2007/01/28") False "" "test" ""
|
||||
[RawTransaction False "a" (Mixed [dollars 1]) "" RegularTransaction,
|
||||
RawTransaction False "b" missingamt "" RegularTransaction
|
||||
] ""))
|
||||
|
||||
,"balancereportacctnames" ~:
|
||||
let gives (opt,pats) e = do
|
||||
|
||||
Loading…
Reference in New Issue
Block a user