fix:bal:budget: don't omit necessary parent accounts in tree mode (#2071)

Parent accounts with no actual or goal amounts would ideally be shown
elided on the same line, but the budget report in tree mode was
omitting them completely. Now --budget always shows them.
The effect is much like forcing --no-elide on, except it might not
show goal amounts that --no-elide does show.

It's not a wonderful fix, but the budget report code is twisty and I
can't afford to spend more time on this.
This commit is contained in:
Simon Michael 2024-02-25 01:16:08 -10:00
parent c701e3a663
commit a871f274c4
2 changed files with 63 additions and 12 deletions

View File

@ -228,7 +228,7 @@ combineBudgetAndActual ropts j
actualsplusgoals = [
-- dbg0With (("actualsplusgoals: "<>)._brrShowDebug) $
PeriodicReportRow acct amtandgoals totamtandgoal avgamtandgoal
| PeriodicReportRow acct actualamts actualtot actualavg <- actualrows -- XXX #2071 can miss budgeted rows with elided parent no actual
| PeriodicReportRow acct actualamts actualtot actualavg <- actualrows
, let mbudgetgoals = HM.lookup (displayFull acct) budgetGoalsByAcct :: Maybe ([BudgetGoal], BudgetTotal, BudgetAverage)
, let budgetmamts = maybe (Nothing <$ periods) (map Just . first3) mbudgetgoals :: [Maybe BudgetGoal]
@ -398,8 +398,10 @@ budgetReportAsTable ReportOpts{..} (PeriodicReport spans items totrow) =
shownitems :: [[(AccountName, WideBuilder, BudgetDisplayRow)]]
shownitems =
map (\i ->
let addacctcolumn = map (\(cs, cvals) -> (renderacct i, cs, cvals))
in addacctcolumn . showrow . rowToBudgetCells $ i)
let
addacctcolumn = map (\(cs, cvals) -> (renderacct i, cs, cvals))
isunbudgetedrow = displayFull (prrName i) == unbudgetedAccountName
in addacctcolumn $ showrow isunbudgetedrow $ rowToBudgetCells i)
items
where
-- FIXME. Have to check explicitly for which to render here, since
@ -412,7 +414,7 @@ budgetReportAsTable ReportOpts{..} (PeriodicReport spans items totrow) =
(totrowcs, totrowtexts) = unzip $ concat showntotrow
where
showntotrow :: [[(WideBuilder, BudgetDisplayRow)]]
showntotrow = [showrow $ rowToBudgetCells totrow]
showntotrow = [showrow False $ rowToBudgetCells totrow]
-- | Get the data cells from a row or totals row, maybe adding
-- the row total and/or row average depending on options.
@ -422,14 +424,27 @@ budgetReportAsTable ReportOpts{..} (PeriodicReport spans items totrow) =
++ [rowavg | average_ && not (null as)]
-- | Render a row's data cells as "BudgetDisplayCell"s, and a rendered list of commodity symbols.
showrow :: [BudgetCell] -> [(WideBuilder, BudgetDisplayRow)]
showrow row =
let cs = budgetCellsCommodities row
(showmixed, percbudget) = mkBudgetDisplayFns cs
in zip (map wbFromText cs)
. transpose
. map (showcell showmixed percbudget)
$ row
-- Also requires a flag indicating whether this is the special <unbudgeted> row.
-- (The types make that hard to check here.)
showrow :: Bool -> [BudgetCell] -> [(WideBuilder, BudgetDisplayRow)]
showrow isunbudgetedrow cells =
let
cs = budgetCellsCommodities cells
-- #2071 If there are no commodities - because there are no actual or goal amounts -
-- the zipped list would be empty, causing this row not to be shown.
-- But rows like this sometimes need to be shown to preserve the account tree structure.
-- So, ensure 0 will be shown as actual amount(s).
-- Unfortunately this disables boring parent eliding, as if --no-elide had been used.
-- (Just turning on --no-elide higher up doesn't work right.)
-- Note, no goal amount will be shown for these rows,
-- whereas --no-elide is likely to show a goal amount aggregated from children.
cs1 = if null cs && not isunbudgetedrow then [""] else cs
(showmixed, percbudget) = mkBudgetDisplayFns cs1
in
zip (map wbFromText cs1) $
transpose $
map (showcell showmixed percbudget)
cells
budgetCellsCommodities :: [BudgetCell] -> [CommoditySymbol]
budgetCellsCommodities = S.toList . foldl' S.union mempty . map budgetCellCommodities

View File

@ -728,3 +728,39 @@ Budget performance in 2020-01-01..2020-02-29:
--------------++--------------
|| A 100 A 200
|| 0 B 200
# ** 40. In tree-mode budget reports, parent accounts with no actual or goal amounts
# are still shown, to preserve the tree structure. The effect is similar to --no-elide. (#2071)
<
2023-07-01
expenses:rent $100
income:gifts:cash
~ monthly 2023-08
(income:employment) $-100
(income:gifts:cash) $-100
$ hledger -f- bal --budget -p 202308 --tree
Budget performance in 2023-08:
|| Aug
==============++=================
income || 0 [0% of $-200]
employment || 0 [0% of $-100]
gifts || 0
cash || 0 [0% of $-100]
--------------++-----------------
|| 0 [0% of $-200]
# ** 41. But, not exactly the same; notice --no-elide shows a goal amount for gifts. (#2071)
$ hledger -f- bal --budget -p 202308 --tree --no-elide
Budget performance in 2023-08:
|| Aug
==============++=================
income || 0 [0% of $-200]
employment || 0 [0% of $-100]
gifts || 0 [0% of $-100]
cash || 0 [0% of $-100]
--------------++-----------------
|| 0 [0% of $-200]