{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Hledger.Cli.Commands.Balance (
balancemode
,balance
,balanceReportAsText
,balanceReportAsCsv
,balanceReportItemAsText
,multiBalanceRowAsCsvText
,multiBalanceRowAsTableText
,multiBalanceReportAsText
,multiBalanceReportAsCsv
,multiBalanceReportAsHtml
,multiBalanceReportHtmlRows
,multiBalanceReportHtmlFootRow
,balanceReportAsTable
,balanceReportTableAsText
,tests_Balance
) where
import Data.Default (def)
import Data.List (transpose, transpose)
import qualified Data.Set as S
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TB
import Data.Time (addDays, fromGregorian)
import System.Console.CmdArgs.Explicit as C
import Lucid as L hiding (value_)
import Safe (headMay, maximumMay)
import Text.Tabular.AsciiWide
(Align(..), Cell(..), Table(..), TableOpts(..), cellWidth, concatTables,
renderColumns, renderRowB, textCell)
import qualified Text.Tabular.AsciiWide as Tab
import Hledger
import Hledger.Cli.CliOptions
import Hledger.Cli.Utils
import Hledger.Read.CsvUtils (CSV, printCSV, printTSV)
balancemode :: Mode RawOpts
balancemode = CommandDoc
-> [Flag RawOpts]
-> [(CommandDoc, [Flag RawOpts])]
-> [Flag RawOpts]
-> ([Arg RawOpts], Maybe (Arg RawOpts))
-> Mode RawOpts
hledgerCommandMode
$(embedFileRelative "Hledger/Cli/Commands/Balance.txt")
(
[forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"sum"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"sum")
CommandDoc
"show sum of posting amounts (default)"
,forall a.
CommandDoc
-> [CommandDoc] -> Update a -> CommandDoc -> CommandDoc -> Flag a
flagOpt CommandDoc
"" [CommandDoc
"budget"] (\CommandDoc
s RawOpts
opts -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc -> RawOpts -> RawOpts
setopt CommandDoc
"budget" CommandDoc
s RawOpts
opts) CommandDoc
"DESCPAT"
([CommandDoc] -> CommandDoc
unlines
[ CommandDoc
"show sum of posting amounts together with budget goals defined by periodic"
, CommandDoc
"transactions. With a DESCPAT argument (must be separated by = not space),"
, CommandDoc
"use only periodic transactions with matching description"
, CommandDoc
"(case insensitive substring match)."
])
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"valuechange"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"valuechange")
CommandDoc
"show total change of value of period-end historical balances (caused by deposits, withdrawals, market price fluctuations)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"gain"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"gain")
CommandDoc
"show unrealised capital gain/loss (historical balance value minus cost basis)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"count"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"count") CommandDoc
"show the count of postings"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"change"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"change")
CommandDoc
"accumulate amounts from column start to column end (in multicolumn reports, default)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"cumulative"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"cumulative")
CommandDoc
"accumulate amounts from report start (specified by e.g. -b/--begin) to column end"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"historical",CommandDoc
"H"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"historical")
CommandDoc
"accumulate amounts from journal start to column end (includes postings before report start date)\n "
]
forall a. [a] -> [a] -> [a]
++ Bool -> [Flag RawOpts]
flattreeflags Bool
True forall a. [a] -> [a] -> [a]
++
[forall a.
[CommandDoc] -> Update a -> CommandDoc -> CommandDoc -> Flag a
flagReq [CommandDoc
"drop"] (\CommandDoc
s RawOpts
opts -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc -> RawOpts -> RawOpts
setopt CommandDoc
"drop" CommandDoc
s RawOpts
opts) CommandDoc
"N" CommandDoc
"omit N leading account name parts (in flat mode)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"declared"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"declared") CommandDoc
"include non-parent declared accounts (best used with -E)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"average",CommandDoc
"A"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"average") CommandDoc
"show a row average column (in multicolumn reports)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"related",CommandDoc
"r"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"related") CommandDoc
"show postings' siblings instead"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"row-total",CommandDoc
"T"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"row-total") CommandDoc
"show a row total column (in multicolumn reports)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"summary-only"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"summary-only") CommandDoc
"display only row summaries (e.g. row total, average) (in multicolumn reports)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"no-total",CommandDoc
"N"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"no-total") CommandDoc
"omit the final total row"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"no-elide"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"no-elide") CommandDoc
"don't squash boring parent accounts (in tree mode)"
,forall a.
[CommandDoc] -> Update a -> CommandDoc -> CommandDoc -> Flag a
flagReq [CommandDoc
"format"] (\CommandDoc
s RawOpts
opts -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc -> RawOpts -> RawOpts
setopt CommandDoc
"format" CommandDoc
s RawOpts
opts) CommandDoc
"FORMATSTR" CommandDoc
"use this custom line format (in simple reports)"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"sort-amount",CommandDoc
"S"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"sort-amount") CommandDoc
"sort by amount instead of account code/name (in flat mode). With multiple columns, sorts by the row total, or by row average if that is displayed."
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"percent", CommandDoc
"%"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"percent") CommandDoc
"express values in percentage of each column's total"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"invert"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"invert") CommandDoc
"display all amounts with reversed sign"
,forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"transpose"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"transpose") CommandDoc
"transpose rows and columns"
,forall a.
[CommandDoc] -> Update a -> CommandDoc -> CommandDoc -> Flag a
flagReq [CommandDoc
"layout"] (\CommandDoc
s RawOpts
opts -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc -> RawOpts -> RawOpts
setopt CommandDoc
"layout" CommandDoc
s RawOpts
opts) CommandDoc
"ARG"
([CommandDoc] -> CommandDoc
unlines
[CommandDoc
"how to lay out multi-commodity amounts and the overall table:"
,CommandDoc
"'wide[,WIDTH]': commodities on one line"
,CommandDoc
"'tall' : commodities on separate lines"
,CommandDoc
"'bare' : commodity symbols in one column"
,CommandDoc
"'tidy' : every attribute in its own column"
])
,[CommandDoc] -> Flag RawOpts
outputFormatFlag [CommandDoc
"txt",CommandDoc
"html",CommandDoc
"csv",CommandDoc
"tsv",CommandDoc
"json"]
,Flag RawOpts
outputFileFlag
]
)
[(CommandDoc, [Flag RawOpts])
generalflagsgroup1]
([Flag RawOpts]
hiddenflags forall a. [a] -> [a] -> [a]
++
[ forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"commodity-column"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"commodity-column")
CommandDoc
"show commodity symbols in a separate column, amounts as bare numbers, one row per commodity"
])
([], forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ CommandDoc -> Arg RawOpts
argsFlag CommandDoc
"[QUERY]")
balance :: CliOpts -> Journal -> IO ()
balance :: CliOpts -> Journal -> IO ()
balance opts :: CliOpts
opts@CliOpts{reportspec_ :: CliOpts -> ReportSpec
reportspec_=ReportSpec
rspec} Journal
j = case BalanceCalculation
balancecalc_ of
BalanceCalculation
CalcBudget -> do
let rspan :: DateSpan
rspan = forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ Journal -> ReportSpec -> (DateSpan, [DateSpan])
reportSpan Journal
j ReportSpec
rspec
budgetreport :: BudgetReport
budgetreport = forall a. HasAmounts a => Map Text AmountStyle -> a -> a
styleAmounts Map Text AmountStyle
styles forall a b. (a -> b) -> a -> b
$ ReportSpec -> BalancingOpts -> DateSpan -> Journal -> BudgetReport
budgetReport ReportSpec
rspec (InputOpts -> BalancingOpts
balancingopts_ forall a b. (a -> b) -> a -> b
$ CliOpts -> InputOpts
inputopts_ CliOpts
opts) DateSpan
rspan Journal
j
render :: BudgetReport -> Text
render = case CommandDoc
fmt of
CommandDoc
"txt" -> ReportOpts -> BudgetReport -> Text
budgetReportAsText ReportOpts
ropts
CommandDoc
"json" -> (forall a. Semigroup a => a -> a -> a
<>Text
"\n") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToJSON a => a -> Text
toJsonText
CommandDoc
"csv" -> [CsvRecord] -> Text
printCSV forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportOpts -> BudgetReport -> [CsvRecord]
budgetReportAsCsv ReportOpts
ropts
CommandDoc
"tsv" -> [CsvRecord] -> Text
printTSV forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportOpts -> BudgetReport -> [CsvRecord]
budgetReportAsCsv ReportOpts
ropts
CommandDoc
_ -> forall a. CommandDoc -> a
error' forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc
unsupportedOutputFormatError CommandDoc
fmt
CliOpts -> Text -> IO ()
writeOutputLazyText CliOpts
opts forall a b. (a -> b) -> a -> b
$ BudgetReport -> Text
render BudgetReport
budgetreport
BalanceCalculation
_ | Bool
multiperiod -> do
let report :: MultiBalanceReport
report = forall a. HasAmounts a => Map Text AmountStyle -> a -> a
styleAmounts Map Text AmountStyle
styles forall a b. (a -> b) -> a -> b
$ ReportSpec -> Journal -> MultiBalanceReport
multiBalanceReport ReportSpec
rspec Journal
j
render :: MultiBalanceReport -> Text
render = case CommandDoc
fmt of
CommandDoc
"txt" -> ReportOpts -> MultiBalanceReport -> Text
multiBalanceReportAsText ReportOpts
ropts
CommandDoc
"csv" -> [CsvRecord] -> Text
printCSV forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportOpts -> MultiBalanceReport -> [CsvRecord]
multiBalanceReportAsCsv ReportOpts
ropts
CommandDoc
"tsv" -> [CsvRecord] -> Text
printTSV forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportOpts -> MultiBalanceReport -> [CsvRecord]
multiBalanceReportAsCsv ReportOpts
ropts
CommandDoc
"html" -> (forall a. Semigroup a => a -> a -> a
<>Text
"\n") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Html a -> Text
L.renderText forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportOpts -> MultiBalanceReport -> Html ()
multiBalanceReportAsHtml ReportOpts
ropts
CommandDoc
"json" -> (forall a. Semigroup a => a -> a -> a
<>Text
"\n") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToJSON a => a -> Text
toJsonText
CommandDoc
_ -> forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a. CommandDoc -> a
error' forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc
unsupportedOutputFormatError CommandDoc
fmt
CliOpts -> Text -> IO ()
writeOutputLazyText CliOpts
opts forall a b. (a -> b) -> a -> b
$ MultiBalanceReport -> Text
render MultiBalanceReport
report
BalanceCalculation
_ -> do
let report :: BalanceReport
report = forall a. HasAmounts a => Map Text AmountStyle -> a -> a
styleAmounts Map Text AmountStyle
styles forall a b. (a -> b) -> a -> b
$ ReportSpec -> Journal -> BalanceReport
balanceReport ReportSpec
rspec Journal
j
render :: ReportOpts -> BalanceReport -> Text
render = case CommandDoc
fmt of
CommandDoc
"txt" -> \ReportOpts
ropts1 -> Builder -> Text
TB.toLazyText forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportOpts -> BalanceReport -> Builder
balanceReportAsText ReportOpts
ropts1
CommandDoc
"csv" -> \ReportOpts
ropts1 -> [CsvRecord] -> Text
printCSV forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportOpts -> BalanceReport -> [CsvRecord]
balanceReportAsCsv ReportOpts
ropts1
CommandDoc
"tsv" -> \ReportOpts
ropts1 -> [CsvRecord] -> Text
printTSV forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportOpts -> BalanceReport -> [CsvRecord]
balanceReportAsCsv ReportOpts
ropts1
CommandDoc
"json" -> forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ (forall a. Semigroup a => a -> a -> a
<>Text
"\n") forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToJSON a => a -> Text
toJsonText
CommandDoc
_ -> forall a. CommandDoc -> a
error' forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc
unsupportedOutputFormatError CommandDoc
fmt
CliOpts -> Text -> IO ()
writeOutputLazyText CliOpts
opts forall a b. (a -> b) -> a -> b
$ ReportOpts -> BalanceReport -> Text
render ReportOpts
ropts BalanceReport
report
where
styles :: Map Text AmountStyle
styles = Rounding -> Journal -> Map Text AmountStyle
journalCommodityStylesWith Rounding
HardRounding Journal
j
ropts :: ReportOpts
ropts@ReportOpts{Bool
Int
CsvRecord
[Status]
Maybe Int
Maybe Text
Maybe ConversionOp
Maybe ValuationType
Maybe NormalSign
BalanceCalculation
BalanceAccumulation
AccountListMode
Layout
StringFormat
Period
Interval
period_ :: ReportOpts -> Period
interval_ :: ReportOpts -> Interval
statuses_ :: ReportOpts -> [Status]
conversionop_ :: ReportOpts -> Maybe ConversionOp
value_ :: ReportOpts -> Maybe ValuationType
infer_prices_ :: ReportOpts -> Bool
depth_ :: ReportOpts -> Maybe Int
date2_ :: ReportOpts -> Bool
empty_ :: ReportOpts -> Bool
no_elide_ :: ReportOpts -> Bool
real_ :: ReportOpts -> Bool
format_ :: ReportOpts -> StringFormat
pretty_ :: ReportOpts -> Bool
querystring_ :: ReportOpts -> CsvRecord
average_ :: ReportOpts -> Bool
related_ :: ReportOpts -> Bool
txn_dates_ :: ReportOpts -> Bool
balancecalc_ :: ReportOpts -> BalanceCalculation
balanceaccum_ :: ReportOpts -> BalanceAccumulation
budgetpat_ :: ReportOpts -> Maybe Text
accountlistmode_ :: ReportOpts -> AccountListMode
drop_ :: ReportOpts -> Int
declared_ :: ReportOpts -> Bool
row_total_ :: ReportOpts -> Bool
no_total_ :: ReportOpts -> Bool
summary_only_ :: ReportOpts -> Bool
show_costs_ :: ReportOpts -> Bool
sort_amount_ :: ReportOpts -> Bool
percent_ :: ReportOpts -> Bool
invert_ :: ReportOpts -> Bool
normalbalance_ :: ReportOpts -> Maybe NormalSign
color_ :: ReportOpts -> Bool
transpose_ :: ReportOpts -> Bool
layout_ :: ReportOpts -> Layout
layout_ :: Layout
transpose_ :: Bool
color_ :: Bool
normalbalance_ :: Maybe NormalSign
invert_ :: Bool
percent_ :: Bool
sort_amount_ :: Bool
show_costs_ :: Bool
summary_only_ :: Bool
no_total_ :: Bool
row_total_ :: Bool
declared_ :: Bool
drop_ :: Int
accountlistmode_ :: AccountListMode
budgetpat_ :: Maybe Text
balanceaccum_ :: BalanceAccumulation
txn_dates_ :: Bool
related_ :: Bool
average_ :: Bool
querystring_ :: CsvRecord
pretty_ :: Bool
format_ :: StringFormat
real_ :: Bool
no_elide_ :: Bool
empty_ :: Bool
date2_ :: Bool
depth_ :: Maybe Int
infer_prices_ :: Bool
value_ :: Maybe ValuationType
conversionop_ :: Maybe ConversionOp
statuses_ :: [Status]
interval_ :: Interval
period_ :: Period
balancecalc_ :: BalanceCalculation
..} = ReportSpec -> ReportOpts
_rsReportOpts ReportSpec
rspec
multiperiod :: Bool
multiperiod = Interval
interval_ forall a. Eq a => a -> a -> Bool
/= Interval
NoInterval Bool -> Bool -> Bool
|| (Layout
layout_ forall a. Eq a => a -> a -> Bool
== Layout
LayoutTidy Bool -> Bool -> Bool
&& Bool
delimited)
delimited :: Bool
delimited = CommandDoc
fmt forall a. Eq a => a -> a -> Bool
== CommandDoc
"csv" Bool -> Bool -> Bool
|| CommandDoc
fmt forall a. Eq a => a -> a -> Bool
== CommandDoc
"tsv"
fmt :: CommandDoc
fmt = CliOpts -> CommandDoc
outputFormatFromOpts CliOpts
opts
balanceReportAsCsv :: ReportOpts -> BalanceReport -> CSV
balanceReportAsCsv :: ReportOpts -> BalanceReport -> [CsvRecord]
balanceReportAsCsv ReportOpts
opts ([BalanceReportItem]
items, Change
total) =
CsvRecord
headers forall a. a -> [a] -> [a]
: forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\(Text
a, Text
_, Int
_, Change
b) -> Text -> Change -> [CsvRecord]
rows Text
a Change
b) [BalanceReportItem]
items forall a. [a] -> [a] -> [a]
++ if ReportOpts -> Bool
no_total_ ReportOpts
opts then [] else Text -> Change -> [CsvRecord]
rows Text
"total" Change
total
where
headers :: CsvRecord
headers = Text
"account" forall a. a -> [a] -> [a]
: case ReportOpts -> Layout
layout_ ReportOpts
opts of
Layout
LayoutBare -> [Text
"commodity", Text
"balance"]
Layout
_ -> [Text
"balance"]
rows :: AccountName -> MixedAmount -> [[T.Text]]
rows :: Text -> Change -> [CsvRecord]
rows Text
name Change
ma = case ReportOpts -> Layout
layout_ ReportOpts
opts of
Layout
LayoutBare ->
forall a b. (a -> b) -> [a] -> [b]
map (\Amount
a -> [Text -> Text
showName Text
name, Amount -> Text
acommodity Amount
a, Change -> Text
renderAmount forall a b. (a -> b) -> a -> b
$ Amount -> Change
mixedAmount Amount
a])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Change -> [Amount]
amounts forall a b. (a -> b) -> a -> b
$ Change -> Change
mixedAmountStripPrices Change
ma
Layout
_ -> [[Text -> Text
showName Text
name, Change -> Text
renderAmount Change
ma]]
showName :: Text -> Text
showName = Int -> Text -> Text
accountNameDrop (ReportOpts -> Int
drop_ ReportOpts
opts)
renderAmount :: Change -> Text
renderAmount Change
amt = WideBuilder -> Text
wbToText forall a b. (a -> b) -> a -> b
$ AmountDisplayOpts -> Change -> WideBuilder
showMixedAmountB AmountDisplayOpts
bopts Change
amt
where
bopts :: AmountDisplayOpts
bopts = AmountDisplayOpts
csvDisplay{displayCommodity :: Bool
displayCommodity=Bool
showcomm, displayCommodityOrder :: Maybe CsvRecord
displayCommodityOrder = Maybe CsvRecord
commorder}
(Bool
showcomm, Maybe CsvRecord
commorder)
| ReportOpts -> Layout
layout_ ReportOpts
opts forall a. Eq a => a -> a -> Bool
== Layout
LayoutBare = (Bool
False, forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Set a -> [a]
S.toList forall a b. (a -> b) -> a -> b
$ Change -> Set Text
maCommodities Change
amt)
| Bool
otherwise = (Bool
True, forall a. Maybe a
Nothing)
balanceReportAsText :: ReportOpts -> BalanceReport -> TB.Builder
balanceReportAsText :: ReportOpts -> BalanceReport -> Builder
balanceReportAsText ReportOpts
opts (([BalanceReportItem]
items, Change
total)) = case ReportOpts -> Layout
layout_ ReportOpts
opts of
Layout
LayoutBare | Bool
iscustom -> forall a. CommandDoc -> a
error' CommandDoc
"Custom format not supported with commodity columns"
Layout
LayoutBare -> ReportOpts -> BalanceReport -> Builder
balanceReportAsText' ReportOpts
opts (([BalanceReportItem]
items, Change
total))
Layout
_ -> [Builder] -> Builder
unlinesB [Builder]
ls forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
unlinesB (if ReportOpts -> Bool
no_total_ ReportOpts
opts then [] else [Builder
overline, Builder
totalLines])
where
([Builder]
ls, [[Int]]
sizes) = forall a b. [(a, b)] -> ([a], [b])
unzip forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (ReportOpts -> BalanceReportItem -> (Builder, [Int])
balanceReportItemAsText ReportOpts
opts) [BalanceReportItem]
items
(Builder
totalLines, [Int]
_) = ReportOpts -> (Text, Int, Change) -> (Builder, [Int])
renderBalanceReportItem ReportOpts
opts (Text
"",Int
0,Change
total)
iscustom :: Bool
iscustom = case ReportOpts -> StringFormat
format_ ReportOpts
opts of
OneLine ((FormatField Bool
_ Maybe Int
_ Maybe Int
_ ReportItemField
TotalField):[StringFormatComponent]
_) -> Bool
False
TopAligned ((FormatField Bool
_ Maybe Int
_ Maybe Int
_ ReportItemField
TotalField):[StringFormatComponent]
_) -> Bool
False
BottomAligned ((FormatField Bool
_ Maybe Int
_ Maybe Int
_ ReportItemField
TotalField):[StringFormatComponent]
_) -> Bool
False
StringFormat
_ -> Bool
True
overlinewidth :: Int
overlinewidth = if Bool
iscustom then forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (forall a b. (a -> b) -> [a] -> [b]
map forall a. Integral a => [a] -> a
maximum' forall a b. (a -> b) -> a -> b
$ forall a. [[a]] -> [[a]]
transpose [[Int]]
sizes) else Int
20
overline :: Builder
overline = Text -> Builder
TB.fromText forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
T.replicate Int
overlinewidth Text
"-"
balanceReportAsText' :: ReportOpts -> BalanceReport -> TB.Builder
balanceReportAsText' :: ReportOpts -> BalanceReport -> Builder
balanceReportAsText' ReportOpts
opts (([BalanceReportItem]
items, Change
total)) =
[Builder] -> Builder
unlinesB forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (TableOpts -> [Int] -> Header Cell -> Builder
renderColumns forall a. Default a => a
def{tableBorders :: Bool
tableBorders=Bool
False} [Int]
sizes forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall h. Properties -> [Header h] -> Header h
Tab.Group Properties
Tab.NoLine forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall h. h -> Header h
Tab.Header) forall a b. (a -> b) -> a -> b
$
[[Cell]]
ls forall a. [a] -> [a] -> [a]
++ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[[Cell
overline], [Cell]
totalline] | Bool -> Bool
not (ReportOpts -> Bool
no_total_ ReportOpts
opts)]
where
render :: (a, Text, Int, Change) -> [Cell]
render (a
_, Text
acctname, Int
dep, Change
amt) =
[ Align -> [WideBuilder] -> Cell
Cell Align
TopRight [WideBuilder]
damts
, Align -> [WideBuilder] -> Cell
Cell Align
TopLeft (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> WideBuilder
wbFromText CsvRecord
cs)
, Align -> [WideBuilder] -> Cell
Cell Align
TopLeft (forall a. Int -> a -> [a]
replicate (forall (t :: * -> *) a. Foldable t => t a -> Int
length [WideBuilder]
damts forall a. Num a => a -> a -> a
- Int
1) forall a. Monoid a => a
mempty forall a. [a] -> [a] -> [a]
++ [Text -> WideBuilder
wbFromText Text
dispname]) ]
where dopts :: AmountDisplayOpts
dopts = AmountDisplayOpts
oneLine{displayCommodity :: Bool
displayCommodity=ReportOpts -> Layout
layout_ ReportOpts
opts forall a. Eq a => a -> a -> Bool
/= Layout
LayoutBare, displayCommodityOrder :: Maybe CsvRecord
displayCommodityOrder=forall a. a -> Maybe a
Just CsvRecord
cs, displayColour :: Bool
displayColour=ReportOpts -> Bool
color_ ReportOpts
opts}
cs :: CsvRecord
cs = if Change -> Bool
mixedAmountLooksZero Change
amt then [Text
""] else forall a. Set a -> [a]
S.toList forall a b. (a -> b) -> a -> b
$ Change -> Set Text
maCommodities Change
amt
dispname :: Text
dispname = Int -> Text -> Text
T.replicate ((Int
dep forall a. Num a => a -> a -> a
- Int
1) forall a. Num a => a -> a -> a
* Int
2) Text
" " forall a. Semigroup a => a -> a -> a
<> Text
acctname
damts :: [WideBuilder]
damts = AmountDisplayOpts -> Change -> [WideBuilder]
showMixedAmountLinesB AmountDisplayOpts
dopts Change
amt
ls :: [[Cell]]
ls = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall {a}. (a, Text, Int, Change) -> [Cell]
render [BalanceReportItem]
items
totalline :: [Cell]
totalline = forall {a}. (a, Text, Int, Change) -> [Cell]
render (CommandDoc
"", Text
"", Int
0, Change
total)
sizes :: [Int]
sizes = forall a. a -> Maybe a -> a
fromMaybe Int
0 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Ord a => [a] -> Maybe a
maximumMay forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Cell -> Int
cellWidth forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
forall a. [[a]] -> [[a]]
transpose ([[Cell]
totalline | Bool -> Bool
not (ReportOpts -> Bool
no_total_ ReportOpts
opts)] forall a. [a] -> [a] -> [a]
++ [[Cell]]
ls)
overline :: Cell
overline = Align -> [WideBuilder] -> Cell
Cell Align
TopLeft forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> WideBuilder
wbFromText forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> Text -> Text
T.replicate Text
"-" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a -> a
fromMaybe Int
0 forall a b. (a -> b) -> a -> b
$ forall a. [a] -> Maybe a
headMay [Int]
sizes
balanceReportItemAsText :: ReportOpts -> BalanceReportItem -> (TB.Builder, [Int])
balanceReportItemAsText :: ReportOpts -> BalanceReportItem -> (Builder, [Int])
balanceReportItemAsText ReportOpts
opts (Text
_, Text
accountName, Int
dep, Change
amt) =
ReportOpts -> (Text, Int, Change) -> (Builder, [Int])
renderBalanceReportItem ReportOpts
opts (Text
accountName, Int
dep, Change
amt)
renderBalanceReportItem :: ReportOpts -> (AccountName, Int, MixedAmount) -> (TB.Builder, [Int])
renderBalanceReportItem :: ReportOpts -> (Text, Int, Change) -> (Builder, [Int])
renderBalanceReportItem ReportOpts
opts (Text
acctname, Int
dep, Change
total) =
case ReportOpts -> StringFormat
format_ ReportOpts
opts of
OneLine [StringFormatComponent]
comps -> [Cell] -> (Builder, [Int])
renderRow' forall a b. (a -> b) -> a -> b
$ Bool -> Bool -> [StringFormatComponent] -> [Cell]
render Bool
True Bool
True [StringFormatComponent]
comps
TopAligned [StringFormatComponent]
comps -> [Cell] -> (Builder, [Int])
renderRow' forall a b. (a -> b) -> a -> b
$ Bool -> Bool -> [StringFormatComponent] -> [Cell]
render Bool
True Bool
False [StringFormatComponent]
comps
BottomAligned [StringFormatComponent]
comps -> [Cell] -> (Builder, [Int])
renderRow' forall a b. (a -> b) -> a -> b
$ Bool -> Bool -> [StringFormatComponent] -> [Cell]
render Bool
False Bool
False [StringFormatComponent]
comps
where
renderRow' :: [Cell] -> (Builder, [Int])
renderRow' [Cell]
is = ( TableOpts -> Header Cell -> Builder
renderRowB forall a. Default a => a
def{tableBorders :: Bool
tableBorders=Bool
False, borderSpaces :: Bool
borderSpaces=Bool
False}
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall h. Properties -> [Header h] -> Header h
Tab.Group Properties
Tab.NoLine forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall h. h -> Header h
Tab.Header [Cell]
is
, forall a b. (a -> b) -> [a] -> [b]
map Cell -> Int
cellWidth [Cell]
is )
render :: Bool -> Bool -> [StringFormatComponent] -> [Cell]
render Bool
topaligned Bool
oneline = forall a b. (a -> b) -> [a] -> [b]
map (Bool
-> Bool
-> ReportOpts
-> (Text, Int, Change)
-> StringFormatComponent
-> Cell
renderComponent Bool
topaligned Bool
oneline ReportOpts
opts (Text
acctname, Int
dep, Change
total))
renderComponent :: Bool -> Bool -> ReportOpts -> (AccountName, Int, MixedAmount) -> StringFormatComponent -> Cell
renderComponent :: Bool
-> Bool
-> ReportOpts
-> (Text, Int, Change)
-> StringFormatComponent
-> Cell
renderComponent Bool
_ Bool
_ ReportOpts
_ (Text, Int, Change)
_ (FormatLiteral Text
s) = Align -> Text -> Cell
textCell Align
TopLeft Text
s
renderComponent Bool
topaligned Bool
oneline ReportOpts
opts (Text
acctname, Int
dep, Change
total) (FormatField Bool
ljust Maybe Int
mmin Maybe Int
mmax ReportItemField
field) = case ReportItemField
field of
ReportItemField
DepthSpacerField -> Align -> [WideBuilder] -> Cell
Cell Align
align [Builder -> Int -> WideBuilder
WideBuilder (Text -> Builder
TB.fromText forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
T.replicate Int
d Text
" ") Int
d]
where d :: Int
d = forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. a -> a
id forall a. Ord a => a -> a -> a
min Maybe Int
mmax forall a b. (a -> b) -> a -> b
$ Int
dep forall a. Num a => a -> a -> a
* forall a. a -> Maybe a -> a
fromMaybe Int
1 Maybe Int
mmin
ReportItemField
AccountField -> Align -> Text -> Cell
textCell Align
align forall a b. (a -> b) -> a -> b
$ Bool -> Maybe Int -> Maybe Int -> Text -> Text
formatText Bool
ljust Maybe Int
mmin Maybe Int
mmax Text
acctname
ReportItemField
TotalField -> Align -> [WideBuilder] -> Cell
Cell Align
align forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ AmountDisplayOpts -> Change -> WideBuilder
showMixedAmountB AmountDisplayOpts
dopts Change
total
ReportItemField
_ -> Align -> [WideBuilder] -> Cell
Cell Align
align [forall a. Monoid a => a
mempty]
where
align :: Align
align | Bool
topaligned Bool -> Bool -> Bool
&& Bool
ljust = Align
TopLeft
| Bool
topaligned = Align
TopRight
| Bool
ljust = Align
BottomLeft
| Bool
otherwise = Align
BottomRight
dopts :: AmountDisplayOpts
dopts = AmountDisplayOpts
noCost{displayCommodity :: Bool
displayCommodity = ReportOpts -> Layout
layout_ ReportOpts
opts forall a. Eq a => a -> a -> Bool
/= Layout
LayoutBare
,displayOneLine :: Bool
displayOneLine = Bool
oneline
,displayMinWidth :: Maybe Int
displayMinWidth = Maybe Int
mmin
,displayMaxWidth :: Maybe Int
displayMaxWidth = Maybe Int
mmax
,displayColour :: Bool
displayColour = ReportOpts -> Bool
color_ ReportOpts
opts
}
multiBalanceReportAsCsv :: ReportOpts -> MultiBalanceReport -> CSV
multiBalanceReportAsCsv :: ReportOpts -> MultiBalanceReport -> [CsvRecord]
multiBalanceReportAsCsv opts :: ReportOpts
opts@ReportOpts{Bool
Int
CsvRecord
[Status]
Maybe Int
Maybe Text
Maybe ConversionOp
Maybe ValuationType
Maybe NormalSign
BalanceCalculation
BalanceAccumulation
AccountListMode
Layout
StringFormat
Period
Interval
layout_ :: Layout
transpose_ :: Bool
color_ :: Bool
normalbalance_ :: Maybe NormalSign
invert_ :: Bool
percent_ :: Bool
sort_amount_ :: Bool
show_costs_ :: Bool
summary_only_ :: Bool
no_total_ :: Bool
row_total_ :: Bool
declared_ :: Bool
drop_ :: Int
accountlistmode_ :: AccountListMode
budgetpat_ :: Maybe Text
balanceaccum_ :: BalanceAccumulation
balancecalc_ :: BalanceCalculation
txn_dates_ :: Bool
related_ :: Bool
average_ :: Bool
querystring_ :: CsvRecord
pretty_ :: Bool
format_ :: StringFormat
real_ :: Bool
no_elide_ :: Bool
empty_ :: Bool
date2_ :: Bool
depth_ :: Maybe Int
infer_prices_ :: Bool
value_ :: Maybe ValuationType
conversionop_ :: Maybe ConversionOp
statuses_ :: [Status]
interval_ :: Interval
period_ :: Period
period_ :: ReportOpts -> Period
interval_ :: ReportOpts -> Interval
statuses_ :: ReportOpts -> [Status]
conversionop_ :: ReportOpts -> Maybe ConversionOp
value_ :: ReportOpts -> Maybe ValuationType
infer_prices_ :: ReportOpts -> Bool
depth_ :: ReportOpts -> Maybe Int
date2_ :: ReportOpts -> Bool
empty_ :: ReportOpts -> Bool
no_elide_ :: ReportOpts -> Bool
real_ :: ReportOpts -> Bool
format_ :: ReportOpts -> StringFormat
pretty_ :: ReportOpts -> Bool
querystring_ :: ReportOpts -> CsvRecord
average_ :: ReportOpts -> Bool
related_ :: ReportOpts -> Bool
txn_dates_ :: ReportOpts -> Bool
balancecalc_ :: ReportOpts -> BalanceCalculation
balanceaccum_ :: ReportOpts -> BalanceAccumulation
budgetpat_ :: ReportOpts -> Maybe Text
accountlistmode_ :: ReportOpts -> AccountListMode
drop_ :: ReportOpts -> Int
declared_ :: ReportOpts -> Bool
row_total_ :: ReportOpts -> Bool
no_total_ :: ReportOpts -> Bool
summary_only_ :: ReportOpts -> Bool
show_costs_ :: ReportOpts -> Bool
sort_amount_ :: ReportOpts -> Bool
percent_ :: ReportOpts -> Bool
invert_ :: ReportOpts -> Bool
normalbalance_ :: ReportOpts -> Maybe NormalSign
color_ :: ReportOpts -> Bool
transpose_ :: ReportOpts -> Bool
layout_ :: ReportOpts -> Layout
..} MultiBalanceReport
report = forall a. [[a]] -> [[a]]
maybeTranspose [CsvRecord]
allRows
where
allRows :: [CsvRecord]
allRows = case Layout
layout_ of
Layout
LayoutTidy -> [CsvRecord]
rows
Layout
_ -> [CsvRecord]
rows forall a. [a] -> [a] -> [a]
++ [CsvRecord]
totals
([CsvRecord]
rows, [CsvRecord]
totals) = ReportOpts -> MultiBalanceReport -> ([CsvRecord], [CsvRecord])
multiBalanceReportAsCsv' ReportOpts
opts MultiBalanceReport
report
maybeTranspose :: [[a]] -> [[a]]
maybeTranspose = if Bool
transpose_ then forall a. [[a]] -> [[a]]
transpose else forall a. a -> a
id
multiBalanceReportAsCsv' :: ReportOpts -> MultiBalanceReport -> (CSV, CSV)
multiBalanceReportAsCsv' :: ReportOpts -> MultiBalanceReport -> ([CsvRecord], [CsvRecord])
multiBalanceReportAsCsv' opts :: ReportOpts
opts@ReportOpts{Bool
Int
CsvRecord
[Status]
Maybe Int
Maybe Text
Maybe ConversionOp
Maybe ValuationType
Maybe NormalSign
BalanceCalculation
BalanceAccumulation
AccountListMode
Layout
StringFormat
Period
Interval
layout_ :: Layout
transpose_ :: Bool
color_ :: Bool
normalbalance_ :: Maybe NormalSign
invert_ :: Bool
percent_ :: Bool
sort_amount_ :: Bool
show_costs_ :: Bool
summary_only_ :: Bool
no_total_ :: Bool
row_total_ :: Bool
declared_ :: Bool
drop_ :: Int
accountlistmode_ :: AccountListMode
budgetpat_ :: Maybe Text
balanceaccum_ :: BalanceAccumulation
balancecalc_ :: BalanceCalculation
txn_dates_ :: Bool
related_ :: Bool
average_ :: Bool
querystring_ :: CsvRecord
pretty_ :: Bool
format_ :: StringFormat
real_ :: Bool
no_elide_ :: Bool
empty_ :: Bool
date2_ :: Bool
depth_ :: Maybe Int
infer_prices_ :: Bool
value_ :: Maybe ValuationType
conversionop_ :: Maybe ConversionOp
statuses_ :: [Status]
interval_ :: Interval
period_ :: Period
period_ :: ReportOpts -> Period
interval_ :: ReportOpts -> Interval
statuses_ :: ReportOpts -> [Status]
conversionop_ :: ReportOpts -> Maybe ConversionOp
value_ :: ReportOpts -> Maybe ValuationType
infer_prices_ :: ReportOpts -> Bool
depth_ :: ReportOpts -> Maybe Int
date2_ :: ReportOpts -> Bool
empty_ :: ReportOpts -> Bool
no_elide_ :: ReportOpts -> Bool
real_ :: ReportOpts -> Bool
format_ :: ReportOpts -> StringFormat
pretty_ :: ReportOpts -> Bool
querystring_ :: ReportOpts -> CsvRecord
average_ :: ReportOpts -> Bool
related_ :: ReportOpts -> Bool
txn_dates_ :: ReportOpts -> Bool
balancecalc_ :: ReportOpts -> BalanceCalculation
balanceaccum_ :: ReportOpts -> BalanceAccumulation
budgetpat_ :: ReportOpts -> Maybe Text
accountlistmode_ :: ReportOpts -> AccountListMode
drop_ :: ReportOpts -> Int
declared_ :: ReportOpts -> Bool
row_total_ :: ReportOpts -> Bool
no_total_ :: ReportOpts -> Bool
summary_only_ :: ReportOpts -> Bool
show_costs_ :: ReportOpts -> Bool
sort_amount_ :: ReportOpts -> Bool
percent_ :: ReportOpts -> Bool
invert_ :: ReportOpts -> Bool
normalbalance_ :: ReportOpts -> Maybe NormalSign
color_ :: ReportOpts -> Bool
transpose_ :: ReportOpts -> Bool
layout_ :: ReportOpts -> Layout
..} (PeriodicReport [DateSpan]
colspans [PeriodicReportRow DisplayName Change]
items PeriodicReportRow () Change
tr) =
(CsvRecord
headers forall a. a -> [a] -> [a]
: forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap PeriodicReportRow DisplayName Change -> [CsvRecord]
fullRowAsTexts [PeriodicReportRow DisplayName Change]
items, [CsvRecord]
totalrows)
where
headers :: CsvRecord
headers = Text
"account" forall a. a -> [a] -> [a]
: case Layout
layout_ of
Layout
LayoutTidy -> [Text
"period", Text
"start_date", Text
"end_date", Text
"commodity", Text
"value"]
Layout
LayoutBare -> Text
"commodity" forall a. a -> [a] -> [a]
: CsvRecord
dateHeaders
Layout
_ -> CsvRecord
dateHeaders
dateHeaders :: CsvRecord
dateHeaders = forall a b. (a -> b) -> [a] -> [b]
map DateSpan -> Text
showDateSpan [DateSpan]
colspans forall a. [a] -> [a] -> [a]
++ [Text
"total" | Bool
row_total_] forall a. [a] -> [a] -> [a]
++ [Text
"average" | Bool
average_]
fullRowAsTexts :: PeriodicReportRow DisplayName Change -> [CsvRecord]
fullRowAsTexts PeriodicReportRow DisplayName Change
row = forall a b. (a -> b) -> [a] -> [b]
map (forall {a}. PeriodicReportRow DisplayName a -> Text
showName PeriodicReportRow DisplayName Change
row forall a. a -> [a] -> [a]
:) forall a b. (a -> b) -> a -> b
$ forall a.
ReportOpts
-> [DateSpan] -> PeriodicReportRow a Change -> [CsvRecord]
multiBalanceRowAsCsvText ReportOpts
opts [DateSpan]
colspans PeriodicReportRow DisplayName Change
row
showName :: PeriodicReportRow DisplayName a -> Text
showName = Int -> Text -> Text
accountNameDrop Int
drop_ forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {a}. PeriodicReportRow DisplayName a -> Text
prrFullName
totalrows :: [CsvRecord]
totalrows
| Bool
no_total_ = forall a. Monoid a => a
mempty
| Bool
otherwise = forall a b. (a -> b) -> [a] -> [b]
map (Text
"total" forall a. a -> [a] -> [a]
:) forall a b. (a -> b) -> a -> b
$ forall a.
ReportOpts
-> [DateSpan] -> PeriodicReportRow a Change -> [CsvRecord]
multiBalanceRowAsCsvText ReportOpts
opts [DateSpan]
colspans PeriodicReportRow () Change
tr
multiBalanceReportAsHtml :: ReportOpts -> MultiBalanceReport -> Html ()
multiBalanceReportAsHtml :: ReportOpts -> MultiBalanceReport -> Html ()
multiBalanceReportAsHtml ReportOpts
ropts MultiBalanceReport
mbr =
let
(Html ()
headingsrow,[Html ()]
bodyrows,[Html ()]
mtotalsrows) = ReportOpts -> MultiBalanceReport -> (Html (), [Html ()], [Html ()])
multiBalanceReportHtmlRows ReportOpts
ropts MultiBalanceReport
mbr
in
forall arg result. Term arg result => arg -> result
table_ forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$
[Html ()
headingsrow]
forall a. [a] -> [a] -> [a]
++ [Html ()]
bodyrows
forall a. [a] -> [a] -> [a]
++ [Html ()]
mtotalsrows
multiBalanceReportHtmlRows :: ReportOpts -> MultiBalanceReport -> (Html (), [Html ()], [Html ()])
multiBalanceReportHtmlRows :: ReportOpts -> MultiBalanceReport -> (Html (), [Html ()], [Html ()])
multiBalanceReportHtmlRows ReportOpts
ropts MultiBalanceReport
mbr =
let
(CsvRecord
headingsrow:[CsvRecord]
bodyrows, [CsvRecord]
mtotalsrows)
| ReportOpts -> Bool
transpose_ ReportOpts
ropts = forall a. CommandDoc -> a
error' CommandDoc
"Sorry, --transpose with HTML output is not yet supported"
| Bool
otherwise = ReportOpts -> MultiBalanceReport -> ([CsvRecord], [CsvRecord])
multiBalanceReportAsCsv' ReportOpts
ropts MultiBalanceReport
mbr
in
(ReportOpts -> CsvRecord -> Html ()
multiBalanceReportHtmlHeadRow ReportOpts
ropts CsvRecord
headingsrow
,forall a b. (a -> b) -> [a] -> [b]
map (ReportOpts -> CsvRecord -> Html ()
multiBalanceReportHtmlBodyRow ReportOpts
ropts) [CsvRecord]
bodyrows
,ReportOpts -> CsvRecord -> Html ()
multiBalanceReportHtmlFootRow ReportOpts
ropts forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [CsvRecord]
mtotalsrows
)
multiBalanceReportHtmlHeadRow :: ReportOpts -> [T.Text] -> Html ()
multiBalanceReportHtmlHeadRow :: ReportOpts -> CsvRecord -> Html ()
multiBalanceReportHtmlHeadRow ReportOpts
_ [] = forall a. Monoid a => a
mempty
multiBalanceReportHtmlHeadRow ReportOpts
ropts (Text
acct:CsvRecord
cells) =
let
defstyle :: Attribute
defstyle = forall arg result. TermRaw arg result => arg -> result
style_ Text
""
(CsvRecord
amts,CsvRecord
tot,CsvRecord
avg)
| ReportOpts -> Bool
row_total_ ReportOpts
ropts Bool -> Bool -> Bool
&& ReportOpts -> Bool
average_ ReportOpts
ropts = (CsvRecord
ini2, CsvRecord
sndlst2, CsvRecord
lst2)
| ReportOpts -> Bool
row_total_ ReportOpts
ropts = (CsvRecord
ini1, CsvRecord
lst1, [])
| ReportOpts -> Bool
average_ ReportOpts
ropts = (CsvRecord
ini1, [], CsvRecord
lst1)
| Bool
otherwise = (CsvRecord
cells, [], [])
where
n :: Int
n = forall (t :: * -> *) a. Foldable t => t a -> Int
length CsvRecord
cells
(CsvRecord
ini1,CsvRecord
lst1) = forall a. Int -> [a] -> ([a], [a])
splitAt (Int
nforall a. Num a => a -> a -> a
-Int
1) CsvRecord
cells
(CsvRecord
ini2, CsvRecord
rest) = forall a. Int -> [a] -> ([a], [a])
splitAt (Int
nforall a. Num a => a -> a -> a
-Int
2) CsvRecord
cells
(CsvRecord
sndlst2,CsvRecord
lst2) = forall a. Int -> [a] -> ([a], [a])
splitAt Int
1 CsvRecord
rest
in
forall arg result. Term arg result => arg -> result
tr_ forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$
forall arg result. Term arg result => arg -> result
td_ [Text -> Attribute
class_ Text
"account"] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
acct)
forall a. a -> [a] -> [a]
: [forall arg result. Term arg result => arg -> result
td_ [Text -> Attribute
class_ Text
"", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
amts]
forall a. [a] -> [a] -> [a]
++ [forall arg result. Term arg result => arg -> result
td_ [Text -> Attribute
class_ Text
"rowtotal", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
tot]
forall a. [a] -> [a] -> [a]
++ [forall arg result. Term arg result => arg -> result
td_ [Text -> Attribute
class_ Text
"rowaverage", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
avg]
multiBalanceReportHtmlBodyRow :: ReportOpts -> [T.Text] -> Html ()
multiBalanceReportHtmlBodyRow :: ReportOpts -> CsvRecord -> Html ()
multiBalanceReportHtmlBodyRow ReportOpts
_ [] = forall a. Monoid a => a
mempty
multiBalanceReportHtmlBodyRow ReportOpts
ropts (Text
label:CsvRecord
cells) =
let
defstyle :: Attribute
defstyle = forall arg result. TermRaw arg result => arg -> result
style_ Text
"text-align:right"
(CsvRecord
amts,CsvRecord
tot,CsvRecord
avg)
| ReportOpts -> Bool
row_total_ ReportOpts
ropts Bool -> Bool -> Bool
&& ReportOpts -> Bool
average_ ReportOpts
ropts = (CsvRecord
ini2, CsvRecord
sndlst2, CsvRecord
lst2)
| ReportOpts -> Bool
row_total_ ReportOpts
ropts = (CsvRecord
ini1, CsvRecord
lst1, [])
| ReportOpts -> Bool
average_ ReportOpts
ropts = (CsvRecord
ini1, [], CsvRecord
lst1)
| Bool
otherwise = (CsvRecord
cells, [], [])
where
n :: Int
n = forall (t :: * -> *) a. Foldable t => t a -> Int
length CsvRecord
cells
(CsvRecord
ini1,CsvRecord
lst1) = forall a. Int -> [a] -> ([a], [a])
splitAt (Int
nforall a. Num a => a -> a -> a
-Int
1) CsvRecord
cells
(CsvRecord
ini2, CsvRecord
rest) = forall a. Int -> [a] -> ([a], [a])
splitAt (Int
nforall a. Num a => a -> a -> a
-Int
2) CsvRecord
cells
(CsvRecord
sndlst2,CsvRecord
lst2) = forall a. Int -> [a] -> ([a], [a])
splitAt Int
1 CsvRecord
rest
in
forall arg result. Term arg result => arg -> result
tr_ forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$
forall arg result. Term arg result => arg -> result
td_ [Text -> Attribute
class_ Text
"account", forall arg result. TermRaw arg result => arg -> result
style_ Text
"text-align:left"] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
label)
forall a. a -> [a] -> [a]
: [forall arg result. Term arg result => arg -> result
td_ [Text -> Attribute
class_ Text
"amount", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
amts]
forall a. [a] -> [a] -> [a]
++ [forall arg result. Term arg result => arg -> result
td_ [Text -> Attribute
class_ Text
"amount rowtotal", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
tot]
forall a. [a] -> [a] -> [a]
++ [forall arg result. Term arg result => arg -> result
td_ [Text -> Attribute
class_ Text
"amount rowaverage", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
avg]
multiBalanceReportHtmlFootRow :: ReportOpts -> [T.Text] -> Html ()
ReportOpts
_ropts [] = forall a. Monoid a => a
mempty
multiBalanceReportHtmlFootRow ReportOpts
ropts (Text
acct:CsvRecord
cells) =
let
defstyle :: Attribute
defstyle = forall arg result. TermRaw arg result => arg -> result
style_ Text
"text-align:right"
(CsvRecord
amts,CsvRecord
tot,CsvRecord
avg)
| ReportOpts -> Bool
row_total_ ReportOpts
ropts Bool -> Bool -> Bool
&& ReportOpts -> Bool
average_ ReportOpts
ropts = (CsvRecord
ini2, CsvRecord
sndlst2, CsvRecord
lst2)
| ReportOpts -> Bool
row_total_ ReportOpts
ropts = (CsvRecord
ini1, CsvRecord
lst1, [])
| ReportOpts -> Bool
average_ ReportOpts
ropts = (CsvRecord
ini1, [], CsvRecord
lst1)
| Bool
otherwise = (CsvRecord
cells, [], [])
where
n :: Int
n = forall (t :: * -> *) a. Foldable t => t a -> Int
length CsvRecord
cells
(CsvRecord
ini1,CsvRecord
lst1) = forall a. Int -> [a] -> ([a], [a])
splitAt (Int
nforall a. Num a => a -> a -> a
-Int
1) CsvRecord
cells
(CsvRecord
ini2, CsvRecord
rest) = forall a. Int -> [a] -> ([a], [a])
splitAt (Int
nforall a. Num a => a -> a -> a
-Int
2) CsvRecord
cells
(CsvRecord
sndlst2,CsvRecord
lst2) = forall a. Int -> [a] -> ([a], [a])
splitAt Int
1 CsvRecord
rest
in
forall arg result. Term arg result => arg -> result
tr_ forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$
forall arg result. Term arg result => arg -> result
th_ [forall arg result. TermRaw arg result => arg -> result
style_ Text
"text-align:left"] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
acct)
forall a. a -> [a] -> [a]
: [forall arg result. Term arg result => arg -> result
th_ [Text -> Attribute
class_ Text
"amount coltotal", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
amts]
forall a. [a] -> [a] -> [a]
++ [forall arg result. Term arg result => arg -> result
th_ [Text -> Attribute
class_ Text
"amount coltotal", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
tot]
forall a. [a] -> [a] -> [a]
++ [forall arg result. Term arg result => arg -> result
th_ [Text -> Attribute
class_ Text
"amount colaverage", Attribute
defstyle] (forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
a) | Text
a <- CsvRecord
avg]
multiBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> TL.Text
multiBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> Text
multiBalanceReportAsText ropts :: ReportOpts
ropts@ReportOpts{Bool
Int
CsvRecord
[Status]
Maybe Int
Maybe Text
Maybe ConversionOp
Maybe ValuationType
Maybe NormalSign
BalanceCalculation
BalanceAccumulation
AccountListMode
Layout
StringFormat
Period
Interval
layout_ :: Layout
transpose_ :: Bool
color_ :: Bool
normalbalance_ :: Maybe NormalSign
invert_ :: Bool
percent_ :: Bool
sort_amount_ :: Bool
show_costs_ :: Bool
summary_only_ :: Bool
no_total_ :: Bool
row_total_ :: Bool
declared_ :: Bool
drop_ :: Int
accountlistmode_ :: AccountListMode
budgetpat_ :: Maybe Text
balanceaccum_ :: BalanceAccumulation
balancecalc_ :: BalanceCalculation
txn_dates_ :: Bool
related_ :: Bool
average_ :: Bool
querystring_ :: CsvRecord
pretty_ :: Bool
format_ :: StringFormat
real_ :: Bool
no_elide_ :: Bool
empty_ :: Bool
date2_ :: Bool
depth_ :: Maybe Int
infer_prices_ :: Bool
value_ :: Maybe ValuationType
conversionop_ :: Maybe ConversionOp
statuses_ :: [Status]
interval_ :: Interval
period_ :: Period
period_ :: ReportOpts -> Period
interval_ :: ReportOpts -> Interval
statuses_ :: ReportOpts -> [Status]
conversionop_ :: ReportOpts -> Maybe ConversionOp
value_ :: ReportOpts -> Maybe ValuationType
infer_prices_ :: ReportOpts -> Bool
depth_ :: ReportOpts -> Maybe Int
date2_ :: ReportOpts -> Bool
empty_ :: ReportOpts -> Bool
no_elide_ :: ReportOpts -> Bool
real_ :: ReportOpts -> Bool
format_ :: ReportOpts -> StringFormat
pretty_ :: ReportOpts -> Bool
querystring_ :: ReportOpts -> CsvRecord
average_ :: ReportOpts -> Bool
related_ :: ReportOpts -> Bool
txn_dates_ :: ReportOpts -> Bool
balancecalc_ :: ReportOpts -> BalanceCalculation
balanceaccum_ :: ReportOpts -> BalanceAccumulation
budgetpat_ :: ReportOpts -> Maybe Text
accountlistmode_ :: ReportOpts -> AccountListMode
drop_ :: ReportOpts -> Int
declared_ :: ReportOpts -> Bool
row_total_ :: ReportOpts -> Bool
no_total_ :: ReportOpts -> Bool
summary_only_ :: ReportOpts -> Bool
show_costs_ :: ReportOpts -> Bool
sort_amount_ :: ReportOpts -> Bool
percent_ :: ReportOpts -> Bool
invert_ :: ReportOpts -> Bool
normalbalance_ :: ReportOpts -> Maybe NormalSign
color_ :: ReportOpts -> Bool
transpose_ :: ReportOpts -> Bool
layout_ :: ReportOpts -> Layout
..} MultiBalanceReport
r = Builder -> Text
TB.toLazyText forall a b. (a -> b) -> a -> b
$
Text -> Builder
TB.fromText Text
title
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
TB.fromText Text
"\n\n"
forall a. Semigroup a => a -> a -> a
<> ReportOpts -> Table Text Text WideBuilder -> Builder
balanceReportTableAsText ReportOpts
ropts (ReportOpts -> MultiBalanceReport -> Table Text Text WideBuilder
balanceReportAsTable ReportOpts
ropts MultiBalanceReport
r)
where
title :: Text
title = Text
mtitle forall a. Semigroup a => a -> a -> a
<> Text
" in " forall a. Semigroup a => a -> a -> a
<> DateSpan -> Text
showDateSpan (forall a b. PeriodicReport a b -> DateSpan
periodicReportSpan MultiBalanceReport
r) forall a. Semigroup a => a -> a -> a
<> Text
valuationdesc forall a. Semigroup a => a -> a -> a
<> Text
":"
mtitle :: Text
mtitle = case (BalanceCalculation
balancecalc_, BalanceAccumulation
balanceaccum_) of
(BalanceCalculation
CalcValueChange, BalanceAccumulation
PerPeriod ) -> Text
"Period-end value changes"
(BalanceCalculation
CalcValueChange, BalanceAccumulation
Cumulative ) -> Text
"Cumulative period-end value changes"
(BalanceCalculation
CalcGain, BalanceAccumulation
PerPeriod ) -> Text
"Incremental gain"
(BalanceCalculation
CalcGain, BalanceAccumulation
Cumulative ) -> Text
"Cumulative gain"
(BalanceCalculation
CalcGain, BalanceAccumulation
Historical ) -> Text
"Historical gain"
(BalanceCalculation
_, BalanceAccumulation
PerPeriod ) -> Text
"Balance changes"
(BalanceCalculation
_, BalanceAccumulation
Cumulative ) -> Text
"Ending balances (cumulative)"
(BalanceCalculation
_, BalanceAccumulation
Historical) -> Text
"Ending balances (historical)"
valuationdesc :: Text
valuationdesc =
(case Maybe ConversionOp
conversionop_ of
Just ConversionOp
ToCost -> Text
", converted to cost"
Maybe ConversionOp
_ -> Text
"")
forall a. Semigroup a => a -> a -> a
<> (case Maybe ValuationType
value_ of
Just (AtThen Maybe Text
_mc) -> Text
", valued at posting date"
Just (AtEnd Maybe Text
_mc) | Bool
changingValuation -> Text
""
Just (AtEnd Maybe Text
_mc) -> Text
", valued at period ends"
Just (AtNow Maybe Text
_mc) -> Text
", current value"
Just (AtDate Day
d Maybe Text
_mc) -> Text
", valued at " forall a. Semigroup a => a -> a -> a
<> Day -> Text
showDate Day
d
Maybe ValuationType
Nothing -> Text
"")
changingValuation :: Bool
changingValuation = case (BalanceCalculation
balancecalc_, BalanceAccumulation
balanceaccum_) of
(BalanceCalculation
CalcValueChange, BalanceAccumulation
PerPeriod) -> Bool
True
(BalanceCalculation
CalcValueChange, BalanceAccumulation
Cumulative) -> Bool
True
(BalanceCalculation, BalanceAccumulation)
_ -> Bool
False
balanceReportAsTable :: ReportOpts -> MultiBalanceReport -> Table T.Text T.Text WideBuilder
balanceReportAsTable :: ReportOpts -> MultiBalanceReport -> Table Text Text WideBuilder
balanceReportAsTable opts :: ReportOpts
opts@ReportOpts{Bool
summary_only_ :: Bool
summary_only_ :: ReportOpts -> Bool
summary_only_, Bool
average_ :: Bool
average_ :: ReportOpts -> Bool
average_, Bool
row_total_ :: Bool
row_total_ :: ReportOpts -> Bool
row_total_, BalanceAccumulation
balanceaccum_ :: BalanceAccumulation
balanceaccum_ :: ReportOpts -> BalanceAccumulation
balanceaccum_}
(PeriodicReport [DateSpan]
spans [PeriodicReportRow DisplayName Change]
items PeriodicReportRow () Change
tr) =
forall {rh} {a}. Table rh rh a -> Table rh rh a
maybetranspose forall a b. (a -> b) -> a -> b
$
forall {ch}. Table Text ch WideBuilder -> Table Text ch WideBuilder
addtotalrow forall a b. (a -> b) -> a -> b
$
forall rh ch a. Header rh -> Header ch -> [[a]] -> Table rh ch a
Table
(forall h. Properties -> [Header h] -> Header h
Tab.Group Properties
Tab.NoLine forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall h. h -> Header h
Tab.Header (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [CsvRecord]
accts))
(forall h. Properties -> [Header h] -> Header h
Tab.Group Properties
Tab.NoLine forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall h. h -> Header h
Tab.Header CsvRecord
colheadings)
(forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[[WideBuilder]]]
rows)
where
totalscolumn :: Bool
totalscolumn = Bool
row_total_ Bool -> Bool -> Bool
&& BalanceAccumulation
balanceaccum_ forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [BalanceAccumulation
Cumulative, BalanceAccumulation
Historical]
colheadings :: CsvRecord
colheadings = [Text
"Commodity" | ReportOpts -> Layout
layout_ ReportOpts
opts forall a. Eq a => a -> a -> Bool
== Layout
LayoutBare]
forall a. [a] -> [a] -> [a]
++ (if Bool -> Bool
not Bool
summary_only_ then forall a b. (a -> b) -> [a] -> [b]
map (BalanceAccumulation -> [DateSpan] -> DateSpan -> Text
reportPeriodName BalanceAccumulation
balanceaccum_ [DateSpan]
spans) [DateSpan]
spans else [])
forall a. [a] -> [a] -> [a]
++ [Text
" Total" | Bool
totalscolumn]
forall a. [a] -> [a] -> [a]
++ [Text
"Average" | Bool
average_]
fullRowAsTexts :: PeriodicReportRow DisplayName Change
-> (CsvRecord, [[WideBuilder]])
fullRowAsTexts PeriodicReportRow DisplayName Change
row =
let rs :: [[WideBuilder]]
rs = forall a.
ReportOpts -> PeriodicReportRow a Change -> [[WideBuilder]]
multiBalanceRowAsTableText ReportOpts
opts PeriodicReportRow DisplayName Change
row
in (forall a. Int -> a -> [a]
replicate (forall (t :: * -> *) a. Foldable t => t a -> Int
length [[WideBuilder]]
rs) (forall {a}. PeriodicReportRow DisplayName a -> Text
renderacct PeriodicReportRow DisplayName Change
row), [[WideBuilder]]
rs)
([CsvRecord]
accts, [[[WideBuilder]]]
rows) = forall a b. [(a, b)] -> ([a], [b])
unzip forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PeriodicReportRow DisplayName Change
-> (CsvRecord, [[WideBuilder]])
fullRowAsTexts [PeriodicReportRow DisplayName Change]
items
renderacct :: PeriodicReportRow DisplayName a -> Text
renderacct PeriodicReportRow DisplayName a
row =
Int -> Text -> Text
T.replicate ((forall a. PeriodicReportRow DisplayName a -> Int
prrDepth PeriodicReportRow DisplayName a
row forall a. Num a => a -> a -> a
- Int
1) forall a. Num a => a -> a -> a
* Int
2) Text
" " forall a. Semigroup a => a -> a -> a
<> forall {a}. PeriodicReportRow DisplayName a -> Text
prrDisplayName PeriodicReportRow DisplayName a
row
addtotalrow :: Table Text ch WideBuilder -> Table Text ch WideBuilder
addtotalrow
| ReportOpts -> Bool
no_total_ ReportOpts
opts = forall a. a -> a
id
| Bool
otherwise =
let totalrows :: [[WideBuilder]]
totalrows = forall a.
ReportOpts -> PeriodicReportRow a Change -> [[WideBuilder]]
multiBalanceRowAsTableText ReportOpts
opts PeriodicReportRow () Change
tr
rh :: Header Text
rh = forall h. Properties -> [Header h] -> Header h
Tab.Group Properties
Tab.NoLine forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> a -> [a]
replicate (forall (t :: * -> *) a. Foldable t => t a -> Int
length [[WideBuilder]]
totalrows) forall a b. (a -> b) -> a -> b
$ forall h. h -> Header h
Tab.Header Text
""
ch :: Header [a]
ch = forall h. h -> Header h
Tab.Header []
in (forall a b c. (a -> b -> c) -> b -> a -> c
flip (forall rh ch a ch2.
Properties -> Table rh ch a -> Table rh ch2 a -> Table rh ch a
concatTables Properties
Tab.SingleLine) forall a b. (a -> b) -> a -> b
$ forall rh ch a. Header rh -> Header ch -> [[a]] -> Table rh ch a
Table Header Text
rh forall {a}. Header [a]
ch [[WideBuilder]]
totalrows)
maybetranspose :: Table rh rh a -> Table rh rh a
maybetranspose | ReportOpts -> Bool
transpose_ ReportOpts
opts = \(Table Header rh
rh Header rh
ch [[a]]
vals) -> forall rh ch a. Header rh -> Header ch -> [[a]] -> Table rh ch a
Table Header rh
ch Header rh
rh (forall a. [[a]] -> [[a]]
transpose [[a]]
vals)
| Bool
otherwise = forall a. a -> a
id
multiBalanceRowAsWbs :: AmountDisplayOpts -> ReportOpts -> [DateSpan] -> PeriodicReportRow a MixedAmount -> [[WideBuilder]]
multiBalanceRowAsWbs :: forall a.
AmountDisplayOpts
-> ReportOpts
-> [DateSpan]
-> PeriodicReportRow a Change
-> [[WideBuilder]]
multiBalanceRowAsWbs AmountDisplayOpts
bopts ReportOpts{Bool
Int
CsvRecord
[Status]
Maybe Int
Maybe Text
Maybe ConversionOp
Maybe ValuationType
Maybe NormalSign
BalanceCalculation
BalanceAccumulation
AccountListMode
Layout
StringFormat
Period
Interval
layout_ :: Layout
transpose_ :: Bool
color_ :: Bool
normalbalance_ :: Maybe NormalSign
invert_ :: Bool
percent_ :: Bool
sort_amount_ :: Bool
show_costs_ :: Bool
summary_only_ :: Bool
no_total_ :: Bool
row_total_ :: Bool
declared_ :: Bool
drop_ :: Int
accountlistmode_ :: AccountListMode
budgetpat_ :: Maybe Text
balanceaccum_ :: BalanceAccumulation
balancecalc_ :: BalanceCalculation
txn_dates_ :: Bool
related_ :: Bool
average_ :: Bool
querystring_ :: CsvRecord
pretty_ :: Bool
format_ :: StringFormat
real_ :: Bool
no_elide_ :: Bool
empty_ :: Bool
date2_ :: Bool
depth_ :: Maybe Int
infer_prices_ :: Bool
value_ :: Maybe ValuationType
conversionop_ :: Maybe ConversionOp
statuses_ :: [Status]
interval_ :: Interval
period_ :: Period
period_ :: ReportOpts -> Period
interval_ :: ReportOpts -> Interval
statuses_ :: ReportOpts -> [Status]
conversionop_ :: ReportOpts -> Maybe ConversionOp
value_ :: ReportOpts -> Maybe ValuationType
infer_prices_ :: ReportOpts -> Bool
depth_ :: ReportOpts -> Maybe Int
date2_ :: ReportOpts -> Bool
empty_ :: ReportOpts -> Bool
no_elide_ :: ReportOpts -> Bool
real_ :: ReportOpts -> Bool
format_ :: ReportOpts -> StringFormat
pretty_ :: ReportOpts -> Bool
querystring_ :: ReportOpts -> CsvRecord
average_ :: ReportOpts -> Bool
related_ :: ReportOpts -> Bool
txn_dates_ :: ReportOpts -> Bool
balancecalc_ :: ReportOpts -> BalanceCalculation
balanceaccum_ :: ReportOpts -> BalanceAccumulation
budgetpat_ :: ReportOpts -> Maybe Text
accountlistmode_ :: ReportOpts -> AccountListMode
drop_ :: ReportOpts -> Int
declared_ :: ReportOpts -> Bool
row_total_ :: ReportOpts -> Bool
no_total_ :: ReportOpts -> Bool
summary_only_ :: ReportOpts -> Bool
show_costs_ :: ReportOpts -> Bool
sort_amount_ :: ReportOpts -> Bool
percent_ :: ReportOpts -> Bool
invert_ :: ReportOpts -> Bool
normalbalance_ :: ReportOpts -> Maybe NormalSign
color_ :: ReportOpts -> Bool
transpose_ :: ReportOpts -> Bool
layout_ :: ReportOpts -> Layout
..} [DateSpan]
colspans (PeriodicReportRow a
_ [Change]
as Change
rowtot Change
rowavg) =
case Layout
layout_ of
LayoutWide Maybe Int
width -> [forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (AmountDisplayOpts -> Change -> WideBuilder
showMixedAmountB AmountDisplayOpts
bopts{displayMaxWidth :: Maybe Int
displayMaxWidth=Maybe Int
width}) [Change]
allamts]
Layout
LayoutTall -> forall a. a -> [[a]] -> [[a]]
paddedTranspose forall a. Monoid a => a
mempty
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (AmountDisplayOpts -> Change -> [WideBuilder]
showMixedAmountLinesB AmountDisplayOpts
bopts{displayMaxWidth :: Maybe Int
displayMaxWidth=forall a. Maybe a
Nothing})
forall a b. (a -> b) -> a -> b
$ [Change]
allamts
Layout
LayoutBare -> forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (:) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> WideBuilder
wbFromText CsvRecord
cs)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [[a]] -> [[a]]
transpose
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (AmountDisplayOpts -> Change -> [WideBuilder]
showMixedAmountLinesB AmountDisplayOpts
bopts{displayCommodity :: Bool
displayCommodity=Bool
False, displayCommodityOrder :: Maybe CsvRecord
displayCommodityOrder=forall a. a -> Maybe a
Just CsvRecord
cs, displayMinWidth :: Maybe Int
displayMinWidth=forall a. Maybe a
Nothing})
forall a b. (a -> b) -> a -> b
$ [Change]
allamts
Layout
LayoutTidy -> forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (forall a b. (a -> b) -> [a] -> [b]
map forall b c a. (b -> c) -> (a -> b) -> a -> c
. DateSpan -> [WideBuilder] -> [WideBuilder]
addDateColumns) [DateSpan]
colspans
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ( forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Text
c WideBuilder
a -> [Text -> WideBuilder
wbFromText Text
c, WideBuilder
a]) CsvRecord
cs
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AmountDisplayOpts -> Change -> [WideBuilder]
showMixedAmountLinesB AmountDisplayOpts
bopts{displayCommodity :: Bool
displayCommodity=Bool
False, displayCommodityOrder :: Maybe CsvRecord
displayCommodityOrder=forall a. a -> Maybe a
Just CsvRecord
cs, displayMinWidth :: Maybe Int
displayMinWidth=forall a. Maybe a
Nothing})
forall a b. (a -> b) -> a -> b
$ [Change]
as
where
totalscolumn :: Bool
totalscolumn = Bool
row_total_ Bool -> Bool -> Bool
&& BalanceAccumulation
balanceaccum_ forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [BalanceAccumulation
Cumulative, BalanceAccumulation
Historical]
cs :: CsvRecord
cs = if forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Change -> Bool
mixedAmountLooksZero [Change]
allamts then [Text
""] else forall a. Set a -> [a]
S.toList forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Change -> Set Text
maCommodities [Change]
allamts
allamts :: [Change]
allamts = (if Bool -> Bool
not Bool
summary_only_ then [Change]
as else []) forall a. [a] -> [a] -> [a]
++
[Change
rowtot | Bool
totalscolumn Bool -> Bool -> Bool
&& Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Change]
as)] forall a. [a] -> [a] -> [a]
++
[Change
rowavg | Bool
average_ Bool -> Bool -> Bool
&& Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Change]
as)]
addDateColumns :: DateSpan -> [WideBuilder] -> [WideBuilder]
addDateColumns spn :: DateSpan
spn@(DateSpan Maybe EFDay
s Maybe EFDay
e) = (Text -> WideBuilder
wbFromText (DateSpan -> Text
showDateSpan DateSpan
spn) forall a. a -> [a] -> [a]
:)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> WideBuilder
wbFromText (forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" EFDay -> Text
showEFDate Maybe EFDay
s) forall a. a -> [a] -> [a]
:)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> WideBuilder
wbFromText (forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" (EFDay -> Text
showEFDate forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Day -> Day) -> EFDay -> EFDay
modifyEFDay (Integer -> Day -> Day
addDays (-Integer
1))) Maybe EFDay
e) forall a. a -> [a] -> [a]
:)
paddedTranspose :: a -> [[a]] -> [[a]]
paddedTranspose :: forall a. a -> [[a]] -> [[a]]
paddedTranspose a
_ [] = [[]]
paddedTranspose a
n [[a]]
as1 = forall a. Int -> [a] -> [a]
take (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall (t :: * -> *) a. Foldable t => t a -> Int
length forall a b. (a -> b) -> a -> b
$ [[a]]
as1) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[a]] -> [[a]]
trans forall a b. (a -> b) -> a -> b
$ [[a]]
as1
where
trans :: [[a]] -> [[a]]
trans ([] : [[a]]
xss) = (a
n forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map [a] -> a
h [[a]]
xss) forall a. a -> [a] -> [a]
: [[a]] -> [[a]]
trans ([a
n] forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map [a] -> [a]
t [[a]]
xss)
trans ((a
x : [a]
xs) : [[a]]
xss) = (a
x forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map [a] -> a
h [[a]]
xss) forall a. a -> [a] -> [a]
: [[a]] -> [[a]]
trans ([a] -> [a]
m [a]
xs forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map [a] -> [a]
t [[a]]
xss)
trans [] = []
h :: [a] -> a
h (a
x:[a]
_) = a
x
h [] = a
n
t :: [a] -> [a]
t (a
_:[a]
xs) = [a]
xs
t [] = [a
n]
m :: [a] -> [a]
m (a
x:[a]
xs) = a
xforall a. a -> [a] -> [a]
:[a]
xs
m [] = [a
n]
multiBalanceRowAsCsvText :: ReportOpts -> [DateSpan] -> PeriodicReportRow a MixedAmount -> [[T.Text]]
multiBalanceRowAsCsvText :: forall a.
ReportOpts
-> [DateSpan] -> PeriodicReportRow a Change -> [CsvRecord]
multiBalanceRowAsCsvText ReportOpts
opts [DateSpan]
colspans = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap WideBuilder -> Text
wbToText) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a.
AmountDisplayOpts
-> ReportOpts
-> [DateSpan]
-> PeriodicReportRow a Change
-> [[WideBuilder]]
multiBalanceRowAsWbs AmountDisplayOpts
csvDisplay ReportOpts
opts [DateSpan]
colspans
multiBalanceRowAsTableText :: ReportOpts -> PeriodicReportRow a MixedAmount -> [[WideBuilder]]
multiBalanceRowAsTableText :: forall a.
ReportOpts -> PeriodicReportRow a Change -> [[WideBuilder]]
multiBalanceRowAsTableText ReportOpts
opts = forall a.
AmountDisplayOpts
-> ReportOpts
-> [DateSpan]
-> PeriodicReportRow a Change
-> [[WideBuilder]]
multiBalanceRowAsWbs AmountDisplayOpts
oneLine{displayColour :: Bool
displayColour=ReportOpts -> Bool
color_ ReportOpts
opts} ReportOpts
opts []
tests_Balance :: TestTree
tests_Balance = CommandDoc -> [TestTree] -> TestTree
testGroup CommandDoc
"Balance" [
CommandDoc -> [TestTree] -> TestTree
testGroup CommandDoc
"balanceReportAsText" [
CommandDoc -> IO () -> TestTree
testCase CommandDoc
"unicode in balance layout" forall a b. (a -> b) -> a -> b
$ do
Journal
j <- Text -> IO Journal
readJournal' Text
"2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n"
let rspec :: ReportSpec
rspec = ReportSpec
defreportspec{_rsReportOpts :: ReportOpts
_rsReportOpts=ReportOpts
defreportopts{no_total_ :: Bool
no_total_=Bool
True}}
Builder -> Text
TB.toLazyText (ReportOpts -> BalanceReport -> Builder
balanceReportAsText (ReportSpec -> ReportOpts
_rsReportOpts ReportSpec
rspec) (ReportSpec -> Journal -> BalanceReport
balanceReport ReportSpec
rspec{_rsDay :: Day
_rsDay=Integer -> Int -> Int -> Day
fromGregorian Integer
2008 Int
11 Int
26} Journal
j))
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?=
[Text] -> Text
TL.unlines
[Text
" -100 актив:наличные"
,Text
" 100 расходы:покупки"
]
]
]