diff --git a/hledger-lib/Hledger/Reports/BudgetReport.hs b/hledger-lib/Hledger/Reports/BudgetReport.hs index 039a56fce..01f14bca8 100644 --- a/hledger-lib/Hledger/Reports/BudgetReport.hs +++ b/hledger-lib/Hledger/Reports/BudgetReport.hs @@ -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 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 diff --git a/hledger/test/balance/budget.test b/hledger/test/balance/budget.test index 992b9f20e..e83a3cf39 100644 --- a/hledger/test/balance/budget.test +++ b/hledger/test/balance/budget.test @@ -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]