diff --git a/hledger-lib/Hledger/Reports/BudgetReport.hs b/hledger-lib/Hledger/Reports/BudgetReport.hs index e37a56edc..996d1d69a 100644 --- a/hledger-lib/Hledger/Reports/BudgetReport.hs +++ b/hledger-lib/Hledger/Reports/BudgetReport.hs @@ -270,7 +270,7 @@ budgetReportAsText :: ReportOpts -> BudgetReport -> String budgetReportAsText ropts budgetr@(PeriodicReport ( _, rows, _)) = printf "Budget performance in %s:\n\n" (showDateSpan $ budgetReportSpan budgetr) ++ - tableAsText ropts showcell (budgetReportAsTable ropts budgetr) + tableAsText ropts showcell (maybetranspose $ budgetReportAsTable ropts budgetr) where actualwidth = maximum [ maybe 0 (length . showMixedAmountOneLineWithoutPrice) amt @@ -319,6 +319,9 @@ budgetReportAsText ropts budgetr@(PeriodicReport ( _, rows, _)) = -- don't show the budget amount in color, it messes up alignment showbudgetamt = showMixedAmountOneLineWithoutPrice + maybetranspose | transpose_ ropts = \(Table rh ch vals) -> Table ch rh (transpose vals) + | otherwise = id + -- | Build a 'Table' from a multi-column balance report. budgetReportAsTable :: ReportOpts -> BudgetReport -> Table String String (Maybe MixedAmount, Maybe MixedAmount) budgetReportAsTable diff --git a/hledger-lib/Hledger/Reports/ReportOptions.hs b/hledger-lib/Hledger/Reports/ReportOptions.hs index 17687b838..d33ac8e2b 100644 --- a/hledger-lib/Hledger/Reports/ReportOptions.hs +++ b/hledger-lib/Hledger/Reports/ReportOptions.hs @@ -112,6 +112,7 @@ data ReportOpts = ReportOpts { -- normally positive for a more conventional display. ,color_ :: Bool ,forecast_ :: Bool + ,transpose_ :: Bool } deriving (Show, Data, Typeable) instance Default ReportOpts where def = defreportopts @@ -144,6 +145,7 @@ defreportopts = ReportOpts def def def + def rawOptsToReportOpts :: RawOpts -> IO ReportOpts rawOptsToReportOpts rawopts = checkReportOpts <$> do @@ -176,6 +178,7 @@ rawOptsToReportOpts rawopts = checkReportOpts <$> do ,pretty_tables_ = boolopt "pretty-tables" rawopts' ,color_ = color ,forecast_ = boolopt "forecast" rawopts' + ,transpose_ = boolopt "transpose" rawopts' } -- | Do extra validation of raw option values, raising an error if there's a problem. diff --git a/hledger/Hledger/Cli/Commands/Balance.hs b/hledger/Hledger/Cli/Commands/Balance.hs index 2bf0af1c8..dd00eb106 100644 --- a/hledger/Hledger/Cli/Commands/Balance.hs +++ b/hledger/Hledger/Cli/Commands/Balance.hs @@ -291,6 +291,7 @@ balancemode = (defCommandMode $ ["balance"] ++ aliases) { -- also accept but don ,flagNone ["budget"] (setboolopt "budget") "show performance compared to budget goals defined by periodic transactions" ,flagNone ["show-unbudgeted"] (setboolopt "show-unbudgeted") "with --budget, show unbudgeted accounts also" ,flagNone ["invert"] (setboolopt "invert") "display all amounts with reversed sign" + ,flagNone ["transpose"] (setboolopt "transpose") "transpose rows and columns" ] ++ outputflags ,groupHidden = [] @@ -469,6 +470,7 @@ renderComponent1 opts (acctname, depth, total) (FormatField ljust min max field) -- and will include the final totals row unless --no-total is set. multiBalanceReportAsCsv :: ReportOpts -> MultiBalanceReport -> CSV multiBalanceReportAsCsv opts (MultiBalanceReport (colspans, items, (coltotals,tot,avg))) = + maybetranspose $ ("Account" : map showDateSpan colspans ++ (if row_total_ opts then ["Total"] else []) ++ (if average_ opts then ["Average"] else []) @@ -488,7 +490,10 @@ multiBalanceReportAsCsv opts (MultiBalanceReport (colspans, items, (coltotals,to ++ (if row_total_ opts then [tot] else []) ++ (if average_ opts then [avg] else []) )] - + where + maybetranspose | transpose_ opts = transpose + | otherwise = id + -- | Render a multi-column balance report as HTML. multiBalanceReportAsHtml :: ReportOpts -> MultiBalanceReport -> Html () multiBalanceReportAsHtml ropts mbr = @@ -505,7 +510,8 @@ multiBalanceReportAsHtml ropts mbr = multiBalanceReportHtmlRows :: ReportOpts -> MultiBalanceReport -> (Html (), [Html ()], Maybe (Html ())) multiBalanceReportHtmlRows ropts mbr = let - headingsrow:rest = multiBalanceReportAsCsv ropts mbr + headingsrow:rest | transpose_ ropts = error' "Sorry, --transpose is not supported with HTML output yet" + | otherwise = multiBalanceReportAsCsv ropts mbr (bodyrows, mtotalsrow) | no_total_ ropts = (rest, Nothing) | otherwise = (init rest, Just $ last rest) in @@ -592,6 +598,7 @@ multiBalanceReportAsText opts r = -- | Build a 'Table' from a multi-column balance report. balanceReportAsTable :: ReportOpts -> MultiBalanceReport -> Table String String MixedAmount balanceReportAsTable opts (MultiBalanceReport (colspans, items, (coltotals,tot,avg))) = + maybetranspose $ addtotalrow $ Table (T.Group NoLine $ map Header accts) @@ -617,7 +624,9 @@ balanceReportAsTable opts (MultiBalanceReport (colspans, items, (coltotals,tot,a ++ (if row_total_ opts && not (null coltotals) then [tot] else []) ++ (if average_ opts && not (null coltotals) then [avg] else []) )) - + maybetranspose | transpose_ opts = \(Table rh ch vals) -> Table ch rh (transpose vals) + | otherwise = id + -- | Given a table representing a multi-column balance report (for example, -- made using 'balanceReportAsTable'), render it in a format suitable for -- console output. diff --git a/hledger/hledger_balance.m4.md b/hledger/hledger_balance.m4.md index 2f45c05ff..ee8a79c43 100644 --- a/hledger/hledger_balance.m4.md +++ b/hledger/hledger_balance.m4.md @@ -38,6 +38,10 @@ Show accounts and their balances. Aliases: b, bal. : select the output format. Supported formats: txt, csv, html. +`--transpose` +: transposes rows and columns in multi-column reports. Supported formats: +txt, csv + `-o FILE --output-file=FILE` : write output to FILE. A file extension matching one of the above formats selects that format. diff --git a/tests/balance/transpose.test b/tests/balance/transpose.test new file mode 100644 index 000000000..2d4cb1f79 --- /dev/null +++ b/tests/balance/transpose.test @@ -0,0 +1,67 @@ +hledger -f balance-multicol.journal balance -M -A --transpose +>>> +Balance changes in 2012/12/01-2013/03/31: + + || assets assets:cash assets:checking | +=========++======================================+==== + Dec || 0 0 10 | 10 + Jan || 0 0 0 | 0 + Feb || 1 1 0 | 2 + Mar || 0 0 1 | 1 + Average || 0 0 3 | 3 +>>>=0 + +hledger -f balance-multicol.journal balance -M -A -O csv --transpose +>>> +"Account","assets","assets:cash","assets:checking","Total:" +"2012/12","0","0","10","10" +"2013/01","0","0","0","0" +"2013/02","1","1","0","2" +"2013/03","0","0","1","1" +"Average","0","0","3","3" +>>>=0 + + +hledger bal -D -b 2016-12-01 -e 2016-12-04 -f - --budget +<<< +2016/12/01 + expenses:food $10 + assets:cash + +2016/12/02 + expenses:food $9 + assets:cash + +2016/12/03 + expenses:food $11 + assets:cash + +2016/12/02 + expenses:leisure $5 + assets:cash + +2016/12/03 + expenses:movies $25 + assets:cash + +2016/12/03 + expenses:cab $15 + assets:cash + +~ daily from 2016/1/1 + expenses:food $10 + expenses:leisure $15 + assets:cash +>>> +Budget performance in 2016/12/01-2016/12/03: + + || 2016/12/01 2016/12/02 2016/12/03 +==================++================================================================== + assets || $-10 [ 40% of $-25] $-14 [ 56% of $-25] $-51 [ 204% of $-25] + assets:cash || $-10 [ 40% of $-25] $-14 [ 56% of $-25] $-51 [ 204% of $-25] + expenses || $10 [ 40% of $25] $14 [ 56% of $25] $51 [ 204% of $25] + expenses:food || $10 [ 100% of $10] $9 [ 90% of $10] $11 [ 110% of $10] + expenses:leisure || 0 [ 0% of $15] $5 [ 33% of $15] 0 [ 0% of $15] +------------------++------------------------------------------------------------------ + || 0 [ 0] 0 [ 0] 0 [ 0] +>>>=0