diff --git a/packages/loot-core/src/server/budget/goals/goalsBy.ts b/packages/loot-core/src/server/budget/goals/goalsBy.ts index 862aebe91f6..d58110a7220 100644 --- a/packages/loot-core/src/server/budget/goals/goalsBy.ts +++ b/packages/loot-core/src/server/budget/goals/goalsBy.ts @@ -43,5 +43,5 @@ export async function goalsBy( } else { errors.push(`by templates are not supported in Report budgets`); } - return { to_budget, errors }; + return { to_budget, errors, remainder }; } diff --git a/packages/loot-core/src/server/budget/goals/goalsPercentage.ts b/packages/loot-core/src/server/budget/goals/goalsPercentage.ts index 2f296b7aa4e..4c8f5b8f8b3 100644 --- a/packages/loot-core/src/server/budget/goals/goalsPercentage.ts +++ b/packages/loot-core/src/server/budget/goals/goalsPercentage.ts @@ -31,7 +31,7 @@ export async function goalsPercentage( ); if (!income_category) { errors.push(`Could not find category “${template.category}”`); - return { errors }; + return { to_budget, errors }; } if (template.previous) { let sheetName_lastmonth = monthUtils.sheetForMonth( diff --git a/packages/loot-core/src/server/budget/goals/goalsRemainder.ts b/packages/loot-core/src/server/budget/goals/goalsRemainder.ts index 0d1de680d93..0b93748f308 100644 --- a/packages/loot-core/src/server/budget/goals/goalsRemainder.ts +++ b/packages/loot-core/src/server/budget/goals/goalsRemainder.ts @@ -19,3 +19,28 @@ export async function goalsRemainder( } return { to_budget }; } + +export function findRemainder(priority_list, categories, category_templates) { + // find all remainder templates, place them at highest priority + let remainder_found; + let remainder_weight_total = 0; + let remainder_priority = priority_list[priority_list.length - 1] + 1; + for (let c = 0; c < categories.length; c++) { + let category = categories[c]; + let templates = category_templates[category.id]; + if (templates) { + for (let i = 0; i < templates.length; i++) { + if (templates[i].type === 'remainder') { + templates[i].priority = remainder_priority; + remainder_weight_total += templates[i].weight; + remainder_found = true; + } + } + } + } + return { + remainder_found: remainder_found, + remainder_priority: remainder_priority, + remainder_weight_total: remainder_weight_total, + }; +} diff --git a/packages/loot-core/src/server/budget/goals/goalsSchedule.ts b/packages/loot-core/src/server/budget/goals/goalsSchedule.ts index 83ff73bc274..f75bd7506ee 100644 --- a/packages/loot-core/src/server/budget/goals/goalsSchedule.ts +++ b/packages/loot-core/src/server/budget/goals/goalsSchedule.ts @@ -4,7 +4,7 @@ import * as db from '../../db'; import { getRuleForSchedule, getNextDate } from '../../schedules/app'; import { isReflectBudget } from '../actions'; -export async function goalsSchededule( +export async function goalsSchedule( scheduleFlag, template_lines, current_month, @@ -165,5 +165,5 @@ export async function goalsSchededule( increment = Math.round(increment); to_budget += increment; } - return { to_budget, errors }; + return { to_budget, errors, remainder }; } diff --git a/packages/loot-core/src/server/budget/goals/goalsSimple.ts b/packages/loot-core/src/server/budget/goals/goalsSimple.ts index e0637967d17..7a297c323eb 100644 --- a/packages/loot-core/src/server/budget/goals/goalsSimple.ts +++ b/packages/loot-core/src/server/budget/goals/goalsSimple.ts @@ -12,7 +12,7 @@ export async function goalsSimple( if (template.limit != null) { if (limitCheck) { errors.push(`More than one “up to” limit found.`); - return { errors }; + return { to_budget, errors, limit, limitCheck, hold }; } else { limitCheck = true; limit = amountToInteger(template.limit.amount); @@ -27,5 +27,5 @@ export async function goalsSimple( increment = limit; } to_budget += increment; - return { to_budget, errors }; + return { to_budget, errors, limit, limitCheck, hold }; } diff --git a/packages/loot-core/src/server/budget/goals/goalsSpend.ts b/packages/loot-core/src/server/budget/goals/goalsSpend.ts index 6088ca0df22..dc49fc18335 100644 --- a/packages/loot-core/src/server/budget/goals/goalsSpend.ts +++ b/packages/loot-core/src/server/budget/goals/goalsSpend.ts @@ -41,7 +41,7 @@ export async function goalsSpend( let increment = 0; if (num_months < 0) { errors.push(`${template.month} is in the past.`); - return { errors }; + return { to_budget, errors }; } else if (num_months === 0) { increment = target - already_budgeted; } else { diff --git a/packages/loot-core/src/server/budget/goals/goalsWeek.ts b/packages/loot-core/src/server/budget/goals/goalsWeek.ts index c41a823854b..f7d3aed87f2 100644 --- a/packages/loot-core/src/server/budget/goals/goalsWeek.ts +++ b/packages/loot-core/src/server/budget/goals/goalsWeek.ts @@ -14,9 +14,9 @@ export async function goalsWeek( let amount = amountToInteger(template.amount); let weeks = template.weeks != null ? Math.round(template.weeks) : 1; if (template.limit != null) { - if (limit != null) { + if (limit > 0) { errors.push(`More than one “up to” limit found.`); - return { errors }; + return { to_budget, errors, limit, limitCheck, hold }; } else { limitCheck = true; limit = amountToInteger(template.limit.amount); @@ -32,5 +32,5 @@ export async function goalsWeek( } w = monthUtils.addWeeks(w, weeks); } - return { to_budget, errors }; + return { to_budget, errors, limit, limitCheck, hold }; } diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index 35bfe788689..5846cfc1833 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -8,8 +8,8 @@ import { setBudget, getSheetValue, isReflectBudget, setGoal } from './actions'; import { parse } from './goal-template.pegjs'; import { goalsBy } from './goals/goalsBy'; import { goalsPercentage } from './goals/goalsPercentage'; -import { goalsRemainder } from './goals/goalsRemainder'; -import { goalsSchededule } from './goals/goalsSchedule'; +import { findRemainder, goalsRemainder } from './goals/goalsRemainder'; +import { goalsSchedule } from './goals/goalsSchedule'; import { goalsSimple } from './goals/goalsSimple'; import { goalsSpend } from './goals/goalsSpend'; import { goalsWeek } from './goals/goalsWeek'; @@ -200,23 +200,8 @@ async function processTemplate( .sort() .filter((item, index, curr) => curr.indexOf(item) === index); - // find all remainder templates, place them at highest priority - let remainder_found; - let remainder_weight_total = 0; - let remainder_priority = priority_list[priority_list.length - 1] + 1; - for (let c = 0; c < categories.length; c++) { - let category = categories[c]; - let templates = category_templates[category.id]; - if (templates) { - for (let i = 0; i < templates.length; i++) { - if (templates[i].type === 'remainder') { - templates[i].priority = remainder_priority; - remainder_weight_total += templates[i].weight; - remainder_found = true; - } - } - } - } + let { remainder_found, remainder_priority, remainder_weight_total } = + findRemainder(priority_list, categories, category_templates); if (remainder_found) priority_list.push(remainder_priority); let sheetName = monthUtils.sheetForMonth(month); @@ -304,7 +289,6 @@ async function processTemplate( available_start, budgetAvailable, prev_budgeted, - force, ); if (to_budget != null) { num_applied++; @@ -444,7 +428,6 @@ async function applyCategoryTemplate( available_start, budgetAvailable, prev_budgeted, - force, ) { let current_month = `${month}-01`; let errors = []; @@ -517,15 +500,17 @@ async function applyCategoryTemplate( } }); } - let sheetName = monthUtils.sheetForMonth(month); - let spent = await getSheetValue(sheetName, `sum-amount-${category.id}`); - let balance = await getSheetValue(sheetName, `leftover-${category.id}`); + + const sheetName = monthUtils.sheetForMonth(month); + const spent = await getSheetValue(sheetName, `sum-amount-${category.id}`); + const balance = await getSheetValue(sheetName, `leftover-${category.id}`); + const last_month_balance = balance - spent - prev_budgeted; let to_budget = 0; let limit = 0; let hold = false; let limitCheck = false; - let last_month_balance = balance - spent - prev_budgeted; let remainder = 0; + for (let l = 0; l < template_lines.length; l++) { let template = template_lines[l]; switch (template.type) { @@ -540,6 +525,9 @@ async function applyCategoryTemplate( ); to_budget = goalsReturn.to_budget; errors = goalsReturn.errors; + limit = goalsReturn.limit; + limitCheck = goalsReturn.limitCheck; + hold = goalsReturn.hold; break; } case 'by': { @@ -555,6 +543,7 @@ async function applyCategoryTemplate( ); to_budget = goalsReturn.to_budget; errors = goalsReturn.errors; + remainder = goalsReturn.remainder; break; } case 'week': { @@ -569,6 +558,9 @@ async function applyCategoryTemplate( ); to_budget = goalsReturn.to_budget; errors = goalsReturn.errors; + limit = goalsReturn.limit; + limitCheck = goalsReturn.limitCheck; + hold = goalsReturn.hold; break; } case 'spend': { @@ -598,7 +590,7 @@ async function applyCategoryTemplate( break; } case 'schedule': { - let goalsReturn = await goalsSchededule( + let goalsReturn = await goalsSchedule( scheduleFlag, template_lines, current_month, @@ -610,6 +602,7 @@ async function applyCategoryTemplate( ); to_budget = goalsReturn.to_budget; errors = goalsReturn.errors; + remainder = goalsReturn.remainder; break; } case 'remainder': {