pelagia-portal/App/app/(portal)/po/[id]/actions.ts
2026-05-18 23:18:58 +05:30

115 lines
3.6 KiB
TypeScript

"use server";
import { auth } from "@/auth";
import { db } from "@/lib/db";
import { canPerformAction } from "@/lib/po-state-machine";
import { notify } from "@/lib/notifier";
import { revalidatePath } from "next/cache";
export async function provideVendorId({
poId,
vendorId,
}: {
poId: string;
vendorId: string;
}): Promise<{ ok: true } | { error: string }> {
const session = await auth();
if (!session?.user) return { error: "Unauthorized" };
if (!vendorId) return { error: "Please select a vendor with a verified ID." };
const po = await db.purchaseOrder.findUnique({
where: { id: poId },
include: { submitter: true },
});
if (!po) return { error: "PO not found" };
if (!canPerformAction(po.status, "provide_vendor_id", session.user.role)) {
return { error: "You cannot provide a vendor ID for this PO in its current state." };
}
const vendor = await db.vendor.findUnique({ where: { id: vendorId } });
if (!vendor?.vendorId) return { error: "The selected vendor does not have a verified ID." };
await db.purchaseOrder.update({
where: { id: poId },
data: {
vendorId,
status: "MGR_REVIEW",
actions: {
create: { actionType: "VENDOR_ID_PROVIDED", actorId: session.user.id },
},
},
});
const managers = await db.user.findMany({ where: { role: "MANAGER", isActive: true } });
await notify({ event: "VENDOR_ID_PROVIDED", po, recipients: managers });
revalidatePath(`/po/${poId}`);
return { ok: true };
}
export async function submitDraftPo(
poId: string
): Promise<{ ok: true } | { error: string }> {
const session = await auth();
if (!session?.user) return { error: "Unauthorized" };
const po = await db.purchaseOrder.findUnique({
where: { id: poId },
include: { submitter: true },
});
if (!po) return { error: "PO not found" };
if (po.status !== "DRAFT") return { error: "Only draft purchase orders can be submitted." };
if (po.submitterId !== session.user.id && session.user.role !== "SUPERUSER") {
return { error: "You can only submit your own purchase orders." };
}
await db.purchaseOrder.update({
where: { id: poId },
data: {
status: "MGR_REVIEW",
submittedAt: new Date(),
actions: {
create: { actionType: "SUBMITTED", actorId: session.user.id },
},
},
});
const managers = await db.user.findMany({ where: { role: "MANAGER", isActive: true } });
await notify({ event: "PO_SUBMITTED", po, recipients: [po.submitter, ...managers] });
revalidatePath(`/po/${poId}`);
revalidatePath("/dashboard");
revalidatePath("/my-orders");
return { ok: true };
}
export async function discardDraftPo(
poId: string
): Promise<{ ok: true } | { error: string }> {
const session = await auth();
if (!session?.user) return { error: "Unauthorized" };
const po = await db.purchaseOrder.findUnique({
where: { id: poId },
select: { id: true, status: true, submitterId: true },
});
if (!po) return { error: "PO not found" };
if (po.status !== "DRAFT") return { error: "Only DRAFT purchase orders can be discarded." };
const { role, id: userId } = session.user;
const canDiscard =
po.submitterId === userId || ["MANAGER", "SUPERUSER"].includes(role);
if (!canDiscard) return { error: "You do not have permission to discard this PO." };
// POAction has no cascade — delete child records before the PO
await db.$transaction([
db.pOAction.deleteMany({ where: { poId } }),
db.notification.deleteMany({ where: { poId } }),
db.purchaseOrder.delete({ where: { id: poId } }),
]);
revalidatePath("/my-orders");
revalidatePath("/dashboard");
return { ok: true };
}