Order System
The Order System manages the complete e-commerce transaction lifecycle in Helium, from order creation through payment processing to product delivery.
Overview
An order represents a user’s purchase of a production. Key capabilities:
- Create orders with optional coupon discounts
- Process payments via ePay gateways or account balance
- Track order status through lifecycle states
- Automatically cancel unpaid orders after timeout
- Publish events to notify other modules
- Admin order management and intervention
Order Data Model
Each order tracks:
- User and production reference
- Final amount after discounts
- Applied coupon (if any)
- Current status and timestamps
- Payment method and provider
- Soft deletion flag
Order Status Lifecycle
Orders transition through the following states:
┌─────────┐ payment ┌──────┐ delivery ┌───────────┐
│ Unpaid │──────────────────>│ Paid │─────────────────>│ Delivered │
└─────────┘ └──────┘ └───────────┘
│ │
│ timeout/ │ admin/
│ manual │ user
│ │
v v
┌───────────┐ ┌───────────┐
│ Cancelled │ │ Refunding │
└───────────┘ └───────────┘
│
│ processed
v
┌──────────┐
│ Refunded │
└──────────┘
Status Definitions
Unpaid: Order created, payment pending. Auto-cancelled after timeout (default: 30 minutes)Paid: Payment confirmed. Awaiting product deliveryDelivered: Packages delivered to user’s accountCancelled: Order cancelled before paymentRefunding: Refund in progress (not fully implemented)Refunded: Refund completed (not fully implemented)
Payment Methods
- Alipay: AliPay via ePay gateway
- WeChatPay: WeChat Pay via ePay gateway
- Usdt: USDT cryptocurrency via ePay gateway
- AccountBalance: Direct payment from user’s account balance
- AdminChange: Admin manually marked as paid
Order Creation
User Purchase Flow
- Browse available productions
- Select production and apply coupon (optional)
- Create order → receives order ID
- Choose payment method (ePay or balance)
- Complete payment → order marked as paid
- System delivers packages automatically
Validation Rules
When creating an order, the system validates:
- Unpaid Order Limit: Users cannot have more than
max_unpaid_ordersunpaid orders (default: 5) - Production Existence: Production must exist and be available for purchase
- Coupon Validation (if coupon applied):
- Coupon code must be valid
- Current time within coupon’s validity window
- Global usage limit not exceeded
- Per-user usage limit not exceeded
- Production price meets coupon’s minimum amount requirement
Possible Results
- Created: Order created successfully, returns order ID
- ProductionNotFound: Selected production doesn’t exist
- CouponInvalid: Coupon is invalid or not applicable
- TooManyUnpaid: User has reached the unpaid order limit
Payment Processing
Payment Methods
1. ePay Gateway Payment
ePay (易支付) is a third-party payment aggregator supporting:
- AliPay
- WeChat Pay
- USDT cryptocurrency
Payment Flow:
User → Request Payment URL → Get Signed URL → Redirect to ePay
↓
User ← Return to App ← OrderPaidEvent ← Callback ← Payment Complete
Process:
- User requests payment URL with order ID, provider, and channel
- System generates signed payment URL
- User redirected to ePay gateway
- User completes payment on external site
- ePay sends callback to server with payment result
- System verifies signature and updates order status
OrderPaidEventpublished to trigger delivery- User redirected back to app
Security: All callbacks are signature-verified using provider’s secret key to prevent fraud.
2. Account Balance Payment
Users can pay directly from their account balance.
Process:
- User requests to pay with balance
- System checks sufficient balance available
- Balance deducted atomically with order update
- Balance change logged for audit trail
OrderPaidEventpublished to trigger delivery
Transaction Safety: Balance deduction and order update occur in a single atomic transaction with pessimistic locking to prevent race conditions.
Order Cancellation
Cancellation Methods
1. User Cancellation
Users can cancel their own unpaid orders at any time. Once cancelled, the order cannot be restored.
2. Automatic Cancellation
A cron job automatically cancels unpaid orders after a timeout period (default: 30 minutes). This prevents abandoned orders from cluttering the system.
Configuration: auto_cancel_after in shop config (default: 30 minutes)
3. Admin Cancellation
Administrators can manually cancel orders through the management interface.
Order Events
The order system publishes events via RabbitMQ for inter-module communication.
Event Types
| Event | When Published | Consumers |
|---|---|---|
OrderCreatedEvent | Order created | Internal tracking |
OrderPaidEvent | Payment confirmed | Market module (affiliate rewards), Delivery system |
OrderCancelledEvent | Order cancelled | Internal tracking |
OrderDeliveredEvent | Products delivered | ⚠️ Not yet implemented |
OrderPaidEvent → Product Delivery
When OrderPaidEvent is published, the system should:
- Retrieve order and production details
- Find current master package of the package series
- Create package queue items for the user
- Trigger package activation
- Update order status to
Delivered
Status: ⚠️ The delivery hook that consumes OrderPaidEvent needs to be implemented or located in the codebase.
Product Delivery
When an order is paid, the system delivers products by creating package queue items.
Delivery Flow
OrderPaidEvent → Delivery Hook → Create Package Queue Items → Activate First Package
What Happens
- Delivery hook receives
OrderPaidEvent - Looks up order and production details
- Finds current master package of the package series
- Creates
package_amountqueue items (e.g., 3 items for quarterly plan) - Links items to order for refund tracking
- First package automatically activates for user
- Order status updates to
Delivered
Important: The delivery hook snapshots the master package version at payment time, ensuring users receive the package version that was advertised when they purchased.
⚠️ Implementation Status: The delivery hook needs to be implemented or located in the codebase.
Admin Management
Administrators can manage orders through the management interface.
Admin Operations
| Operation | Permissions | Description |
|---|---|---|
| List Orders | Moderator, SuperAdmin, CustomerSupport | View all orders with filters (user, production, status) |
| Show Order Detail | Moderator, SuperAdmin, CustomerSupport | View complete order information |
| Mark as Paid | Moderator, SuperAdmin, CustomerSupport | Manually mark order as paid (triggers delivery) |
| Change Amount | Moderator, SuperAdmin, CustomerSupport | Adjust order amount for corrections or refunds |
Common Use Cases
- Manual Payment Processing: Mark orders as paid after offline payments
- Customer Support: View order details and history for troubleshooting
- Price Adjustments: Correct pricing errors or apply custom discounts
- Partial Refunds: Adjust order amount for partial refunds
Audit Trail
All admin operations are automatically logged with:
- Admin user ID and role
- Operation performed
- Target order ID
- Parameters and changes
- Timestamp and result
API Overview
The order system exposes a gRPC service: ShopOrderService (see proto/shop/order.proto)
Main Operations
| Operation | Purpose |
|---|---|
VerifyCoupon | Check if a coupon code is valid |
CreateOrder | Create new order with optional coupon |
ListOrders | Get user’s order history |
GetOrderDetail | View specific order details |
GetEpayUrl | Generate payment gateway URL |
PayOrderWithBalance | Pay with account balance |
CancelOrder | Cancel unpaid order |
DeleteOrder | Hide order from user’s list |
ListEpayProviders | Get available payment providers |
Configuration
Stored in Redis under key shop:
| Setting | Default | Description |
|---|---|---|
max_unpaid_orders | 5 | Maximum unpaid orders per user |
auto_cancel_after | 30 minutes | Timeout before auto-cancellation |
epay_notify_url | - | Server callback URL for payment notifications |
epay_return_url | - | User redirect URL after payment |
Usage Examples
User Purchase Flow
// 1. Verify coupon (optional)
const couponResponse = await orderService.verifyCoupon({ code: "DISCOUNT10" });
const couponId = couponResponse.isValid ? couponResponse.coupon.id : null;
// 2. Create order
const createResponse = await orderService.createOrder({
productionId: selectedProductionId,
couponId: couponId,
});
if (createResponse.result === "TOO_MANY_UNPAID") {
showError("Please pay or cancel existing orders first");
return;
}
const orderId = createResponse.orderId;
// 3. Choose payment method
if (useAccountBalance) {
// Pay with balance
const payResponse = await orderService.payOrderWithBalance({ orderId });
if (payResponse.result === "NOT_ENOUGH_BALANCE") {
showError("Insufficient balance");
return;
}
showSuccess("Payment successful!");
} else {
// Pay with ePay
const providers = await orderService.listEpayProviders({});
const urlResponse = await orderService.getEpayUrl({
orderId: orderId,
providerId: providers.providers[0].id,
channel: "EPAY_CHANNEL_ALI_PAY",
});
// Redirect to payment gateway
window.location.href = urlResponse.url;
}
// 4. Check order status
const detailResponse = await orderService.getOrderDetail({ orderId });
if (detailResponse.detail) {
console.log("Order status:", detailResponse.detail.order.orderStatus);
console.log("Production:", detailResponse.detail.production.title);
} else {
console.error("Order not found or not accessible");
}
Implementation Status
Completed Features
- ✅ Order creation with coupon validation
- ✅ ePay payment gateway integration
- ✅ Account balance payment
- ✅ Order cancellation (user, automatic, admin)
- ✅ Order tracking and status management
- ✅ Event publishing for inter-module communication
- ✅ Admin management operations
- ✅ Complete gRPC API
Pending Implementation
- ⚠️ Product delivery hook: Needs to consume
OrderPaidEventand create package queue items - ⚠️ OrderDeliveredEvent: Not currently published (implement or remove)
- ⚠️ Refund workflow: Status states exist but full refund process not implemented
Important Notes
For Backend Developers
- Transaction Safety: Balance payments use atomic transactions with pessimistic locking
- Idempotency: Payment callbacks can be replayed safely without duplicate charges
- Event-Driven Architecture: Use RabbitMQ events for cross-module communication
- Signature Verification: Always verify ePay callback signatures to prevent fraud
- Processor Pattern: All APIs exposed via
Processortrait, not object-oriented methods [[memory:6079830]]
For Frontend Developers
- Order Status Polling: After payment, poll order status until
Delivered - ePay Redirect: Handle user redirect to external payment gateway
- Error Handling: Handle all result enums (TooManyUnpaid, CouponInvalid, etc.)
- Coupon Verification: Always verify coupon before order creation to show discount preview
- Balance Check: Check user balance before offering balance payment option
See Also:
- Production - Product catalog and version control
- Shop Module Introduction - Shop module overview
- Package Queue - Package delivery mechanism
- Balance System - User balance management (if documented)