diff --git a/hledger-lib/Hledger/Data/Account.hs b/hledger-lib/Hledger/Data/Account.hs index c98a75904..970439916 100644 --- a/hledger-lib/Hledger/Data/Account.hs +++ b/hledger-lib/Hledger/Data/Account.hs @@ -125,7 +125,7 @@ clipAccounts d a = a{asubs=subs} clipAccountsAndAggregate :: Int -> [Account] -> [Account] clipAccountsAndAggregate d as = combined where - clipped = [a{aname=clipAccountName d $ aname a} | a <- as] + clipped = [a{aname=clipOrEllipsifyAccountName d $ aname a} | a <- as] combined = [a{aebalance=sum (map aebalance same)} | same@(a:_) <- groupBy (\a1 a2 -> aname a1 == aname a2) clipped] {- diff --git a/hledger-lib/Hledger/Data/AccountName.hs b/hledger-lib/Hledger/Data/AccountName.hs index 2fa7c166c..ea61ca2c1 100644 --- a/hledger-lib/Hledger/Data/AccountName.hs +++ b/hledger-lib/Hledger/Data/AccountName.hs @@ -108,9 +108,17 @@ elideAccountName width s = | length ss > 1 = elideparts width (done++[take 2 $ head ss]) (tail ss) | otherwise = done++ss +-- | Keep only the first n components of an account name, where n +-- is a positive integer. If n is 0, returns the empty string. clipAccountName :: Int -> AccountName -> AccountName clipAccountName n = accountNameFromComponents . take n . accountNameComponents +-- | Keep only the first n components of an account name, where n +-- is a positive integer. If n is 0, returns "...". +clipOrEllipsifyAccountName :: Int -> AccountName -> AccountName +clipOrEllipsifyAccountName 0 = const "..." +clipOrEllipsifyAccountName n = accountNameFromComponents . take n . accountNameComponents + -- | Convert an account name to a regular expression matching it and its subaccounts. accountNameToAccountRegex :: String -> String accountNameToAccountRegex "" = "" diff --git a/hledger-lib/Hledger/Reports/BalanceReport.hs b/hledger-lib/Hledger/Reports/BalanceReport.hs index 6492379f3..020420984 100644 --- a/hledger-lib/Hledger/Reports/BalanceReport.hs +++ b/hledger-lib/Hledger/Reports/BalanceReport.hs @@ -67,6 +67,9 @@ balanceReport opts q j = (items, total) accts = ledgerRootAccount $ ledgerFromJournal q $ journalSelectingAmountFromOpts opts j accts' :: [Account] + | queryDepth q == 0 = + dbg "accts" $ + take 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts accts | flat_ opts = dbg "accts" $ filterzeros $ filterempty $ @@ -75,7 +78,8 @@ balanceReport opts q j = (items, total) filter (not.aboring) $ drop 1 $ flattenAccounts $ markboring $ - prunezeros $ clipAccounts (queryDepth q) accts + prunezeros $ + clipAccounts (queryDepth q) accts where balance = if flat_ opts then aebalance else aibalance filterzeros = if empty_ opts then id else filter (not . isZeroMixedAmount . balance) @@ -99,14 +103,18 @@ markBoringParentAccounts = tieAccountParents . mapAccounts mark | otherwise = a balanceReportItem :: ReportOpts -> Query -> Account -> BalanceReportItem -balanceReportItem opts _ a@Account{aname=name} +balanceReportItem opts q a | flat_ opts = ((name, name, 0), (if flatShowsExclusiveBalance then aebalance else aibalance) a) | otherwise = ((name, elidedname, indent), aibalance a) where + name | queryDepth q > 0 = aname a + | otherwise = "..." elidedname = accountNameFromComponents (adjacentboringparentnames ++ [accountLeafName name]) adjacentboringparentnames = reverse $ map (accountLeafName.aname) $ takeWhile aboring $ parents indent = length $ filter (not.aboring) parents - parents = init $ parentAccounts a + -- parents exclude the tree's root node + parents = case parentAccounts a of [] -> [] + as -> init as -- -- the above using the newer multi balance report code: -- balanceReport' opts q j = (items, total) diff --git a/hledger-lib/Hledger/Reports/MultiBalanceReports.hs b/hledger-lib/Hledger/Reports/MultiBalanceReports.hs index 9af2116d6..44fbaf7d0 100644 --- a/hledger-lib/Hledger/Reports/MultiBalanceReports.hs +++ b/hledger-lib/Hledger/Reports/MultiBalanceReports.hs @@ -129,7 +129,7 @@ multiBalanceReport opts q j = MultiBalanceReport (displayspans, items, totals) displayedAccts :: [ClippedAccountName] = dbg "displayedAccts" $ (if tree_ opts then expandAccountNames else id) $ - nub $ map (clipAccountName depth) $ + nub $ map (clipOrEllipsifyAccountName depth) $ if empty_ opts then nub $ sort $ startAccts ++ postedAccts else postedAccts acctBalChangesPerSpan :: [[(ClippedAccountName, MixedAmount)]] = @@ -150,7 +150,7 @@ multiBalanceReport opts q j = MultiBalanceReport (displayspans, items, totals) HistoricalBalance -> drop 1 $ scanl (+) (startingBalanceFor a) changes CumulativeBalance -> drop 1 $ scanl (+) nullmixedamt changes _ -> changes - , empty_ opts || any (not . isZeroMixedAmount) displayedBals + , empty_ opts || depth == 0 || any (not . isZeroMixedAmount) displayedBals ] totals :: [MixedAmount] = @@ -162,6 +162,6 @@ multiBalanceReport opts q j = MultiBalanceReport (displayspans, items, totals) dbg "highestlevelaccts" $ [a | a <- displayedAccts, not $ any (`elem` displayedAccts) $ init $ expandAccountName a] - dbg s = let p = "multiBalanceReport" in Hledger.Utils.dbg (p++" "++s) -- add prefix in debug output - -- dbg = const id -- exclude from debug output + dbg s = let p = "multiBalanceReport" in Hledger.Utils.dbg (p++" "++s) -- add prefix in this function's debug output + -- dbg = const id -- exclude this function from debug output diff --git a/hledger-lib/Hledger/Reports/PostingsReport.hs b/hledger-lib/Hledger/Reports/PostingsReport.hs index 3e657e7b7..cecb73826 100644 --- a/hledger-lib/Hledger/Reports/PostingsReport.hs +++ b/hledger-lib/Hledger/Reports/PostingsReport.hs @@ -85,7 +85,7 @@ postingsReport opts q j = (totallabel, items) whichdate = whichDateFromOpts opts itemps | interval == NoInterval = map (,Nothing) reportps | otherwise = summarisePostingsByInterval interval whichdate depth showempty reportspan reportps - items = postingsReportItems itemps (nullposting,Nothing) whichdate depth startbal runningcalc 1 + items = dbg "items" $ postingsReportItems itemps (nullposting,Nothing) whichdate depth startbal runningcalc 1 where startbal = if balancetype_ opts == HistoricalBalance then sumPostings precedingps else 0 runningcalc | average_ opts = \i avg amt -> avg + (amt - avg) `divideMixedAmount` (fromIntegral i) -- running average @@ -108,7 +108,7 @@ postingsReportItems ((p,menddate):ps) (pprev,menddateprev) wd d b runningcalcfn isfirstintxn = ptransaction p /= ptransaction pprev isdifferentdate = case wd of PrimaryDate -> postingDate p /= postingDate pprev SecondaryDate -> postingDate2 p /= postingDate2 pprev - p' = p{paccount=clipAccountName d $ paccount p} + p' = p{paccount= clipOrEllipsifyAccountName d $ paccount p} b' = runningcalcfn itemnum b (pamount p) -- | Generate one postings report line item, containing the posting, @@ -150,8 +150,10 @@ type SummaryPosting = (Posting, Maybe Day) -- postings within it, aggregate the postings into one summary posting per -- account. -- --- When a depth argument is present, postings to accounts of greater depth are --- also aggregated where possible. +-- When a depth argument is present, postings to accounts of greater +-- depth are also aggregated where possible. If the depth is 0, all +-- postings in the span are aggregated into a single posting with +-- account name "...". -- -- The showempty flag includes spans with no postings and also postings -- with 0 amount. @@ -166,8 +168,10 @@ summarisePostingsInDateSpan (DateSpan b e) wd depth showempty ps b' = fromMaybe (maybe nulldate postingdate $ headMay ps) b e' = fromMaybe (maybe (addDays 1 nulldate) postingdate $ lastMay ps) e summaryp = nullposting{pdate=Just b'} - clippedanames = nub $ map (clipAccountName depth) anames - summaryps = [summaryp{paccount=a,pamount=balance a} | a <- clippedanames] + clippedanames | depth > 0 = nub $ map (clipAccountName depth) anames + | otherwise = ["..."] + summaryps | depth > 0 = [summaryp{paccount=a,pamount=balance a} | a <- clippedanames] + | otherwise = [summaryp{paccount="...",pamount=sum $ map pamount ps}] summarypes = map (, Just e') $ (if showempty then id else filter (not . isZeroMixedAmount . pamount)) summaryps anames = sort $ nub $ map paccount ps -- aggregate balances by account, like ledgerFromJournal, then do depth-clipping diff --git a/tests/balance/depth.test b/tests/balance/depth.test index 7b970c498..e2f196c43 100644 --- a/tests/balance/depth.test +++ b/tests/balance/depth.test @@ -1,4 +1,4 @@ -# 1 +# 1. hledgerdev -f sample.journal balance --no-total --depth 1 >>> $-1 assets @@ -7,3 +7,22 @@ hledgerdev -f sample.journal balance --no-total --depth 1 $1 liabilities >>>=0 +# 2. Depth 0 aggregates everything into one line +hledgerdev -f sample.journal balance --no-total --depth 0 +>>> + 0 ... +>>>=0 + +# 3. Ditto in a multi-column balance report. +hledgerdev -f sample.journal balance -M -e 2008/4 --depth 0 +>>> +Balance changes in 2008/01: + + || 2008/01 +=====++========== + ... || 0 +-----++---------- + || 0 + +>>>=0 + diff --git a/tests/register/depth.test b/tests/register/depth.test index 19ea80c51..78dcd72cb 100644 --- a/tests/register/depth.test +++ b/tests/register/depth.test @@ -8,7 +8,7 @@ hledgerdev -f - register aa --depth 1 2010/01/01 x a 1 1 >>>=0 -# 2. similar to above, postings with same clipped account name are not aggregated +# 2. separate postings remain separate hledgerdev -f - register aa --depth 2 <<< 2010/1/1 x @@ -28,7 +28,7 @@ hledgerdev -f - register aa --depth 2 2010/01/02 z a:aa 1 3 >>>=0 -# 3. as above, but with a reporting interval causing postings to be aggregated +# 3. with a reporting interval, all postings are aggregated under each (clipped) account hledgerdev -f - register aa --depth 1 --daily <<< 2010/1/1 x @@ -56,3 +56,26 @@ hledgerdev -f - register a --depth 1 --cleared 2012/01/01 (a) 1 1 >>>2 >>>=0 + +# 5. depth 0 aggregates everything into a single line +hledgerdev -f - register --depth 0 --daily a b +<<< +2010/1/1 x + a:aa 1 + b:bb 2 + c:cc + +2010/1/1 y + a:aa 1 + b:bb 2 + c:cc + +2010/1/2 z + a:aa 1 + b:bb 2 + c:cc +>>> +2010/01/01d ... 6 6 +2010/01/02d ... 3 9 +>>>=0 +