diff --git a/hledger-lib/Hledger/Reports/BudgetReport.hs b/hledger-lib/Hledger/Reports/BudgetReport.hs index 3c73c8800..e226ec540 100644 --- a/hledger-lib/Hledger/Reports/BudgetReport.hs +++ b/hledger-lib/Hledger/Reports/BudgetReport.hs @@ -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, -- for BudgetReport. 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: where 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 = dbg5 "budget goal txns" $ [makeBudgetTxn t | pt <- jperiodictxns j + , pat `T.isInfixOf` T.toLower (ptdescription pt) , t <- runPeriodicTransaction pt budgetspan ] makeBudgetTxn t = txnTieKnot $ t { tdescription = T.pack "Budget transaction" } diff --git a/hledger-lib/Hledger/Reports/ReportOptions.hs b/hledger-lib/Hledger/Reports/ReportOptions.hs index 43079f156..fb82f42d3 100644 --- a/hledger-lib/Hledger/Reports/ReportOptions.hs +++ b/hledger-lib/Hledger/Reports/ReportOptions.hs @@ -117,8 +117,11 @@ data ReportOpts = ReportOpts { -- for account transactions reports (aregister) ,txn_dates_ :: Bool -- for balance reports (bal, bs, cf, is) - ,balancecalc_ :: BalanceCalculation - ,balanceaccum_ :: BalanceAccumulation + ,balancecalc_ :: BalanceCalculation -- ^ What to calculate in balance report cells + ,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 ,drop_ :: Int ,row_total_ :: Bool @@ -167,6 +170,7 @@ defreportopts = ReportOpts , txn_dates_ = False , balancecalc_ = def , balanceaccum_ = def + , budgetpat_ = Nothing , accountlistmode_ = ALFlat , drop_ = 0 , row_total_ = False @@ -212,8 +216,9 @@ rawOptsToReportOpts rawopts = do ,average_ = boolopt "average" rawopts ,related_ = boolopt "related" rawopts ,txn_dates_ = boolopt "txn-dates" rawopts - ,balancecalc_ = balancecalcopt rawopts + ,balancecalc_ = balancecalcopt rawopts ,balanceaccum_ = balanceaccumopt rawopts + ,budgetpat_ = maybebudgetpatternopt rawopts ,accountlistmode_ = accountlistmodeopt rawopts ,drop_ = posintopt "drop" rawopts ,row_total_ = boolopt "row-total" rawopts @@ -289,6 +294,10 @@ accountlistmodeopt = "flat" -> Just ALFlat _ -> 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 = fromMaybe CalcChange . choiceopt parse where diff --git a/hledger/Hledger/Cli/Commands/Balance.hs b/hledger/Hledger/Cli/Commands/Balance.hs index b7958c4e9..30aec8a77 100644 --- a/hledger/Hledger/Cli/Commands/Balance.hs +++ b/hledger/Hledger/Cli/Commands/Balance.hs @@ -277,8 +277,14 @@ balancemode = hledgerCommandMode ( [flagNone ["sum"] (setboolopt "sum") "show sum of posting amounts (default)" - ,flagNone ["budget"] (setboolopt "budget") - "show sum of posting amounts compared to budget goals defined by periodic transactions\n " + -- XXX --budget[=DESCPAT], --forecast[=PERIODEXP], could be more consistent + ,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") "show change of value of period-end historical balances" ,flagNone ["change"] (setboolopt "change") diff --git a/hledger/Hledger/Cli/Commands/Balance.md b/hledger/Hledger/Cli/Commands/Balance.md index e5a95c197..893506e05 100644 --- a/hledger/Hledger/Cli/Commands/Balance.md +++ b/hledger/Hledger/Cli/Commands/Balance.md @@ -606,7 +606,7 @@ Budget performance in 2020-01-01..2020-01-15: || $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) 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] ``` +#### 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 For single-period balance reports displayed in the terminal (only), diff --git a/hledger/test/balance/budget.test b/hledger/test/balance/budget.test index 6793b325b..de1474c24 100644 --- a/hledger/test/balance/budget.test +++ b/hledger/test/balance/budget.test @@ -595,3 +595,19 @@ Budget performance in 2020Q1: 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] + +# 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/ +>=