refactor: split showBalanceReport into reusable-data-generating and rendering steps

This commit is contained in:
Simon Michael 2010-07-25 18:24:40 +00:00
parent af21a0c507
commit 137ed3e43f
4 changed files with 46 additions and 34 deletions

View File

@ -110,46 +110,57 @@ import System.IO.UTF8
#endif #endif
type BalanceReportData = ([BalanceReportItem]
,MixedAmount -- ^ total balance of all accounts
)
type BalanceReportItem = (AccountName -- ^ full account name
,AccountName -- ^ account name elided for display: the leaf name,
-- prefixed by any boring parents immediately above
,Int -- ^ account depth within this report, excludes boring parents
,MixedAmount) -- ^ account balance, includes subs unless --flat is present
-- | Print a balance report. -- | Print a balance report.
balance :: [Opt] -> [String] -> Journal -> IO () balance :: [Opt] -> [String] -> Journal -> IO ()
balance opts args j = do balance opts args j = do
t <- getCurrentLocalTime t <- getCurrentLocalTime
putStr $ showBalanceReport opts (optsToFilterSpec opts args t) j putStr $ showBalanceReport opts $ balanceReport opts (optsToFilterSpec opts args t) j
-- | Generate a balance report with the specified options for this journal. -- | Render balance report data as plain text suitable for console output.
showBalanceReport :: [Opt] -> FilterSpec -> Journal -> String showBalanceReport :: [Opt] -> BalanceReportData -> String
showBalanceReport opts filterspec j = acctsstr ++ totalstr showBalanceReport opts (items,total) = acctsstr ++ totalstr
where where
l = journalToLedger filterspec j acctsstr = unlines $ map showitem items
acctsstr = unlines $ map showacct interestingaccts
where
showacct = showInterestingAccount opts l interestingaccts
interestingaccts = filter (isInteresting opts l) acctnames
acctnames = sort $ tail $ flatten $ treemap aname accttree
accttree = ledgerAccountTree (fromMaybe 99999 $ depthFromOpts opts) l
totalstr | NoTotal `elem` opts = "" totalstr | NoTotal `elem` opts = ""
| otherwise = printf "--------------------\n%s\n" $ padleft 20 $ showMixedAmountWithoutPrice total | otherwise = printf "--------------------\n%s\n" $ padleft 20 $ showMixedAmountWithoutPrice total
-- | Render one balance report line item as plain text.
showitem :: BalanceReportItem -> String
showitem (a, adisplay, adepth, abal) = concatTopPadded [amt, " ", name]
where where
total = sum $ map abalance $ ledgerTopAccounts l total = sum $ map abalance $ ledgerTopAccounts l
-- | Display one line of the balance report with appropriate indenting and eliding. -- | Get data for a balance report with the specified options for this journal.
showInterestingAccount :: [Opt] -> Ledger -> [AccountName] -> AccountName -> String balanceReport :: [Opt] -> FilterSpec -> Journal -> BalanceReportData
showInterestingAccount opts l interestingaccts a = concatTopPadded [amt, " ", name] balanceReport opts filterspec j = (items, total)
where where
amt = padleft 20 $ showMixedAmountWithoutPrice bal items = map mkitem interestingaccts
bal | Flat `elem` opts = exclusiveBalance acct interestingaccts = filter (isInteresting opts l) acctnames
| otherwise = abalance acct acctnames = sort $ tail $ flatten $ treemap aname accttree
acct = ledgerAccount l a accttree = ledgerAccountTree (fromMaybe 99999 $ depthFromOpts opts) l
name | Flat `elem` opts = accountNameDrop (dropFromOpts opts) a total = sum $ map abalance $ ledgerTopAccounts l
| otherwise = depthspacer ++ partialname l = journalToLedger filterspec j
parents = parentAccountNames a -- | Get data for one balance report line item.
interestingparents = filter (`elem` interestingaccts) parents mkitem :: AccountName -> BalanceReportItem
depthspacer = replicate (indentperlevel * length interestingparents) ' ' mkitem a = (a, adisplay, adepth, abal)
indentperlevel = 2 where
-- the partial name is the account's leaf name, prefixed by the adisplay = accountNameFromComponents $ reverse (map accountLeafName ps) ++ [accountLeafName a]
-- names of any boring parents immediately above where ps = takeWhile boring parents where boring = not . (`elem` interestingparents)
partialname = accountNameFromComponents $ reverse (map accountLeafName ps) ++ [accountLeafName a] adepth = length interestingparents
where ps = takeWhile boring parents where boring = not . (`elem` interestingparents) interestingparents = filter (`elem` interestingaccts) parents
parents = parentAccountNames a
abal | Flat `elem` opts = exclusiveBalance acct
| otherwise = abalance acct
where acct = ledgerAccount l a
exclusiveBalance :: Account -> MixedAmount exclusiveBalance :: Account -> MixedAmount
exclusiveBalance = sumPostings . apostings exclusiveBalance = sumPostings . apostings

View File

@ -229,7 +229,7 @@ resetTrailAndEnter t scr a = enter t scr (aargs a) $ clearLocs a
updateData :: LocalTime -> AppState -> AppState updateData :: LocalTime -> AppState -> AppState
updateData t a@AppState{aopts=opts,ajournal=j} = updateData t a@AppState{aopts=opts,ajournal=j} =
case screen a of case screen a of
BalanceScreen -> a{abuf=lines $ showBalanceReport opts fspec j} BalanceScreen -> a{abuf=lines $ showBalanceReport opts $ balanceReport opts fspec j}
RegisterScreen -> a{abuf=lines $ showRegisterReport opts fspec j} RegisterScreen -> a{abuf=lines $ showRegisterReport opts fspec j}
PrintScreen -> a{abuf=lines $ showTransactions fspec j} PrintScreen -> a{abuf=lines $ showTransactions fspec j}
where fspec = optsToFilterSpec opts (currentArgs a) t where fspec = optsToFilterSpec opts (currentArgs a) t

View File

@ -100,7 +100,8 @@ getRegisterPage :: Handler HledgerWebApp RepHtml
getRegisterPage = withLatestJournalRender showRegisterReport getRegisterPage = withLatestJournalRender showRegisterReport
getBalancePage :: Handler HledgerWebApp RepHtml getBalancePage :: Handler HledgerWebApp RepHtml
getBalancePage = withLatestJournalRender showBalanceReport getBalancePage = withLatestJournalRender render
where render opts filterspec j = showBalanceReport opts $ balanceReport opts filterspec j
withLatestJournalRender :: ([Opt] -> FilterSpec -> Journal -> String) -> Handler HledgerWebApp RepHtml withLatestJournalRender :: ([Opt] -> FilterSpec -> Journal -> String) -> Handler HledgerWebApp RepHtml
withLatestJournalRender reportfn = do withLatestJournalRender reportfn = do

View File

@ -109,7 +109,7 @@ tests = TestList [
let (opts,args) `gives` es = do let (opts,args) `gives` es = do
l <- samplejournalwithopts opts args l <- samplejournalwithopts opts args
t <- getCurrentLocalTime t <- getCurrentLocalTime
showBalanceReport opts (optsToFilterSpec opts args t) l `is` unlines es showBalanceReport opts (balanceReport opts (optsToFilterSpec opts args t) l) `is` unlines es
in TestList in TestList
[ [
@ -245,7 +245,7 @@ tests = TestList [
," c:d " ," c:d "
]) >>= either error return ]) >>= either error return
let j' = journalCanonicaliseAmounts $ journalConvertAmountsToCost j -- enable cost basis adjustment let j' = journalCanonicaliseAmounts $ journalConvertAmountsToCost j -- enable cost basis adjustment
showBalanceReport [] nullfilterspec j' `is` showBalanceReport [] (balanceReport [] nullfilterspec j') `is`
unlines unlines
[" $500 a:b" [" $500 a:b"
," $-500 c:d" ," $-500 c:d"
@ -260,7 +260,7 @@ tests = TestList [
," test:a 1" ," test:a 1"
," test:b" ," test:b"
]) ])
showBalanceReport [] nullfilterspec l `is` showBalanceReport [] (balanceReport [] nullfilterspec l) `is`
unlines unlines
[" 1 test:a" [" 1 test:a"
," -1 test:b" ," -1 test:b"
@ -586,7 +586,7 @@ tests = TestList [
,"unicode in balance layout" ~: do ,"unicode in balance layout" ~: do
l <- readJournalWithOpts [] l <- readJournalWithOpts []
"2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n" "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n"
showBalanceReport [] (optsToFilterSpec [] [] t1) l `is` unlines showBalanceReport [] (balanceReport [] (optsToFilterSpec [] [] t1) l) `is` unlines
[" -100 актив:наличные" [" -100 актив:наличные"
," 100 расходы:покупки" ," 100 расходы:покупки"
,"--------------------" ,"--------------------"