Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 delivery
  • Delivered: Packages delivered to user’s account
  • Cancelled: Order cancelled before payment
  • Refunding: 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

  1. Browse available productions
  2. Select production and apply coupon (optional)
  3. Create order → receives order ID
  4. Choose payment method (ePay or balance)
  5. Complete payment → order marked as paid
  6. System delivers packages automatically

Validation Rules

When creating an order, the system validates:

  1. Unpaid Order Limit: Users cannot have more than max_unpaid_orders unpaid orders (default: 5)
  2. Production Existence: Production must exist and be available for purchase
  3. 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:

  1. User requests payment URL with order ID, provider, and channel
  2. System generates signed payment URL
  3. User redirected to ePay gateway
  4. User completes payment on external site
  5. ePay sends callback to server with payment result
  6. System verifies signature and updates order status
  7. OrderPaidEvent published to trigger delivery
  8. 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:

  1. User requests to pay with balance
  2. System checks sufficient balance available
  3. Balance deducted atomically with order update
  4. Balance change logged for audit trail
  5. OrderPaidEvent published 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

EventWhen PublishedConsumers
OrderCreatedEventOrder createdInternal tracking
OrderPaidEventPayment confirmedMarket module (affiliate rewards), Delivery system
OrderCancelledEventOrder cancelledInternal tracking
OrderDeliveredEventProducts delivered⚠️ Not yet implemented

OrderPaidEvent → Product Delivery

When OrderPaidEvent is published, the system should:

  1. Retrieve order and production details
  2. Find current master package of the package series
  3. Create package queue items for the user
  4. Trigger package activation
  5. 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

  1. Delivery hook receives OrderPaidEvent
  2. Looks up order and production details
  3. Finds current master package of the package series
  4. Creates package_amount queue items (e.g., 3 items for quarterly plan)
  5. Links items to order for refund tracking
  6. First package automatically activates for user
  7. 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

OperationPermissionsDescription
List OrdersModerator, SuperAdmin, CustomerSupportView all orders with filters (user, production, status)
Show Order DetailModerator, SuperAdmin, CustomerSupportView complete order information
Mark as PaidModerator, SuperAdmin, CustomerSupportManually mark order as paid (triggers delivery)
Change AmountModerator, SuperAdmin, CustomerSupportAdjust 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

OperationPurpose
VerifyCouponCheck if a coupon code is valid
CreateOrderCreate new order with optional coupon
ListOrdersGet user’s order history
GetOrderDetailView specific order details
GetEpayUrlGenerate payment gateway URL
PayOrderWithBalancePay with account balance
CancelOrderCancel unpaid order
DeleteOrderHide order from user’s list
ListEpayProvidersGet available payment providers

Configuration

Stored in Redis under key shop:

SettingDefaultDescription
max_unpaid_orders5Maximum unpaid orders per user
auto_cancel_after30 minutesTimeout 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 OrderPaidEvent and 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

  1. Transaction Safety: Balance payments use atomic transactions with pessimistic locking
  2. Idempotency: Payment callbacks can be replayed safely without duplicate charges
  3. Event-Driven Architecture: Use RabbitMQ events for cross-module communication
  4. Signature Verification: Always verify ePay callback signatures to prevent fraud
  5. Processor Pattern: All APIs exposed via Processor trait, not object-oriented methods [[memory:6079830]]

For Frontend Developers

  1. Order Status Polling: After payment, poll order status until Delivered
  2. ePay Redirect: Handle user redirect to external payment gateway
  3. Error Handling: Handle all result enums (TooManyUnpaid, CouponInvalid, etc.)
  4. Coupon Verification: Always verify coupon before order creation to show discount preview
  5. Balance Check: Check user balance before offering balance payment option

See Also: