diff --git a/App/pelagia-portal/app/(portal)/po/[id]/actions.ts b/App/pelagia-portal/app/(portal)/po/[id]/actions.ts index 219d0f9..aa28917 100644 --- a/App/pelagia-portal/app/(portal)/po/[id]/actions.ts +++ b/App/pelagia-portal/app/(portal)/po/[id]/actions.ts @@ -48,6 +48,42 @@ export async function provideVendorId({ 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 }> { diff --git a/App/pelagia-portal/app/(portal)/po/[id]/edit/actions.ts b/App/pelagia-portal/app/(portal)/po/[id]/edit/actions.ts index 8d5d7e6..7a390a8 100644 --- a/App/pelagia-portal/app/(portal)/po/[id]/edit/actions.ts +++ b/App/pelagia-portal/app/(portal)/po/[id]/edit/actions.ts @@ -41,7 +41,7 @@ export async function updatePo( return { error: "You can only edit your own purchase orders." }; } - const intent = formData.get("intent") as "save" | "resubmit"; + const intent = formData.get("intent") as "save" | "submit" | "resubmit"; const parsed = createPoSchema.safeParse({ title: formData.get("title"), @@ -74,7 +74,9 @@ export async function updatePo( 0 ); + const isSubmit = intent === "submit" && po.status === "DRAFT"; const isResubmit = intent === "resubmit" && po.status === "EDITS_REQUESTED"; + const shouldSubmit = isSubmit || isResubmit; // Before mutating, snapshot the current PO state so the manager can see // exactly what the submitter changed when they resubmit after edits requested. @@ -150,8 +152,8 @@ export async function updatePo( tcPaymentTerms: data.tcPaymentTerms ?? null, tcOthers: data.tcOthers ?? null, totalAmount: total, - status: isResubmit ? "MGR_REVIEW" : "DRAFT", - submittedAt: isResubmit ? new Date() : po.submittedAt, + status: shouldSubmit ? "MGR_REVIEW" : "DRAFT", + submittedAt: shouldSubmit ? new Date() : po.submittedAt, lineItems: { deleteMany: {}, create: data.lineItems.map((item, idx) => ({ @@ -168,18 +170,18 @@ export async function updatePo( })), }, actions: { - create: isResubmit + create: shouldSubmit ? { actionType: "SUBMITTED", actorId: session.user.id, - ...(resubmitSnapshot ? { metadata: { editSnapshot: resubmitSnapshot } } : {}), + ...(isResubmit && resubmitSnapshot ? { metadata: { editSnapshot: resubmitSnapshot } } : {}), } : undefined, }, }, }); - if (isResubmit) { + if (shouldSubmit) { const [fullPo, managers] = await Promise.all([ db.purchaseOrder.findUnique({ where: { id: poId }, include: { submitter: true } }), db.user.findMany({ where: { role: "MANAGER", isActive: true } }), diff --git a/App/pelagia-portal/app/(portal)/po/[id]/edit/edit-po-form.tsx b/App/pelagia-portal/app/(portal)/po/[id]/edit/edit-po-form.tsx index 519bd01..21de1be 100644 --- a/App/pelagia-portal/app/(portal)/po/[id]/edit/edit-po-form.tsx +++ b/App/pelagia-portal/app/(portal)/po/[id]/edit/edit-po-form.tsx @@ -53,12 +53,13 @@ export function EditPoForm({ po, vessels, accounts, vendors }: Props) { accountId: li.accountId ?? undefined, })) ); - const [submitting, setSubmitting] = useState<"save" | "resubmit" | null>(null); + const [submitting, setSubmitting] = useState<"save" | "submit" | "resubmit" | null>(null); const [error, setError] = useState(""); const hasPerLineAccounts = po.lineItems.some((li) => li.accountId); const [multiAccount, setMultiAccount] = useState(hasPerLineAccounts); const [defaultAccountId, setDefaultAccountId] = useState(po.accountId ?? ""); + const canSubmit = po.status === "DRAFT"; const canResubmit = po.status === "EDITS_REQUESTED"; async function handleSubmit(intent: "save" | "resubmit") { @@ -283,6 +284,12 @@ export function EditPoForm({ po, vessels, accounts, vendors }: Props) { className="rounded-lg border border-neutral-300 bg-white px-4 py-2.5 text-sm font-medium text-neutral-700 hover:bg-neutral-50 disabled:opacity-60 transition-colors"> {submitting === "save" ? "Saving…" : "Save Draft"} + {canSubmit && ( + + )} {canResubmit && ( + {error && {error}} + + ); +}