diff --git a/hledger-lib/Hledger/Reports/BudgetReport.hs b/hledger-lib/Hledger/Reports/BudgetReport.hs index cd5c12d33..475032b5d 100644 --- a/hledger-lib/Hledger/Reports/BudgetReport.hs +++ b/hledger-lib/Hledger/Reports/BudgetReport.hs @@ -18,6 +18,7 @@ module Hledger.Reports.BudgetReport ( budgetReport, budgetReportAsTable, budgetReportAsText, + budgetReportAsCsv, -- * Helpers reportPeriodName, -- * Tests @@ -44,12 +45,14 @@ import qualified Data.Text as T --import qualified Data.Text.Lazy as TL --import System.Console.CmdArgs.Explicit as C --import Lucid as L + import Text.Printf (printf) import Text.Tabular as T import Text.Tabular.AsciiWide as T import Hledger.Data import Hledger.Utils +import Hledger.Read.CsvReader (CSV) import Hledger.Reports.ReportOptions import Hledger.Reports.ReportTypes import Hledger.Reports.MultiBalanceReport @@ -335,6 +338,45 @@ reportPeriodName balancetype spans = multiyear = (>1) $ length $ nubSort $ map spanStartYear spans _ -> maybe "" (showDate . prevday) . spanEnd +-- XXX generalise this with multiBalanceReportAsCsv ? +-- | Render a budget report as CSV. Like multiBalanceReportAsCsv, +-- but includes alternating actual and budget amount columns. +budgetReportAsCsv :: ReportOpts -> BudgetReport -> CSV +budgetReportAsCsv + ReportOpts{average_, row_total_, no_total_, transpose_} + (PeriodicReport colspans items (PeriodicReportRow _ abtotals (magrandtot,mbgrandtot) (magrandavg,mbgrandavg))) + = (if transpose_ then transpose else id) $ + + -- heading row + ("Account" : + concatMap (\span -> [showDateSpan span, "budget"]) colspans + ++ concat [["Total" ,"budget"] | row_total_] + ++ concat [["Average","budget"] | average_] + ) : + + -- account rows + [T.unpack (displayFull a) : + map showmamt (flattentuples abamts) + ++ concat [[showmamt mactualrowtot, showmamt mbudgetrowtot] | row_total_] + ++ concat [[showmamt mactualrowavg, showmamt mbudgetrowavg] | average_] + | PeriodicReportRow a abamts (mactualrowtot,mbudgetrowtot) (mactualrowavg,mbudgetrowavg) <- items + ] + + -- totals row + ++ concat [ + [ + "Total:" : + map showmamt (flattentuples abtotals) + ++ concat [[showmamt magrandtot,showmamt mbgrandtot] | row_total_] + ++ concat [[showmamt magrandavg,showmamt mbgrandavg] | average_] + ] + | not no_total_ + ] + + where + flattentuples abs = concat [[a,b] | (a,b) <- abs] + showmamt = maybe "" (showMixedAmountOneLineWithoutPrice False) + -- tests tests_BudgetReport = tests "BudgetReport" [ diff --git a/hledger/Hledger/Cli/Commands/Balance.hs b/hledger/Hledger/Cli/Commands/Balance.hs index ed4fec0d5..48763aad8 100644 --- a/hledger/Hledger/Cli/Commands/Balance.hs +++ b/hledger/Hledger/Cli/Commands/Balance.hs @@ -273,6 +273,7 @@ import Hledger import Hledger.Cli.CliOptions import Hledger.Cli.Utils import Hledger.Read.CsvReader (CSV, printCSV) +import Hledger.Reports.BudgetReport (budgetReportAsCsv) -- | Command line options for this command. @@ -322,6 +323,7 @@ balance opts@CliOpts{rawopts_=rawopts,reportspec_=rspec} j = do render = case fmt of "txt" -> budgetReportAsText ropts "json" -> (++"\n") . TL.unpack . toJsonText + "csv" -> (++"\n") . printCSV . budgetReportAsCsv ropts _ -> const $ error' $ unsupportedOutputFormatError fmt writeOutput opts $ render budgetreport @@ -345,6 +347,10 @@ balance opts@CliOpts{rawopts_=rawopts,reportspec_=rspec} j = do _ -> const $ error' $ unsupportedOutputFormatError fmt -- PARTIAL: writeOutput opts $ render ropts report + +-- XXX should all the per-report, per-format rendering code live in the command module, +-- like the below, or in the report module, like budgetReportAsText/budgetReportAsCsv ? + -- rendering single-column balance reports -- | Render a single-column balance report as CSV. diff --git a/hledger/Hledger/Cli/Commands/Balance.md b/hledger/Hledger/Cli/Commands/Balance.md index f447f59bb..1110ab7a0 100644 --- a/hledger/Hledger/Cli/Commands/Balance.md +++ b/hledger/Hledger/Cli/Commands/Balance.md @@ -531,4 +531,4 @@ This command also supports the [output destination](hledger.html#output-destination) and [output format](hledger.html#output-format) options The output formats supported are -`txt`, `csv`, (multicolumn non-budget reports only) `html`, and (experimental) `json`. +`txt`, `csv`, `html`, and `json`. diff --git a/hledger/test/balance/budget.test b/hledger/test/balance/budget.test index fded9e5ed..a9fe0b0d9 100644 --- a/hledger/test/balance/budget.test +++ b/hledger/test/balance/budget.test @@ -515,7 +515,7 @@ Budget performance in 2019-01-01..2019-01-02: ------------------++------------------------ || 0 [ 0] -# 25. -E shows d +# 25. -E shows d and e $ hledger bal -f- --budget -E Budget performance in 2019-01-01..2019-01-02: @@ -532,3 +532,27 @@ Budget performance in 2019-01-01..2019-01-02: ------------------++------------------------ || 0 [ 0] +# 26. The totals row shows correct totals. +# -T/--total and -A/--average adds those columns. +$ hledger bal -f- --budget -TA not:income +Budget performance in 2019-01-01..2019-01-02: + + || 2019-01-01..2019-01-02 Total Average +==================++============================================================== + expenses:bills || $80 [22% of $370] $80 [22% of $370] $80 [22% of $370] + expenses:bills:a || $10 [50% of $20] $10 [50% of $20] $10 [50% of $20] + expenses:bills:b || $40 [20% of $200] $40 [20% of $200] $40 [20% of $200] + expenses:bills:c || 0 [ 0% of $50] 0 [ 0% of $50] 0 [ 0% of $50] + expenses:bills:f || $10 [ 0] $10 [ 0] $10 [ 0] +------------------++-------------------------------------------------------------- + || $80 [22% of $370] $80 [22% of $370] $80 [22% of $370] + +# 27. CSV output works. +$ hledger bal -f- --budget -TA not:income -O csv +"Account","2019-01-01..2019-01-02","budget","Total","budget","Average","budget" +"expenses:bills","$80","$370","$80","$370","$80","$370" +"expenses:bills:a","$10","$20","$10","$20","$10","$20" +"expenses:bills:b","$40","$200","$40","$200","$40","$200" +"expenses:bills:c","","$50","","$50","","$50" +"expenses:bills:f","$10","0","$10","0","$10","0" +"Total:","$80","$370","$80","$370","$80","$370"