fix(orders): keep stock-PO button visible after per-row in-stock toggle

The per-row in-stock checkbox flips item_status to ready_invoice
(legacy behaviour, no PO created by that path). The previous
markInStockReady filter required item_status in
[pending, processed] and the render used that same filter to
gate the button count. Result: the moment a line was ticked
in-stock via the checkbox, it dropped out of that filter and
the {supplier} stock PO button disappeared, leaving the
operator no way to fire the paper-trail PO from the same page.

Loosen both filters to in_stock=true AND purchase_order is
empty, regardless of item_status. The bottom button now stays
clickable after a per-row tick, and re-clicking is a no-op
(the purchase_order guard skips already-linked lines).

Lifecycle for the item is unchanged: ready_invoice, qty_collected
= quantity, no driver collection. The PO is the only thing that
gets created when this button fires.
This commit is contained in:
Dave 2026-09-23 13:37:32 +02:00
parent b43ad41ab4
commit 582c0ba1b9

View file

@ -1441,14 +1441,26 @@ export default function ProcessOrderPage({ params }: { params: Promise<{ id: str
const markInStockReady = async (supplierId: string) => {
const supplier = suppliers.find((s) => s.id === supplierId);
if (!supplier) return;
// Filter is loose on purpose: the per-row in-stock checkbox
// flips `item_status` to `ready_invoice` (legacy behaviour, no
// PO created by that path) which used to push these lines out
// of this filter and hide the bottom button. We want to issue
// the paper-trail PO from this button for ANY in-stock line
// that doesn't already have one, regardless of item_status,
// so the operator can tick the checkbox and then fire the PO
// from the same page without losing access to the action.
//
// The `purchase_order` guard skips lines already linked to a
// PO — a re-click must not duplicate.
const inStock = items.filter(
(it) =>
(it.supplier || "") === supplierId &&
["pending", "processed"].includes(it.item_status) &&
it.in_stock,
it.in_stock &&
(typeof it.purchase_order !== "string" ||
it.purchase_order === ""),
);
if (inStock.length === 0) {
toast.error("No in-stock items for this supplier");
toast.error("No in-stock items need a PO");
return;
}
@ -2086,12 +2098,26 @@ export default function ProcessOrderPage({ params }: { params: Promise<{ id: str
const editable = list.filter((it) =>
["pending", "processed"].includes(it.item_status),
);
if (editable.length === 0) return null;
// Lines that still need a stock-replenishment PO:
// any `in_stock=true` line without one yet, regardless
// of item_status. The per-row in-stock checkbox flips
// a line to `ready_invoice` (without creating a PO),
// which would otherwise push it out of `editable` and
// hide this button — yet the operator still needs to
// fire the paper-trail PO for it.
const needsStockPo = list.filter(
(it) =>
it.in_stock &&
(typeof it.purchase_order !== "string" ||
it.purchase_order === ""),
);
if (editable.length === 0 && needsStockPo.length === 0) {
return null;
}
const nonInStockCount = editable.filter(
(it) => !it.in_stock,
).length;
const inStockCount = editable.filter((it) => it.in_stock)
.length;
const inStockCount = needsStockPo.length;
const isBusy =
sendingSupplier === supplierId ||
markingInStockSupplier === supplierId;