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 <noreply@anthropic.com>
This commit is contained in:
Hardik 2026-05-27 03:45:40 +05:30
parent d82d18bac2
commit 7169d52885
6 changed files with 20 additions and 14 deletions

View file

@ -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] });
await notify({ event: "PAYMENT_SENT", po, recipients: [po.submitter, ...managers] });
revalidatePath("/payments"); revalidatePath("/payments");
revalidatePath(`/po/${poId}`); revalidatePath(`/po/${poId}`);

View file

@ -76,7 +76,7 @@ export async function submitDraftPo(
}); });
const managers = await db.user.findMany({ where: { role: "MANAGER", isActive: true } }); 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(`/po/${poId}`);
revalidatePath("/dashboard"); revalidatePath("/dashboard");

View file

@ -187,7 +187,7 @@ export async function updatePo(
db.user.findMany({ where: { role: "MANAGER", isActive: true } }), db.user.findMany({ where: { role: "MANAGER", isActive: true } }),
]); ]);
if (fullPo) { if (fullPo) {
await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: [fullPo.submitter, ...managers] }); await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: managers });
} }
} }

View file

@ -132,13 +132,12 @@ export async function confirmReceipt({
revalidatePath(`/admin/sites/${siteId}`); revalidatePath(`/admin/sites/${siteId}`);
} }
// Notify on full close only const managers = await db.user.findMany({ where: { role: "MANAGER", isActive: true } });
if (allDelivered) { if (allDelivered) {
const [managers, accounts] = await Promise.all([ const accounts = await db.user.findMany({ where: { role: "ACCOUNTS", isActive: true } });
db.user.findMany({ where: { role: "MANAGER", isActive: true } }),
db.user.findMany({ where: { role: "ACCOUNTS", isActive: true } }),
]);
await notify({ event: "RECEIPT_CONFIRMED", po, recipients: [...managers, ...accounts] }); await notify({ event: "RECEIPT_CONFIRMED", po, recipients: [...managers, ...accounts] });
} else {
await notify({ event: "PARTIAL_RECEIPT_CONFIRMED", po, recipients: managers });
} }
revalidatePath(`/po/${poId}`); revalidatePath(`/po/${poId}`);

View file

@ -146,7 +146,7 @@ export async function createPo(
db.user.findMany({ where: { role: "MANAGER", isActive: true } }), db.user.findMany({ where: { role: "MANAGER", isActive: true } }),
]); ]);
if (fullPo) { if (fullPo) {
await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: [fullPo.submitter, ...managers] }); await notify({ event: "PO_SUBMITTED", po: fullPo, recipients: managers });
} }
} }

View file

@ -17,7 +17,8 @@ export type NotificationEvent =
| "VENDOR_ID_PROVIDED" | "VENDOR_ID_PROVIDED"
| "PAYMENT_PROCESSING" | "PAYMENT_PROCESSING"
| "PAYMENT_SENT" | "PAYMENT_SENT"
| "RECEIPT_CONFIRMED"; | "RECEIPT_CONFIRMED"
| "PARTIAL_RECEIPT_CONFIRMED";
interface NotifyParams { interface NotifyParams {
event: NotificationEvent; event: NotificationEvent;
@ -136,6 +137,9 @@ function buildInAppBody(
case "RECEIPT_CONFIRMED": case "RECEIPT_CONFIRMED":
return `Receipt confirmed — ${pn} closed`; return `Receipt confirmed — ${pn} closed`;
case "PARTIAL_RECEIPT_CONFIRMED":
return `Partial receipt confirmed on ${pn} — items still outstanding`;
default: default:
return `Update on ${pn}`; return `Update on ${pn}`;
} }
@ -195,6 +199,7 @@ function buildActionLabel(event: NotificationEvent, recipient: User, po: Purchas
case "PAYMENT_SENT": case "PAYMENT_SENT":
return isSubmitter ? "Confirm Receipt" : "View Purchase Order"; return isSubmitter ? "Confirm Receipt" : "View Purchase Order";
case "RECEIPT_CONFIRMED": case "RECEIPT_CONFIRMED":
case "PARTIAL_RECEIPT_CONFIRMED":
return "View Purchase Order"; return "View Purchase Order";
default: default:
return "View Purchase Order"; return "View Purchase Order";
@ -213,9 +218,10 @@ function buildSubject(event: NotificationEvent, poNumber: string): string | null
EDITS_REQUESTED: `Edits requested on ${base}`, EDITS_REQUESTED: `Edits requested on ${base}`,
VENDOR_ID_REQUESTED: `Vendor ID needed for ${base}`, VENDOR_ID_REQUESTED: `Vendor ID needed for ${base}`,
VENDOR_ID_PROVIDED: `Vendor ID provided for ${base}`, VENDOR_ID_PROVIDED: `Vendor ID provided for ${base}`,
PAYMENT_PROCESSING: `Payment initiated for ${base}`, PAYMENT_PROCESSING: `Payment initiated for ${base}`,
PAYMENT_SENT: `Payment confirmed for ${base}`, PAYMENT_SENT: `Payment confirmed for ${base}`,
RECEIPT_CONFIRMED: `Receipt confirmed — ${base} closed`, RECEIPT_CONFIRMED: `Receipt confirmed — ${base} closed`,
PARTIAL_RECEIPT_CONFIRMED: `Partial receipt confirmed for ${base}`,
}; };
return map[event] ?? null; return map[event] ?? null;
} }
@ -251,6 +257,8 @@ function buildEmailBody(
return `Payment has been confirmed for <strong>${po.poNumber}</strong>. Please confirm delivery/receipt when the goods arrive.`; return `Payment has been confirmed for <strong>${po.poNumber}</strong>. Please confirm delivery/receipt when the goods arrive.`;
case "RECEIPT_CONFIRMED": case "RECEIPT_CONFIRMED":
return `Receipt has been confirmed for <strong>${po.poNumber}</strong>. The order is now closed.`; return `Receipt has been confirmed for <strong>${po.poNumber}</strong>. The order is now closed.`;
case "PARTIAL_RECEIPT_CONFIRMED":
return `A partial delivery has been confirmed for <strong>${po.poNumber}</strong>. Some items are still outstanding.`;
default: default:
return `There has been an update on purchase order ${po.poNumber}.`; return `There has been an update on purchase order ${po.poNumber}.`;
} }