How the Order Workflow and State Machine Work in Mall (macrozheng/mall)

The Mall e-commerce platform implements a finite-state machine for orders using an integer status field in the OmsOrder entity, with six distinct states ranging from pending payment (0) to invalid (5), guarded by service methods in OmsPortalOrderServiceImpl and OmsOrderServiceImpl that enforce valid transitions.

The macrozheng/mall repository provides a comprehensive Spring Boot e-commerce solution with sophisticated order lifecycle management. The order workflow and state machine architecture ensures data integrity by codifying business rules—such as preventing payment on cancelled orders—directly into the service layer transition guards.

Order State Definitions in OmsOrder

At the core of the workflow is the OmsOrder model class located at mall-mbg/src/main/java/com/macro/mall/model/OmsOrder.java. The Javadoc on line 52 defines the status field as an integer representing the order's lifecycle stage:

  • 0: 待付款 (Pending payment)
  • 1: 待发货 (Waiting for delivery / Paid)
  • 2: 已发货 (Shipped)
  • 3: 已完成 (Completed / Buyer confirmed receipt)
  • 4: 已关闭 (Closed / Cancelled)
  • 5: 无效订单 (Invalid / Reserved for future use)

The system treats this status column as the single source of truth, with all transitions mediated through specific service methods that validate preconditions before persisting changes.

Order Creation and Initial State

New orders enter the system with status 0 (pending payment). In mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsPortalOrderServiceImpl.java, the generateOrder method instantiates an OmsOrder object and explicitly sets the initial state at line 197:

order.setStatus(0);

At this stage, the order is persisted to the database and a delayed message is queued for automatic timeout handling. No permanent inventory deduction occurs yet; stock remains locked pending payment confirmation.

Payment Success Transition (0 → 1)

When a buyer completes payment, the paySuccess method at line 55 of OmsPortalOrderServiceImpl.java executes the transition to status 1 (waiting for delivery). This method enforces a critical guard condition: it verifies the current status is exactly 0 before proceeding.

// Simplified logic from OmsPortalOrderServiceImpl.java
if (order.getStatus() != 0) {
    throw new BusinessException("Order is not in pending payment status");
}
order.setStatus(1);
order.setPaymentTime(new Date());

If the order has already been cancelled (status 4) or is in any other state, the payment is rejected to prevent charging customers for invalid orders.

Backend Shipment Transition (1 → 2)

The transition to status 2 (shipped) is initiated by administrators through the delivery method in mall-admin/src/main/java/com/macro/mall/service/impl/OmsOrderServiceImpl.java. At line 52, the service creates an OmsOrderOperateHistory entry with orderStatus = 2 to audit the shipment event.

While the current implementation primarily logs this via history records, the state change signals to the frontend that logistics information—such as tracking numbers—has been associated with the order. The buyer can now view shipment details and anticipate delivery.

Buyer Confirmation Transition (2 → 3)

Once the buyer receives the goods, they invoke confirmReceiveOrder at line 66 of OmsPortalOrderServiceImpl.java to transition the order to status 3 (completed). This method applies two validation guards:

  1. Ownership verification: The order must belong to the currently authenticated user.
  2. State verification: The order must currently have status 2 (shipped).

Upon successful validation, the method updates status to 3, sets the confirmation flag, and records the receipt timestamp, effectively closing the transaction lifecycle from the buyer's perspective.

Order Cancellation and Closure (→ 4)

Orders transition to status 4 (closed) through three distinct pathways, all implemented in the service layer:

Automated Timeout Cancellation

The OrderTimeOutCancelTask scheduled component runs every ten minutes to identify unpaid orders exceeding their expiration window. It delegates to cancelTimeOutOrder at line 94 of OmsPortalOrderServiceImpl.java, which executes:

// Batch update from status 0 to 4 for expired orders
portalOrderDao.updateOrderStatus(orderIds, 4);

This batch operation releases locked inventory and reverts any applied coupon usage automatically.

Manual Cancellation

Administrators may manually cancel pending orders via the cancelOrder method at line 25 of OmsPortalOrderServiceImpl.java. This method specifically targets orders with status = 0, updating them to 4 while triggering resource reclamation.

Administrative Closure

For disputes or post-payment issues, the close method at line 63 of OmsOrderServiceImpl.java creates a new OmsOrder record—or updates existing records—to status 4, providing a formal audit trail for forced terminations outside the standard workflow.

Invalid State Reservation (5)

Status 5 (invalid order) is defined in the OmsOrder entity but remains unused in the current codebase. It is reserved for future data-migration scenarios or soft-delete implementations where orders must be retained for audit purposes while being excluded from active business metrics.

State Transition Guards and Enforcement

The state machine enforces business rules through explicit guard clauses in service methods:

  • Transition 0 → 1: paySuccess validates status == 0
  • Transition 2 → 3: confirmReceiveOrder validates status == 2
  • Transition to 4: Cancellation methods validate the order is cancellable (typically status 0)

These guards prevent illegal transitions—such as attempting to ship a cancelled order or paying a completed order—at the application layer before any database update occurs.

Practical Implementation Examples

The following snippets demonstrate typical service invocations for managing the order lifecycle:

// Create order (status becomes 0)
Map<String, Object> result = portalOrderService.generateOrder(orderParam);

// Process payment (status 0 → 1)
int updated = portalOrderService.paySuccess(orderId, 1); // 1 = Alipay

// Admin marks as shipped (status 1 → 2)
List<OmsOrderDeliveryParam> deliveries = Collections.singletonList(
    new OmsOrderDeliveryParam(orderId, "SF Express", "SF123456789", 1));
int shipped = orderService.delivery(deliveries);

// Buyer confirms receipt (status 2 → 3)
portalOrderService.confirmReceiveOrder(orderId);

// Cancel unpaid order (status 0 → 4)
orderService.cancelOrder(orderId);

Summary

  • The order workflow and state machine in macrozheng/mall uses six integer states (0-5) defined in OmsOrder.java to model the complete e-commerce lifecycle from pending payment through completion or cancellation.
  • State transitions are guarded by methods in OmsPortalOrderServiceImpl (frontend) and OmsOrderServiceImpl (backend) that validate preconditions before updating the status field, ensuring illegal transitions are rejected.
  • Automated timeout handling via OrderTimeOutCancelTask ensures unpaid orders automatically close after expiration, releasing inventory resources and reverting coupon usage without manual intervention.
  • The architecture separates concerns between customer-facing actions (payment, confirmation) and administrative controls (shipping, forced closure) while maintaining data integrity through rigorous status validation at the service layer.

Frequently Asked Questions

What are the integer status values for orders in the Mall project?

The OmsOrder.status field uses six integer codes defined at line 52 of mall-mbg/src/main/java/com/macro/mall/model/OmsOrder.java: 0 (pending payment), 1 (waiting for delivery), 2 (shipped), 3 (completed), 4 (closed/cancelled), and 5 (invalid/reserved).

How does Mall prevent invalid order state transitions?

Service methods enforce guard conditions that check the current status before allowing updates. For example, paySuccess in OmsPortalOrderServiceImpl.java throws an exception if the order status is not 0, and confirmReceiveOrder requires status 2. This prevents operations like paying for cancelled orders or confirming receipt of unshipped items.

What triggers automatic order cancellation in the Mall workflow?

The OrderTimeOutCancelTask scheduled task runs every ten minutes to detect unpaid orders past their expiration time. It calls cancelTimeOutOrder in OmsPortalOrderServiceImpl.java (line 94), which batch-updates eligible orders from status 0 to 4 and releases locked stock and coupons automatically.

Can an order move from "shipped" (status 2) back to "waiting for delivery" (status 1)?

No, the state machine does not support backward transitions. Once confirmReceiveOrder or administrative closure methods update the status, the change is unidirectional. Business reversals—such as returns—are handled through separate return-apply workflows in OmsPortalOrderReturnApplyServiceImpl.java rather than by reverting the main order state.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →