🐛 improve budgeting of schedules templates (#5319)

* fix

* fix

* didn't need that

* prevent div by 0
This commit is contained in:
youngcw
2025-07-17 12:49:00 -07:00
committed by GitHub
parent 38ab63638a
commit e4a993ad67
2 changed files with 50 additions and 14 deletions

View File

@@ -159,7 +159,7 @@ async function createScheduleList(
return { t: t.filter(c => c.completed === 0), errors };
}
async function getPayMonthOfTotal(t: ScheduleTemplateTarget[]) {
function getPayMonthOfTotal(t: ScheduleTemplateTarget[]) {
//return the contribution amounts of full or every month type schedules
let total = 0;
const schedules = t.filter(c => c.num_months === 0);
@@ -194,20 +194,53 @@ async function getSinkingContributionTotal(
return total;
}
async function getSinkingBaseContributionTotal(t: ScheduleTemplateTarget[]) {
function getSinkingBaseContributionTotal(t: ScheduleTemplateTarget[]) {
//return only the base contribution of each schedule
let total = 0;
for (const schedule of t) {
let monthlyAmount = schedule.target / schedule.target_interval;
if (schedule.target_frequency === 'yearly') {
monthlyAmount /= 12;
let monthlyAmount = 0;
let prevDate;
let intervalMonths;
switch (schedule.target_frequency) {
case 'yearly':
monthlyAmount = schedule.target / schedule.target_interval / 12;
break;
case 'monthly':
monthlyAmount = schedule.target / schedule.target_interval;
break;
case 'weekly':
prevDate = monthUtils.subWeeks(
schedule.next_date_string,
schedule.target_interval,
);
intervalMonths = monthUtils.differenceInCalendarMonths(
schedule.next_date_string,
prevDate,
);
// shouldn't be possible, but better check
if (intervalMonths === 0) intervalMonths = 1;
monthlyAmount = schedule.target / intervalMonths;
break;
case 'daily':
prevDate = monthUtils.subDays(
schedule.next_date_string,
schedule.target_interval,
);
intervalMonths = monthUtils.differenceInCalendarMonths(
schedule.next_date_string,
prevDate,
);
// shouldn't be possible, but better check
if (intervalMonths === 0) intervalMonths = 1;
monthlyAmount = schedule.target / intervalMonths;
break;
}
total += monthlyAmount;
}
return total;
}
async function getSinkingTotal(t: ScheduleTemplateTarget[]) {
function getSinkingTotal(t: ScheduleTemplateTarget[]) {
//sum the total of all upcoming schedules
let total = 0;
for (const schedule of t) {
@@ -227,7 +260,6 @@ export async function runSchedule(
category: CategoryEntity,
) {
const scheduleTemplates = template_lines.filter(t => t.type === 'schedule');
//in the case of multiple templates per category, schedules may have wrong priority level
const t = await createScheduleList(
scheduleTemplates,
@@ -241,20 +273,18 @@ export async function runSchedule(
(c.target_frequency === 'monthly' &&
c.target_interval === 1 &&
c.num_months === 0) ||
(c.target_frequency === 'weekly' &&
c.target_interval >= 0 &&
c.num_months === 0) ||
c.target_frequency === 'daily' ||
(c.target_frequency === 'weekly' && c.target_interval <= 4) ||
(c.target_frequency === 'daily' && c.target_interval <= 31) ||
isReflectBudget();
const t_payMonthOf = t.t.filter(isPayMonthOf);
const t_sinking = t.t
.filter(c => !isPayMonthOf(c))
.sort((a, b) => a.next_date_string.localeCompare(b.next_date_string));
const totalPayMonthOf = await getPayMonthOfTotal(t_payMonthOf);
const totalSinking = await getSinkingTotal(t_sinking);
const totalPayMonthOf = getPayMonthOfTotal(t_payMonthOf);
const totalSinking = getSinkingTotal(t_sinking);
const totalSinkingBaseContribution =
await getSinkingBaseContributionTotal(t_sinking);
getSinkingBaseContributionTotal(t_sinking);
if (balance >= totalSinking + totalPayMonthOf) {
to_budget += Math.round(totalPayMonthOf + totalSinkingBaseContribution);