This section generally speaks to the components that the CartOperationService
invokes when processing an add and update cart item request. For more details on how these operations differ for specific types of products, see the Cart Operations for Specific Product Types section.
The following diagram illustrates the add-to-cart flow at a high level with update being similar:
Description:
Request is sent from the client to create the cart, or add to an existing cart
If creating a new cart, the controller delegates to CartOperationService
to create a new empty cart.
If adding to an existing cart, the CartResolverService is used by the controller to resolve the cart by ID, if it exists.
The CartOperationService
then executes the add item request which
Retrieves product information for all items added to the cart
A product’s ID must always be submitted along with an add-to-cart request, even if the item added is a Variant, ItemChoice, or IncludedProduct, in which cases it is the parent product’s.
Hydrates product information onto the appropriate cart items using CartItemCatalogInformationService
Validates cart item configurations using CartItemConfigurationService
Validates inventory availability for all items
Handles merging or rejecting similar items using CartItemMergingService
Sets any cart attributes included in the add request
Assigns items to FulfillmentGroups
, creating those groups as necessary
By default, there is only 1 per cart
Override DefaultCartOperationService#addUnassignedItemsToFulfillmentGroup to change behavior
Prices the cart
This process is fairly complicated in itself and has been summarized in the diagram in several steps
Price the cart (get merchandise prices)
Apply order and order item offers/discounts
Price fulfillment
Apply fulfillment and fulfillment item offers/discounts
Calculate totals
Subtotal
Fulfillment total
Total before tax
Total after tax
Persists the cart
If no cart was resolved, then this results in a create-cart request
Service responsible for mapping CatalogItem
information onto CartItems
. By default, this maps the details from Broadleaf’s Product
and Variant
domains.
DefaultCartItemCatalogInformationService
is the default implementation of CartItemCatalogInformationService
.
It handles mapping properties directly from products onto cart items.
It also runs any configured CartItemProductMappers to map properties from products and variants that are not required by default.
However, it also relies on BroadleafProductService to handle the following:
Determining which Variant
on the Product
DTO matches a cart item
Determining which IncludedProduct
or ItemChoice
matches a dependent cart item
This is because CartOperationService
will retrieve all of the related CatalogItems
and their full hierarchies before calling CartItemCatalogInformationService
.
Then, it passes in the matching catalog item with its entire hierarchy without further narrowing since catalog item info can be inherited by its subdomains (e.g. Product
information can be inherited by it’s Variants
, IncludedProducts
, and ItemChoice
ProductOptions
).
This creates a complication when CartItems
match specific Variants
since something must now determine which Variant
on the Product
DTO to hydrate information from.
Likewise for dependent CartItems
that match IncludedProducts
or ItemChoices
.
BroadleafProductService provides a centralized location for handling these deeper hierarchical data for Product
.
CartItemProductMappers
provide a configurable way to define which properties of a product or variant are mapped to which properties of a cart item.
This is in addition to the default mappings provided by CartItemCatalogInformationService
for required properties.
PropertyDrivenCartItemProductMapper
is the only default implementation of CartItemProductMapper
.
It reads mappings from CartItemMappingProperties
.
broadleaf:
cartoperation:
mapping:
cartitem:
productMappings:
- attributeName: 'productUri'
valuePath: '$.uri'
- attributeName: 'productDescription'
valuePath: '$.description'
- attributeName: 'categoryIds'
valuePath: '$.parentCategories[*].id'
- attributeName: 'categoryNames'
valuePath: '$.parentCategories[*].name'
variantMappings:
...
Service that handles operations involving the hierarchical data for complex products, e.g., products with variants, included products, or item-choice product options. In particular it handles the following:
Determining which Variant
on the Product
DTO matches a cart item
Determining which IncludedProduct
or ItemChoice
matches a dependent cart item
Service that handles hydration and validation for the hierarchical data of complex products, e.g., products with variants, included products, or item-choice product options. In particular it handles the following:
Hydrating IncludedProduct
or ItemChoice
info onto CartItems
Validating CartItem
and dependent CartItem
configurations, e.g.,
They have all of the require attributes
All attributes have valid values
They have a positive quantity or meet any min or max quantity requirements if applicable
DefaultCartItemConfigurationService
makes use of several other configuration services for particular domains:
IncludedProductConfigurationService
for populating IncludedProduct
info on CartItems
and validating them
ItemChoiceConfigurationService
for populating ItemChoice
ProductOption
info on CartItems
and validating them
AttributeChoiceConfigurationService
for validating AttributeChoice
ProductOption
info on CartItems
Validation error messages are made accessible to API callers and auditors through one of the following properties of CartItem
depending on what produced the errors:
globalConfigErrors
: List of global configuration errors.
attributeConfigErrors
: Map of configuration errors related to the item’s attribute choice values that are derived from AttributeChoice ProductOptions, where the key is the attribute name: COLOR
, SIZE
, etc.
dependentItemConfigErrors
: Map of configuration errors related to the item’s dependent cart items where the key is the item’s identifier, e.g., a ItemChoice#choiceKey.
Each error is an object with an errorCode
and an errorMessage
string.
DefaultCartItemConfigurationService
and its related configuration services make use of a Spring’s MessageSource to provide localized error messages so that these messages can be shown directly to frontend users.
Otherwise, the caller can use the errorCode
.
The message keys and their default values are as follows:
cartItem.configError.genericError=The item you added to the cart was not configured correctly. Please correct the errors and try again.
cartItem.configError.nonPositiveQuantity=Cannot add an item to the cart with a quantity less than 1.
cartItem.configError.nonPositiveDependentItemQuantity=Cannot add an item to the cart with a quantity less than 1.
cartItem.configError.requiredAttributeMissing={0} is required
cartItem.configError.noMatchingAllowedValue={0} does not have a valid value
cartItem.configError.noVariantFound=The selected combination of options is invalid.
cartItem.configError.requiredAttributesMissingOnItem=Some of the required options are missing.
cartItem.configError.dependentItems.quantity.min=Must select at least {0, number}
cartItem.configError.dependentItems.quantity.max=Must select no more than {0, number}
cartItem.configError.mismatchedDependentItemsFoundOnItem=Mismatched items found on Cart Item and have been removed.
cartItem.configError.misconfiguredDependentItems=Some of the items are misconfigured.
Inventory checks involve taking each cart item’s SKU and calculating the total quantity of that SKU in the cart across all items, then sending a request to through InventoryProvider to determine whether there is sufficient inventory available to satisfy that quantity. If insufficient inventory remains, then a message is added to the cart item’s global config errors like with other validation messages and can be displayed to the user, already localized.
Note
|
When checking inventory availability for serialized inventory, make sure to provide the sku reference in the following format: When adding to cart, the serialization value should be declared using a cart item attribute choice named |
DefaultCartItemMergingService
provides for configuring different merging types in cases such as adding the same item to the cart multiple times.
The default types are:
COMBINE
: Items with the same configurations are combined into one line item.
Basically, this means the quantity of an existing item is incremented if the same item is added again.
SEPARATE
: Each add request results in a new line item even if the same item is already in the cart.
REJECT_OR_IGNORE
: The same item cannot be added to the cart more than once.
By default for single item add requests, this merging type will result in an RejectedItemMergeException
if the same item is already in the cart.
The caller can handle as desired.
For bulk add requests, no exception is thrown, the item is simply ignored.
To change the default behavior, override DefaultCartItemMergingService#handleRejectedMerges
This service also makes calls to CatalogProvider to retrieve the merging types of each product since that information is not stored on the cart.
Use broadleaf.cartoperation.service.mergingType
to set the global behavior.
This can be overridden for specific products with Product#mergingType
, which takes the same values.
It could be useful to have the global merging type be COMBINE
because that works for most products in a catalog but to also override it for specific products such as those that are very large or require special fulfillment considerations.