elide boring accounts in balance report, like ledger

This commit is contained in:
Simon Michael 2007-02-19 21:20:06 +00:00
parent 6a55237836
commit c370d34de6
5 changed files with 73 additions and 61 deletions

View File

@ -47,52 +47,66 @@ addDataToAccountNameTree l ant =
where where
aname = antacctname ant aname = antacctname ant
showAccountTreeWithBalances :: Ledger -> Int -> Tree Account -> String -- would be straightforward except we want to elide boring accounts when
showAccountTreeWithBalances l depth at = (showAccountTreesWithBalances l depth) (branches at) -- displaying account trees:
-- a (0 txns, only 1 subacct)
showAccountTreesWithBalances :: Ledger -> Int -> [Tree Account] -> String -- b (another boring acct.)
showAccountTreesWithBalances _ 0 _ = "" -- c
showAccountTreesWithBalances l depth ats =
concatMap showAccountBranch ats
where
showAccountBranch :: Tree Account -> String
showAccountBranch at =
topacct ++ "\n" ++ subaccts
-- case boring of
-- True ->
-- False ->
where
topacct = (showAmount bal) ++ " " ++ (indentAccountName name)
showAmount amt = printf "%20s" (show amt)
name = aname $ atacct at
txns = atransactions $ atacct at
bal = abalance $ atacct at
subaccts = (showAccountTreesWithBalances l (depth - 1)) $ branches at
boring = (length txns == 0) && ((length subaccts) == 1)
-- we want to elide boring accounts in the account tree
--
-- a (2 txns)
-- b (boring acct - 0 txns, exactly 1 sub)
-- c (5 txns)
-- d -- d
-- to: -- becomes:
-- a (2 txns) -- a:b:c
-- b:c (5 txns) -- d
-- d showAccountTree :: Ledger -> Int -> Int -> Tree Account -> String
showAccountTree _ 0 _ _ = ""
showAccountTree l maxdepth indentlevel t
-- if this acct is boring, don't show it (unless this is as deep as we're going)
| (boringacct && (maxdepth > 1)) = subacctsindented 0
-- elideAccountTree at = at -- otherwise show normal indented account name with balance
-- if this acct has one or more boring parents, prepend their names
| otherwise =
bal ++ " " ++ indent ++ parentnames ++ leafname ++ "\n" ++ (subacctsindented 1)
elideAccountTree :: Tree Account -> Tree Account where
elideAccountTree = id boringacct = isBoringAccount2 l name
boringparents = takeWhile (isBoringAccount2 l) $ parentAccountNames name
bal = printf "%20s" $ show $ abalance $ atacct t
indent = replicate (indentlevel * 2) ' '
parentnames = concatMap (++ ":") $ map accountLeafName boringparents
leafname = accountLeafName name
name = aname $ atacct t
subacctsindented i =
case maxdepth > 1 of
True -> concatMap (showAccountTree l (maxdepth-1) (indentlevel+i)) $ branches t
False -> ""
isBoringAccount :: Tree Account -> Bool
isBoringAccount at =
(length txns == 0) && ((length subaccts) == 1) && (not $ name == "top")
where
a = atacct at
name = aname a
txns = atransactions a
subaccts = branches at
isBoringAccount2 :: Ledger -> AccountName -> Bool
isBoringAccount2 l a
| a == "top" = False
| (length txns == 0) && ((length subs) == 1) = True
| otherwise = False
where
txns = transactionsInAccountNamed l a
subs = subAccountNamesFrom (ledgerAccountNames l) a
ledgerAccountTree :: Ledger -> Tree Account ledgerAccountTree :: Ledger -> Tree Account
ledgerAccountTree l = elideAccountTree $ addDataToAccountNameTree l (ledgerAccountNameTree l) ledgerAccountTree l = addDataToAccountNameTree l (ledgerAccountNameTree l)
-- ledgerAccountTreeForAccount :: Ledger -> AccountName -> Tree Account
-- ledgerAccountTreeForAccount l a = addDataToAccountNameTree l (ledgerAccountNameTree l)
ledgerAccountsMatching :: Ledger -> [String] -> [Account] ledgerAccountsMatching :: Ledger -> [String] -> [Account]
ledgerAccountsMatching l acctpats = undefined ledgerAccountsMatching l acctpats = undefined
showLedgerAccounts :: Ledger -> Int -> String showLedgerAccounts :: Ledger -> Int -> String
showLedgerAccounts l depth = showLedgerAccounts l maxdepth =
showAccountTreeWithBalances l depth (ledgerAccountTree l) concatMap (showAccountTree l maxdepth 0) (branches (ledgerAccountTree l))

View File

@ -29,11 +29,15 @@ expandAccountNames as = nub $ concat $ map expand as
topAccountNames :: [AccountName] -> [AccountName] topAccountNames :: [AccountName] -> [AccountName]
topAccountNames as = [a | a <- expandAccountNames as, accountNameLevel a == 1] topAccountNames as = [a | a <- expandAccountNames as, accountNameLevel a == 1]
parentAccountName :: AccountName -> Maybe AccountName parentAccountName :: AccountName -> AccountName
parentAccountName a = parentAccountName a =
case accountNameLevel a > 1 of accountNameFromComponents $ rtail $ accountNameComponents a
True -> Just $ accountNameFromComponents $ rtail $ accountNameComponents a
False -> Nothing parentAccountNames :: AccountName -> [AccountName]
parentAccountNames a = parentAccountNames' $ parentAccountName a
where
parentAccountNames' "" = []
parentAccountNames' a = [a] ++ (parentAccountNames' $ parentAccountName a)
s `isSubAccountNameOf` p = s `isSubAccountNameOf` p =
((p ++ ":") `isPrefixOf` s) && (accountNameLevel s == (accountNameLevel p + 1)) ((p ++ ":") `isPrefixOf` s) && (accountNameLevel s == (accountNameLevel p + 1))
@ -47,8 +51,10 @@ matchAccountName s a =
Nothing -> False Nothing -> False
otherwise -> True otherwise -> True
indentAccountName :: AccountName -> String indentAccountName :: Int -> AccountName -> String
indentAccountName a = replicate (((accountNameLevel a) - 1) * 2) ' ' ++ (accountLeafName a) indentAccountName indentcorrection a =
replicate (indentlevel * 2) ' ' ++ (accountLeafName a)
where indentlevel = ((accountNameLevel a) - 1) + indentcorrection
-- We could almost get by with just the above, but we need smarter -- We could almost get by with just the above, but we need smarter
@ -75,14 +81,8 @@ accountNameTreeFrom accts =
subs = (subAccountNamesFrom accts) subs = (subAccountNamesFrom accts)
showAccountNameTree :: Tree AccountName -> String showAccountNameTree :: Tree AccountName -> String
showAccountNameTree at = showAccountNameTrees $ branches at showAccountNameTree t =
topacct ++ "\n" ++ concatMap showAccountNameTree (branches t)
showAccountNameTrees :: [Tree AccountName] -> String
showAccountNameTrees ats =
concatMap showAccountNameBranch ats
where where
showAccountNameBranch at = topacct ++ "\n" ++ subaccts topacct = indentAccountName 0 $ antacctname t
where
topacct = indentAccountName $ antacctname at
subaccts = showAccountNameTrees $ branches at

View File

@ -15,9 +15,9 @@ data Ledger = Ledger {
instance Show Ledger where instance Show Ledger where
show l = printf "Ledger with %d normal, %d modifier, %d periodic entries" show l = printf "Ledger with %d normal, %d modifier, %d periodic entries"
(show $ length $ modifier_entries l) (length $ modifier_entries l)
(show $ length $ periodic_entries l) (length $ periodic_entries l)
(show $ length $ entries l) (length $ entries l)
ledgerTransactions :: Ledger -> [EntryTransaction] ledgerTransactions :: Ledger -> [EntryTransaction]
ledgerTransactions l = entryTransactionsFrom $ entries l ledgerTransactions l = entryTransactionsFrom $ entries l

2
TODO
View File

@ -1,6 +1,4 @@
basic features basic features
balance
elide boring accounts
handle mixed amounts and currencies handle mixed amounts and currencies
print print
entry entry

View File

@ -4,7 +4,7 @@ hledger - ledger-compatible money management utilities (& haskell study)
GPLv3, (c) Simon Michael & contributors, GPLv3, (c) Simon Michael & contributors,
John Wiegley's ledger is at http://newartisans.com/ledger.html John Wiegley's ledger is at http://newartisans.com/ledger.html
The model/type/class hierarchy is roughly like this: modules/models are organized roughly like this:
hledger hledger
Options Options
@ -95,7 +95,7 @@ printBalance opts args ledger = do
-- False -> depthOption opts -- False -> depthOption opts
putStr $ case showsubs of putStr $ case showsubs of
True -> showLedgerAccounts ledger 999 True -> showLedgerAccounts ledger 999
False -> showLedgerAccounts ledger (getDepth opts) False -> showLedgerAccounts ledger 1
where where
showsubs = (ShowSubs `elem` opts) showsubs = (ShowSubs `elem` opts)
(acctpats,_) = ledgerPatternArgs args (acctpats,_) = ledgerPatternArgs args