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 | ||||
|     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; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user