b2c-ordering

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

B2C Ordering

B2C订单管理

The OrderMgr API provides order creation, status management, and querying. Understanding the order lifecycle is essential for checkout implementation and order processing.
OrderMgr API提供订单创建、状态管理和查询能力,理解订单生命周期对于结账功能实现和订单处理至关重要。

Order Lifecycle

订单生命周期

Orders progress through these statuses:
Basket → CREATED → NEW → (COMPLETED or CANCELLED or FAILED)
StatusDescriptionCan Transition To
CREATED
Order created, not yet placed
NEW
,
FAILED
NEW
Order placed, awaiting fulfillment
OPEN
,
COMPLETED
,
CANCELLED
,
FAILED
OPEN
Order in processing
COMPLETED
,
CANCELLED
COMPLETED
Order fulfilled-
CANCELLED
Order cancelled
NEW
(via
undoCancel
)
FAILED
Order failed (payment, validation)- (cannot be reopened)
Important: Once an order reaches
FAILED
status, it cannot be reopened or cancelled. Use
failOrder(order, true)
to reopen the basket for retry instead.
订单会依次经过以下状态:
Basket → CREATED → NEW → (COMPLETED or CANCELLED or FAILED)
状态描述可转换为
CREATED
订单已创建,尚未提交
NEW
,
FAILED
NEW
订单已提交,等待履约
OPEN
,
COMPLETED
,
CANCELLED
,
FAILED
OPEN
订单处理中
COMPLETED
,
CANCELLED
COMPLETED
订单已履约-
CANCELLED
订单已取消
NEW
(通过
undoCancel
方法)
FAILED
订单失败(支付、校验问题)-(无法重新打开)
重要提示: 订单一旦进入
FAILED
状态,就无法重新打开或取消,可调用
failOrder(order, true)
重新打开购物篮供用户重试。

Creating Orders

创建订单

Standard Flow (Synchronous)

标准流程(同步)

javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');
var Status = require('dw/system/Status');

function createOrder(basket) {
    var order;

    Transaction.wrap(function() {
        // Create order from basket (status: CREATED)
        order = OrderMgr.createOrder(basket);
    });

    if (!order) {
        return { error: true, message: 'Order creation failed' };
    }

    // Authorize payment
    var paymentResult = authorizePayment(order);

    if (!paymentResult.success) {
        Transaction.wrap(function() {
            OrderMgr.failOrder(order, true); // Reopen basket
        });
        return { error: true, message: 'Payment failed' };
    }

    // Place the order (status: CREATED → NEW)
    var placeResult;
    Transaction.wrap(function() {
        placeResult = OrderMgr.placeOrder(order);
    });

    if (placeResult.error) {
        return { error: true, message: 'Order placement failed' };
    }

    // Set confirmation status
    Transaction.wrap(function() {
        order.setConfirmationStatus(order.CONFIRMATION_STATUS_CONFIRMED);
    });

    return { error: false, order: order };
}
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');
var Status = require('dw/system/Status');

function createOrder(basket) {
    var order;

    Transaction.wrap(function() {
        // 从购物篮创建订单(状态:CREATED)
        order = OrderMgr.createOrder(basket);
    });

    if (!order) {
        return { error: true, message: 'Order creation failed' };
    }

    // 支付授权
    var paymentResult = authorizePayment(order);

    if (!paymentResult.success) {
        Transaction.wrap(function() {
            OrderMgr.failOrder(order, true); // 重新打开购物篮
        });
        return { error: true, message: 'Payment failed' };
    }

    // 提交订单(状态:CREATED → NEW)
    var placeResult;
    Transaction.wrap(function() {
        placeResult = OrderMgr.placeOrder(order);
    });

    if (placeResult.error) {
        return { error: true, message: 'Order placement failed' };
    }

    // 设置确认状态
    Transaction.wrap(function() {
        order.setConfirmationStatus(order.CONFIRMATION_STATUS_CONFIRMED);
    });

    return { error: false, order: order };
}

Async Flow (SCAPI Pattern)

异步流程(SCAPI模式)

For SCAPI/headless, create the order before payment authorization:
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');

// Step 1: Create order (before payment)
function createOrderAsync(basket, orderNo) {
    var order;

    Transaction.wrap(function() {
        // Create with specific order number (for idempotency)
        order = OrderMgr.createOrder(basket, orderNo);
    });

    return order;
}

// Step 2: After payment success, place the order
function placeOrderAfterPayment(order) {
    Transaction.wrap(function() {
        OrderMgr.placeOrder(order);
        order.setConfirmationStatus(order.CONFIRMATION_STATUS_CONFIRMED);
        order.setExportStatus(order.EXPORT_STATUS_READY);
    });
}

// Step 2 (alt): Payment failed, fail the order
function failOrderAfterPayment(order) {
    Transaction.wrap(function() {
        OrderMgr.failOrder(order, false); // Don't reopen basket
    });
}
针对SCAPI/ headless场景,在支付授权前先创建订单:
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');

// 步骤1:创建订单(支付前)
function createOrderAsync(basket, orderNo) {
    var order;

    Transaction.wrap(function() {
        // 使用指定订单号创建(保证幂等性)
        order = OrderMgr.createOrder(basket, orderNo);
    });

    return order;
}

// 步骤2:支付成功后提交订单
function placeOrderAfterPayment(order) {
    Transaction.wrap(function() {
        OrderMgr.placeOrder(order);
        order.setConfirmationStatus(order.CONFIRMATION_STATUS_CONFIRMED);
        order.setExportStatus(order.EXPORT_STATUS_READY);
    });
}

// 步骤2(备选):支付失败,标记订单失败
function failOrderAfterPayment(order) {
    Transaction.wrap(function() {
        OrderMgr.failOrder(order, false); // 不重新打开购物篮
    });
}

OrderMgr API Reference

OrderMgr API参考

Order Creation

订单创建

MethodDescription
createOrder(basket)
Create order with auto-generated number
createOrder(basket, orderNo)
Create order with specific number
createOrderNo()
Generate next order number
createOrderSequenceNo()
Get next sequence number (for custom formatting)
方法描述
createOrder(basket)
使用自动生成的订单号创建订单
createOrder(basket, orderNo)
使用指定订单号创建订单
createOrderNo()
生成下一个订单号
createOrderSequenceNo()
获取下一个序列号(用于自定义订单号格式)

Order Status

订单状态

MethodDescription
placeOrder(order)
Place order (CREATED → NEW)
failOrder(order, reopenBasket)
Fail order (set to FAILED status)
cancelOrder(order)
Cancel order (set to CANCELLED status)
undoCancelOrder(order)
Revert cancelled order to NEW
Note: There is no
undoFailOrder()
method. Failed orders cannot be reopened. Use
failOrder(order, true)
to reopen the basket for retry.
方法描述
placeOrder(order)
提交订单(CREATED → NEW)
failOrder(order, reopenBasket)
标记订单失败(设置为FAILED状态)
cancelOrder(order)
取消订单(设置为CANCELLED状态)
undoCancelOrder(order)
将已取消的订单恢复为NEW状态
注意: 不存在
undoFailOrder()
方法,失败的订单无法重新打开,请使用
failOrder(order, true)
重新打开购物篮供用户重试。

Order Queries

订单查询

MethodDescription
getOrder(orderNo)
Get order by number
searchOrder(query, ...args)
Search for single order
searchOrders(query, sortString, ...args)
Search for multiple orders
queryOrder(query, ...args)
Query single order
queryOrders(query, sortString, ...args)
Query multiple orders
方法描述
getOrder(orderNo)
根据订单号获取订单
searchOrder(query, ...args)
搜索单个订单
searchOrders(query, sortString, ...args)
搜索多个订单
queryOrder(query, ...args)
查询单个订单
queryOrders(query, sortString, ...args)
查询多个订单

Querying Orders

查询订单

Get Order by Number

根据订单号获取订单

javascript
var OrderMgr = require('dw/order/OrderMgr');

var order = OrderMgr.getOrder('00001234');

if (order) {
    var status = order.status.value;
    var total = order.totalGrossPrice;
}
javascript
var OrderMgr = require('dw/order/OrderMgr');

var order = OrderMgr.getOrder('00001234');

if (order) {
    var status = order.status.value;
    var total = order.totalGrossPrice;
}

Search Orders

搜索订单

javascript
var OrderMgr = require('dw/order/OrderMgr');

// Search by customer email
var orders = OrderMgr.searchOrders(
    'customerEmail = {0} AND status != {1}',
    'creationDate desc',
    'customer@example.com',
    dw.order.Order.ORDER_STATUS_FAILED
);

while (orders.hasNext()) {
    var order = orders.next();
    // Process order
}
orders.close();
javascript
var OrderMgr = require('dw/order/OrderMgr');

// 根据客户邮箱搜索
var orders = OrderMgr.searchOrders(
    'customerEmail = {0} AND status != {1}',
    'creationDate desc',
    'customer@example.com',
    dw.order.Order.ORDER_STATUS_FAILED
);

while (orders.hasNext()) {
    var order = orders.next();
    // 处理订单
}
orders.close();

Query by Date Range

根据日期范围查询

javascript
var OrderMgr = require('dw/order/OrderMgr');
var Calendar = require('dw/util/Calendar');

var startDate = new Calendar();
startDate.add(Calendar.DAY_OF_YEAR, -7);

var orders = OrderMgr.searchOrders(
    'creationDate >= {0} AND status = {1}',
    'creationDate desc',
    startDate.time,
    dw.order.Order.ORDER_STATUS_NEW
);

while (orders.hasNext()) {
    var order = orders.next();
    // Process order
}
orders.close();
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Calendar = require('dw/util/Calendar');

var startDate = new Calendar();
startDate.add(Calendar.DAY_OF_YEAR, -7);

var orders = OrderMgr.searchOrders(
    'creationDate >= {0} AND status = {1}',
    'creationDate desc',
    startDate.time,
    dw.order.Order.ORDER_STATUS_NEW
);

while (orders.hasNext()) {
    var order = orders.next();
    // 处理订单
}
orders.close();

Order Status Management

订单状态管理

Cancel Order

取消订单

javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');
var Order = require('dw/order/Order');

function cancelOrder(orderNo) {
    var order = OrderMgr.getOrder(orderNo);

    if (!order) {
        return { error: true, message: 'Order not found' };
    }

    // Can only cancel NEW or OPEN orders
    if (order.status.value !== Order.ORDER_STATUS_NEW &&
        order.status.value !== Order.ORDER_STATUS_OPEN) {
        return { error: true, message: 'Order cannot be cancelled' };
    }

    Transaction.wrap(function() {
        OrderMgr.cancelOrder(order);
    });

    return { error: false };
}
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');
var Order = require('dw/order/Order');

function cancelOrder(orderNo) {
    var order = OrderMgr.getOrder(orderNo);

    if (!order) {
        return { error: true, message: 'Order not found' };
    }

    // 仅可取消NEW或OPEN状态的订单
    if (order.status.value !== Order.ORDER_STATUS_NEW &&
        order.status.value !== Order.ORDER_STATUS_OPEN) {
        return { error: true, message: 'Order cannot be cancelled' };
    }

    Transaction.wrap(function() {
        OrderMgr.cancelOrder(order);
    });

    return { error: false };
}

Fail Order

标记订单失败

javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');

function failOrder(order, reopenBasket) {
    // reopenBasket: true = customer can retry checkout
    //               false = basket is lost

    Transaction.wrap(function() {
        OrderMgr.failOrder(order, reopenBasket);
    });
}
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');

function failOrder(order, reopenBasket) {
    // reopenBasket: true = 客户可重试结账
    //               false = 购物篮不可用

    Transaction.wrap(function() {
        OrderMgr.failOrder(order, reopenBasket);
    });
}

Handling Failed Orders

处理失败订单

Failed orders cannot be reopened. Instead, use
failOrder(order, true)
to reopen the basket:
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');

// When payment fails, fail the order and reopen basket
function handlePaymentFailure(order) {
    Transaction.wrap(function() {
        // reopenBasket=true allows customer to retry checkout
        OrderMgr.failOrder(order, true);
    });

    // Basket is now available again for the customer
    return { error: true, message: 'Payment failed. Please try again.' };
}
失败的订单无法重新打开,请使用
failOrder(order, true)
重新打开购物篮:
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');

// 支付失败时,标记订单失败并重新打开购物篮
function handlePaymentFailure(order) {
    Transaction.wrap(function() {
        // reopenBasket=true允许客户重试结账
        OrderMgr.failOrder(order, true);
    });

    // 购物篮现在已重新对客户开放
    return { error: true, message: 'Payment failed. Please try again.' };
}

SCAPI: Fail with Reopen (B2C 24.3+)

SCAPI:失败并重新打开购物篮(B2C 24.3+)

For SCAPI integrations, use the
failed_with_reopen
status to fail an order while reopening the basket:
http
PATCH /checkout/orders/v1/organizations/{orgId}/orders/{orderNo}?siteId={siteId}
Authorization: Bearer {token}
Content-Type: application/json

{
    "status": "failed_with_reopen"
}
This is equivalent to
OrderMgr.failOrder(order, true)
in Script API.
针对SCAPI集成,可使用
failed_with_reopen
状态标记订单失败,同时重新打开购物篮:
http
PATCH /checkout/orders/v1/organizations/{orgId}/orders/{orderNo}?siteId={siteId}
Authorization: Bearer {token}
Content-Type: application/json

{
    "status": "failed_with_reopen"
}
该操作等效于Script API中的
OrderMgr.failOrder(order, true)

Undo Cancelled Order

恢复已取消的订单

Cancelled orders can be reopened using
undoCancelOrder()
:
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');
var Order = require('dw/order/Order');

function reopenCancelledOrder(orderNo) {
    var order = OrderMgr.getOrder(orderNo);

    if (order.status.value !== Order.ORDER_STATUS_CANCELLED) {
        return { error: true, message: 'Order is not cancelled' };
    }

    Transaction.wrap(function() {
        // Revert to NEW status
        OrderMgr.undoCancelOrder(order);
    });

    return { error: false, order: order };
}
已取消的订单可通过
undoCancelOrder()
方法重新打开:
javascript
var OrderMgr = require('dw/order/OrderMgr');
var Transaction = require('dw/system/Transaction');
var Order = require('dw/order/Order');

function reopenCancelledOrder(orderNo) {
    var order = OrderMgr.getOrder(orderNo);

    if (order.status.value !== Order.ORDER_STATUS_CANCELLED) {
        return { error: true, message: 'Order is not cancelled' };
    }

    Transaction.wrap(function() {
        // 恢复为NEW状态
        OrderMgr.undoCancelOrder(order);
    });

    return { error: false, order: order };
}

Order Properties

订单属性

PropertyDescription
orderNo
Order number
status
Current order status
confirmationStatus
Confirmation status
exportStatus
Export status for OMS
paymentStatus
Payment status
shippingStatus
Shipping status
customerEmail
Customer email
customerName
Customer name
totalGrossPrice
Order total (with tax)
totalNetPrice
Order total (without tax)
totalTax
Total tax amount
creationDate
Order creation date
productLineItems
Line items in order
shipments
Order shipments
paymentInstruments
Payment instruments
属性描述
orderNo
订单号
status
当前订单状态
confirmationStatus
确认状态
exportStatus
OMS导出状态
paymentStatus
支付状态
shippingStatus
配送状态
customerEmail
客户邮箱
customerName
客户姓名
totalGrossPrice
订单总价(含税)
totalNetPrice
订单总价(不含税)
totalTax
总税额
creationDate
订单创建日期
productLineItems
订单商品行
shipments
订单配送信息
paymentInstruments
支付工具信息

Custom Order Numbers

自定义订单号

Use the
dw.order.createOrderNo
hook for custom order number generation:
javascript
// hooks.json
{
    "hooks": [
        {
            "name": "dw.order.createOrderNo",
            "script": "./hooks/orderNo.js"
        }
    ]
}
javascript
// hooks/orderNo.js
var OrderMgr = require('dw/order/OrderMgr');
var Site = require('dw/system/Site');

exports.createOrderNo = function() {
    var seqNo = OrderMgr.createOrderSequenceNo();
    var prefix = Site.current.ID.toUpperCase();
    var year = new Date().getFullYear();

    return prefix + '-' + year + '-' + seqNo;
};
可使用
dw.order.createOrderNo
钩子实现自定义订单号生成逻辑:
javascript
// hooks.json
{
    "hooks": [
        {
            "name": "dw.order.createOrderNo",
            "script": "./hooks/orderNo.js"
        }
    ]
}
javascript
// hooks/orderNo.js
var OrderMgr = require('dw/order/OrderMgr');
var Site = require('dw/system/Site');

exports.createOrderNo = function() {
    var seqNo = OrderMgr.createOrderSequenceNo();
    var prefix = Site.current.ID.toUpperCase();
    var year = new Date().getFullYear();

    return prefix + '-' + year + '-' + seqNo;
};

Best Practices

最佳实践

Do

推荐做法

  • Always wrap order operations in transactions
  • Check order status before transitions
  • Close order iterators when done
  • Use
    failOrder(order, true)
    to let customers retry
  • Implement idempotent order creation (use specific order numbers)
  • Set appropriate export/confirmation status
  • 所有订单操作始终包裹在事务中
  • 状态转换前先检查当前订单状态
  • 订单迭代器使用完毕后记得关闭
  • 使用
    failOrder(order, true)
    允许客户重试
  • 实现幂等的订单创建逻辑(使用指定订单号)
  • 设置合适的导出/确认状态

Don't

禁止做法

  • Place orders before successful payment authorization
  • Cancel orders without refund processing
  • Leave orders in CREATED status indefinitely
  • Forget to handle concurrent order modifications
  • Skip status validation before transitions
  • 支付授权成功前提交订单
  • 未处理退款就取消订单
  • 让订单长期处于CREATED状态
  • 忽略订单并发修改的处理
  • 状态转换前跳过状态校验

Error Handling

错误处理

ScenarioSolution
Basket is emptyValidate basket before
createOrder()
Invalid basketCheck for missing shipping/billing addresses
Payment failedUse
failOrder(order, true)
to reopen basket
Order number existsUse auto-generated numbers or validate uniqueness
Status transition invalidCheck current status before calling status methods
场景解决方案
购物篮为空调用
createOrder()
前先校验购物篮
购物篮信息无效检查是否缺少配送/账单地址
支付失败使用
failOrder(order, true)
重新打开购物篮
订单号已存在使用自动生成的订单号或提前校验唯一性
状态转换无效调用状态修改方法前先检查当前状态

Related Skills

相关技能

  • b2c-hooks - Order hooks (calculate, payment, createOrderNo)
  • b2c-hooks - 订单钩子(计算、支付、createOrderNo)