diff --git a/hledger-lib/Hledger/Reports/BudgetReport.hs b/hledger-lib/Hledger/Reports/BudgetReport.hs index 5e7e8a0c0..8a43148f5 100644 --- a/hledger-lib/Hledger/Reports/BudgetReport.hs +++ b/hledger-lib/Hledger/Reports/BudgetReport.hs @@ -82,10 +82,12 @@ budgetReport rspec bopts reportspan j = dbg4 "sortedbudgetreport" budgetreport jperiodictxns j actualj = journalWithBudgetAccountNames budgetedaccts showunbudgeted j budgetj = journalAddBudgetGoalTransactions bopts ropts reportspan j - actualreport@(PeriodicReport actualspans _ _) = - dbg5 "actualreport" $ multiBalanceReport rspec{_rsReportOpts=ropts{empty_=True}} actualj + priceoracle = journalPriceOracle (infer_prices_ ropts) j budgetgoalreport@(PeriodicReport _ budgetgoalitems budgetgoaltotals) = - dbg5 "budgetgoalreport" $ multiBalanceReport rspec{_rsReportOpts=ropts{empty_=True}} budgetj + dbg5 "budgetgoalreport" $ multiBalanceReportWith rspec{_rsReportOpts=ropts{empty_=True}} budgetj priceoracle mempty + budgetedacctsseen = S.fromList $ map prrFullName budgetgoalitems + actualreport@(PeriodicReport actualspans _ _) = + dbg5 "actualreport" $ multiBalanceReportWith rspec{_rsReportOpts=ropts{empty_=True}} actualj priceoracle budgetedacctsseen budgetgoalreport' -- If no interval is specified: -- budgetgoalreport's span might be shorter actualreport's due to periodic txns; diff --git a/hledger-lib/Hledger/Reports/MultiBalanceReport.hs b/hledger-lib/Hledger/Reports/MultiBalanceReport.hs index dccca4397..8d9ffb1a7 100644 --- a/hledger-lib/Hledger/Reports/MultiBalanceReport.hs +++ b/hledger-lib/Hledger/Reports/MultiBalanceReport.hs @@ -47,6 +47,8 @@ import qualified Data.Map as M import Data.Maybe (fromMaybe, isJust, mapMaybe) import Data.Ord (Down(..)) import Data.Semigroup (sconcat) +import Data.Set (Set) +import qualified Data.Set as Set import Data.Time.Calendar (fromGregorian) import Safe (lastDef, minimumMay) @@ -102,16 +104,16 @@ type ClippedAccountName = AccountName -- by the balance command (in multiperiod mode) and (via compoundBalanceReport) -- by the bs/cf/is commands. multiBalanceReport :: ReportSpec -> Journal -> MultiBalanceReport -multiBalanceReport rspec j = multiBalanceReportWith rspec j (journalPriceOracle infer j) +multiBalanceReport rspec j = multiBalanceReportWith rspec j (journalPriceOracle infer j) mempty where infer = infer_prices_ $ _rsReportOpts rspec --- | A helper for multiBalanceReport. This one takes an extra argument, --- a PriceOracle to be used for looking up market prices. Commands which --- run multiple reports (bs etc.) can generate the price oracle just --- once for efficiency, passing it to each report by calling this --- function directly. -multiBalanceReportWith :: ReportSpec -> Journal -> PriceOracle -> MultiBalanceReport -multiBalanceReportWith rspec' j priceoracle = report +-- | A helper for multiBalanceReport. This one takes some extra arguments, +-- a 'PriceOracle' to be used for looking up market prices, and a set of +-- 'AccountName's which should not be elided. Commands which run multiple +-- reports (bs etc.) can generate the price oracle just once for efficiency, +-- passing it to each report by calling this function directly. +multiBalanceReportWith :: ReportSpec -> Journal -> PriceOracle -> Set AccountName -> MultiBalanceReport +multiBalanceReportWith rspec' j priceoracle unelidableaccts = report where -- Queries, report/column dates. reportspan = dbg3 "reportspan" $ reportSpan j rspec' @@ -127,7 +129,7 @@ multiBalanceReportWith rspec' j priceoracle = report -- Generate and postprocess the report, negating balances and taking percentages if needed report = dbg4 "multiBalanceReportWith" $ - generateMultiBalanceReport rspec j priceoracle colps startbals + generateMultiBalanceReport rspec j priceoracle unelidableaccts colps startbals -- | Generate a compound balance report from a list of CBCSubreportSpec. This -- shares postings between the subreports. @@ -159,7 +161,7 @@ compoundBalanceReportWith rspec' j priceoracle subreportspecs = cbr ( cbcsubreporttitle -- Postprocess the report, negating balances and taking percentages if needed , cbcsubreporttransform $ - generateMultiBalanceReport rspecsub j priceoracle colps' startbals' + generateMultiBalanceReport rspecsub j priceoracle mempty colps' startbals' , cbcsubreportincreasestotal ) where @@ -343,17 +345,17 @@ calculateReportMatrix rspec@ReportSpec{_rsReportOpts=ropts} j priceoracle startb -- | Lay out a set of postings grouped by date span into a regular matrix with rows -- given by AccountName and columns by DateSpan, then generate a MultiBalanceReport -- from the columns. -generateMultiBalanceReport :: ReportSpec -> Journal -> PriceOracle +generateMultiBalanceReport :: ReportSpec -> Journal -> PriceOracle -> Set AccountName -> [(DateSpan, [Posting])] -> HashMap AccountName Account -> MultiBalanceReport -generateMultiBalanceReport rspec@ReportSpec{_rsReportOpts=ropts} j priceoracle colps startbals = +generateMultiBalanceReport rspec@ReportSpec{_rsReportOpts=ropts} j priceoracle unelidableaccts colps startbals = report where -- Process changes into normal, cumulative, or historical amounts, plus value them matrix = calculateReportMatrix rspec j priceoracle startbals colps -- All account names that will be displayed, possibly depth-clipped. - displaynames = dbg5 "displaynames" $ displayedAccounts rspec matrix + displaynames = dbg5 "displaynames" $ displayedAccounts rspec unelidableaccts matrix -- All the rows of the report. rows = dbg5 "rows" . (if invert_ ropts then map (fmap maNegate) else id) -- Negate amounts if applicable @@ -394,9 +396,11 @@ buildReportRows ropts displaynames = -- | Calculate accounts which are to be displayed in the report, as well as -- their name and depth -displayedAccounts :: ReportSpec -> HashMap AccountName (Map DateSpan Account) +displayedAccounts :: ReportSpec + -> Set AccountName + -> HashMap AccountName (Map DateSpan Account) -> HashMap AccountName DisplayName -displayedAccounts ReportSpec{_rsQuery=query,_rsReportOpts=ropts} valuedaccts +displayedAccounts ReportSpec{_rsQuery=query,_rsReportOpts=ropts} unelidableaccts valuedaccts | depth == 0 = HM.singleton "..." $ DisplayName "..." "..." 1 | otherwise = HM.mapWithKey (\a _ -> displayedName a) displayedAccts where @@ -421,7 +425,8 @@ displayedAccounts ReportSpec{_rsQuery=query,_rsReportOpts=ropts} valuedaccts -- Accounts interesting for their own sake isInteresting name amts = d <= depth -- Throw out anything too deep - && ( (empty_ ropts && keepWhenEmpty amts) -- Keep empty accounts when called with --empty + && ( name `Set.member` unelidableaccts -- Unelidable accounts should be kept unless too deep + ||(empty_ ropts && keepWhenEmpty amts) -- Keep empty accounts when called with --empty || not (isZeroRow balance amts) -- Keep everything with a non-zero balance in the row ) where diff --git a/hledger/test/balance/budget.test b/hledger/test/balance/budget.test index de1474c24..d6b978f61 100644 --- a/hledger/test/balance/budget.test +++ b/hledger/test/balance/budget.test @@ -409,7 +409,31 @@ Budget performance in 2019-01-01..2019-01-03: -------------------++--------------------------- || 0 [ 0] -# 20. Subaccounts + nested budgets +# 20. Also should work when there are no postings directly in budgeted parents (#1800) +$ hledger -f- bal -e 2019-01-02 --budget -E +Budget performance in 2019-01-01: + + || 2019-01-01 +===============================++=========================== + expenses:personal || $10.00 [1% of $1,000.00] + expenses:personal:electronics || $10.00 + liabilities || $-10.00 [1% of $-1000.00] +-------------------------------++--------------------------- + || 0 [ 0] + +# 21. Also should work when there are no postings directly in budgeted parents with --tree (#1800) +$ hledger -f- bal -e 2019-01-02 --budget --tree -E +Budget performance in 2019-01-01: + + || 2019-01-01 +===================++=========================== + expenses:personal || $10.00 [1% of $1,000.00] + electronics || $10.00 + liabilities || $-10.00 [1% of $-1000.00] +-------------------++--------------------------- + || 0 [ 0] + +# 22. Subaccounts + nested budgets < ~ monthly from 2019/01 expenses:personal $1,000.00 @@ -439,7 +463,7 @@ Budget performance in 2019-01-01..2019-01-03: -------------------------------++---------------------------- || 0 [ 0] -# 21. +# 23. $ hledger -f- bal --budget -E Budget performance in 2019-01-01..2019-01-03: @@ -452,7 +476,7 @@ Budget performance in 2019-01-01..2019-01-03: ----------------------------------------++---------------------------- || 0 [ 0] -# 22. +# 24. $ hledger -f- bal --budget --tree Budget performance in 2019-01-01..2019-01-03: @@ -464,7 +488,7 @@ Budget performance in 2019-01-01..2019-01-03: -------------------++---------------------------- || 0 [ 0] -# 23. +# 25. $ hledger -f- bal --budget --tree -E Budget performance in 2019-01-01..2019-01-03: @@ -477,7 +501,7 @@ Budget performance in 2019-01-01..2019-01-03: -------------------++---------------------------- || 0 [ 0] -## 24. Zero budget == no budget +# 26. Zero budget == no budget < ~ monthly from 2019-01 expenses:bills $100 ; bills has a $100 budget of its own, separate from subaccounts @@ -515,7 +539,7 @@ Budget performance in 2019-01-01..2019-01-02: ------------------++------------------------ || 0 [ 0] -# 25. -E shows d and e +# 27. -E shows d and e $ hledger bal -f- --budget -E Budget performance in 2019-01-01..2019-01-02: @@ -532,7 +556,7 @@ Budget performance in 2019-01-01..2019-01-02: ------------------++------------------------ || 0 [ 0] -# 26. The totals row shows correct totals. +# 28. 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: @@ -547,7 +571,7 @@ Budget performance in 2019-01-01..2019-01-02: ------------------++-------------------------------------------------------------- || $80 [22% of $370] $80 [22% of $370] $80 [22% of $370] -# 27. CSV output works. +# 29. 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" @@ -557,7 +581,7 @@ $ hledger bal -f- --budget -TA not:income -O csv "expenses:bills:f","$10","0","$10","0","$10","0" "Total:","$80","$370","$80","$370","$80","$370" -# 28. You would expect this to show a budget goal in jan, feb, mar. +# 30. You would expect this to show a budget goal in jan, feb, mar. # But by the usual report date logic, which picks the oldest and newest # transaction date (1/15 and 3/15) as start and end date by default, # and since "monthly" generates transactions on the 1st, @@ -585,7 +609,7 @@ Budget performance in 2020Q1: ---------------++----------------------------------------------------------- || 0 [ 0% of $500] 0 [0% of $500] 0 [ 0% of $500] -# 29. Specifying the report period works around it. +# 31. Specifying the report period works around it. $ hledger -f- bal --budget -M date:2020q1 Budget performance in 2020Q1: @@ -596,7 +620,7 @@ Budget performance in 2020Q1: ---------------++----------------------------------------------------------- || 0 [ 0% of $500] 0 [0% of $500] 0 [ 0% of $500] -# 30. Select from multiple named budgets. +# 32. Select from multiple named budgets. < ~ weekly weekly budget (aaa) 1