cleanup
This commit is contained in:
@@ -7,6 +7,7 @@ import { useEffect, useState } from "react";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
|
||||
import { useAuth } from "../../auth/AuthProvider";
|
||||
import { ConfirmActionDialog } from "../../components/ConfirmActionDialog";
|
||||
import { FileAttachmentsPanel } from "../../components/FileAttachmentsPanel";
|
||||
import { api, ApiError } from "../../lib/api";
|
||||
import { emptyPurchaseReceiptInput, purchaseStatusOptions } from "./config";
|
||||
@@ -25,6 +26,20 @@ export function PurchaseDetailPage() {
|
||||
const [isUpdatingStatus, setIsUpdatingStatus] = useState(false);
|
||||
const [isOpeningPdf, setIsOpeningPdf] = useState(false);
|
||||
const [planningRollup, setPlanningRollup] = useState<DemandPlanningRollupDto | null>(null);
|
||||
const [pendingConfirmation, setPendingConfirmation] = useState<
|
||||
| {
|
||||
kind: "status" | "receipt";
|
||||
title: string;
|
||||
description: string;
|
||||
impact: string;
|
||||
recovery: string;
|
||||
confirmLabel: string;
|
||||
confirmationLabel?: string;
|
||||
confirmationValue?: string;
|
||||
nextStatus?: PurchaseOrderStatus;
|
||||
}
|
||||
| null
|
||||
>(null);
|
||||
|
||||
const canManage = user?.permissions.includes("purchasing.write") ?? false;
|
||||
const canReceive = canManage && (user?.permissions.includes(permissions.inventoryWrite) ?? false);
|
||||
@@ -107,7 +122,7 @@ export function PurchaseDetailPage() {
|
||||
}));
|
||||
}
|
||||
|
||||
async function handleStatusChange(nextStatus: PurchaseOrderStatus) {
|
||||
async function applyStatusChange(nextStatus: PurchaseOrderStatus) {
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
@@ -118,7 +133,7 @@ export function PurchaseDetailPage() {
|
||||
try {
|
||||
const nextDocument = await api.updatePurchaseOrderStatus(token, activeDocument.id, nextStatus);
|
||||
setDocument(nextDocument);
|
||||
setStatus("Purchase order status updated.");
|
||||
setStatus("Purchase order status updated. Confirm vendor communication and receiving expectations if this moved the order into a terminal state.");
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof ApiError ? error.message : "Unable to update purchase order status.";
|
||||
setStatus(message);
|
||||
@@ -127,8 +142,7 @@ export function PurchaseDetailPage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleReceiptSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
async function applyReceipt() {
|
||||
if (!token || !canReceive) {
|
||||
return;
|
||||
}
|
||||
@@ -155,7 +169,7 @@ export function PurchaseDetailPage() {
|
||||
receivedAt: new Date().toISOString(),
|
||||
notes: "",
|
||||
}));
|
||||
setReceiptStatus("Purchase receipt recorded.");
|
||||
setReceiptStatus("Purchase receipt recorded. Inventory has been increased; verify stock balances and post a correcting movement if quantities were overstated.");
|
||||
setStatus("Purchase order updated after receipt.");
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof ApiError ? error.message : "Unable to record purchase receipt.";
|
||||
@@ -165,6 +179,39 @@ export function PurchaseDetailPage() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleStatusChange(nextStatus: PurchaseOrderStatus) {
|
||||
const label = purchaseStatusOptions.find((option) => option.value === nextStatus)?.label ?? nextStatus;
|
||||
setPendingConfirmation({
|
||||
kind: "status",
|
||||
title: `Set purchase order to ${label}`,
|
||||
description: `Update ${activeDocument.documentNumber} from ${activeDocument.status} to ${nextStatus}.`,
|
||||
impact:
|
||||
nextStatus === "CLOSED"
|
||||
? "This closes the order operationally and can change inbound supply expectations, shortage coverage, and vendor follow-up."
|
||||
: "This changes the purchasing state used by receiving, planning, and audit review.",
|
||||
recovery: "If the status is wrong, set the order back to the correct state and verify any downstream receiving or planning assumptions.",
|
||||
confirmLabel: `Set ${label}`,
|
||||
confirmationLabel: nextStatus === "CLOSED" ? "Type purchase order number to confirm:" : undefined,
|
||||
confirmationValue: nextStatus === "CLOSED" ? activeDocument.documentNumber : undefined,
|
||||
nextStatus,
|
||||
});
|
||||
}
|
||||
|
||||
function handleReceiptSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
const totalReceiptQuantity = openLines.reduce((sum, line) => sum + Math.max(0, Math.floor(receiptQuantities[line.id] ?? 0)), 0);
|
||||
setPendingConfirmation({
|
||||
kind: "receipt",
|
||||
title: "Post purchase receipt",
|
||||
description: `Receive ${totalReceiptQuantity} total units into ${receiptForm.warehouseId && receiptForm.locationId ? "the selected stock location" : "inventory"} for ${activeDocument.documentNumber}.`,
|
||||
impact: "This increases inventory immediately and becomes part of the PO receipt history.",
|
||||
recovery: "If quantities are wrong, post the correcting inventory movement and review the remaining quantities on the purchase order.",
|
||||
confirmLabel: "Post receipt",
|
||||
confirmationLabel: totalReceiptQuantity > 0 ? "Type purchase order number to confirm:" : undefined,
|
||||
confirmationValue: totalReceiptQuantity > 0 ? activeDocument.documentNumber : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
async function handleOpenPdf() {
|
||||
if (!token) {
|
||||
return;
|
||||
@@ -464,6 +511,41 @@ export function PurchaseDetailPage() {
|
||||
emptyMessage="No vendor supporting documents have been uploaded for this purchase order yet."
|
||||
/>
|
||||
<div className="rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
||||
<ConfirmActionDialog
|
||||
open={pendingConfirmation != null}
|
||||
title={pendingConfirmation?.title ?? "Confirm purchasing action"}
|
||||
description={pendingConfirmation?.description ?? ""}
|
||||
impact={pendingConfirmation?.impact}
|
||||
recovery={pendingConfirmation?.recovery}
|
||||
confirmLabel={pendingConfirmation?.confirmLabel ?? "Confirm"}
|
||||
confirmationLabel={pendingConfirmation?.confirmationLabel}
|
||||
confirmationValue={pendingConfirmation?.confirmationValue}
|
||||
isConfirming={
|
||||
(pendingConfirmation?.kind === "status" && isUpdatingStatus) ||
|
||||
(pendingConfirmation?.kind === "receipt" && isSavingReceipt)
|
||||
}
|
||||
onClose={() => {
|
||||
if (!isUpdatingStatus && !isSavingReceipt) {
|
||||
setPendingConfirmation(null);
|
||||
}
|
||||
}}
|
||||
onConfirm={async () => {
|
||||
if (!pendingConfirmation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingConfirmation.kind === "status" && pendingConfirmation.nextStatus) {
|
||||
await applyStatusChange(pendingConfirmation.nextStatus);
|
||||
setPendingConfirmation(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingConfirmation.kind === "receipt") {
|
||||
await applyReceipt();
|
||||
setPendingConfirmation(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user