Cart Calculate API
The Cart Calculate API (CCA) enables you to customize cart calculation, including calculations that occur during checkout.
The Cart Calculate API provides more control and flexibility with common integrations used in cart and checkout, including tax, inventory, pricing, promotions, and shipping. The Cart Calculate API contains individual calculators for each integration that can be configured and extended based on your business needs.
With the Cart Calculate API, you have granular control over selective integrations. You can easily turn off entire services that aren't needed. For example, if you only sell digital products, you don’t need a shipping service. In addition, you can control integrations at the step level. For example, you only want to show estimated tax in cart, but callout to your tax integration to display calculated tax in checkout. With full control over your integrations, cart and checkout can be optimized to run only the integrations you need, when you need them, optimizing both your storefront and API performance.
The Cart Calculate API consists of three levels of control:
- Orchestrators -- control which calculators are invoked and when they’re invoked.
- Calculators -- control cart calculations, such as those needed for shipping and tax.
- Services -- control specific calculations but aren’t necessarily limited to use cases involving cart calculation. For example, the Pricing service, which is used in cart calculations, also affects your store's PDP (Product Detail Page) pages.
By default, the Cart Calculate API is enabled for new webstores created in Spring '24 and later releases. See Enable and Disable the Cart Calculate API for a Webstore to toggle the Cart Calculate API on and off. If the Cart Calculate API is off and your store has customizations that trigger cart item changes using SObject, Apex DML, or Delivery Group APIs then you must configure the Apex Price integration. If the Cart Calculate API is off and pricing integration isn’t configured, re-pricing won’t occur during checkout.
With a custom orchestrator, you can control which calculators are invoked and when they’re invoked. If you implement a custom orchestrator, the system invokes your orchestrator whenever cart calculations are needed.
For example, if the buyer adds a product to the cart, the system invokes your custom orchestrator, assuming that your custom orchestrator is both available and registered with the system.
Custom orchestrators extend the CartExtension.CartCalculate
class and are registered for the Commerce_Domain_Cart_Calculate
extension point.
By default, the system invokes calculators in the following order, but your orchestrator can modify this order or even skip one or more calculators:
Order | Calculator | Invoked for Cart | Invoked for Checkout | EPN/Base Class |
---|---|---|---|---|
1 | pricing | Yes | Yes |
|
2 | promotions | Yes | Yes |
|
3 | inventory | Yes | Yes |
|
4 | shipping | No | Yes |
|
5 | postShipping | No | Yes | N/A |
6 | taxes | No | Yes |
|
Although calculators are invoked in this order, the shipping, postShipping, and taxes calculators are only invoked during checkout by default. See Default Calculator Invocation Logic for more information about default behavior. Also see Custom Invocation Logic Example for an example of how to customize the default behavior.
The postShipping calculator selects the least expensive delivery method and adds a shipping charge for the method. You can't modify this behavior with a custom calculator. Your custom orchestrator, however, can skip this calculator if that's appropriate for your use case.
This following code snippet is taken from the CartCalculateSample.cls sample orchestrator.
This sample shows the default system invocation logic for calculators. A boolean variable is defined for each calculator, and the corresponding calculator is invoked only if the boolean variable evaluates to true
.
For example, the runPricing
variable is set to true
only if the buyer adds, deletes, or updates a cart item, or if the buyer starts checkout.
If the runPricing
variable evaluates to true
, the price calculator is invoked. Otherwise, the price calculator is skipped and the orchestrator proceeds to the next calculator.
In your custom orchestrator, you can change the invocation logic as needed for your own use cases.
When implementing your custom orchestrator, it's important to understand how buyer actions impact cart and checkout calculations.
By default, shipping and tax calculators are invoked only during checkout, but you can customize this logic if you want.
The following code snippet shows an example of custom invocation logic. In this example, the shipping, post shipping, and taxes calculators can be invoked before the buyer starts checkout:
In the default invocation logic, the runShipping
variable is only set to true
if the buyer changes a delivery group:
This buyer action (changing a delivery group) is allowed only during checkout in B2B and B2C stores. Therefore, by default, the shipping calculator is invoked only during checkout.
In the custom invocation logic, this variable is also set to true
if the buyer changes an item in the cart or changes a coupon:
Two of these buyer actions -- buyerActions.isCartItemChanged()
and buyerActions.isCouponChanged()
-- can occur before checkout. Therefore, in the custom logic, the shipping calculator is invoked both before and during checkout.
The custom invocation logic makes similar changes to the runPostShipping
and runTaxes
variables, enabling them to be invoked before and during checkout.
This example shows how to modify calculator invocation logic, but the custom logic wouldn't work in production without further customizations. For example, the Connect API resources for carts don’t accept a shipping address as an input. The sample invocation logic, therefore, would only make sense for a “flat rate” shipping scheme, not one based on address. Also, a custom tax calculator would be required, because the default tax calculator logic requires a shipping address.
Before checkout, a buyer can perform various actions that affect calculations for the cart:
- Add an item to the cart: sets
buyerAction.isCartItemChanged()
totrue
, which executes the pricing and promotions calculators by default. - Remove an item from the cart: sets
buyerAction.isCartItemChanged()
totrue
, which executes the pricing and promotions calculators by default. - Change the quantity of an item in the cart: sets
buyerAction.isCartItemChanged()
totrue
, which executes the pricing and promotions calculators by default. - Add a coupon to the cart: sets
buyerAction.isCouponChanged()
totrue
, which executes the promotions calculator by default. - Remove a coupon from the cart: sets
buyerAction.isCouponChanged()
totrue
, which executes the promotions calculator by default.
When the buyer is ready to proceed to checkout, or after the buyer has already started checkout, the buyer can perform other actions that affect calculations for checkout:
- Start checkout: sets
buyerAction.isCheckoutStarted()
totrue
, which executes the pricing, promotions, and inventory calculators by default. - Update shipping address: sets
buyerAction.isDeliveryGroupChanged()
totrue
, which executes the shipping and taxes calculators by default. - Update delivery method: sets
buyerAction.isDeliveryMethodSelected()
totrue
, which executes the taxes calculator by default.
To get information about buyer actions, you can use the BuyerActions and BuyerActionDetails objects.
The BuyerActions
object provides several boolean methods that indicate which buyer actions have occurred since the previous cart calculation:
isCartItemChanged()
-- Returnstrue
if the buyer has created, updated, or deleted a cart item;false
otherwise.
isCheckoutStarted()
-- Returnstrue
if the buyer has started checkout;false
otherwise.isCouponChanged()
-- Returnstrue
if the buyer has created, updated, or deleted a coupon;false
otherwise.isDeliveryGroupChanged()
-- Returnstrue
if the buyer has created, updated, or deleted a delivery group;false
otherwise.isDeliveryMethodSelected()
-- Returnstrue
if the buyer has selected a delivery method;false
otherwise.
You obtain a BuyerActions
object from the CartExtension.CartCalculateOrchestratorRequest
object passed into your custom orchestrator's calculate()
method. The CartExtension.CartCalculateOrchestratorRequest
provides a getBuyerActions()
method, which returns the BuyerActions
object for the cart.
The BuyerActionDetails
object provides additional details about buyer actions. This object isn't typically used in your custom orchestrator class, but it can be useful in one or more of your custom calculator classes.
The BuyerActionDetails
object provides the following methods:
isCheckoutStarted()
-- Returnstrue
if the buyer has started checkout;false
otherwise. This method behaves the same as theBuyerActions.isCheckoutStarted()
method, but is accessible within a custom calculator class.getDeliveryGroupChanges()
-- Returns a list ofCartDeliveryGroupChange
objects with detailed info about the changes.getCartItemChanges()
-- Returns a list ofCartItemChange
objects with detailed info about the changes.getCouponChanges()
-- Returns a list ofCouponChange
objects with detailed info about the changes.
You obtain a BuyerActionDetails
object from the CartExtension.CartCalculateCalculatorRequest
object passed into your custom calculator's calculate()
method. The CartExtension.CartCalculateCalculatorRequest
object provides a getOptionalBuyerActionDetails()
method, which returns a CartExtension.OptionalBuyerActionDetails
object.
The CartExtension.OptionalBuyerActionDetails
object provides a get()
method, which returns a BuyerActionDetails
object.
The BuyerActionDetails.getDeliveryGroupChanges()
method returns a List of CartDeliveryGroupChange
objects.
The CartDeliverGroupChange
object provides one method -- getChangedDeliveryGroup()
-- which returns an OptionalCartDeliveryGroup
object. This object is "optional" because it's possible the delivery group was deleted.
The BuyerActionDetails.getCartItemChanges()
method returns a List of CartItemChange
objects.
See CartItemChange.
The CartItemChange
object provides the following methods:
getChangedItem()
-- returns anOptionalCartItem
object. This object is "optional" because it's possible the cart item was deleted.isAdded()
-- returnstrue
if the cart item was added to the cart; otherwise,false
.isRemoved()
-- returnstrue
if the cart item was removed from the cart; otherwise,false
.isQuantityIncreased()
-- returnstrue
if the quantity was increased for the cart item; otherwise,false
.isQuantityDecreased()
-- returnstrue
if the quantity was decreased for the cart item; otherwise,false
.
The BuyerActionDetails.getCouponChanges()
method returns a List of CouponChange
objects.
See CouponChange.
The CouponChange
object provides the following methods:
getChangedAdjustmentBasis()
-- returns anOptionalCartAdjustmentBasis
object. This object is "optional" because it's possible the coupon was deleted.isAdded()
-- returnstrue
if the coupon was added to the cart; otherwise,false
.isRemoved()
-- returnstrue
if the coupon was removed from the cart; otherwise,false
.
Some calculator default implementations call underlying services:
- pricing -- invokes the pricing service, which is extensible via the
Commerce_Domain_Pricing_Service
base class. - promotions -- invokes the promotions service, which isn’t extensible.
- inventory -- invokes the inventory service, which is extensible via the
Commerce_Domain_Inventory_Service
base class. - shipping -- doesn't invoke a service.
- postShipping -- doesn't invoke a service.
- taxes -- invokes the tax service, which is extensible via the
Commerce_Domain_Tax_Service
base class.
Starting in Spring '24, the Cart Calculate API is enabled for all new webstores.
If you create a webstore in the Spring '24 release (or later) and the store is based on an LWR template, you can immediately use the Cart Calculate API.
If you created a webstore prior to the Spring '24 release and the store is based on an LWR template, you can manually enable the Cart Calculate API for your store.
If your webstore is based on an Aura template, the Cart Calculate API isn't supported. You can manually disable the Cart Calculate API for your store.
The Cart Calculate API isn't compatible with integrations. Your webstore can either use extensions or integrations, but not both. Although extensions are now the preferred way to customize Salesforce Commerce, integrations remain fully supported. If you want your Spring '24 (or later) webstore to use integrations, you must disable the Cart Calculate API.
To disable the Cart Calculate API for a webstore:
- In the Developer Console, click Query Editor.
- Enter the following query and click Execute:
Select Id, Name, OptionsCartCalculateEnabled FROM Webstore
- In the OptionsCartCalculateEnabled column, set the value to
false
for the Webstore.
To enable the Cart Calculate API for a webstore:
- In the Developer Console, click Query Editor.
- Enter the following query and click Execute:
Select Id, Name, OptionsCartCalculateEnabled FROM Webstore
- In the OptionsCartCalculateEnabled column, set the value to
true
for the Webstore.