From 7169d52885be3c82652431f496e6eb61a99251e4 Mon Sep 17 00:00:00 2001 From: Hardik Date: Wed, 27 May 2026 03:45:40 +0530 Subject: [PATCH] fix(notifications): rationalise who gets which email PO_SUBMITTED: managers only, submitter no longer copied PAYMENT_SENT: submitter only (it is a receipt prompt, not a manager action) PARTIAL_RECEIPT_CONFIRMED: managers now notified via new event type RECEIPT_CONFIRMED: unchanged (managers + accounts) Co-Authored-By: Claude Sonnet 4.6 --- App/app/(portal)/payments/actions.ts | 3 +-- App/app/(portal)/po/[id]/actions.ts | 2 +- App/app/(portal)/po/[id]/edit/actions.ts | 2 +- App/app/(portal)/po/[id]/receipt/actions.ts | 9 ++++----- App/app/(portal)/po/new/actions.ts | 2 +- App/lib/notifier.ts | 16 ++++++++++++---- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/App/app/(portal)/payments/actions.ts b/App/app/(portal)/payments/actions.ts index d047338..5d6ee37 100644 --- a/App/app/(portal)/payments/actions.ts +++ b/App/app/(portal)/payments/actions.ts @@ -177,8 +177,7 @@ export async function markPaid({ }); } - const managers = await db.user.findMany({ where: { role: "MANAGER", isActive: true } }); - await notify({ event: "PAYMENT_SENT", po, recipients: [po.submitter, ...managers] }); + await notify({ event: "PAYMENT_SENT", po, recipients: [po.submitter] }); revalidatePath("/payments"); revalidatePath(`/po/${poId}`); diff --git a/App/app/(portal)/po/[id]/actions.ts b/App/app/(portal)/po/[id]/actions.ts index aa28917..0c9f3e5 100644 --- a/App/app/(portal)/po/[id]/actions.ts +++ b/App/app/(portal)/po/[id]/actions.ts @@ -76,7 +76,7 @@ export async function submitDraftPo( }); const managers = await db.user.findMany({ where: { role: "MANAGER", isActive: true } }); - await notify({ event: "PO_SUBMITTED", po, recipients: [po.submitter, ...managers] }); + await notify({ event: "PO_SUBMITTED", po, recipients: managers }); revalidatePath(`/po/${poId}`); revalidatePath("/dashboard"); diff --git a/App/app/(portal)/po/[id]/edit/actions.ts b/App/app/(portal)/po/[id]/edit/actions.ts index 7a390a8..5c2198a 100644 --- a/App/app/(portal)/po/[id]/edit/actions.ts +++ b/App/app/(portal)/po/[id]/edit/actions.ts @@ -187,7 +187,7 @@ export async function updatePo( db.user.findMany({ where: { role: "MANAGER", isActive: true } }), ]); if (fullPo) { - await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: [fullPo.submitter, ...managers] }); + await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: managers }); } } diff --git a/App/app/(portal)/po/[id]/receipt/actions.ts b/App/app/(portal)/po/[id]/receipt/actions.ts index c52fef2..1f04b4a 100644 --- a/App/app/(portal)/po/[id]/receipt/actions.ts +++ b/App/app/(portal)/po/[id]/receipt/actions.ts @@ -132,13 +132,12 @@ export async function confirmReceipt({ revalidatePath(`/admin/sites/${siteId}`); } - // Notify on full close only + const managers = await db.user.findMany({ where: { role: "MANAGER", isActive: true } }); if (allDelivered) { - const [managers, accounts] = await Promise.all([ - db.user.findMany({ where: { role: "MANAGER", isActive: true } }), - db.user.findMany({ where: { role: "ACCOUNTS", isActive: true } }), - ]); + const accounts = await db.user.findMany({ where: { role: "ACCOUNTS", isActive: true } }); await notify({ event: "RECEIPT_CONFIRMED", po, recipients: [...managers, ...accounts] }); + } else { + await notify({ event: "PARTIAL_RECEIPT_CONFIRMED", po, recipients: managers }); } revalidatePath(`/po/${poId}`); diff --git a/App/app/(portal)/po/new/actions.ts b/App/app/(portal)/po/new/actions.ts index 0bbd801..3caa6e2 100644 --- a/App/app/(portal)/po/new/actions.ts +++ b/App/app/(portal)/po/new/actions.ts @@ -146,7 +146,7 @@ export async function createPo( db.user.findMany({ where: { role: "MANAGER", isActive: true } }), ]); if (fullPo) { - await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: [fullPo.submitter, ...managers] }); + await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: managers }); } } diff --git a/App/lib/notifier.ts b/App/lib/notifier.ts index f475142..d06da20 100644 --- a/App/lib/notifier.ts +++ b/App/lib/notifier.ts @@ -17,7 +17,8 @@ export type NotificationEvent = | "VENDOR_ID_PROVIDED" | "PAYMENT_PROCESSING" | "PAYMENT_SENT" - | "RECEIPT_CONFIRMED"; + | "RECEIPT_CONFIRMED" + | "PARTIAL_RECEIPT_CONFIRMED"; interface NotifyParams { event: NotificationEvent; @@ -136,6 +137,9 @@ function buildInAppBody( case "RECEIPT_CONFIRMED": return `Receipt confirmed — ${pn} closed`; + case "PARTIAL_RECEIPT_CONFIRMED": + return `Partial receipt confirmed on ${pn} — items still outstanding`; + default: return `Update on ${pn}`; } @@ -195,6 +199,7 @@ function buildActionLabel(event: NotificationEvent, recipient: User, po: Purchas case "PAYMENT_SENT": return isSubmitter ? "Confirm Receipt" : "View Purchase Order"; case "RECEIPT_CONFIRMED": + case "PARTIAL_RECEIPT_CONFIRMED": return "View Purchase Order"; default: return "View Purchase Order"; @@ -213,9 +218,10 @@ function buildSubject(event: NotificationEvent, poNumber: string): string | null EDITS_REQUESTED: `Edits requested on ${base}`, VENDOR_ID_REQUESTED: `Vendor ID needed for ${base}`, VENDOR_ID_PROVIDED: `Vendor ID provided for ${base}`, - PAYMENT_PROCESSING: `Payment initiated for ${base}`, - PAYMENT_SENT: `Payment confirmed for ${base}`, - RECEIPT_CONFIRMED: `Receipt confirmed — ${base} closed`, + PAYMENT_PROCESSING: `Payment initiated for ${base}`, + PAYMENT_SENT: `Payment confirmed for ${base}`, + RECEIPT_CONFIRMED: `Receipt confirmed — ${base} closed`, + PARTIAL_RECEIPT_CONFIRMED: `Partial receipt confirmed for ${base}`, }; return map[event] ?? null; } @@ -251,6 +257,8 @@ function buildEmailBody( return `Payment has been confirmed for ${po.poNumber}. Please confirm delivery/receipt when the goods arrive.`; case "RECEIPT_CONFIRMED": return `Receipt has been confirmed for ${po.poNumber}. The order is now closed.`; + case "PARTIAL_RECEIPT_CONFIRMED": + return `A partial delivery has been confirmed for ${po.poNumber}. Some items are still outstanding.`; default: return `There has been an update on purchase order ${po.poNumber}.`; }