mcpField
B
b2c-ordering

b2c-ordering

github.com/salesforcecommercecloud开发5794 次安装今天更新
代码仓库

关于 b2c-ordering

面向 Salesforce B2C Commerce 开发者的订单管理技能,涵盖 OrderMgr 创建、查询及状态转换,并说明 SCAPI 支付授权与订单放置流程。

主要功能

  1. 01订单生命周期与状态转换
  2. 02创建及查询订单
  3. 03取消、失败与恢复购物篮
  4. 04SCAPI 支付和订单放置指导

适用场景

  1. 01实现结账后的订单创建
  2. 02处理支付失败并允许重试
  3. 03按状态或日期检索订单

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/salesforcecommercecloud/b2c-developer-tooling --skill b2c-ordering

安装后在 Claude Code 中输入/b2c-ordering确认已加载。

附带文件evals/trigger-evals.json

详细介绍

原文在翻译后有更新,译文可能不是最新。

B2C 订购

OrderMgr API 提供订单创建、状态管理和查询功能。了解订单生命周期对于结账实现和订单处理至关重要。

订单生命周期

订单会经历以下状态:

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) 重新打开购物篮以便重试。

创建订单

标准流程(同步)
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 };
}
SCAPI 流程:创建、通过 Order PI 授权,然后提交

优先使用 Shopper Orders 状态机,而不要从 order.afterPOST 手动提交:

POST /checkout/shopper-orders/v1/organizations/{orgId}/orders
  -> commits order in CREATED

PATCH /checkout/shopper-orders/v1/organizations/{orgId}/orders/{orderNo}/payment-instruments/{piId}
  -> invokes dw.order.payment.authorizeCreditCard or dw.order.payment.authorize
  -> passes successfullyAuthorized to order.payment_instrument.afterPATCH
  -> default afterPATCH places when authorized coverage reaches the order total

NEW     -> success
CREATED -> not fully placed; authorize remaining PIs, fail safely, or reconcile

成功的自定义订单 PI afterPATCH 实现应返回 undefined,这样平台就会执行基于覆盖范围的默认提交行为。非空的 Status 会终止执行并抑制该实现。

发生确定性的支付失败时,请使用 Shopper Orders fail 操作,并设置 reopenBasket=true。 如果网关结果不确定,应保留 CREATED 订单以便对账,而不要冒重复授权的风险。

当结账流程确实需要通过单个服务器端阶段创建订单、授权并执行 Commerce 端的提交或失败转换,或者处理方无法参与订单 PI 授权时,可使用 dw.ocapi.shop.order.afterPOST 作为替代方案。该钩子在订单创建事务中运行:不要添加嵌套的 Transaction.wrap,并且要了解 Status.ERROR 会回滚 Commerce 订单,但不会回滚外部网关副作用。请参阅 b2c-hooks。

OrderMgr API 参考

订单创建
方法描述
createOrder(basket)创建订单并自动生成订单号
createOrder(basket, orderNo)使用指定编号创建订单
createOrderNo()生成下一个订单号
createOrderSequenceNo()获取下一个序列号(用于自定义格式)
订单状态
方法描述
placeOrder(order)提交订单(CREATED → NEW)
failOrder(order, reopenBasket)将订单设为失败(状态设为 FAILED)
cancelOrder(order)取消订单(状态设为 CANCELLED)
undoCancelOrder(order)将已取消的订单恢复为 NEW

注意: 没有 undoFailOrder() 方法。失败的订单无法重新打开。请使用 failOrder(order, true) 重新打开购物篮以便重试。

订单查询
方法描述
getOrder(orderNo)按编号获取订单
searchOrder(query, ...args)搜索单个订单
searchOrders(query, sortString, ...args)搜索多个订单
queryOrder(query, ...args)查询单个订单
queryOrders(query, sortString, ...args)查询多个订单

查询订单

按编号获取订单
var OrderMgr = require('dw/order/OrderMgr');

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

if (order) {
    var status = order.status.value;
    var total = order.totalGrossPrice;
}
搜索订单
var OrderMgr = require('dw/order/OrderMgr');

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

while (orders.hasNext()) {
    var order = orders.next();
    // Process order
}
orders.close();
按日期范围查询
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();

订单状态管理

取消订单
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 };
}
使订单失败
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);
    });
}
处理失败的订单

失败的订单无法重新打开。 请改用 failOrder(order, true) 重新打开购物篮:

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.' };
}
SCAPI:失败订单并重新打开购物篮

对于 SCAPI 集成,在确定支付失败后使用 Shopper Orders 失败操作:

POST /checkout/shopper-orders/v1/organizations/{orgId}/orders/{orderNo}/actions/fail?siteId={siteId}&reopenBasket=true
Authorization: Bearer {token}
Content-Type: application/json

{
    "reasonCode": "payment_auth_failure"
}

当前面向支付的原因代码包括 payment_auth_failure、payment_confirm_failure 和 payment_capture_failure。如果订单已不处于可失败的状态,端点会返回 409。生成特定版本的代码前,请确认当前的 Shopper Orders 架构。

撤销已取消的订单

可以使用 undoCancelOrder() 重新打开已取消的订单:

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 };
}

订单属性

属性描述
orderNo订单编号
status当前订单状态
confirmationStatus确认状态
exportStatusOMS 的导出状态
paymentStatus支付状态
shippingStatus配送状态
customerEmail客户邮箱
customerName客户姓名
totalGrossPrice订单总额(含税)
totalNetPrice订单总额(不含税)
totalTax税额合计
creationDate订单创建日期
productLineItems订单中的商品项
shipments订单配送单
paymentInstruments支付方式

自定义订单编号

使用 dw.order.createOrderNo hook 自定义订单编号生成:

// hooks.json
{
    "hooks": [
        {
            "name": "dw.order.createOrderNo",
            "script": "./hooks/orderNo.js"
        }
    ]
}
// 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;
};

最佳实践

应该
  • 仅当调用方尚未提供事务时,才将 Script API 订单修改操作包装在事务中
  • 在状态转换前检查订单状态
  • 完成后关闭订单迭代器
  • 使用 failOrder(order, true) 以便客户重试
  • 实现幂等的订单创建(使用特定订单编号)
  • 设置适当的导出状态和确认状态
不应该
  • 在支付授权成功前下单
  • 未处理退款就取消订单
  • 让订单无限期处于 CREATED 状态
  • 忘记处理并发订单修改
  • 状态转换前跳过状态验证

错误处理

场景解决方案
购物篮为空在调用 createOrder() 前验证购物篮
购物篮无效检查是否缺少配送地址或账单地址
支付失败使用 failOrder(order, true) 重新打开购物篮
订单编号已存在使用自动生成的编号或验证其唯一性
状态转换无效调用状态方法前检查当前状态

相关技能

  • b2c-hooks - 订单 hooks(calculate、payment、createOrderNo)

评论

支持 Markdown