Server-Side Order Status Flow in mini-shop-server: A Complete Guide
The mini-shop-server implements a linear order status flow using integer enums defined in app/libs/enums.py, transitioning from UNPAID (1) → PAID (2) → DELIVERED (3), with additional states for out-of-stock handling reserved for future admin workflows.
The server-side order status flow in mini-shop-server governs how e-commerce transactions progress from creation to fulfillment. This Flask-based application centralizes status definitions in OrderStatusEnum and enforces state transitions through service-layer validation in app/service/order.py and app/service/pay.py.
Order Status Enum Definition
All order states are centralized in app/libs/enums.py as integer values to ensure database efficiency and code consistency.
# app/libs/enums.py
class OrderStatusEnum(Enum):
UNPAID = 1 # 待支付
PAID = 2 # 已支付
DELIVERED = 3 # 已发货
PAID_BUT_OUT_OF = 4 # 已支付,但库存不足
HANDLED_OUT_OF = 5 # 已处理 PAID_BUT_OUT_OF
The default status for new orders is UNPAID (1), which represents the initial state before any payment processing begins.
Database Schema and Default Status
The Order model in app/models/order.py defines the status column with a default value that aligns with the enum.
# app/models/order.py
order_status = Column(SmallInteger, default=1,
comment='订单状态 1:未支付 2:已支付 3:已发货 4:已支付,但库存不足 ')
When OrderService creates a new instance via __create_order(), it relies on this default rather than explicit assignment, ensuring every order begins in the UNPAID state.
Lifecycle State Transitions
The server-side logic enforces a strict linear progression through the order lifecycle, with validation gates at each transition point.
Order Creation (UNPAID)
The OrderService.palce() method (note: method name appears as palce in source) initiates the flow by creating an order record after validating stock availability.
# app/service/order.py – __create_order()
order = Order()
order.user_id = self.uid
order.order_no = order_no
# … other fields …
db.session.add(order)
Because the model defines default=1, the resulting database row has order_status = 1 (UNPAID) without explicit assignment in the service code.
Payment Validation (UNPAID Check)
Before processing payment, PayService.__check_order_valid() enforces that the order must be in UNPAID status to prevent duplicate charges.
# app/service/pay.py – __check_order_valid()
if order.order_status != OrderStatusEnum.UNPAID:
raise OrderException(msg='订单已支付', error_code=8003, code=404)
This guard ensures that only orders in the initial state can proceed to the external payment gateway. Upon successful payment confirmation (typically handled by a webhook or callback not fully implemented in the current repository), the status would transition to PAID (2).
Delivery Processing (PAID → DELIVERED)
The OrderService.delivery() method handles the final transition, moving an order from PAID to DELIVERED when an admin marks it as shipped.
# app/service/order.py – delivery()
order = Order.query.filter_by(id=order_id).first_or_404()
if order.order_status != OrderStatusEnum.PAID:
raise OrderException(code=403, error_code=8002,
msg='订单未支付,或已经更新过订单了')
order.order_status = OrderStatusEnum.DELIVERED
This strict validation prevents shipping orders that have not been paid, maintaining data integrity in the fulfillment workflow.
Out-of-Stock Handling States
The enum defines two additional states for edge cases: PAID_BUT_OUT_OF (4) and HANDLED_OUT_OF (5). These represent a scenario where payment succeeds but inventory is subsequently found insufficient.
Currently, the repository defines these states in OrderStatusEnum but contains no automated logic to transition orders into these states. They serve as placeholders for a future admin workflow where staff manually handle stock shortages after payment confirmation.
Implementation Examples
Creating a New Order
from app.service.order import OrderService
uid = 12 # current user id
cart_items = [{'product_id': 3, 'count': 2},
{'product_id': 7, 'count': 1}]
order_info = OrderService().palce(uid, cart_items)
# order_info contains order_no, order_id, create_time and pass=True
The resulting database record has order_status = 1 (UNPAID).
Validating Payment Eligibility
from app.service.pay import PayService
pay = PayService(order_id=order_info['order_id'])
pay.pay() # raises OrderException if order_status != UNPAID
The __check_order_valid method ensures only unpaid orders proceed to the payment gateway.
Marking an Order as Delivered
from app.service.order import OrderService
OrderService.delivery(order_id=order_info['order_id'])
# order_status becomes 3 (DELIVERED)
This only succeeds if the order is currently in PAID status.
Summary
- Status definitions live in
app/libs/enums.pyasOrderStatusEnum, using integer values for database efficiency. - Default state is
UNPAID(1), set automatically by theorder_statuscolumn default inapp/models/order.py. - Payment validation occurs in
PayService.__check_order_valid(), which blocks requests for orders not inUNPAIDstatus. - Delivery transition is handled by
OrderService.delivery(), strictly requiringPAIDstatus before updating toDELIVERED. - Out-of-stock states (
PAID_BUT_OUT_OF,HANDLED_OUT_OF) are defined but lack automated transition logic in the current codebase.
Frequently Asked Questions
How does mini-shop-server prevent duplicate payments for the same order?
The server enforces a status check in PayService.__check_order_valid() located in app/service/pay.py. Before initiating any payment gateway interaction, the code verifies that order.order_status == OrderStatusEnum.UNPAID. If the status has already transitioned to PAID or any other state, an OrderException is raised with the message "订单已支付" (order already paid), preventing duplicate transactions.
What happens if an admin tries to ship an order that hasn't been paid?
The OrderService.delivery() method in app/service/order.py explicitly guards against this scenario. It queries the order and checks if order.order_status != OrderStatusEnum.PAID before proceeding. If the order is not in PAID status, the method raises an OrderException with code 403 and the message "订单未支付,或已经更新过订单了" (order not paid or already updated), ensuring only paid orders can enter the DELIVERED state.
Are the out-of-stock order statuses automatically triggered by inventory checks?
No, the statuses PAID_BUT_OUT_OF (4) and HANDLED_OUT_OF (5) defined in app/libs/enums.py are not automatically triggered by any existing logic in the repository. While the enum defines these states for scenarios where payment succeeds but inventory is insufficient, the current codebase in app/service/order.py and app/service/pay.py contains no code paths that transition orders into these states. They serve as placeholders for future manual admin workflows to handle post-payment stock shortages.
Which database column stores the order status, and what is its default value?
The order status is stored in the order_status column of the Order model defined in app/models/order.py. The column is defined as Column(SmallInteger, default=1, comment='订单状态 1:未支付 2:已支付 3:已发货 4:已支付,但库存不足 '). This default value of 1 corresponds to OrderStatusEnum.UNPAID, ensuring every newly created order starts in the unpaid state without requiring explicit assignment in the creation service logic.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →