fix: budget: Make sure boring parents of unbudgeted accounts are not
elided if they have a budget. (#1800) This only affects calls with --budget and -E, but not with --no-elide.
This commit is contained in:
		
							parent
							
								
									d9b0184720
								
							
						
					
					
						commit
						8cd9e81c34
					
				| @ -82,10 +82,12 @@ budgetReport rspec bopts reportspan j = dbg4 "sortedbudgetreport" budgetreport | |||||||
|       jperiodictxns j |       jperiodictxns j | ||||||
|     actualj = journalWithBudgetAccountNames budgetedaccts showunbudgeted j |     actualj = journalWithBudgetAccountNames budgetedaccts showunbudgeted j | ||||||
|     budgetj = journalAddBudgetGoalTransactions bopts ropts reportspan j |     budgetj = journalAddBudgetGoalTransactions bopts ropts reportspan j | ||||||
|     actualreport@(PeriodicReport actualspans _ _) = |     priceoracle = journalPriceOracle (infer_prices_ ropts) j | ||||||
|         dbg5 "actualreport" $ multiBalanceReport rspec{_rsReportOpts=ropts{empty_=True}} actualj |  | ||||||
|     budgetgoalreport@(PeriodicReport _ budgetgoalitems budgetgoaltotals) = |     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' |     budgetgoalreport' | ||||||
|       -- If no interval is specified: |       -- If no interval is specified: | ||||||
|       -- budgetgoalreport's span might be shorter actualreport's due to periodic txns; |       -- budgetgoalreport's span might be shorter actualreport's due to periodic txns; | ||||||
|  | |||||||
| @ -47,6 +47,8 @@ import qualified Data.Map as M | |||||||
| import Data.Maybe (fromMaybe, isJust, mapMaybe) | import Data.Maybe (fromMaybe, isJust, mapMaybe) | ||||||
| import Data.Ord (Down(..)) | import Data.Ord (Down(..)) | ||||||
| import Data.Semigroup (sconcat) | import Data.Semigroup (sconcat) | ||||||
|  | import Data.Set (Set) | ||||||
|  | import qualified Data.Set as Set | ||||||
| import Data.Time.Calendar (fromGregorian) | import Data.Time.Calendar (fromGregorian) | ||||||
| import Safe (lastDef, minimumMay) | import Safe (lastDef, minimumMay) | ||||||
| 
 | 
 | ||||||
| @ -102,16 +104,16 @@ type ClippedAccountName = AccountName | |||||||
| -- by the balance command (in multiperiod mode) and (via compoundBalanceReport) | -- by the balance command (in multiperiod mode) and (via compoundBalanceReport) | ||||||
| -- by the bs/cf/is commands. | -- by the bs/cf/is commands. | ||||||
| multiBalanceReport :: ReportSpec -> Journal -> MultiBalanceReport | 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 |   where infer = infer_prices_ $ _rsReportOpts rspec | ||||||
| 
 | 
 | ||||||
| -- | A helper for multiBalanceReport. This one takes an extra argument, | -- | A helper for multiBalanceReport. This one takes some extra arguments, | ||||||
| -- a PriceOracle to be used for looking up market prices. Commands which | -- a 'PriceOracle' to be used for looking up market prices, and a set of | ||||||
| -- run multiple reports (bs etc.) can generate the price oracle just | -- 'AccountName's which should not be elided. Commands which run multiple | ||||||
| -- once for efficiency, passing it to each report by calling this | -- reports (bs etc.) can generate the price oracle just once for efficiency, | ||||||
| -- function directly. | -- passing it to each report by calling this function directly. | ||||||
| multiBalanceReportWith :: ReportSpec -> Journal -> PriceOracle -> MultiBalanceReport | multiBalanceReportWith :: ReportSpec -> Journal -> PriceOracle -> Set AccountName -> MultiBalanceReport | ||||||
| multiBalanceReportWith rspec' j priceoracle = report | multiBalanceReportWith rspec' j priceoracle unelidableaccts = report | ||||||
|   where |   where | ||||||
|     -- Queries, report/column dates. |     -- Queries, report/column dates. | ||||||
|     reportspan = dbg3 "reportspan" $ reportSpan j rspec' |     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 |     -- Generate and postprocess the report, negating balances and taking percentages if needed | ||||||
|     report = dbg4 "multiBalanceReportWith" $ |     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 | -- | Generate a compound balance report from a list of CBCSubreportSpec. This | ||||||
| -- shares postings between the subreports. | -- shares postings between the subreports. | ||||||
| @ -159,7 +161,7 @@ compoundBalanceReportWith rspec' j priceoracle subreportspecs = cbr | |||||||
|             ( cbcsubreporttitle |             ( cbcsubreporttitle | ||||||
|             -- Postprocess the report, negating balances and taking percentages if needed |             -- Postprocess the report, negating balances and taking percentages if needed | ||||||
|             , cbcsubreporttransform $ |             , cbcsubreporttransform $ | ||||||
|                 generateMultiBalanceReport rspecsub j priceoracle colps' startbals' |                 generateMultiBalanceReport rspecsub j priceoracle mempty colps' startbals' | ||||||
|             , cbcsubreportincreasestotal |             , cbcsubreportincreasestotal | ||||||
|             ) |             ) | ||||||
|           where |           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 | -- | 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 | -- given by AccountName and columns by DateSpan, then generate a MultiBalanceReport | ||||||
| -- from the columns. | -- from the columns. | ||||||
| generateMultiBalanceReport :: ReportSpec -> Journal -> PriceOracle | generateMultiBalanceReport :: ReportSpec -> Journal -> PriceOracle -> Set AccountName | ||||||
|                            -> [(DateSpan, [Posting])] -> HashMap AccountName Account |                            -> [(DateSpan, [Posting])] -> HashMap AccountName Account | ||||||
|                            -> MultiBalanceReport |                            -> MultiBalanceReport | ||||||
| generateMultiBalanceReport rspec@ReportSpec{_rsReportOpts=ropts} j priceoracle colps startbals = | generateMultiBalanceReport rspec@ReportSpec{_rsReportOpts=ropts} j priceoracle unelidableaccts colps startbals = | ||||||
|     report |     report | ||||||
|   where |   where | ||||||
|     -- Process changes into normal, cumulative, or historical amounts, plus value them |     -- Process changes into normal, cumulative, or historical amounts, plus value them | ||||||
|     matrix = calculateReportMatrix rspec j priceoracle startbals colps |     matrix = calculateReportMatrix rspec j priceoracle startbals colps | ||||||
| 
 | 
 | ||||||
|     -- All account names that will be displayed, possibly depth-clipped. |     -- 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. |     -- All the rows of the report. | ||||||
|     rows = dbg5 "rows" . (if invert_ ropts then map (fmap maNegate) else id)  -- Negate amounts if applicable |     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 | -- | Calculate accounts which are to be displayed in the report, as well as | ||||||
| -- their name and depth | -- their name and depth | ||||||
| displayedAccounts :: ReportSpec -> HashMap AccountName (Map DateSpan Account) | displayedAccounts :: ReportSpec | ||||||
|  |                   -> Set AccountName | ||||||
|  |                   -> HashMap AccountName (Map DateSpan Account) | ||||||
|                   -> HashMap AccountName DisplayName |                   -> HashMap AccountName DisplayName | ||||||
| displayedAccounts ReportSpec{_rsQuery=query,_rsReportOpts=ropts} valuedaccts | displayedAccounts ReportSpec{_rsQuery=query,_rsReportOpts=ropts} unelidableaccts valuedaccts | ||||||
|     | depth == 0 = HM.singleton "..." $ DisplayName "..." "..." 1 |     | depth == 0 = HM.singleton "..." $ DisplayName "..." "..." 1 | ||||||
|     | otherwise  = HM.mapWithKey (\a _ -> displayedName a) displayedAccts |     | otherwise  = HM.mapWithKey (\a _ -> displayedName a) displayedAccts | ||||||
|   where |   where | ||||||
| @ -421,7 +425,8 @@ displayedAccounts ReportSpec{_rsQuery=query,_rsReportOpts=ropts} valuedaccts | |||||||
|     -- Accounts interesting for their own sake |     -- Accounts interesting for their own sake | ||||||
|     isInteresting name amts = |     isInteresting name amts = | ||||||
|         d <= depth                                 -- Throw out anything too deep |         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 |            || not (isZeroRow balance amts)         -- Keep everything with a non-zero balance in the row | ||||||
|            ) |            ) | ||||||
|       where |       where | ||||||
|  | |||||||
| @ -409,7 +409,31 @@ Budget performance in 2019-01-01..2019-01-03: | |||||||
| -------------------++--------------------------- | -------------------++--------------------------- | ||||||
|                    ||       0 [              0]  |                    ||       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 | ~ monthly from 2019/01 | ||||||
|     expenses:personal             $1,000.00 |     expenses:personal             $1,000.00 | ||||||
| @ -439,7 +463,7 @@ Budget performance in 2019-01-01..2019-01-03: | |||||||
| -------------------------------++---------------------------- | -------------------------------++---------------------------- | ||||||
|                                ||       0 [               0]  |                                ||       0 [               0]  | ||||||
| 
 | 
 | ||||||
| # 21. | # 23. | ||||||
| $ hledger -f- bal --budget -E | $ hledger -f- bal --budget -E | ||||||
| Budget performance in 2019-01-01..2019-01-03: | Budget performance in 2019-01-01..2019-01-03: | ||||||
| 
 | 
 | ||||||
| @ -452,7 +476,7 @@ Budget performance in 2019-01-01..2019-01-03: | |||||||
| ----------------------------------------++---------------------------- | ----------------------------------------++---------------------------- | ||||||
|                                         ||       0 [               0]  |                                         ||       0 [               0]  | ||||||
| 
 | 
 | ||||||
| # 22. | # 24. | ||||||
| $ hledger -f- bal --budget --tree | $ hledger -f- bal --budget --tree | ||||||
| Budget performance in 2019-01-01..2019-01-03: | Budget performance in 2019-01-01..2019-01-03: | ||||||
| 
 | 
 | ||||||
| @ -464,7 +488,7 @@ Budget performance in 2019-01-01..2019-01-03: | |||||||
| -------------------++---------------------------- | -------------------++---------------------------- | ||||||
|                    ||       0 [               0]  |                    ||       0 [               0]  | ||||||
| 
 | 
 | ||||||
| # 23. | # 25. | ||||||
| $ hledger -f- bal --budget --tree -E | $ hledger -f- bal --budget --tree -E | ||||||
| Budget performance in 2019-01-01..2019-01-03: | Budget performance in 2019-01-01..2019-01-03: | ||||||
| 
 | 
 | ||||||
| @ -477,7 +501,7 @@ Budget performance in 2019-01-01..2019-01-03: | |||||||
| -------------------++---------------------------- | -------------------++---------------------------- | ||||||
|                    ||       0 [               0]  |                    ||       0 [               0]  | ||||||
| 
 | 
 | ||||||
| ## 24. Zero budget == no budget | # 26. Zero budget == no budget | ||||||
| < | < | ||||||
| ~ monthly from 2019-01 | ~ monthly from 2019-01 | ||||||
|   expenses:bills     $100  ; bills has a $100 budget of its own, separate from subaccounts |   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]  |                   ||       0 [           0]  | ||||||
| 
 | 
 | ||||||
| # 25. -E shows d and e | # 27. -E shows d and e | ||||||
| $ hledger bal -f- --budget -E | $ hledger bal -f- --budget -E | ||||||
| Budget performance in 2019-01-01..2019-01-02: | Budget performance in 2019-01-01..2019-01-02: | ||||||
| 
 | 
 | ||||||
| @ -532,7 +556,7 @@ Budget performance in 2019-01-01..2019-01-02: | |||||||
| ------------------++------------------------ | ------------------++------------------------ | ||||||
|                   ||       0 [           0]  |                   ||       0 [           0]  | ||||||
| 
 | 
 | ||||||
| # 26. The totals row shows correct totals. | # 28. The totals row shows correct totals. | ||||||
| # -T/--total and -A/--average adds those columns. | # -T/--total and -A/--average adds those columns. | ||||||
| $ hledger bal -f- --budget -TA not:income | $ hledger bal -f- --budget -TA not:income | ||||||
| Budget performance in 2019-01-01..2019-01-02: | 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]  |                   ||      $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 | $ hledger bal -f- --budget -TA not:income -O csv | ||||||
| "Account","2019-01-01..2019-01-02","budget","Total","budget","Average","budget" | "Account","2019-01-01..2019-01-02","budget","Total","budget","Average","budget" | ||||||
| "expenses:bills","$80","$370","$80","$370","$80","$370" | "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" | "expenses:bills:f","$10","0","$10","0","$10","0" | ||||||
| "Total:","$80","$370","$80","$370","$80","$370" | "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  | # 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,  | # transaction date (1/15 and 3/15) as start and end date by default,  | ||||||
| # and since "monthly" generates transactions on the 1st, | # 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]  |                ||     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 | $ hledger -f- bal --budget -M date:2020q1 | ||||||
| Budget performance in 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]  |                ||     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 | ~ weekly   weekly budget | ||||||
|   (aaa)   1 |   (aaa)   1 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user