[AI] Add option to 'Copy [budget] to future months'#7420
[AI] Add option to 'Copy [budget] to future months'#7420nikhilweee wants to merge 18 commits intoactualbudget:masterfrom
Conversation
Adds a new per-category budget menu option that copies the current month's budgeted amount to all future months that already exist in the budget. Works for both envelope and tracking budget types, and on both desktop (inline popover) and mobile (modal) views.
|
👋 Hello contributor! We would love to review your PR! Before we can do that, please make sure:
We do this to reduce the TOIL the core contributor team has to go through for each PR and to allow for speedy reviews and merges. For more information, please see our Contributing Guide. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR introduces a "Copy until year end" feature for per-category budgets. Users can now copy the current month's budgeted amount to all remaining months within the same calendar year. Changes span frontend components, backend action logic, server endpoint registration, tests, and documentation. ChangesCopy Until Year End Feature
Sequence DiagramsequenceDiagram
participant User
participant UI as BudgetMenu<br/>(Desktop/Mobile)
participant Mutation as useBudgetActions<br/>Mutation
participant Server as Backend<br/>budget/copy-until-year-end
participant DB as Budget<br/>Database
User->>UI: Select "Copy until year end"
UI->>Mutation: onCopyUntilYearEnd() or<br/>onMenuAction('copy-until-year-end')
Mutation->>Mutation: Dispatch mutation with<br/>type & category/month
Mutation->>Server: send('budget/copy-until-year-end',<br/>{ month, category })
Server->>Server: Read current month<br/>budget amount
Server->>Server: Compute future months<br/>within year boundary
Server->>DB: setBudget() for each<br/>future month
DB-->>Server: Budgets updated
Server-->>UI: Success (undoable)
UI->>User: Show undo notification<br/>"Budget copied until year end"
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/loot-core/src/server/budget/actions.test.ts (1)
15-77: Add one tracking-budget test for this new action.Current coverage validates envelope behavior, but the feature target includes tracking budgets too. Please add a case that sets budget type to tracking and verifies
copyToFutureMonthsstill copies the selected category budget into later created months.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/loot-core/src/server/budget/actions.test.ts` around lines 15 - 77, Add a new test case in the same describe block that mirrors the "copies the current month budget to all future created months" test but uses a tracking budget: after setupDatabase(), call setBudget with category 'cat1', month '2024-01', amount (e.g. 5000) and include the tracking type flag (e.g. type: 'tracking' or tracking: true depending on setBudget signature), keep later months set to other values, call copyToFutureMonths({ month: '2024-01', category: 'cat1' }) and assert via getSheetValue('budget202401'/'budget202402'/'budget202403', 'budget-cat1') that the tracking budget from 2024-01 was copied into the later months. Ensure you await sheet.waitOnSpreadsheet() where other tests do.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/loot-core/src/server/budget/actions.test.ts`:
- Around line 15-77: Add a new test case in the same describe block that mirrors
the "copies the current month budget to all future created months" test but uses
a tracking budget: after setupDatabase(), call setBudget with category 'cat1',
month '2024-01', amount (e.g. 5000) and include the tracking type flag (e.g.
type: 'tracking' or tracking: true depending on setBudget signature), keep later
months set to other values, call copyToFutureMonths({ month: '2024-01',
category: 'cat1' }) and assert via
getSheetValue('budget202401'/'budget202402'/'budget202403', 'budget-cat1') that
the tracking budget from 2024-01 was copied into the later months. Ensure you
await sheet.waitOnSpreadsheet() where other tests do.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 762f4e6e-2b58-4cfc-bf12-dc5d71dfe1e0
📒 Files selected for processing (13)
packages/desktop-client/src/budget/mutations.tspackages/desktop-client/src/components/budget/envelope/BudgetMenu.tsxpackages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsxpackages/desktop-client/src/components/budget/tracking/BudgetMenu.tsxpackages/desktop-client/src/components/budget/tracking/TrackingBudgetComponents.tsxpackages/desktop-client/src/components/mobile/budget/BudgetCell.tsxpackages/desktop-client/src/components/modals/EnvelopeBudgetMenuModal.tsxpackages/desktop-client/src/components/modals/TrackingBudgetMenuModal.tsxpackages/desktop-client/src/modals/modalsSlice.tspackages/loot-core/src/server/budget/actions.test.tspackages/loot-core/src/server/budget/actions.tspackages/loot-core/src/server/budget/app.tsupcoming-release-notes/7420.md
|
This is ready for review from my end. The failing CI seems to be an infrastructure issue. Happy to work with you to resolve it. |
✅ Deploy Preview for actualbudget ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for actualbudget-storybook ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for actualbudget-website ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for actualbudget ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for actualbudget ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for actualbudget-storybook ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for actualbudget-website ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Hi folks, now that CI is fixed I'd really appreciate some feedback! |
|
Why would you want to push out a budget amount for a whole year? That seems like it would make more extra work not less |
|
@youngcw it is very useful in yearly budget planning where you set future months budgets in advance. Right now the app only allows you to "look back" at the past 1, 3, 6, 12 month averages however I like to plan future month's budgets too. Let's say I allocate budgets from Jan to Dec but in March I realise I need to allocate 500 cocos every month because I added a monthly expense. Instead of clicking "copy last month's budget" 9 times, I'd rather just have a way to "carry over" the current budget amount to future months. If it helps I am happy to limit this feature to 12 months. |
|
@StephenBrown2 ah yes sorry forgot to mention that I'm currently already using tracking budget where I don't need to have the funds for before I set up the budget for future months. I'm sure everybody uses actualbudget differently and in my case I also like to go back and re-evaluate previous months budgets. With rollover spending turned on, this PR allows me to easily set the budget for all future months. I'm coming from Monarch Money and there if you set a budget for a month, it's automatically set to all future months by default. Another reason why I really miss this feature. I did take a look at templates, and forgive me if I'm mistaken but it looks like I will still need to apply the 'template' to all months individually. The goal of this PR is to have a one-click solution instead. In a case where I observe that I spend 300 cocos on groceries in Jan, Feb and March, I can simplty click this button to set the grocery budget for all future months to 300 with one click. Even if there was a keyboard shortcut to go to the same category in the next month (like a tab key) that would have given me a lot of mileage but unfortuntaely we don't have that option either. |
|
Would it make sense to only enable this on the tracking budget then? |
|
@youngcw That's a fair question. My primary use case is tracking budget, so limiting it there would still work for me personally. That said, I'd argue there's value in keeping it for envelope budgeting too. A few reasons:
I'm happy to limit it to tracking budget if that's the direction you prefer, but wanted to make the case that envelope users have legitimate reasons to want this too. |
Only copy the budget value to future months that already have a non-zero budget set for the category. Months with no budget (zero) are left untouched.
|
Also just pushed an update: the action now skips future months where the budget is zero/unset for that category. So it only updates months that already have a value. It won't fill in months you haven't planned yet. @StephenBrown2 hopefully this should address the over-budgeting concern for envelope users as well. |
|
Hey @youngcw, @joel-jeremy with the latest update I think the over-budgeting concern for envelope users is addressed. What do you think? Any other blockers before this can move forward? |
|
Hey @youngcw @joel-jeremy let me know what you think. This has been up for a while, would love to move it forward. |
|
Hey @youngcw @joel-jeremy just checking in again. I think the previous concerns have been addressed. Is there anything else blocking this from moving forward? |
|
Im still not seeing how this is useful at all with the envelope budget style, especially with the change to not budget in months with not budget at apply time. I can see this being useful with the tracking budget. I would be fine adding this to the tracking budget, maybe with the check to only extend out to the end of the current year. It could be added to the tracking budget and then see if anyone wants it in the envelope budget. There should be some documentation about this especially if you leave in the only apply to existing budgets check. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/desktop-client/src/components/mobile/budget/BudgetCell.tsx`:
- Around line 138-140: The undo notification message passed to
showUndoNotification is not translated; update the call in BudgetCell
(function/component BudgetCell, where showUndoNotification is used) to wrap the
user-facing string with t(...) and interpolate category.name via i18n (e.g., use
a placeholder like "{{name}} budget copied until year end." and pass { name:
category.name } to t) so the displayed message is localized; the t function is
already imported/destructured in scope.
In `@packages/docs/docs/getting-started/tracking-budget.md`:
- Around line 71-75: Update the "Copy until year end" paragraph so it
consistently states that the action copies the current month's budget only to
remaining months in the same calendar year that already have a non‑zero or
explicitly set budget for that category (i.e., it will skip future months where
that category's budget is zero or unset); revise the first sentence and the
example to reflect this precise behavior and replace the ambiguous phrase "has
already been created in the budget" with "already have a non‑zero or explicitly
set budget for that category" and note that months with zero/unset category
budgets are skipped.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0f8f2a33-e2c0-4d1d-8bbc-d543e06653a3
📒 Files selected for processing (11)
packages/desktop-client/src/budget/mutations.tspackages/desktop-client/src/components/budget/tracking/BudgetMenu.tsxpackages/desktop-client/src/components/budget/tracking/TrackingBudgetComponents.tsxpackages/desktop-client/src/components/mobile/budget/BudgetCell.tsxpackages/desktop-client/src/components/modals/TrackingBudgetMenuModal.tsxpackages/desktop-client/src/modals/modalsSlice.tspackages/docs/docs/getting-started/tracking-budget.mdpackages/loot-core/src/server/budget/actions.test.tspackages/loot-core/src/server/budget/actions.tspackages/loot-core/src/server/budget/app.tsupcoming-release-notes/7420.md
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/loot-core/src/server/budget/actions.test.ts
| The **Copy until year end** option in the per-category budget menu copies the current month's budgeted amount to all remaining months of the same calendar year at once. | ||
|
|
||
| To use it, click the budget amount for a category to open the budget menu, then select **Copy until year end**. The current month's amount will be written to every future month in the same year that has already been created in the budget. | ||
|
|
||
| This is useful when you add or change a recurring expense and want to update all future planned months without clicking through each one individually. For example, if you realise in March that your grocery budget should be $300 for the rest of the year, you can set it once and copy it to April through December in one click. |
There was a problem hiding this comment.
Documentation inconsistency: first sentence contradicts the qualification in the second.
Line 71 says the amount is copied to "all remaining months" (unconditionally), while line 73 scopes that to "every future month … that has already been created in the budget." A user reading the first sentence will expect a write to every month through December; the qualifier on line 73 then surprises them.
Additionally, from the PR discussion, the action skips future months where that category's budget is zero or unset. The phrase "has already been created in the budget" is ambiguous — it could mean the month period exists, or that the category row is non-zero. If the intent is the latter, that distinction is worth spelling out (as youngcw specifically requested docs for this behaviour).
Suggested fix to make the section self-consistent and accurate:
📝 Proposed documentation fix
-The **Copy until year end** option in the per-category budget menu copies the current month's budgeted amount to all remaining months of the same calendar year at once.
+The **Copy until year end** option in the per-category budget menu copies the current month's budgeted amount to every later month in the same calendar year that already has a non-zero budget set for that category.
-To use it, click the budget amount for a category to open the budget menu, then select **Copy until year end**. The current month's amount will be written to every future month in the same year that has already been created in the budget.
+To use it, click the budget amount for a category to open the budget menu, then select **Copy until year end**. The current month's amount will be written to every future month in the same year where that category already has a budgeted amount set; months where the category budget is zero or unset are left unchanged.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| The **Copy until year end** option in the per-category budget menu copies the current month's budgeted amount to all remaining months of the same calendar year at once. | |
| To use it, click the budget amount for a category to open the budget menu, then select **Copy until year end**. The current month's amount will be written to every future month in the same year that has already been created in the budget. | |
| This is useful when you add or change a recurring expense and want to update all future planned months without clicking through each one individually. For example, if you realise in March that your grocery budget should be $300 for the rest of the year, you can set it once and copy it to April through December in one click. | |
| The **Copy until year end** option in the per-category budget menu copies the current month's budgeted amount to every later month in the same calendar year that already has a non-zero budget set for that category. | |
| To use it, click the budget amount for a category to open the budget menu, then select **Copy until year end**. The current month's amount will be written to every future month in the same year where that category already has a budgeted amount set; months where the category budget is zero or unset are left unchanged. | |
| This is useful when you add or change a recurring expense and want to update all future planned months without clicking through each one individually. For example, if you realise in March that your grocery budget should be $300 for the rest of the year, you can set it once and copy it to April through December in one click. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/docs/docs/getting-started/tracking-budget.md` around lines 71 - 75,
Update the "Copy until year end" paragraph so it consistently states that the
action copies the current month's budget only to remaining months in the same
calendar year that already have a non‑zero or explicitly set budget for that
category (i.e., it will skip future months where that category's budget is zero
or unset); revise the first sentence and the example to reflect this precise
behavior and replace the ambiguous phrase "has already been created in the
budget" with "already have a non‑zero or explicitly set budget for that
category" and note that months with zero/unset category budgets are skipped.
There was a problem hiding this comment.
Thanks for catching the inconsistency. I addressed it in efd96b6, but I diverged from the suggested wording: the skip-zero behavior was deliberately removed in f39a312 (based on reviewer feedback to keep this simple and tracking-only). The action now copies the current month's amount to every future month in the same calendar year, regardless of whether the existing budget is zero or non-zero. The updated docs reflect that.
There was a problem hiding this comment.
@nikhilweee, thanks for the clarification! That makes perfect sense — since the skip-zero logic was removed, the docs correctly describing an unconditional copy to all future months is the right approach. The updated wording ("overwriting any existing value for that category in those months") is clear and accurate. Appreciate you explaining the context behind the divergence from the suggestion.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
Adds a new per-category budget menu option that copies the current month's budgeted amount to all future months that already exist in the budget. Only months with a non-zero budget value for the selected category are updated, months with no budget set are skipped. Works for both envelope and tracking budget types, and on both desktop (inline popover) and mobile (modal) views.
Description
I often find myself looking for a way to adjust the budget for multiple months at a time, and today there is no way to do so. The only option is to manually click on each month and copy paste values which is unsustainable. This PR adds an option to copy the current month's budget to future months.
Related issue(s)
None that I could find. Although similar issues discuss copying last month's budget to the current month.
Testing
In the budget view, after entering a value in the 'budget' column, click the dropdown and select 'copy to future months'. This should copy the value to all future months that already exist in the budget.
Checklist
Bundle Stats
View detailed bundle stats
desktop-client
Total
Changeset
src/components/budget/tracking/BudgetMenu.tsxsrc/components/mobile/budget/BudgetCell.tsxsrc/components/modals/TrackingBudgetMenuModal.tsxsrc/budget/mutations.tssrc/components/budget/tracking/TrackingBudgetComponents.tsxlocale/en.jsonlocale/pt-BR.jsonlocale/ca.jsonlocale/es.jsonlocale/fr.jsonlocale/de.jsonlocale/it.jsonlocale/uk.jsonlocale/nb-NO.jsonlocale/zh-Hans.jsonlocale/nl.jsonlocale/pl.jsonlocale/da.jsonlocale/th.jsonView detailed bundle breakdown
Added
No assets were added
Removed
No assets were removed
Bigger
Smaller
Unchanged
loot-core
Total
Changeset
home/runner/work/actual/actual/packages/loot-core/src/server/budget/actions.tshome/runner/work/actual/actual/packages/loot-core/src/shared/months.tshome/runner/work/actual/actual/packages/loot-core/src/server/budget/app.tsView detailed bundle breakdown
Added
Removed
Bigger
No assets were bigger
Smaller
No assets were smaller
Unchanged
No assets were unchanged
api
Total
Changeset
home/runner/work/actual/actual/packages/loot-core/src/server/budget/actions.tshome/runner/work/actual/actual/packages/loot-core/src/shared/months.tshome/runner/work/actual/actual/packages/loot-core/src/server/budget/app.tsView detailed bundle breakdown
Added
No assets were added
Removed
No assets were removed
Bigger
Smaller
No assets were smaller
Unchanged
cli
Total
View detailed bundle breakdown
Added
No assets were added
Removed
No assets were removed
Bigger
No assets were bigger
Smaller
No assets were smaller
Unchanged
crdt
Total
View detailed bundle breakdown
Added
No assets were added
Removed
No assets were removed
Bigger
No assets were bigger
Smaller
No assets were smaller
Unchanged