feat: integrate reminder payloads into appointment creation and update notification jobs and adjust quiet hours logic
This commit is contained in:
@@ -16,6 +16,7 @@ export interface CreateJobServiceParams {
|
||||
scheduledAt?: Date;
|
||||
appointmentStart?: Date;
|
||||
payload?: CreateJobParams["payload"];
|
||||
reminderPayload?: CreateJobParams["payload"];
|
||||
}
|
||||
|
||||
export class NotificationJobService {
|
||||
@@ -81,6 +82,7 @@ export class NotificationJobService {
|
||||
channel,
|
||||
type: "reminder",
|
||||
scheduledAt: reminderScheduledAt,
|
||||
payload: params.reminderPayload,
|
||||
});
|
||||
jobs.push(job);
|
||||
}
|
||||
@@ -153,12 +155,9 @@ export class NotificationJobService {
|
||||
if (isInsideQuietHours) {
|
||||
// Shift to quiet hours end
|
||||
let adjusted = scheduled.hour(toHour).minute(toMinute).second(0);
|
||||
// If quiet hours cross midnight (e.g. 22:00-07:00) and end is before start,
|
||||
// the end is on the next day
|
||||
if (toHour < fromHour) {
|
||||
if (scheduledHour >= fromHour || scheduledHour < toHour) {
|
||||
adjusted = adjusted.add(1, "day");
|
||||
}
|
||||
// If quiet hours cross midnight, only the pre-midnight segment ends next day.
|
||||
if (toHour < fromHour && scheduledHour >= fromHour) {
|
||||
adjusted = adjusted.add(1, "day");
|
||||
}
|
||||
return adjusted.toDate();
|
||||
}
|
||||
|
||||
@@ -112,6 +112,45 @@ describe("NotificationJobService.createJob", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("passes reminder snapshot payload to scheduled reminder jobs", async () => {
|
||||
jest.useFakeTimers().setSystemTime(new Date("2026-07-21T14:00:00.000Z"));
|
||||
const resolvedPolicy: ResolvedPolicy = {
|
||||
channels: ["whatsapp", "email"],
|
||||
timezone: "America/Argentina/Buenos_Aires",
|
||||
reminderRules: [{ offset: 30, enabled: true }],
|
||||
};
|
||||
const payload = { message: "Creation body" };
|
||||
const reminderPayload = {
|
||||
email: "client@example.com",
|
||||
phoneNumber: "5491112345678",
|
||||
companyOwnerId: "owner-1",
|
||||
emailMessage: "Reminder email body",
|
||||
wapMessage: "Reminder WAP body",
|
||||
};
|
||||
mockResolverResolve.mockResolvedValue(resolvedPolicy);
|
||||
mockJobCreate.mockResolvedValue({ id: "job-1" });
|
||||
|
||||
await service.createJob({
|
||||
companyId: "company-1",
|
||||
clientId: "client-1",
|
||||
appointmentId: "appt-1",
|
||||
type: "creation",
|
||||
appointmentStart: new Date("2026-07-21T15:00:00.000Z"),
|
||||
payload,
|
||||
reminderPayload,
|
||||
});
|
||||
|
||||
const createCalls = mockJobCreate.mock.calls.map((call) => call[0]);
|
||||
expect(createCalls.filter((job) => job.type === "creation")).toEqual([
|
||||
expect.objectContaining({ channel: "whatsapp", payload }),
|
||||
expect.objectContaining({ channel: "email", payload }),
|
||||
]);
|
||||
expect(createCalls.filter((job) => job.type === "reminder")).toEqual([
|
||||
expect.objectContaining({ channel: "whatsapp", payload: reminderPayload }),
|
||||
expect.objectContaining({ channel: "email", payload: reminderPayload }),
|
||||
]);
|
||||
});
|
||||
|
||||
it("skips reminder jobs scheduled in the past", async () => {
|
||||
jest.useFakeTimers().setSystemTime(new Date("2026-07-21T14:29:00.000Z"));
|
||||
const resolvedPolicy: ResolvedPolicy = {
|
||||
@@ -206,6 +245,27 @@ describe("NotificationJobService.createJob", () => {
|
||||
expect(createCall.scheduledAt.getUTCDate()).toBe(22); // next day
|
||||
});
|
||||
|
||||
it("adjusts early morning quiet hours crossing midnight to the same day", async () => {
|
||||
const resolvedPolicy: ResolvedPolicy = {
|
||||
channels: ["system"],
|
||||
timezone: "America/Argentina/Buenos_Aires",
|
||||
quietHours: { from: "22:00", to: "07:00" },
|
||||
};
|
||||
mockResolverResolve.mockResolvedValue(resolvedPolicy);
|
||||
mockJobCreate.mockResolvedValue({ id: "job-1" });
|
||||
|
||||
await service.createJob({
|
||||
companyId: "company-1",
|
||||
clientId: "client-1",
|
||||
appointmentId: "appt-1",
|
||||
type: "creation",
|
||||
scheduledAt: new Date("2026-07-21T05:00:00.000Z"),
|
||||
});
|
||||
|
||||
const createCall = mockJobCreate.mock.calls[0][0];
|
||||
expect(createCall.scheduledAt.toISOString()).toBe("2026-07-21T07:00:00.000Z");
|
||||
});
|
||||
|
||||
it("does not adjust scheduledAt when outside quiet hours", async () => {
|
||||
const resolvedPolicy: ResolvedPolicy = {
|
||||
channels: ["system"],
|
||||
|
||||
Reference in New Issue
Block a user