From 6c60e4a97b78d53e4a609222e04d2a8774502bb1 Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Tue, 23 Jan 2018 10:47:47 -0800 Subject: [PATCH] bs/cf/is: always show a tabular report, even with no report interval Previously, if you specified no report interval, the text output of these commands was a simple report like the original balance command, with amounts on the left and account names on the right. Also, balances used arithmetic sign like the balance command. Now it always draws a table, with account names in the left column, and shows balances with normal-positive sign, consistent with the multicolumn reports. Less code, fewer bugs. --- hledger/Hledger/Cli/Commands/Balance.hs | 2 +- hledger/Hledger/Cli/CompoundBalanceCommand.hs | 158 ++++++------------ tests/balancesheet/balancesheet.test | 80 +++++---- tests/cashflow/cashflow.test | 100 +++++------ tests/cli/multiple-files.test | 29 ++-- tests/incomestatement/incomestatement.test | 135 ++++++++------- 6 files changed, 229 insertions(+), 275 deletions(-) diff --git a/hledger/Hledger/Cli/Commands/Balance.hs b/hledger/Hledger/Cli/Commands/Balance.hs index 551ac26a2..0179b1962 100644 --- a/hledger/Hledger/Cli/Commands/Balance.hs +++ b/hledger/Hledger/Cli/Commands/Balance.hs @@ -313,7 +313,7 @@ balance opts@CliOpts{rawopts_=rawopts,reportopts_=ropts} j = do -- ie when there's a report interval, or when --historical or --cumulative -- are used (balanceReport doesn't handle those). -- Otherwise prefer the older balanceReport since it can elide boring parents. - -- See also compoundBalanceCommandSingleColumnReport, singleBalanceReport etc. + -- See also singleBalanceReport etc. case interval of NoInterval -> do let report diff --git a/hledger/Hledger/Cli/CompoundBalanceCommand.hs b/hledger/Hledger/Cli/CompoundBalanceCommand.hs index 469d1c34a..ff547ae5d 100644 --- a/hledger/Hledger/Cli/CompoundBalanceCommand.hs +++ b/hledger/Hledger/Cli/CompoundBalanceCommand.hs @@ -13,9 +13,8 @@ module Hledger.Cli.CompoundBalanceCommand ( ,compoundBalanceCommand ) where -import Data.List (intercalate, foldl') +import Data.List (foldl') import Data.Maybe (fromMaybe) -import Data.Monoid (Sum(..), (<>)) import qualified Data.Text as TS import qualified Data.Text.Lazy as TL import System.Console.CmdArgs.Explicit as C @@ -122,7 +121,7 @@ compoundBalanceCommandMode CompoundBalanceCommandSpec{..} = (defCommandMode $ cb -- | Generate a runnable command from a compound balance command specification. compoundBalanceCommand :: CompoundBalanceCommandSpec -> (CliOpts -> Journal -> IO ()) -compoundBalanceCommand CompoundBalanceCommandSpec{..} opts@CliOpts{command_=cmd, reportopts_=ropts, rawopts_=rawopts} j = do +compoundBalanceCommand CompoundBalanceCommandSpec{..} opts@CliOpts{reportopts_=ropts, rawopts_=rawopts} j = do d <- getCurrentDay let -- use the default balance type for this report, unless the user overrides @@ -147,7 +146,6 @@ compoundBalanceCommand CompoundBalanceCommandSpec{..} opts@CliOpts{command_=cmd, -- are used in single column mode, since in that situation we will be using -- singleBalanceReport which does not support eliding boring parents, -- and tree mode hides this.. or something.. - -- see also compoundBalanceCommandSingleColumnReport, #565 ropts' | not (flat_ ropts) && interval_ ropts==NoInterval && @@ -158,86 +156,58 @@ compoundBalanceCommand CompoundBalanceCommandSpec{..} opts@CliOpts{command_=cmd, userq = queryFromOpts d ropts' format = outputFormatFromOpts opts - case interval_ ropts' of + -- make a CompoundBalanceReport + subreports = + map (\CBCSubreportSpec{..} -> + (cbcsubreporttitle + ,mbrNormaliseSign cbcsubreportnormalsign $ -- <- convert normal-negative to normal-positive + compoundBalanceSubreport ropts' userq j cbcsubreportquery cbcsubreportnormalsign + -- ^ allow correct amount sorting + ,cbcsubreportincreasestotal + )) + cbcqueries + subtotalrows = + [(coltotals, increasesoveralltotal) + | (_, MultiBalanceReport (_,_,(coltotals,_,_)), increasesoveralltotal) <- subreports + ] + -- Sum the subreport totals by column. Handle these cases: + -- - no subreports + -- - empty subreports, having no subtotals (#588) + -- - subreports with a shorter subtotals row than the others + overalltotals = case subtotalrows of + [] -> ([], nullmixedamt, nullmixedamt) + rs -> + let + numcols = maximum $ map (length.fst) rs -- partial maximum is ok, rs is non-null + paddedsignedsubtotalrows = + [map (if increasesoveralltotal then id else negate) $ -- maybe flip the signs + take numcols $ as ++ repeat nullmixedamt -- pad short rows with zeros + | (as,increasesoveralltotal) <- rs + ] + coltotals = foldl' (zipWith (+)) zeros paddedsignedsubtotalrows -- sum the columns + where zeros = replicate numcols nullmixedamt + grandtotal = sum coltotals + grandavg | null coltotals = nullmixedamt + | otherwise = grandtotal `divideMixedAmount` fromIntegral (length coltotals) + in + (coltotals, grandtotal, grandavg) + colspans = + case subreports of + (_, MultiBalanceReport (ds,_,_), _):_ -> ds + [] -> [] + cbr = + (title + ,colspans + ,subreports + ,overalltotals + ) - -- single-column report - -- TODO refactor, support output format like multi column - -- TODO support sign normalisation ? - NoInterval -> do - let - -- concatenate the rendering and sum the totals from each subreport - (output, total) = - foldMap (compoundBalanceCommandSingleColumnReport ropts' userq j) cbcqueries - - writeOutput opts $ unlines $ - [title ++ "\n"] ++ - output ++ - if (no_total_ ropts' || cmd=="cashflow") - then [] - else - [ "Total:" - , "--------------------" - , padLeftWide 20 $ showamt (getSum total) - , "" - ] - where - showamt | color_ ropts' = cshowMixedAmountWithoutPrice - | otherwise = showMixedAmountWithoutPrice - - -- multi-column report - _ -> do - let - -- make a CompoundBalanceReport - subreports = - map (\CBCSubreportSpec{..} -> - (cbcsubreporttitle - ,mbrNormaliseSign cbcsubreportnormalsign $ -- <- convert normal-negative to normal-positive - compoundBalanceSubreport ropts' userq j cbcsubreportquery cbcsubreportnormalsign - -- ^ allow correct amount sorting - ,cbcsubreportincreasestotal - )) - cbcqueries - subtotalrows = - [(coltotals, increasesoveralltotal) - | (_, MultiBalanceReport (_,_,(coltotals,_,_)), increasesoveralltotal) <- subreports - ] - -- Sum the subreport totals by column. Handle these cases: - -- - no subreports - -- - empty subreports, having no subtotals (#588) - -- - subreports with a shorter subtotals row than the others - overalltotals = case subtotalrows of - [] -> ([], nullmixedamt, nullmixedamt) - rs -> - let - numcols = maximum $ map (length.fst) rs -- partial maximum is ok, rs is non-null - paddedsignedsubtotalrows = - [map (if increasesoveralltotal then id else negate) $ -- maybe flip the signs - take numcols $ as ++ repeat nullmixedamt -- pad short rows with zeros - | (as,increasesoveralltotal) <- rs - ] - coltotals = foldl' (zipWith (+)) zeros paddedsignedsubtotalrows -- sum the columns - where zeros = replicate numcols nullmixedamt - grandtotal = sum coltotals - grandavg | null coltotals = nullmixedamt - | otherwise = grandtotal `divideMixedAmount` fromIntegral (length coltotals) - in - (coltotals, grandtotal, grandavg) - colspans = - case subreports of - (_, MultiBalanceReport (ds,_,_), _):_ -> ds - [] -> [] - cbr = - (title - ,colspans - ,subreports - ,overalltotals - ) - -- render appropriately - writeOutput opts $ - case format of - "csv" -> printCSV (compoundBalanceReportAsCsv ropts cbr) ++ "\n" - "html" -> (++ "\n") $ TL.unpack $ L.renderText $ compoundBalanceReportAsHtml ropts cbr - _ -> compoundBalanceReportAsText ropts' cbr + -- render appropriately + writeOutput opts $ + case format of + "csv" -> printCSV (compoundBalanceReportAsCsv ropts cbr) ++ "\n" + "html" -> (++ "\n") $ TL.unpack $ L.renderText $ compoundBalanceReportAsHtml ropts cbr + _ -> compoundBalanceReportAsText ropts' cbr -- | Given a MultiBalanceReport and its normal balance sign, -- if it is known to be normally negative, convert it to normally positive. @@ -252,28 +222,6 @@ mbrNegate (MultiBalanceReport (colspans, rows, totalsrow)) = mbrRowNegate (acct,shortacct,indent,amts,tot,avg) = (acct,shortacct,indent,map negate amts,-tot,-avg) mbrTotalsRowNegate (amts,tot,avg) = (map negate amts,-tot,-avg) --- | Run one subreport for a compound balance command in single-column mode. --- Currently this returns the plain text rendering of the subreport, and its total. --- The latter is wrapped in a Sum for easy monoidal combining. -compoundBalanceCommandSingleColumnReport - :: ReportOpts - -> Query - -> Journal - -> CBCSubreportSpec - -> ([String], Sum MixedAmount) -compoundBalanceCommandSingleColumnReport ropts userq j CBCSubreportSpec{..} = - ([subreportstr], Sum total) - where - q = And [cbcsubreportquery j, userq] - ropts' = ropts{normalbalance_=Just cbcsubreportnormalsign} - r@(_,total) - -- XXX For --historical/--cumulative, we must use singleBalanceReport; - -- otherwise we use balanceReport -- because it supports eliding boring parents. - -- See also compoundBalanceCommand, Balance.hs -> balance. - | balancetype_ ropts `elem` [CumulativeChange, HistoricalBalance] = singleBalanceReport ropts' q j - | otherwise = balanceReport ropts' q j - subreportstr = intercalate "\n" [cbcsubreporttitle <> ":", balanceReportAsText ropts r] - -- | Run one subreport for a compound balance command in multi-column mode. -- This returns a MultiBalanceReport. compoundBalanceSubreport :: ReportOpts -> Query -> Journal -> (Journal -> Query) -> NormalSign -> MultiBalanceReport diff --git a/tests/balancesheet/balancesheet.test b/tests/balancesheet/balancesheet.test index 467eee96c..415df5dc5 100644 --- a/tests/balancesheet/balancesheet.test +++ b/tests/balancesheet/balancesheet.test @@ -7,18 +7,20 @@ hledger -f - balancesheet >>> Balance Sheet 2016/01/01 -Assets: - 1 assets --------------------- - 1 - -Liabilities: --------------------- - 0 - -Total: --------------------- - 1 + || 2016/01/01 +=============++============ + Assets || +-------------++------------ + assets || 1 +-------------++------------ + || 1 +=============++============ + Liabilities || +-------------++------------ +-------------++------------ + || +=============++============ + Net: || 1 >>>2 >>>= 0 @@ -150,19 +152,21 @@ hledger -f- balancesheet >>> Balance Sheet 2017/01/01 -Assets: - 1 assets - 1 b --------------------- - 1 - -Liabilities: --------------------- - 0 - -Total: --------------------- - 1 + || 2017/01/01 +=============++============ + Assets || +-------------++------------ + assets || 1 + b || 1 +-------------++------------ + || 1 +=============++============ + Liabilities || +-------------++------------ +-------------++------------ + || +=============++============ + Net: || 1 >>>2 >>>=0 @@ -175,18 +179,20 @@ hledger -f- balancesheet --flat >>> Balance Sheet 2017/01/01 -Assets: - 1 assets:b --------------------- - 1 - -Liabilities: --------------------- - 0 - -Total: --------------------- - 1 + || 2017/01/01 +=============++============ + Assets || +-------------++------------ + assets:b || 1 +-------------++------------ + || 1 +=============++============ + Liabilities || +-------------++------------ +-------------++------------ + || +=============++============ + Net: || 1 >>>2 >>>=0 diff --git a/tests/cashflow/cashflow.test b/tests/cashflow/cashflow.test index 87b73f812..692b376f6 100644 --- a/tests/cashflow/cashflow.test +++ b/tests/cashflow/cashflow.test @@ -7,10 +7,13 @@ hledger -f - cashflow >>> Cashflow Statement 2016/01/01 -Cash flows: - 1 assets --------------------- - 1 + || 2016/01/01 +============++============ + Cash flows || +------------++------------ + assets || 1 +------------++------------ + || 1 >>>2 >>>= 0 @@ -40,10 +43,13 @@ hledger -f - cashflow -b 2016 -e 2017 >>> Cashflow Statement 2016 -Cash flows: - $-40.00 assets:checking --------------------- - $-40.00 + || 2016 +=================++========= + Cash flows || +-----------------++--------- + assets:checking || $-40.00 +-----------------++--------- + || $-40.00 >>>2 >>>= 0 @@ -73,10 +79,13 @@ hledger -f - cashflow -b 2015 -e 2017 >>> Cashflow Statement 2015/01/01-2016/12/31 -Cash flows: - $9,960.00 assets:checking --------------------- - $9,960.00 + || 2015/01/01-2016/12/31 +=================++======================= + Cash flows || +-----------------++----------------------- + assets:checking || $9,960.00 +-----------------++----------------------- + || $9,960.00 >>>2 >>>= 0 @@ -106,10 +115,13 @@ hledger -f - cashflow -b 2015/11 -e 2015/12 >>> Cashflow Statement 2015/11 -Cash flows: - $10,000.00 assets:checking --------------------- - $10,000.00 + || 2015/11 +=================++============ + Cash flows || +-----------------++------------ + assets:checking || $10,000.00 +-----------------++------------ + || $10,000.00 >>>2 >>>= 0 @@ -139,9 +151,12 @@ hledger -f - cashflow -b 2016/10 -e 2016/11 >>> Cashflow Statement 2016/10 -Cash flows: --------------------- - 0 + || 2016/10 +============++========= + Cash flows || +------------++--------- +------------++--------- + || 0 >>>2 >>>= 0 @@ -180,37 +195,9 @@ Cashflow Statement 2008 (Historical Ending Balances) >>>= 0 -# 8. without -N/--no-total (single column) +# 8. without -N/--no-total hledger -f sample.journal cf >>> -Cashflow Statement 2008 - -Cash flows: - $-1 assets - $1 bank:saving - $-2 cash --------------------- - $-1 - ->>>2 ->>>= 0 - -# 9. with -N (single column) -hledger -f sample.journal cf -N ->>> -Cashflow Statement 2008 - -Cash flows: - $-1 assets - $1 bank:saving - $-2 cash - ->>>2 ->>>= 0 - -# 10. without -N (multi column) -hledger -f sample.journal cf -Y ->>> Cashflow Statement 2008 || 2008 @@ -225,8 +212,8 @@ Cashflow Statement 2008 >>>2 >>>= 0 -# 11. with -N (multi column) -hledger -f sample.journal cf -Y -N +# 9. with -N +hledger -f sample.journal cf -N >>> Cashflow Statement 2008 @@ -240,7 +227,7 @@ Cashflow Statement 2008 >>>2 >>>= 0 -# 12. exclude fixed assets from cashflow +# 10. exclude fixed assets from cashflow hledger -f - cashflow <<< 2016/1/1 @@ -253,10 +240,13 @@ hledger -f - cashflow >>> Cashflow Statement 2016/01/01 -Cash flows: - 1 assets --------------------- - 1 + || 2016/01/01 +============++============ + Cash flows || +------------++------------ + assets || 1 +------------++------------ + || 1 >>>2 >>>= 0 diff --git a/tests/cli/multiple-files.test b/tests/cli/multiple-files.test index 07a0be37e..83a7db3cb 100644 --- a/tests/cli/multiple-files.test +++ b/tests/cli/multiple-files.test @@ -3,20 +3,21 @@ hledger inc -f personal.journal -f business.journal >>> Income Statement 2014/01/01-2014/01/02 -Revenues: --------------------- - 0 - -Expenses: - $2 expenses - $1 food - $1 office supplies --------------------- - $2 - -Total: --------------------- - $2 + || 2014/01/01-2014/01/02 +==========================++======================= + Revenues || +--------------------------++----------------------- +--------------------------++----------------------- + || +==========================++======================= + Expenses || +--------------------------++----------------------- + expenses:food || $1 + expenses:office supplies || $1 +--------------------------++----------------------- + || $2 +==========================++======================= + Net: || $-2 >>>2 >>>=0 diff --git a/tests/incomestatement/incomestatement.test b/tests/incomestatement/incomestatement.test index b6bb53b13..5e18f19ba 100644 --- a/tests/incomestatement/incomestatement.test +++ b/tests/incomestatement/incomestatement.test @@ -7,18 +7,20 @@ hledger -f - incomestatement >>> Income Statement 2016/01/01 -Revenues: - 1 income --------------------- - 1 - -Expenses: --------------------- - 0 - -Total: --------------------- - 1 + || 2016/01/01 +==========++============ + Revenues || +----------++------------ + income || -1 +----------++------------ + || -1 +==========++============ + Expenses || +----------++------------ +----------++------------ + || +==========++============ + Net: || -1 >>>2 >>>= 0 @@ -48,19 +50,21 @@ hledger -f - incomestatement -b 2016 -e 2017 >>> Income Statement 2016 -Revenues: - $-10.00 revenue:clients:B --------------------- - $-10.00 - -Expenses: - $50.00 expense:hosting --------------------- - $50.00 - -Total: --------------------- - $40.00 + || 2016 +===================++========= + Revenues || +-------------------++--------- + revenue:clients:B || $10.00 +-------------------++--------- + || $10.00 +===================++========= + Expenses || +-------------------++--------- + expense:hosting || $50.00 +-------------------++--------- + || $50.00 +===================++========= + Net: || $-40.00 >>>2 >>>= 0 @@ -90,21 +94,22 @@ hledger -f - incomestatement -b 2015 -e 2017 >>> Income Statement 2015/01/01-2016/12/31 -Revenues: - $-10,010.00 revenue:clients - $-10,000.00 A - $-10.00 B --------------------- - $-10,010.00 - -Expenses: - $50.00 expense:hosting --------------------- - $50.00 - -Total: --------------------- - $-9,960.00 + || 2015/01/01-2016/12/31 +===================++======================= + Revenues || +-------------------++----------------------- + revenue:clients:A || $10,000.00 + revenue:clients:B || $10.00 +-------------------++----------------------- + || $10,010.00 +===================++======================= + Expenses || +-------------------++----------------------- + expense:hosting || $50.00 +-------------------++----------------------- + || $50.00 +===================++======================= + Net: || $9,960.00 >>>2 >>>= 0 @@ -134,18 +139,20 @@ hledger -f - incomestatement -b 2015/10 -e 2015/11 >>> Income Statement 2015/10 -Revenues: - $-10,000.00 revenue:clients:A --------------------- - $-10,000.00 - -Expenses: --------------------- - 0 - -Total: --------------------- - $-10,000.00 + || 2015/10 +===================++============ + Revenues || +-------------------++------------ + revenue:clients:A || $10,000.00 +-------------------++------------ + || $10,000.00 +===================++============ + Expenses || +-------------------++------------ +-------------------++------------ + || +===================++============ + Net: || $10,000.00 >>>2 >>>= 0 @@ -175,17 +182,19 @@ hledger -f - incomestatement -b 2016/10 -e 2016/11 >>> Income Statement 2016/10 -Revenues: --------------------- - 0 - -Expenses: --------------------- - 0 - -Total: --------------------- - 0 + || 2016/10 +==========++========= + Revenues || +----------++--------- +----------++--------- + || 0 +==========++========= + Expenses || +----------++--------- +----------++--------- + || 0 +==========++========= + Net: || 0 >>>2 >>>= 0