diff --git a/packages/loot-core/src/server/budget/goal-template.pegjs b/packages/loot-core/src/server/budget/goal-template.pegjs index 094ece260a4a1f2b54c6f4273796e2ca8e6c9b84..4e93301e7f9c8280a6660c7008e7f7069f18933e 100644 --- a/packages/loot-core/src/server/budget/goal-template.pegjs +++ b/packages/loot-core/src/server/budget/goal-template.pegjs @@ -22,6 +22,8 @@ expr { return { type: 'schedule', name, priority: +priority, full } } / priority: priority? _? remainder: remainder { return { type: 'remainder', priority: null, weight: remainder } } + / priority: priority? _? 'average'i _ amount: positive _ 'months'i? + { return { type: 'average', amount: +amount, priority: +priority }} repeat 'repeat interval' diff --git a/packages/loot-core/src/server/budget/goals/goalsAverage.ts b/packages/loot-core/src/server/budget/goals/goalsAverage.ts new file mode 100644 index 0000000000000000000000000000000000000000..44151a59d1d27437a1edcd9b0bf4f80438d8295e --- /dev/null +++ b/packages/loot-core/src/server/budget/goals/goalsAverage.ts @@ -0,0 +1,31 @@ +// @ts-strict-ignore + +import * as monthUtils from '../../../shared/months'; +import { getSheetValue } from '../actions'; + +export async function goalsAverage( + template, + month, + category, + errors, + to_budget, +) { + // simple has an 'amount' param + let increment = 0; + if (template.amount) { + let sum = 0; + for (let i = 1; i <= template.amount; i++) { + // add up other months + const sheetName = monthUtils.sheetForMonth( + monthUtils.subMonths(month, i), + ); + sum += await getSheetValue(sheetName, `sum-amount-${category.id}`); + } + increment = sum / template.amount; + } else { + errors.push('Number of months to average is not valid'); + return { to_budget, errors }; + } + to_budget += -Math.round(increment); + return { to_budget, errors }; +} diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index d2d6984905372b50672235ae753596351129242b..aed1be66630a901189efc8dd08fb5ff5278e33bf 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -7,6 +7,7 @@ import { batchMessages } from '../sync'; import { setBudget, getSheetValue, isReflectBudget, setGoal } from './actions'; import { parse } from './goal-template.pegjs'; +import { goalsAverage } from './goals/goalsAverage'; import { goalsBy } from './goals/goalsBy'; import { goalsPercentage } from './goals/goalsPercentage'; import { findRemainder, goalsRemainder } from './goals/goalsRemainder'; @@ -609,6 +610,18 @@ async function applyCategoryTemplate( to_budget = goalsReturn.to_budget; break; } + case 'average': { + const goalsReturn = await goalsAverage( + template, + current_month, + category, + errors, + to_budget, + ); + to_budget = goalsReturn.to_budget; + errors = goalsReturn.errors; + break; + } case 'error': return { errors }; default: diff --git a/upcoming-release-notes/2688.md b/upcoming-release-notes/2688.md new file mode 100644 index 0000000000000000000000000000000000000000..f4350661845ef4c7b9e5fa38367fc2489c363991 --- /dev/null +++ b/upcoming-release-notes/2688.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [youngcw] +--- + +Goals: Add template to budget X months average spending. Matches the funcion of the existing budget page button.