From 38900656a398e05a0951c9fd0ad2b49185fcb496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 11 Oct 2026 15:11:27 +0200 Subject: [PATCH] fix(audit): name automatic dose recording in medication audit rows Switching autoMarkTaken on or off now appears in the medication.update row with its previous value, and medication.create records whether the medication starts with doses recorded automatically. --- src/app/api/medications/[id]/route.ts | 4 ++ src/app/api/medications/route.ts | 8 ++- .../medication-auto-mark-taken.test.ts | 52 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/app/api/medications/[id]/route.ts b/src/app/api/medications/[id]/route.ts index da7612a17..13417b366 100644 --- a/src/app/api/medications/[id]/route.ts +++ b/src/app/api/medications/[id]/route.ts @@ -1134,6 +1134,9 @@ export const PUT = apiHandler( active: existing.active, asNeeded: existing.asNeeded, trackIntake: existing.trackIntake, + // v1.42.2 — switching automatic recording on or off is a change + // to how doses are recorded, so the row names it. + autoMarkTaken: existing.autoMarkTaken, endsOn: existing.endsOn, }, after: { @@ -1142,6 +1145,7 @@ export const PUT = apiHandler( active: medication.active, asNeeded: medication.asNeeded, trackIntake: medication.trackIntake, + autoMarkTaken: medication.autoMarkTaken, endsOn: medication.endsOn, }, }), diff --git a/src/app/api/medications/route.ts b/src/app/api/medications/route.ts index d6de31e15..e2fd46d76 100644 --- a/src/app/api/medications/route.ts +++ b/src/app/api/medications/route.ts @@ -491,7 +491,13 @@ async function postMedication(request: NextRequest): Promise { await auditLog("medication.create", { userId: user.id, ipAddress: getClientIp(request), - details: { medicationId: medication.id, name }, + details: { + medicationId: medication.id, + name, + // v1.42.2 — a medication created with its doses recorded + // automatically says so in its audit row. + autoMarkTaken: medication.autoMarkTaken, + }, }); annotate({ diff --git a/tests/integration/medication-auto-mark-taken.test.ts b/tests/integration/medication-auto-mark-taken.test.ts index a0e80eb67..cb79cb58f 100644 --- a/tests/integration/medication-auto-mark-taken.test.ts +++ b/tests/integration/medication-auto-mark-taken.test.ts @@ -377,6 +377,58 @@ describe("auto-mark-taken pass", () => { select: { autoMarkTaken: true, autoMarkTakenSince: true }, }); expect(off).toEqual({ autoMarkTaken: false, autoMarkTakenSince: null }); + + // Each flip is named in the audit row with what it was before; the + // re-save that left it on names no change to it. + const audits = await prisma.auditLog.findMany({ + where: { userId, action: "medication.update" }, + orderBy: { createdAt: "asc" }, + select: { details: true }, + }); + const details = audits.map( + (a) => + JSON.parse(a.details ?? "{}") as { + fields: string[]; + previous: Record; + }, + ); + expect(details).toHaveLength(3); + // Two of the same timestamp: matched by content, not order. + const flips = details + .filter((d) => d.fields.includes("autoMarkTaken")) + .map((d) => d.previous.autoMarkTaken) + .sort(); + expect(flips).toEqual([false, true]); + const resave = details.find((d) => d.fields.includes("name")); + expect(resave?.fields).not.toContain("autoMarkTaken"); + }); + + it("the create audit row says whether doses are recorded automatically", async () => { + const prisma = getPrismaClient(); + const userId = await makeUser(); + const route = await import("@/app/api/medications/route"); + at("2026-06-10T10:00:00.000Z"); + const res = await (route.POST as Handler)( + new NextRequest("http://localhost/api/medications", { + method: "POST", + body: JSON.stringify({ + name: "Vitamin D", + dose: "1 capsule", + autoMarkTaken: true, + schedules: [{ windowStart: "19:00", windowEnd: "19:00" }], + }), + headers: { "content-type": "application/json" }, + }), + { params: Promise.resolve({}) }, + ); + expect(res.status).toBe(201); + const audit = await prisma.auditLog.findFirstOrThrow({ + where: { userId, action: "medication.create" }, + select: { details: true }, + }); + expect(JSON.parse(audit.details ?? "{}")).toMatchObject({ + autoMarkTaken: true, + }); }); });