From eca50f28b0108cf92550299051e6b0ba2779b48b Mon Sep 17 00:00:00 2001 From: Josh Woodward <66183943+Triscal@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:40:41 -0500 Subject: [PATCH] Fix skipping schedules that move before weekend (#7057) * Pushing before weekend to Monday * release notes * lint * Guard against null Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fixing AI commit and addressing second comment * addressing nitpicks * first attempt at a test * [autofix.ci] apply automated fixes * refactor to use condition and fix tests --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../src/server/schedules/app.test.ts | 119 ++++++++++++++++++ .../loot-core/src/server/schedules/app.ts | 23 +++- upcoming-release-notes/7057.md | 6 + 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 upcoming-release-notes/7057.md diff --git a/packages/loot-core/src/server/schedules/app.test.ts b/packages/loot-core/src/server/schedules/app.test.ts index e77db01950..188cc9b45d 100644 --- a/packages/loot-core/src/server/schedules/app.test.ts +++ b/packages/loot-core/src/server/schedules/app.test.ts @@ -11,6 +11,7 @@ import { createSchedule, deleteSchedule, setNextDate, + skipNextDate, updateConditions, updateSchedule, } from './app'; @@ -256,5 +257,123 @@ describe('schedule app', () => { expect(row.next_date).toBe('2021-05-18'); }); + + it('skipNextDate skips `next_date`', async () => { + /* Dec 2020 calendar for reference: + | Su | Mo | Tu | We | Th | Fr | Sa | + | | | 01 | 02 | 03 | 04 | 05 | + | 06 | 07 | 08 | 09 | 10 | 11 | 12 | + | 13 | 14 | 15 | 16 | 17 | 18 | 19 | + | 20 | 21 | 22 | 23 | 24 | 25 | 26 | + | 27 | 28 | 29 | 30 | 31 | + */ + const id = await createSchedule({ + conditions: [ + { + op: 'is', + field: 'date', + value: { + start: '2020-12-05', + frequency: 'weekly', + patterns: [], + }, + }, + ], + }); + + let res = await aqlQuery( + q('schedules').filter({ id }).select(['next_date']), + ); + let row = res.data[0]; + + expect(row.next_date).toBe('2020-12-05'); + + await skipNextDate({ id }); + + res = await aqlQuery(q('schedules').filter({ id }).select(['next_date'])); + row = res.data[0]; + + expect(row.next_date).toBe('2020-12-12'); + }); + + it('skipNextDate skips `next_date` moving `after` weekend', async () => { + /* Dec 2020 calendar for reference: + | Su | Mo | Tu | We | Th | Fr | Sa | + | | | 01 | 02 | 03 | 04 | 05 | + | 06 | 07 | 08 | 09 | 10 | 11 | 12 | + | 13 | 14 | 15 | 16 | 17 | 18 | 19 | + | 20 | 21 | 22 | 23 | 24 | 25 | 26 | + | 27 | 28 | 29 | 30 | 31 | + */ + const id = await createSchedule({ + conditions: [ + { + op: 'is', + field: 'date', + value: { + start: '2020-12-05', + frequency: 'weekly', + patterns: [], + skipWeekend: true, + weekendSolveMode: 'after', + }, + }, + ], + }); + + let res = await aqlQuery( + q('schedules').filter({ id }).select(['next_date']), + ); + let row = res.data[0]; + + expect(row.next_date).toBe('2020-12-07'); + + await skipNextDate({ id }); + + res = await aqlQuery(q('schedules').filter({ id }).select(['next_date'])); + row = res.data[0]; + + expect(row.next_date).toBe('2020-12-14'); + }); + + it('skipNextDate skips `next_date` moving `before` weekend', async () => { + /* Dec 2020 calendar for reference: + | Su | Mo | Tu | We | Th | Fr | Sa | + | | | 01 | 02 | 03 | 04 | 05 | + | 06 | 07 | 08 | 09 | 10 | 11 | 12 | + | 13 | 14 | 15 | 16 | 17 | 18 | 19 | + | 20 | 21 | 22 | 23 | 24 | 25 | 26 | + | 27 | 28 | 29 | 30 | 31 | + */ + const id = await createSchedule({ + conditions: [ + { + op: 'is', + field: 'date', + value: { + start: '2020-12-05', + frequency: 'weekly', + patterns: [], + skipWeekend: true, + weekendSolveMode: 'before', + }, + }, + ], + }); + + let res = await aqlQuery( + q('schedules').filter({ id }).select(['next_date']), + ); + let row = res.data[0]; + + expect(row.next_date).toBe('2020-12-04'); + + await skipNextDate({ id }); + + res = await aqlQuery(q('schedules').filter({ id }).select(['next_date'])); + row = res.data[0]; + + expect(row.next_date).toBe('2020-12-11'); + }); }); }); diff --git a/packages/loot-core/src/server/schedules/app.ts b/packages/loot-core/src/server/schedules/app.ts index 3f36425f1e..195be02dd7 100644 --- a/packages/loot-core/src/server/schedules/app.ts +++ b/packages/loot-core/src/server/schedules/app.ts @@ -111,11 +111,13 @@ export async function setNextDate({ start, conditions, reset, + skipRequested, }: { id: string; start?; conditions?; reset?: boolean; + skipRequested?: boolean; }) { if (conditions == null) { const rule = await getRuleForSchedule(id); @@ -127,10 +129,26 @@ export async function setNextDate({ const { date: dateCond } = extractScheduleConds(conditions); - const { data: nextDate } = await aqlQuery( + let { data: nextDate } = await aqlQuery( q('schedules').filter({ id }).calculate('next_date'), ); + if (skipRequested === true) { + const skipWeekend: boolean = dateCond.value?.skipWeekend; + const weekendSolveMode: string = dateCond.value?.weekendSolveMode; + + if (weekendSolveMode === 'before' && skipWeekend === true) { + const parsedNextDate = parseDate(nextDate); + if (d.isFriday(parsedNextDate) || d.isWeekend(parsedNextDate)) { + // nextDate is on weekend or friday, moving to monday + // so getNextDate and getDateWithSkippedWeekend + // don't push the date back to Friday, thus causing + // `(newNextDate !== nextDate) ` to be false and not updating the next date + nextDate = dayFromDate(d.nextMonday(parsedNextDate)); + } + } + } + // Only do this if a date condition exists if (dateCond) { const newNextDate = getNextDate( @@ -324,12 +342,13 @@ export async function deleteSchedule({ id }) { }); } -async function skipNextDate({ id }) { +export async function skipNextDate({ id }) { return setNextDate({ id, start: nextDate => { return d.addDays(parseDate(nextDate), 1); }, + skipRequested: true, }); } diff --git a/upcoming-release-notes/7057.md b/upcoming-release-notes/7057.md new file mode 100644 index 0000000000..b36fb96ce2 --- /dev/null +++ b/upcoming-release-notes/7057.md @@ -0,0 +1,6 @@ +--- +category: Bugfixes +authors: [Triscal] +--- + +Fix skipping schedules that move before weekend