W115: Delete purchase order
Wipes a PO and every inventory effect it produced. Triggered from the Purchase Order Detail page.
Steps
-
Load the PO. Call
PurchaseOrders.getPoByIdto confirm existence and capturepoNumber. -
Gather the PO's source ids. Before anything cascades, list the PO's items and its receipts' items so their ledger rows can be found: the line ids (
po_item) and the receipt-item ids (po_receipt). -
Physically delete the PO's ledger rows. Call
deleteBySourceon both ledgers forpo_item(the status-drivenORDERrows) andpo_receipt(the receipt-drivenRECEIVErows). The rows are removed outright. Because every row tied to a line — forward, reverse, or edit-trail — shares that line's source id, deleting by(source_type, source_id)sweeps them all, including any leftover reversal pairs from earlier line edits. -
Detach documents. Call
Documents.listByEntity('purchase_order', poId)andDocuments.deletefor each. -
Delete the PO row. Call
PurchaseOrders.deletePo. Items, receipts, and receipt items cascade away at the DB layer.
Returns
Nothing.
Business rules
- Hard delete, not reversal. Deleting the PO removes its ledger rows entirely — the record never happened. Cancellation (status →
Cancelled) is the append-only path that reverses and keeps the audit trail. - Atomic. Steps 3 through 5 share one transaction.
- Both ledgers, both targets. A materials-target PO lands its rows in the materials ledger and a finished-goods-target PO in the FG ledger; the sweep runs against both, so either target is cleaned up.
- Cost cascade is still a v1 gap. The downstream FIFO/cost cascade is not implemented (see W122 steps 7-9), so no downstream cost values are recomputed here.
Errors
NotFoundError. The PO was not found.