143 lines
4.5 KiB
TypeScript
143 lines
4.5 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
vi.mock("./db", () => ({
|
|
getMaterialReturnFollowupByRequestId: vi.fn(),
|
|
upsertMaterialReturnFollowup: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("./mailer", () => ({
|
|
sendOperationalEmail: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("./materialReturnEmail", () => ({
|
|
generateMaterialReturnReminderEmail: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("./materialReturnPdf", () => ({
|
|
generateMaterialReturnStatementPdf: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("./logisticsSettings", () => ({
|
|
getLogisticsSettings: vi.fn(),
|
|
}));
|
|
|
|
import * as db from "./db";
|
|
import { getLogisticsSettings } from "./logisticsSettings";
|
|
import { scheduleMaterialReturnFollowup } from "./materialReturnWorkflow";
|
|
|
|
describe("scheduleMaterialReturnFollowup", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.mocked(getLogisticsSettings).mockResolvedValue({
|
|
materialReturnLeadDays: 4,
|
|
materialReturnGraceDays: 3,
|
|
inventory: {
|
|
tente3x3: 12,
|
|
chapiteau5x5: 10,
|
|
podium: 1,
|
|
autres: null,
|
|
},
|
|
replacementValues: {
|
|
tente3x3: 0,
|
|
chapiteau5x5: 0,
|
|
podium: 0,
|
|
autres: null,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("keeps the standard expiry window for a fresh follow-up", async () => {
|
|
vi.mocked(db.getMaterialReturnFollowupByRequestId).mockResolvedValue(undefined);
|
|
vi.mocked(db.upsertMaterialReturnFollowup).mockResolvedValue(1);
|
|
|
|
const request = {
|
|
id: 12,
|
|
associationId: 3,
|
|
formData: JSON.stringify({ dateRestitution: "2026-06-15" }),
|
|
} as any;
|
|
|
|
await scheduleMaterialReturnFollowup({
|
|
request,
|
|
serviceLabel: "Service technique",
|
|
recipientEmails: ["agent@example.com"],
|
|
});
|
|
|
|
expect(db.upsertMaterialReturnFollowup).toHaveBeenCalledTimes(1);
|
|
const payload = vi.mocked(db.upsertMaterialReturnFollowup).mock.calls[0]?.[1];
|
|
expect(payload.status).toBe("planifie");
|
|
expect(new Date(payload.uploadTokenExpiresAt).toISOString().startsWith("2026-06-18")).toBe(true);
|
|
});
|
|
|
|
it("reactivates an expired upload window when the follow-up is reassigned", async () => {
|
|
const expiredDate = new Date();
|
|
expiredDate.setDate(expiredDate.getDate() - 2);
|
|
expiredDate.setHours(23, 59, 59, 999);
|
|
|
|
vi.mocked(db.getMaterialReturnFollowupByRequestId).mockResolvedValue({
|
|
id: 4,
|
|
requestId: 12,
|
|
associationId: 3,
|
|
status: "en_cours",
|
|
uploadToken: "existing-token",
|
|
uploadTokenExpiresAt: expiredDate,
|
|
} as any);
|
|
vi.mocked(db.upsertMaterialReturnFollowup).mockResolvedValue(4);
|
|
|
|
const request = {
|
|
id: 12,
|
|
associationId: 3,
|
|
formData: JSON.stringify({ dateRestitution: "2026-05-01" }),
|
|
} as any;
|
|
|
|
await scheduleMaterialReturnFollowup({
|
|
request,
|
|
serviceLabel: "Service technique",
|
|
recipientEmails: ["agent@example.com"],
|
|
});
|
|
|
|
const payload = vi.mocked(db.upsertMaterialReturnFollowup).mock.calls[0]?.[1];
|
|
expect(payload.uploadToken).toBe("existing-token");
|
|
expect(new Date(payload.uploadTokenExpiresAt).getTime()).toBeGreaterThan(Date.now());
|
|
expect(payload.status).toBe("planifie");
|
|
});
|
|
|
|
it("generates a new token and a fresh upload window when reactivation is explicit", async () => {
|
|
const futureExpiry = new Date("2026-06-18T23:59:59.999Z");
|
|
|
|
vi.mocked(db.getMaterialReturnFollowupByRequestId).mockResolvedValue({
|
|
id: 4,
|
|
requestId: 12,
|
|
associationId: 3,
|
|
status: "en_attente",
|
|
uploadToken: "existing-token",
|
|
uploadTokenExpiresAt: futureExpiry,
|
|
} as any);
|
|
vi.mocked(db.upsertMaterialReturnFollowup).mockResolvedValue(4);
|
|
|
|
const request = {
|
|
id: 12,
|
|
associationId: 3,
|
|
formData: JSON.stringify({ dateRestitution: "2026-06-15" }),
|
|
} as any;
|
|
const reactivatedAt = new Date("2026-06-20T10:30:00.000Z");
|
|
|
|
await scheduleMaterialReturnFollowup({
|
|
request,
|
|
serviceLabel: "Service technique",
|
|
recipientEmails: ["agent@example.com"],
|
|
}, {
|
|
forceNewToken: true,
|
|
forceImmediateSendWindow: true,
|
|
reactivatedByUserId: 9,
|
|
reactivatedAt,
|
|
reactivationReason: "Suivi rouvert",
|
|
});
|
|
|
|
const payload = vi.mocked(db.upsertMaterialReturnFollowup).mock.calls[0]?.[1];
|
|
expect(payload.uploadToken).not.toBe("existing-token");
|
|
expect(new Date(payload.uploadTokenExpiresAt).getTime()).toBeGreaterThan(futureExpiry.getTime());
|
|
expect(new Date(payload.uploadTokenExpiresAt).getTime()).toBeGreaterThan(reactivatedAt.getTime());
|
|
expect(payload.reactivatedByUserId).toBe(9);
|
|
expect(payload.reactivationReason).toBe("Suivi rouvert");
|
|
});
|
|
});
|