Skip to content

Update vacation status when someone is on vacation#392

Open
arodriguezvaz wants to merge 5 commits into
developfrom
feature-384-update-vacation-status-when-someone-is-on-vacation
Open

Update vacation status when someone is on vacation#392
arodriguezvaz wants to merge 5 commits into
developfrom
feature-384-update-vacation-status-when-someone-is-on-vacation

Conversation

@arodriguezvaz
Copy link
Copy Markdown
Contributor

Every day, checks if there are vacation requests that should be active or ended, and updates their status to ONGOING or COMPLETED accordingly.
Regarding updatedAt: new Date().toISOString() as unknown as Date — there is likely a better solution than this cast, but I couldn't find one

@arodriguezvaz arodriguezvaz changed the title Feature 384 update vacation status when someone is on vacation Update vacation status when someone is on vacation Apr 28, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new scheduled Lambda that runs daily to transition vacation requests from APPROVED → ONGOING (when the vacation starts) and APPROVED/ONGOING → COMPLETED (after the vacation ends), and wires it into the Serverless deployment.

Changes:

  • Introduces update-vacation-status-by-date scheduled function configuration and handler implementation.
  • Registers the new function in serverless.ts so it’s deployed and runnable.
  • Updates package-lock.json (dependency tree cleanup).

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/functions/vacation-request/update-vacation-status-by-date/index.ts Adds scheduled event configuration for the new daily vacation status updater Lambda.
src/functions/vacation-request/update-vacation-status-by-date/handler.ts Implements the daily scan + status transition logic and writes updates to DynamoDB.
serverless.ts Registers the new function so it’s included in the deployed Serverless functions list.
package-lock.json Removes some nested dependency entries as part of lockfile regeneration/cleanup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +54 to +63
await vacationRequestService.updateVacationRequest({
...vacation,
status: [
{
status: nextStatus,
createdBy: "system",
updatedAt: new Date().toISOString() as unknown as Date
}
],
updatedAt: new Date().toISOString()
Comment on lines +33 to +35
const startDate = DateTime.fromISO(vacation.startDate).toISODate();
const endDate = DateTime.fromISO(vacation.endDate).toISODate();

@@ -0,0 +1,14 @@
import { handlerPath } from "src/libs/handler-resolver";
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

Comment on lines +23 to +80
vacations.map(async (vacation) => {
const latestStatus = vacation.status?.at(-1)?.status;

if (!latestStatus) {
throw new Error(
`Vacation request ${vacation.id} has no status, cannot update status by date.`
);
}

let nextStatus: VacationRequestStatuses = latestStatus;
const parsedStartDate = DateTime.fromISO(vacation.startDate);
const parsedEndDate = DateTime.fromISO(vacation.endDate);
if (!parsedStartDate.isValid || !parsedEndDate.isValid) {
throw new Error(
`Vacation request ${vacation.id} has invalid date values: startDate="${vacation.startDate}", endDate="${vacation.endDate}".`
);
}
const startDate = parsedStartDate.toISODate();
const endDate = parsedEndDate.toISODate();
if (!startDate || !endDate) {
throw new Error(
`Vacation request ${vacation.id} could not be converted to ISO dates: startDate="${vacation.startDate}", endDate="${vacation.endDate}".`
);
}

if (
latestStatus === VacationRequestStatuses.Approved &&
startDate <= today &&
endDate >= today
) {
nextStatus = VacationRequestStatuses.Ongoing;
}

if (
(latestStatus === VacationRequestStatuses.Approved ||
latestStatus === VacationRequestStatuses.Ongoing) &&
endDate < today
) {
nextStatus = VacationRequestStatuses.Completed;
}

if (latestStatus === nextStatus) return;
const updatedAt = new Date();
await vacationRequestService.updateVacationRequest({
...vacation,
status: [
{
status: nextStatus,
createdBy: "system",
updatedAt
}
],
updatedAt: updatedAt.toISOString()
});

return nextStatus;
})
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a reasonable chunk of logic in this map.
I'd suggest either adding just a couple of comments to make clear what is happening in the various sections e.g. Checking dates to see if status should be updated.
OR you could refactor into a couple of smaller functions e.g.
checkNextStatus might be a reasonable candidate for a function

OR leave as is is also ok.

Comment on lines +83 to +89
if (result.status === "rejected") {
errors.push(result.reason instanceof Error ? result.reason.message : String(result.reason));
} else if (result.value === VacationRequestStatuses.Ongoing) {
ongoingUpdated += 1;
} else if (result.value === VacationRequestStatuses.Completed) {
completedUpdated += 1;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another candidate for a named function perhaps. Or as is is fine

@@ -0,0 +1,14 @@
import { handlerPath } from "@libs/handler-resolver";

const { DAILY_SCHEDULE_TIMER } = process.env;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this env already exists, and daily is the correct interval for this to run?

throw new Error("Could not resolve current date");
}

const vacations = await vacationRequestService.listVacationRequests();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this listing all vacation requests, for all time? Is there some way this could be a little more targeted, otherwise after some years we might end up with quite a lot of results unnecessarily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants