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