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 = 1OR this is a fresh submission- A proforma invoice document is attached
SHIPPING_READY¶
Before marking as shipped:
container_numbermust 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:
- Looks up current
app_po_status_idfor the PO - Queries
Ref_PO_Transitionsfor a matching (from_status, action, allowed_role) row - If no valid transition found → 403 error
- Runs gatekeeper check if applicable
- Updates
app_po_status_idto the new status - Logs the transition in
Log_PO_History - 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)