Skip to content

State Machine

Overview

The PO workflow is driven by a database-backed state machine. All transitions are validated against the Ref_PO_Transitions table before execution.

Status Table (Ref_PO_Status)

Status_ID Status_Name Label (EN) Label (ZH) Color Terminal?
100 NEW New 新建 #0078d4 No
150 REQUIRES_REVISION Requires Revision 需修改 #c50f1f No
200 PENDING_APPROVAL Pending Approval 待审批 #ca5010 No
300 CONFIRMED Confirmed 已确认 #107c10 No
400 IN_PRODUCTION In Production 生产中 #0e7a0d No
500 SHIPPED Shipped 已发货 #8764b8 No
600 DELIVERED Delivered 已交付 #2d7d9a Yes
900 CANCELLED Cancelled 已取消 #797775 Yes

Transitions Table (Ref_PO_Transitions)

stateDiagram-v2
    [*] --> 100: Cin7 Sync
    100 --> 200: SUBMIT (Vendor)
    200 --> 300: APPROVE (Manager)
    200 --> 150: REJECT (Manager)
    200 --> 100: RECALL (Vendor)
    150 --> 200: SUBMIT (Vendor)
    300 --> 400: MOVE_TO_PRODUCTION (Manager)
    400 --> 500: MARK_SHIPPED (Vendor)
    500 --> 600: CONFIRM_DELIVERY (Manager)
    100 --> 900: CANCEL (Manager)
    150 --> 900: CANCEL (Manager)
Action From To Allowed Roles Gatekeeper
SUBMIT 100 (New) 200 (Pending) Vendor SUBMIT_READY
SUBMIT 150 (Revision) 200 (Pending) Vendor SUBMIT_READY
APPROVE 200 (Pending) 300 (Confirmed) PO_Manager, Admin
REJECT 200 (Pending) 150 (Revision) PO_Manager, Admin
RECALL 200 (Pending) 100 (New) Vendor
MOVE_TO_PRODUCTION 300 (Confirmed) 400 (Production) PO_Manager, Admin
MARK_SHIPPED 400 (Production) 500 (Shipped) Vendor, PO_Manager SHIPPING_READY
CONFIRM_DELIVERY 500 (Shipped) 600 (Delivered) PO_Manager, Admin
CANCEL 100 (New) 900 (Cancelled) PO_Manager, Admin
CANCEL 150 (Revision) 900 (Cancelled) PO_Manager, Admin

Gatekeeper Checks

SUBMIT_READY

Before a vendor can submit, the system verifies:

  • has_pending_changes = 1 OR this is a fresh submission
  • A proforma invoice document is attached

SHIPPING_READY

Before marking as shipped:

  • container_number must be provided (not null/empty)

Transition Engine

All transitions go through a single endpoint:

POST /api/purchase-orders/{poRef}/transition
Body: { "action": "SUBMIT", "comment": "Ready for review" }

The engine:

  1. Looks up current app_po_status_id for the PO
  2. Queries Ref_PO_Transitions for a matching (from_status, action, allowed_role) row
  3. If no valid transition found → 403 error
  4. Runs gatekeeper check if applicable
  5. Updates app_po_status_id to the new status
  6. Logs the transition in Log_PO_History
  7. Returns the new status details

History Log (Log_PO_History)

Every transition is logged with:

  • PO reference
  • Old and new status IDs
  • Action name
  • User who made the change
  • Timestamp
  • Optional comment (e.g., rejection reason)