Goals: Remainder option (#1101)

Added the option to add a remainder goal template. This will use the
remaining available funds and dump them into the respective category.
There is optional weighting. The remainder templates will be forced to
the lowest priority as to run after all other templates.

Usage: `#template remainder <weight>` Add the template line to any
categories you want to catch any remaining funds such as savings. The
amount added to the category will equal
`remaining_budget/total_of_weights*weight`. The default weight is 1.
This commit is contained in:
youngcw
2023-06-06 13:41:09 -07:00
committed by GitHub
parent c42d17897c
commit ed285e9ac5
3 changed files with 47 additions and 3 deletions

View File

@@ -15,12 +15,14 @@ expr
priority: +priority
} }
/ priority: priority? _? monthly: amount limit: limit?
{ return { type: 'simple', monthly, limit, priority: +priority } }
{ return { type: 'simple', monthly, limit, priority: +priority } }
/ priority: priority? _? limit: limit
{ return { type: 'simple', limit , priority: +priority } }
/ priority: priority? _? schedule _ full:full? name: name
{ return { type: 'schedule', name, priority: +priority, full } }
{ return { type: 'schedule', name, priority: +priority, full } }
/ priority: priority? _? remainder: remainder
{ return { type: 'remainder', priority: null, weight: remainder } }
repeat 'repeat interval'
= 'month'i { return { annual: false } }
@@ -48,6 +50,7 @@ upTo = 'up'i _ 'to'i
schedule = 'schedule'i
full = 'full'i _ {return true}
priority = '-'i number: number _ {return number}
remainder = 'remainder'i _? weight: positive? { return +weight || 1 }
_ 'space' = ' '+
d 'digit' = [0-9]

View File

@@ -80,8 +80,35 @@ async function processTemplate(month, force) {
});
}
}
// find all remainder templates, place them after all other templates
let remainder_found;
let remainder_priority = lowestPriority + 1;
let remainder_weight_total = 0;
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;
}
}
}
}
// so the remainders don't get skiped
if (remainder_found) lowestPriority = remainder_priority;
for (let priority = 0; priority <= lowestPriority; priority++) {
// setup scaling for remainder
let remainder_scale = 1;
if (priority === lowestPriority) {
let sheetName = monthUtils.sheetForMonth(month);
let budgetAvailable = await getSheetValue(sheetName, `to-budget`);
remainder_scale = Math.round(budgetAvailable / remainder_weight_total);
}
for (let c = 0; c < categories.length; c++) {
let category = categories[c];
let template = category_templates[category.id];
@@ -132,6 +159,7 @@ async function processTemplate(month, force) {
template,
month,
priority,
remainder_scale,
force,
);
if (to_budget != null) {
@@ -235,6 +263,7 @@ async function applyCategoryTemplate(
template_lines,
month,
priority,
remainder_scale,
force,
) {
let current_month = getCorrectedDate(`${month}-01`);
@@ -549,6 +578,12 @@ async function applyCategoryTemplate(
}
break;
}
case 'remainder': {
to_budget = Math.round(remainder_scale * template.weight);
// can over budget with the rounding, so checking that
if (to_budget > budgetAvailable) to_budget = budgetAvailable;
break;
}
case 'error':
return { errors };
default:

View File

@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [youngcw]
---
Goals: Add remainder option to budget all extra funds automatically.