This is the early access documentation preview for Custom Views. This documentation might not be in sync with our official documentation.
Carts and Orders overview
Overview of the concepts related to carts and orders involved in the checkout process with your Composable Commerce Project.
Carts hold Product Variants that are referred to as Line Items once added to the Cart. A Cart can be ordered and it either belongs to a Customer or an anonymous session. Carts that belong to an anonymous session are referred to as anonymous Carts.
Line Items and Custom Line Items
A Line Item is a snapshot of a Product Variant at the time it is added to a Cart. A Custom Line Item is a generic item not associated to any Product Variant. As such, they can be used for selling services or virtual goods that do not require any tracking of inventory, like additional fees or vouchers.
Line Items
The snapshot of a Product Variant is created from the ProductProjection as follows:
- The current projection is used.
- If the Cart is bound to a Store, the following additional checks and projections are performed:
- For Stores with active Product Selections, the selected Product Variant must be included in at least one of the active Product Selections.
- The selected Product Variant must be available in a Store.
- All LocalizedStrings are filtered according to the locales defined in the Store.
- All Prices are filtered according to the Product distribution Channels defined in the Store. Prices without a Channel are also included.
- All ProductVariantAvailabilities are filtered according to the Inventory supply Channel defined in the Store. Inventory entries without a Channel are also included.
If the Product Variant changes, the relation to the current ProductProjection is kept, but the Line Item is not updated automatically. The Line Item can be updated through the Carts API on demand. With this update, the ProductVariant data is copied to the variant
field of the LineItem.
Carts containing Line Items that reference deleted Product Variants cannot be used to create Orders.
Line Item Price selection
The price of a LineItem is selected from the Product Variant based on several conditions:
selection based on the price mode:
As a first step, the API uses the Product's priceMode value to decide where to look up the prices of a Product Variant. See ProductPriceMode for more details.
selection based on the distribution channel, the currency, the country, and the customer group:
The selection of the price is based on the
distributionChannel
provided on the LineItemDraft or on the Add LineItem update action, and on thecurrency
,country
, and thecustomerGroup
of the Cart. If a price with an exact match cannot be found, wildcards (all countries, all channels, all CustomerGroups) are used.The list below describes the order in which the price is selected. If a price could not be found in one step, the rule in the next step will be applied until a price could be found. The priority order for the selection of the price is customer group > channel > country (customer group has the highest priority and country the lowest).
The price for a specific currency is determined in the following order:- Find a price for the customer group, channel, and country.
- Find a price for the customer group and channel for all countries.
- Find a price for the customer group and country for all channels.
- Find a price for the customer group for all channels and all countries.
- Find a price for the country and channel for all customer groups.
- Find a price for the channel for all customer groups and all countries.
- Find a price for the country for all customer groups and all channels.
- Find a price for all customer groups, all channels, and all countries.
selection based on the price's validity period:
For all of the price selection steps, the prices with a validity period are checked before the prices without any validity period.
If a currently valid price is found, it is used first.tier price selection based on the Line Item quantity:
If the Product Price has some PriceTier, the tier price valid for the Line Item quantity is selected.
If no tier price can be used, the base price is used.
Custom Line Items
A generic Custom Line Item can be added to the Cart just like Line Items, but without Line Item Price selection, meaning you control the price and taxes of the Custom Line Item. Since the money value of a Custom Line Item can be negative, it can be used for discounts applied by vouchers. Furthermore, Custom Line Items can be used to implement a more complex cart logic via Cart Predicates.
A Cart's InventoryMode has no effect on Custom Line Items.
Cart price precision
- Prices with TypedMoney can have cent-precision and high-precision.
- When calculating net and gross prices, prices with decimals are rounded. In case the fraction of
centAmount
is exactly 0.5, the RoundingMode defined bytaxRoundingMode
is applied to the Cart's price. - The tax portions are derived from the net prices in case the tax is not included in the price, meaning the
includedInPrice
field in the TaxRate for the product is set tofalse
. When the tax is included in the price (includedInPrice: true
), then the tax portions are derived from the gross prices. This only applies when thePlatform
TaxMode is used. - When prices are discounted with relative discounts, they are always rounded in favor of the customer with the half-down rounding.
Cart tax rate selection
A Cart cannot calculate taxes for the items in it until the shippingAddress
property is set. The shippingAddress.country
and shippingAddress.state
properties affect the selection criteria. These are compared to the TaxRate
's country
and state
fields. A Tax Rate is only eligible if the country
and state
properties are an exact match. Because the state
field is optional on both TaxRate
and shippingAddress
, this means the following:
- If
shippingAddress.country
andTaxRate.country
are an exact match, and nostate
properties are present, theTaxRate
applies to the Cart. - If
shippingAddress.country
andTaxRate.country
are an exact match, but only one ofshippingAddress.state
orTaxRate.state
is present, the Tax Rate does not apply to the Cart. - If
shippingAddress.country
andTaxRate.country
are an exact match, andshippingAddress.state
andTaxRate.state
are an exact match, the Tax Rate applies to the Cart. - If
shippingAddress.country
andTaxRate.country
are present, andshippingAddress.state
andTaxRate.state
are present, but there is a mismatch of eithercountry
orstate
, the Tax Rate does not apply to the Cart.
If you need to include a state or country sub-unit for shipping purposes, use shippingAddress.region
to avoid Tax Rate conflicts.
Cart tax calculation
Tax mode
By default, the taxed price of a Cart is calculated by Composable Commerce based on the tax rate that applies for the country
(and optionally state
) of the Cart's shippingAddress
. In this default Platform
TaxMode, the TaxRate is taken from the TaxCategory assigned to Products and Shipping Methods.
If you retrieve the tax rates for a location from a third-party service, you can set those yourself in the External
TaxMode. With this mode, you need to tell Composable Commerce whether tax is included in the price you provide on a Line Item, Custom Line Item, or on a Shipping Method.
When includedInPrice: true
, the tax is calculated in a top-down manner, and when includedInPrice: false
, the tax is calculated in a bottom-up manner.
The following example shows the impact of includedInPrice
in the Cart calculation with taxRoundingMode: HalfEven
and taxCalculationMode: LineItemLevel
.
Line Item | Product Variant A | Product Variant B | Shipping |
---|---|---|---|
Line Item: Price | $15 | $25 | $5 |
Quantity | 10 | 5 | --- |
External Tax Rate: includedInPrice | false | true | false |
External Tax Rate: amount | 0.19 | 0.15 | 0.15 |
Taxed Item Price: totalNet | $150 | $108.70 | $5 |
Taxed Item Price: totalGross | $178.5 | $125 | $5.75 |
Calculation formula | 15 x 10 (1 + 0.19) | 25 x 5 / (1 + 0.15) | 5 x (1 + 0.15) |
Tax calculation mode
Due to the principle of rounding on every calculation step, this slight difference in when to apply tax can end up having a considerable effect on the Cart total.
Composable Commerce offers two different tax calculation modes to support the option your use case requires.
The LineItemLevel
TaxCalculationMode enforces tax calculation after multiplying the individual item price by the quantity.
The UnitPriceLevel
mode leads to calculating the taxed price before multiplying by the quantity.
The following example demonstrates the differences in the Cart total depending on the different tax calculation modes. Let's assume:
- A tax of 19% is included in the price for all Line Items.
- The Cart's TaxRoundingMode is
HalfEven
. - The Cart's price precision is two decimals.
Line Item # | Quantity | Unit Price | Line Item Total, Net ( LineItemLevel ) | Line Item Total, Net ( UnitPriceLevel ) | Line Item Total, Gross |
---|---|---|---|---|---|
1 | 1 | $1.00 | $0.84 | $0.84 | $1.00 |
2 | 10 | $1.08 | $9.08 | $9.10 | $10.80 |
3 | 10 | $108.08 | $908.24 | $908.20 | $1080.80 |
4 | 1 | $2.00 | $1.68 | $1.68 | $2.00 |
5 | 50 | $0.01 | $0.42 | $0.50 | $0.50 |
6 | 1 | $4.90 | $4.12 | $4.12 | $4.90 |
Cart Total, Net ( LineItemLevel ) | Cart Total, Net ( UnitPriceLevel ) | Cart Total, Gross | |||
$924.38 | $924.44 | $1100.00 |
As seen from the example, if a Line Item has a quantity of 1, the two modes have no impact on the total net value of a Line Item (see Line Item #1, 4, and 6).
However, if the quantity is more than 1, the two modes calculate the total net value of a Line Item with a difference of several cents (see Line Item #2, 3, and 5).
Depending on the specific Line Item values, the chosen mode can give a greater or lesser net value (see line item #2 compared to #3).
A difference of 6 cents is accumulated in the Cart total. The connection to rounding is especially clear with Line Item #5.
Due to rounding after applying tax to 0.01 and multiplying by quantity 50 upon that, the net value when using UnitPriceLevel
ends up being equal to the gross value.
With LineItemLevel
, where quantity multiplication is performed as a first calculation step, the rounding occurs to a greater value, and the net value ends up being $0.42.
Cart updates
The lifetime of a Cart (controlled by the deleteDaysAfterLastModification
property) can be adjusted according to your requirements.
During this lifetime, a Cart is kept as it was the last time when actions were performed on it. It contains Line Items and Custom Line Items with prices that were valid at the time of the last Cart update and Cart Discounts that were active at that time. Any read method on a Cart alone will not lead to a representation with up-to-date prices and so on, only Cart updates will trigger this.
After all update actions are performed, the Cart:
- removes any Line Items that are invalid (due to deleted Products, Product Variants, or Prices),
- updates any LineItem
price
field if the result of the price selection has changed because of a Product update, - updates the ShippingInfo, in particular, the
price
andshippingMethodState
fields, - updates the discounts, which may affect the LineItem or CustomLineItem
totalPrice
fields and ShippingInfodiscountedPrice
field, - updates the Cart
totalPrice
field, - updates the Tax Rates, in particular, the
taxedPrice
field, - updates the LineItem
productKey
.
To perform the above-mentioned updates without additional update actions, send a request with only the Recalculate update action.
To update the Product data saved in the Line Items, use the Recalculate update action with updateProductData
set to true
.
Frozen Carts
If you want to prevent carts from being modified by changes to prices and discounts that become active or inactive over time, you have the option to freeze the cart. When a cart is frozen, all prices stay as they were at the time that the cart was frozen. Update actions as well as background services modifying prices on the cart are deactivated for frozen carts. Inventory is not reserved for line items in frozen carts. Frozen carts can either be ordered or unfrozen. When unfrozen, a cart continues to accept new updates.
Restrictions of frozen carts:
- Cart Discounts that become active or are created after cart freeze are not applied.
- Cart Discounts and Product Discounts that expire after cart freeze remain applied.
- New Discount Codes can still be added to the cart, but their DiscountCodeState is of
DoesNotMatchCart
. - Regardless of a cart freeze, Cart Discounts that are deleted or that become invalid due to Cart Predicates not matching, are removed from the cart.
- Regardless of a cart freeze, Discount Codes that become invalid due to Cart Predicates not matching, remain present on the cart with the DiscountCodeState of
DoesNotMatchCart
. - Update actions that could change the price of items in the cart are not accepted. Find the list of restricted update actions on the
Frozen
value for CartState. - All other update actions are still supported and applied. The API still performs the validations in the cart ensuring the cart is convertible to an Order, and reports errors if such a validation fails.
Overview of update actions for Cart, Order, and Order Edit
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set Key | ✓ | - | ✓ |
Set Order Number | - | ✓ | ✓ |
Set Purchase Order Number | - | ✓ | ✓ |
Set Customer ID | ✓ | ✓ | ✓ |
Set Customer Email | ✓ | ✓ | ✓ |
Set Customer Group | ✓ | - | ✓ |
Set Anonymous ID | ✓ | - | - |
Set Business Unit | ✓ | - | - |
Add LineItem | ✓ | - | ✓ |
Remove LineItem | ✓ | - | ✓ |
Add CustomLineItem | ✓ | - | ✓ |
Remove CustomLineItem | ✓ | - | ✓ |
Add Shopping List | ✓ | - | ✓ |
Set Cart Total Tax | ✓ | - | - |
Set Order Total Tax | - | - | ✓ |
Change TaxMode | ✓ | - | ✓ |
Change Tax RoundingMode | ✓ | - | ✓ |
Change Tax CalculationMode | ✓ | - | ✓ |
Add DiscountCode | ✓ | - | ✓ |
Remove DiscountCode | ✓ | - | ✓ |
Set DirectDiscounts | ✓ | - | ✓ |
Add Payment | ✓ | ✓ | ✓ |
Remove Payment | ✓ | ✓ | ✓ |
Change PaymentState | - | ✓ | ✓ |
Set Billing Address | ✓ | ✓ | ✓ |
Set Shipping Address | ✓ | ✓ | ✓ |
Add ItemShippingAddress | ✓ | ✓ | ✓ |
Remove ItemShippingAddress | ✓ | ✓ | ✓ |
Update ItemShippingAddress | ✓ | ✓ | ✓ |
Add ShippingMethod | ✓ | - | - |
Add Custom ShippingMethod | ✓ | - | - |
Remove Shipping Method | ✓ | - | - |
Set ShippingMethod | ✓ | - | ✓ |
Set ShippingAddress and ShippingMethod | - | - | ✓ |
Set ShippingAddress and Custom ShippingMethod | - | - | ✓ |
Set Custom ShippingMethod | ✓ | - | ✓ |
Set ShippingRateInput | ✓ | - | ✓ |
Add Delivery | - | ✓ | ✓ |
Remove Delivery | - | ✓ | ✓ |
Change ShipmentState | - | ✓ | ✓ |
Add ReturnInfo | - | ✓ | ✓ |
Set ReturnInfo | - | ✓ | ✓ |
Set ReturnShipmentState | - | ✓ | ✓ |
Set ReturnPaymentState | - | ✓ | ✓ |
Change OrderState | - | ✓ | ✓ |
Transition State | - | ✓ | ✓ |
Update SyncInfo | - | ✓ | ✓ |
Set Locale | ✓ | ✓ | ✓ |
Set Country | ✓ | - | ✓ |
Set Store | - | ✓ | ✓ |
Set Custom Type | ✓ | ✓ | ✓ |
Set CustomField | ✓ | ✓ | ✓ |
Set DeleteDaysAfterLastModification | ✓ | - | - |
Freeze Cart | ✓ | - | - |
Unfreeze Cart | ✓ | - | - |
Recalculate | ✓ | - | - |
on LineItem
Update action | Cart | Order | Order Edit |
---|---|---|---|
Change LineItem Quantity | ✓ | - | ✓ |
Set LineItem TaxRate | ✓ | - | ✓ |
Set LineItem TaxAmount | ✓ | - | ✓ |
Set LineItem Price | ✓ | - | ✓ |
Set LineItem TotalPrice | ✓ | - | ✓ |
Set LineItem DistributionChannel | ✓ | - | ✓ |
Set LineItem ShippingDetails | ✓ | ✓ | ✓ |
Apply DeltaToLineItemShippingDetailTargets | ✓ | - | - |
Set LineItem Custom Type | ✓ | ✓ | ✓ |
Set LineItem CustomField | ✓ | ✓ | ✓ |
Set LineItem InventoryMode | ✓ | - | - |
Set LineItem SupplyChannel | ✓ | - | - |
Transition LineItem State | - | ✓ | ✓ |
Import LineItem State | - | ✓ | ✓ |
on CustomLineItem
Update action | Cart | Order | Order Edit |
---|---|---|---|
Change CustomLineItem Quantity | ✓ | - | ✓ |
Set CustomLineItem TaxRate | ✓ | - | ✓ |
Set CustomLineItem TaxAmount | ✓ | - | ✓ |
Change CustomLineItem Money | ✓ | - | ✓ |
Change CustomLineItem Price Mode | ✓ | - | - |
Set CustomLineItem ShippingDetails | ✓ | ✓ | ✓ |
Apply DeltaToCustomLineItemShippingDetailsTargets | ✓ | - | - |
Set CustomLineItem Custom Type | ✓ | ✓ | ✓ |
Set CustomLineItem CustomField | ✓ | ✓ | ✓ |
Transition CustomLineItem State | - | ✓ | ✓ |
Import CustomLineItem State | - | ✓ | ✓ |
on Billing Address
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set Billing Address Custom Type | ✓ | ✓ | ✓ |
Set Billing Address CustomField | ✓ | ✓ | ✓ |
on Shipping Address
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set Shipping Address Custom Type | ✓ | ✓ | ✓ |
Set Shipping Address CustomField | ✓ | ✓ | ✓ |
on ItemShipping Address
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set ItemShipping Address Custom Type | ✓ | ✓ | ✓ |
Set ItemShipping Address CustomField | ✓ | ✓ | ✓ |
on ShippingMethod
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set ShippingMethod TaxAmount | ✓ | - | ✓ |
Set ShippingMethod TaxRate | ✓ | - | ✓ |
Set Shipping Custom Type | ✓ | - | - |
Set Shipping CustomField | ✓ | - | - |
on Delivery
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set Deliver Address | - | ✓ | ✓ |
Add Parcel to Delivery | - | ✓ | ✓ |
Remove Parcel from Delivery | - | ✓ | ✓ |
Set Delivery Items | - | ✓ | ✓ |
Set Delivery Custom Type | - | ✓ | ✓ |
Set Delivery CustomField | - | ✓ | ✓ |
on Delivery Address
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set Delivery Address Custom Type | - | ✓ | ✓ |
Set Delivery Address CustomField | - | ✓ | ✓ |
on Parcel
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set Parcel Measurements | - | ✓ | ✓ |
Set Parcel Tracking Data | - | ✓ | ✓ |
Set Parcel Items | - | ✓ | ✓ |
Set Parcel Custom Type | - | ✓ | ✓ |
Set Parcel CustomField | - | ✓ | ✓ |
on ReturnItem
Update action | Cart | Order | Order Edit |
---|---|---|---|
Set ReturnItem Custom Type | - | ✓ | ✓ |
Set ReturnItem CustomField | - | ✓ | ✓ |