balance: support CSV for multi-column balance reports

This commit is contained in:
Simon Michael 2014-10-23 05:11:48 -07:00
parent 9d1ef010ac
commit 21ed3dc73d
4 changed files with 49 additions and 30 deletions

View File

@ -242,11 +242,7 @@ module Hledger.Cli.Balance (
,tests_Hledger_Cli_Balance ,tests_Hledger_Cli_Balance
) where ) where
import Data.List
import Data.Maybe
-- import System.Console.CmdArgs
import System.Console.CmdArgs.Explicit as C import System.Console.CmdArgs.Explicit as C
-- import System.Console.CmdArgs.Text
import Text.CSV import Text.CSV
import Test.HUnit import Test.HUnit
import Text.Printf (printf) import Text.Printf (printf)
@ -254,8 +250,6 @@ import Text.Tabular as T
import Text.Tabular.AsciiArt import Text.Tabular.AsciiArt
import Hledger import Hledger
import Prelude hiding (putStr)
import Hledger.Utils.UTF8IOCompat (putStr)
import Hledger.Data.OutputFormat import Hledger.Data.OutputFormat
import Hledger.Cli.Options import Hledger.Cli.Options
import Hledger.Cli.Utils import Hledger.Cli.Utils
@ -287,34 +281,43 @@ balance :: CliOpts -> Journal -> IO ()
balance opts@CliOpts{reportopts_=ropts} j = do balance opts@CliOpts{reportopts_=ropts} j = do
d <- getCurrentDay d <- getCurrentDay
case lineFormatFromOpts ropts of case lineFormatFromOpts ropts of
Left err -> putStr $ unlines [err] Left err -> error' $ unlines [err]
Right _ -> do Right _ -> do
let fmt = outputFormatFromOpts opts let format = outputFormatFromOpts opts
case intervalFromOpts ropts of interval = intervalFromOpts ropts
baltype = balancetype_ ropts
case interval of
NoInterval -> do NoInterval -> do
let render | fmt=="csv" = \_ r -> printCSV (balanceReportAsCsv ropts r) ++ "\n" let report = balanceReport ropts (queryFromOpts d ropts) j
| otherwise = \ropts r -> unlines $ balanceReportAsText ropts r render = case format of
writeOutput opts $ render ropts $ balanceReport ropts (queryFromOpts d ropts) j "csv" -> \ropts r -> (++ "\n") $ printCSV $ balanceReportAsCsv ropts r
_ -> balanceReportAsText
_ -> writeOutput opts $ render ropts report
if fmt=="csv" _ -> do
then error' "Sorry, CSV output with a report period is not supported yet" let report = multiBalanceReport ropts (queryFromOpts d ropts) j
else do render = case format of
let render = case balancetype_ ropts of "csv" -> \ropts r -> (++ "\n") $ printCSV $ multiBalanceReportAsCsv ropts r
_ -> case baltype of
PeriodBalance -> periodBalanceReportAsText PeriodBalance -> periodBalanceReportAsText
CumulativeBalance -> cumulativeBalanceReportAsText CumulativeBalance -> cumulativeBalanceReportAsText
HistoricalBalance -> historicalBalanceReportAsText HistoricalBalance -> historicalBalanceReportAsText
writeOutput opts $ unlines $ render ropts $ multiBalanceReport ropts (queryFromOpts d ropts) j writeOutput opts $ render ropts report
-- single-column balance reports
-- | Render a single-column balance report as CSV. -- | Render a single-column balance report as CSV.
balanceReportAsCsv :: ReportOpts -> BalanceReport -> CSV balanceReportAsCsv :: ReportOpts -> BalanceReport -> CSV
balanceReportAsCsv _ (items,_) = balanceReportAsCsv opts (items, total) =
["account","balance"] : ["account","balance"] :
[[a, showMixedAmountWithoutPrice b] | ((a, _, _), b) <- items] [[a, showMixedAmountWithoutPrice b] | ((a, _, _), b) <- items]
++
if no_total_ opts
then []
else [["total", showMixedAmountOneLineWithoutPrice total]]
-- | Render a single-column balance report as plain text. -- | Render a single-column balance report as plain text.
balanceReportAsText :: ReportOpts -> BalanceReport -> [String] balanceReportAsText :: ReportOpts -> BalanceReport -> String
balanceReportAsText opts ((items, total)) = concat lines ++ t balanceReportAsText opts ((items, total)) = unlines $ concat lines ++ t
where where
lines = case lineFormatFromOpts opts of lines = case lineFormatFromOpts opts of
Right f -> map (balanceReportItemAsText opts f) items Right f -> map (balanceReportItemAsText opts f) items
@ -333,6 +336,7 @@ tests_balanceReportAsText = [
"2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n" "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n"
let opts = defreportopts let opts = defreportopts
balanceReportAsText opts (balanceReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is` balanceReportAsText opts (balanceReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is`
unlines
[" -100 актив:наличные" [" -100 актив:наличные"
," 100 расходы:покупки" ," 100 расходы:покупки"
,"--------------------" ,"--------------------"
@ -385,9 +389,22 @@ formatField opts accountName depth total ljust min max field = case field of
TotalField -> formatValue ljust min max $ showAmountWithoutPrice total TotalField -> formatValue ljust min max $ showAmountWithoutPrice total
_ -> "" _ -> ""
-- multi-column balance reports
-- | Render a multi-column balance report as CSV.
multiBalanceReportAsCsv :: ReportOpts -> MultiBalanceReport -> CSV
multiBalanceReportAsCsv opts (MultiBalanceReport (colspans, items, coltotals)) =
("account" : "short account" : "indent" : map showDateSpan colspans) :
[a : a' : show i : map showMixedAmountOneLineWithoutPrice amts | ((a,a',i), amts) <- items]
++
if no_total_ opts
then []
else [["totals", "", ""] ++ map showMixedAmountOneLineWithoutPrice coltotals]
-- | Render a multi-column period balance report as plain text suitable for console output. -- | Render a multi-column period balance report as plain text suitable for console output.
periodBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> [String] periodBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String
periodBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, coltotals)) = periodBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, coltotals)) =
unlines $
([printf "Balance changes in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $ ([printf "Balance changes in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $
trimborder $ lines $ trimborder $ lines $
render render
@ -413,8 +430,9 @@ periodBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, coltotals
| otherwise = row "" coltotals | otherwise = row "" coltotals
-- | Render a multi-column cumulative balance report as plain text suitable for console output. -- | Render a multi-column cumulative balance report as plain text suitable for console output.
cumulativeBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> [String] cumulativeBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String
cumulativeBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, coltotals)) = cumulativeBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, coltotals)) =
unlines $
([printf "Ending balances (cumulative) in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $ ([printf "Ending balances (cumulative) in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $
trimborder $ lines $ trimborder $ lines $
render id ((" "++) . maybe "" (showDate . prevday) . spanEnd) showMixedAmountOneLineWithoutPrice $ render id ((" "++) . maybe "" (showDate . prevday) . spanEnd) showMixedAmountOneLineWithoutPrice $
@ -434,8 +452,9 @@ cumulativeBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, colto
| otherwise = (+----+ row "" coltotals) | otherwise = (+----+ row "" coltotals)
-- | Render a multi-column historical balance report as plain text suitable for console output. -- | Render a multi-column historical balance report as plain text suitable for console output.
historicalBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> [String] historicalBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String
historicalBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, coltotals)) = historicalBalanceReportAsText opts r@(MultiBalanceReport (colspans, items, coltotals)) =
unlines $
([printf "Ending balances (historical) in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $ ([printf "Ending balances (historical) in %s:" (showDateSpan $ multiBalanceReportSpan r)] ++) $
trimborder $ lines $ trimborder $ lines $
render id ((" "++) . maybe "" (showDate . prevday) . spanEnd) showMixedAmountOneLineWithoutPrice $ render id ((" "++) . maybe "" (showDate . prevday) . spanEnd) showMixedAmountOneLineWithoutPrice $

View File

@ -47,9 +47,9 @@ balancesheet CliOpts{reportopts_=ropts} j = do
LT.putStr $ [lt|Balance Sheet LT.putStr $ [lt|Balance Sheet
Assets: Assets:
#{unlines $ balanceReportAsText ropts assetreport} #{balanceReportAsText ropts assetreport}
Liabilities: Liabilities:
#{unlines $ balanceReportAsText ropts liabilityreport} #{balanceReportAsText ropts liabilityreport}
Total: Total:
-------------------- --------------------
#{padleft 20 $ showMixedAmountWithoutPrice total} #{padleft 20 $ showMixedAmountWithoutPrice total}

View File

@ -51,7 +51,7 @@ cashflow CliOpts{reportopts_=ropts} j = do
LT.putStr $ [lt|Cashflow Statement LT.putStr $ [lt|Cashflow Statement
Cash flows: Cash flows:
#{unlines $ balanceReportAsText ropts cashreport} #{balanceReportAsText ropts cashreport}
Total: Total:
-------------------- --------------------
#{padleft 20 $ showMixedAmountWithoutPrice total} #{padleft 20 $ showMixedAmountWithoutPrice total}

View File

@ -46,9 +46,9 @@ incomestatement CliOpts{reportopts_=ropts} j = do
LT.putStr $ [lt|Income Statement LT.putStr $ [lt|Income Statement
Revenues: Revenues:
#{unlines $ balanceReportAsText ropts incomereport} #{balanceReportAsText ropts incomereport}
Expenses: Expenses:
#{unlines $ balanceReportAsText ropts expensereport} #{balanceReportAsText ropts expensereport}
Total: Total:
-------------------- --------------------
#{padleft 20 $ showMixedAmountWithoutPrice total} #{padleft 20 $ showMixedAmountWithoutPrice total}