feat: bal: select budget( transaction)s by name (#1612)
This makes it possible to keep multiple named budgets in one journal, and select the one you want with --budget's argument. More precisely, you can select the subset of periodic transactions rules which contain a certain fixed, case-insensitive substring. Only one such --budget argument is supported, the last one on the command line takes precedence.
This commit is contained in:
		
							parent
							
								
									b0aa70b27a
								
							
						
					
					
						commit
						d2b799a717
					
				| @ -98,14 +98,21 @@ budgetReport rspec bopts reportspan j = dbg4 "sortedbudgetreport" budgetreport | |||||||
| -- their purpose and effect is to define balance change goals, per account and period, | -- their purpose and effect is to define balance change goals, per account and period, | ||||||
| -- for BudgetReport. | -- for BudgetReport. | ||||||
| journalAddBudgetGoalTransactions :: BalancingOpts -> ReportOpts -> DateSpan -> Journal -> Journal | journalAddBudgetGoalTransactions :: BalancingOpts -> ReportOpts -> DateSpan -> Journal -> Journal | ||||||
| journalAddBudgetGoalTransactions bopts _ropts reportspan j = | journalAddBudgetGoalTransactions bopts ropts reportspan j = | ||||||
|   either error' id $ journalBalanceTransactions bopts j{ jtxns = budgetts }  -- PARTIAL: |   either error' id $ journalBalanceTransactions bopts j{ jtxns = budgetts }  -- PARTIAL: | ||||||
|   where |   where | ||||||
|     budgetspan = dbg3 "budget span" $ reportspan |     budgetspan = dbg3 "budget span" $ reportspan | ||||||
|  |     pat = fromMaybe "" $ dbg3 "budget pattern" $ T.toLower <$> budgetpat_ ropts | ||||||
|  |     -- select periodic transactions matching a pattern | ||||||
|  |     -- (the argument of the (final) --budget option). | ||||||
|  |     -- XXX two limitations/wishes, requiring more extensive type changes: | ||||||
|  |     -- - give an error if pat is non-null and matches no periodic txns | ||||||
|  |     -- - allow a regexp or a full hledger query, not just a substring | ||||||
|     budgetts = |     budgetts = | ||||||
|       dbg5 "budget goal txns" $ |       dbg5 "budget goal txns" $ | ||||||
|       [makeBudgetTxn t |       [makeBudgetTxn t | ||||||
|       | pt <- jperiodictxns j |       | pt <- jperiodictxns j | ||||||
|  |       , pat `T.isInfixOf` T.toLower (ptdescription pt) | ||||||
|       , t <- runPeriodicTransaction pt budgetspan |       , t <- runPeriodicTransaction pt budgetspan | ||||||
|       ] |       ] | ||||||
|     makeBudgetTxn t = txnTieKnot $ t { tdescription = T.pack "Budget transaction" } |     makeBudgetTxn t = txnTieKnot $ t { tdescription = T.pack "Budget transaction" } | ||||||
|  | |||||||
| @ -117,8 +117,11 @@ data ReportOpts = ReportOpts { | |||||||
|     -- for account transactions reports (aregister) |     -- for account transactions reports (aregister) | ||||||
|     ,txn_dates_      :: Bool |     ,txn_dates_      :: Bool | ||||||
|     -- for balance reports (bal, bs, cf, is) |     -- for balance reports (bal, bs, cf, is) | ||||||
|     ,balancecalc_    :: BalanceCalculation |     ,balancecalc_    :: BalanceCalculation  -- ^ What to calculate in balance report cells | ||||||
|     ,balanceaccum_   :: BalanceAccumulation |     ,balanceaccum_   :: BalanceAccumulation -- ^ How to accumulate balance report values over time | ||||||
|  |     ,budgetpat_      :: Maybe T.Text  -- ^ A case-insensitive description substring | ||||||
|  |                                       --   to select periodic transactions for budget reports. | ||||||
|  |                                       --   (Not a regexp, nor a full hledger query, for now.) | ||||||
|     ,accountlistmode_ :: AccountListMode |     ,accountlistmode_ :: AccountListMode | ||||||
|     ,drop_           :: Int |     ,drop_           :: Int | ||||||
|     ,row_total_      :: Bool |     ,row_total_      :: Bool | ||||||
| @ -167,6 +170,7 @@ defreportopts = ReportOpts | |||||||
|     , txn_dates_       = False |     , txn_dates_       = False | ||||||
|     , balancecalc_     = def |     , balancecalc_     = def | ||||||
|     , balanceaccum_    = def |     , balanceaccum_    = def | ||||||
|  |     , budgetpat_       = Nothing | ||||||
|     , accountlistmode_ = ALFlat |     , accountlistmode_ = ALFlat | ||||||
|     , drop_            = 0 |     , drop_            = 0 | ||||||
|     , row_total_       = False |     , row_total_       = False | ||||||
| @ -212,8 +216,9 @@ rawOptsToReportOpts rawopts = do | |||||||
|           ,average_     = boolopt "average" rawopts |           ,average_     = boolopt "average" rawopts | ||||||
|           ,related_     = boolopt "related" rawopts |           ,related_     = boolopt "related" rawopts | ||||||
|           ,txn_dates_   = boolopt "txn-dates" rawopts |           ,txn_dates_   = boolopt "txn-dates" rawopts | ||||||
|           ,balancecalc_  = balancecalcopt rawopts |           ,balancecalc_ = balancecalcopt rawopts | ||||||
|           ,balanceaccum_ = balanceaccumopt rawopts |           ,balanceaccum_ = balanceaccumopt rawopts | ||||||
|  |           ,budgetpat_   = maybebudgetpatternopt rawopts | ||||||
|           ,accountlistmode_ = accountlistmodeopt rawopts |           ,accountlistmode_ = accountlistmodeopt rawopts | ||||||
|           ,drop_        = posintopt "drop" rawopts |           ,drop_        = posintopt "drop" rawopts | ||||||
|           ,row_total_   = boolopt "row-total" rawopts |           ,row_total_   = boolopt "row-total" rawopts | ||||||
| @ -289,6 +294,10 @@ accountlistmodeopt = | |||||||
|       "flat" -> Just ALFlat |       "flat" -> Just ALFlat | ||||||
|       _      -> Nothing |       _      -> Nothing | ||||||
| 
 | 
 | ||||||
|  | -- Get the argument of the --budget option if any, or the empty string. | ||||||
|  | maybebudgetpatternopt :: RawOpts -> Maybe T.Text | ||||||
|  | maybebudgetpatternopt = fmap T.pack . maybestringopt "budget" | ||||||
|  | 
 | ||||||
| balancecalcopt :: RawOpts -> BalanceCalculation | balancecalcopt :: RawOpts -> BalanceCalculation | ||||||
| balancecalcopt = | balancecalcopt = | ||||||
|   fromMaybe CalcChange . choiceopt parse where |   fromMaybe CalcChange . choiceopt parse where | ||||||
|  | |||||||
| @ -277,8 +277,14 @@ balancemode = hledgerCommandMode | |||||||
|   ( |   ( | ||||||
|     [flagNone ["sum"] (setboolopt "sum") |     [flagNone ["sum"] (setboolopt "sum") | ||||||
|       "show sum of posting amounts (default)" |       "show sum of posting amounts (default)" | ||||||
|     ,flagNone ["budget"] (setboolopt "budget") |     -- XXX --budget[=DESCPAT], --forecast[=PERIODEXP], could be more consistent | ||||||
|       "show sum of posting amounts compared to budget goals defined by periodic transactions\n " |     ,flagOpt "" ["budget"] (\s opts -> Right $ setopt "budget" s opts) "DESCPAT" | ||||||
|  |       (unlines | ||||||
|  |       [ "show sum of posting amounts together with budget goals defined by periodic" | ||||||
|  |       , "transactions. With a DESCPAT argument (must be separated by = not space)," | ||||||
|  |       , "use only periodic transactions with matching description" | ||||||
|  |       , "(case insensitive substring match)." | ||||||
|  |       ])     | ||||||
|     ,flagNone ["valuechange"] (setboolopt "valuechange") |     ,flagNone ["valuechange"] (setboolopt "valuechange") | ||||||
|       "show change of value of period-end historical balances" |       "show change of value of period-end historical balances" | ||||||
|     ,flagNone ["change"] (setboolopt "change") |     ,flagNone ["change"] (setboolopt "change") | ||||||
|  | |||||||
| @ -606,7 +606,7 @@ Budget performance in 2020-01-01..2020-01-15: | |||||||
|                ||     $400 [80% of $500]  |                ||     $400 [80% of $500]  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| #### Nested budgets | #### Budgets and subaccounts | ||||||
| 
 | 
 | ||||||
| You can add budgets to any account in your account hierarchy. If you have budgets on both parent account and some of its children, then budget(s) | You can add budgets to any account in your account hierarchy. If you have budgets on both parent account and some of its children, then budget(s) | ||||||
| of the child account(s) would be added to the budget of their parent, much like account balances behave. | of the child account(s) would be added to the budget of their parent, much like account balances behave. | ||||||
| @ -685,6 +685,27 @@ Budget performance in 2019/01: | |||||||
|                                         ||        0 [                 0]  |                                         ||        0 [                 0]  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | #### Selecting budget goals | ||||||
|  | 
 | ||||||
|  | The budget report evaluates periodic transaction rules to generate special "goal transactions", | ||||||
|  | which generate the goal amounts for each account in each report subperiod. | ||||||
|  | When troubleshooting, you can use the print command to show these as forecasted transactions: | ||||||
|  | ```shell | ||||||
|  | $ hledger print --forecast=BUDGETREPORTPERIOD tag:generated | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | By default, the budget report uses all available periodic transaction rules to generate goals. | ||||||
|  | This includes rules with a different report interval from your report.  | ||||||
|  | Eg if you have daily, weekly and monthly periodic rules, | ||||||
|  | all of these will contribute to the goals in a monthly budget report. | ||||||
|  | 
 | ||||||
|  | You can select a subset of periodic rules by providing an argument to the `--budget` flag. | ||||||
|  | `--budget=DESCPAT` will match all periodic rules whose description contains DESCPAT,  | ||||||
|  | a case-insensitive substring (not a regular expression or query). | ||||||
|  | This means you can give your periodic rules descriptions | ||||||
|  | (remember that [two spaces are needed](#two-spaces-between-period-expression-and-description)), | ||||||
|  | and then select from multiple budgets defined in your journal. | ||||||
|  | 
 | ||||||
| ### Customising single-period balance reports | ### Customising single-period balance reports | ||||||
| 
 | 
 | ||||||
| For single-period balance reports displayed in the terminal (only), | For single-period balance reports displayed in the terminal (only), | ||||||
|  | |||||||
| @ -595,3 +595,19 @@ Budget performance in 2020Q1: | |||||||
|  expenses:food ||  $400 [80% of $500]  0 [0% of $500]   $600 [120% of $500]  |  expenses:food ||  $400 [80% of $500]  0 [0% of $500]   $600 [120% of $500]  | ||||||
| ---------------++----------------------------------------------------------- | ---------------++----------------------------------------------------------- | ||||||
|                ||     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. | ||||||
|  | < | ||||||
|  | ~ weekly   weekly budget | ||||||
|  |   (aaa)   1 | ||||||
|  | 
 | ||||||
|  | ~ monthly  monthly budget | ||||||
|  |   (bbb)   10 | ||||||
|  | 
 | ||||||
|  | $ hledger -f- bal --budget=weekly -p 2021-01 | ||||||
|  | > /aaa/ | ||||||
|  | >= | ||||||
|  | 
 | ||||||
|  | $ hledger -f- bal --budget=monthly -p 2021-01 | ||||||
|  | > !/aaa/ | ||||||
|  | >= | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user