Skip to main content

b2c-ordering

Manage the order lifecycle in B2C Commerce including order creation, status transitions, failure handling, and checkout completion. Use this skill whenever the user needs to create an order from a basket, transition order status, handle failed or cancelled orders, implement payment authorization in checkout, or understand async order processing — even if they just say "my order is stuck" or "finish the checkout flow".

Informações da origem

Repositório
SalesforceCommerceCloud/b2c-developer-tooling
Última atividade na origem
28 de agosto de 2026 às 14:13
Idioma detectado do SKILL.md
inglês
Estrelas
54
Forks
21

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
2 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
b2c-ordering
description
Manage the order lifecycle in B2C Commerce including order creation, status transitions, failure handling, and checkout completion. Use this skill whenever the user needs to create an order from a basket, transition order status, handle failed or cancelled orders, implement payment authorization in checkout, or understand async order processing — even if they just say "my order is stuck" or "finish the checkout flow".
# B2C Ordering The OrderMgr API provides order creation, status management, and querying. Understanding the order lifecycle is essential for checkout implementation and order processing. ## Order Lifecycle Orders progress through these statuses: ``` Basket → CREATED → NEW → (COMPLETED or CANCELLED or FAILED) ``` | Status | Description | Can 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. ## 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 }; } ``` ### SCAPI Flow: Create, Authorize Through Order PI, Then Place Lead with the Shopper Orders state machine instead of manually placing from `order.afterPOST`: ```text 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 ``` Return `undefined` from a successful custom order-PI `afterPATCH` implementation so the platform's default coverage-based placement behavior runs. A non-null `Status` ends execution and suppresses that implementation. On a deterministic payment failure, use the Shopper Orders fail action with `reopenBasket=true`. On an indeterminate gateway result, retain the `CREATED` order for reconciliation rather than risking a duplicate authorization. Use `dw.ocapi.shop.order.afterPOST` as the alternative when checkout deliberately needs a single server-side phase that creates, authorizes, and performs the Commerce-side place-or-fail transition, or when the processor cannot participate in order-PI authorization. That hook runs inside order creation's transaction: do not add a nested `Transaction.wrap`, and understand that `Status.ERROR` rolls back the Commerce order but not an external gateway side effect. See [b2c-hooks](../b2c-hooks/SKILL.md#alternative-authorize-and-place-in-orderafterpost). ## OrderMgr API Reference ### Order Creation | Method | Description | |--------|-------------| | `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) | ### Order Status | Method | Description | |--------|-------------| | `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. ### Order Queries | Method | Description | |--------|-------------| | `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 | ## 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; } ``` ### 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(); ``` ### 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(); ``` ## 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 }; } ``` ### 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); }); } ``` ### 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.' }; } ``` ### SCAPI: Fail Order and Reopen Basket For SCAPI integrations, use the Shopper Orders fail action after a deterministic payment failure: ```http 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" } ``` The current payment-oriented reason codes are `payment_auth_failure`, `payment_confirm_failure`, and `payment_capture_failure`. The endpoint returns `409` when the order is no longer in a state that can be failed. Confirm the current Shopper Orders schema before generating version-specific code. ### 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 }; } ``` ## Order Properties | Property | Description | |----------|-------------| | `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 | ## 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; }; ``` ## Best Practices ### Do - Wrap Script API order mutations in a transaction only when the caller does not already provide one - 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 ### 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 ## Error Handling | Scenario | Solution | |----------|----------| | Basket is empty | Validate basket before `createOrder()` | | Invalid basket | Check for missing shipping/billing addresses | | Payment failed | Use `failOrder(order, true)` to reopen basket | | Order number exists | Use auto-generated numbers or validate uniqueness | | Status transition invalid | Check current status before calling status methods | ## Related Skills - [b2c-hooks](../b2c-hooks/SKILL.md) - Order hooks (calculate, payment, createOrderNo)
Ver no GitHub