Broadleaf Microservices
  • v1.0.0-latest-prod

Cart Operation Services Release Notes for 3.0.0-GA

Tip
The 3.x versions are Spring Boot 4.1+ compatible.

Important Updates

Spring Boot Upgrade

  • As of Broadleaf Release Train 3.0.0-GA, all microservices have been upgraded to support Spring Boot 4.1 and Java 25.

Requirements

  • JDK 17 is required for Broadleaf release trains 3.0.0-GA, and beyond.

New Features & Notable Changes

Allow Disabling Anonymous Historical Cart Endpoints

Added configuration properties to allow users to disable the anonymous history endpoints in Cart Ops altogether if not in use. Cart Ops was chosen for this as it will short-circuit the requests at the earliest point to improve performance. This is granular in case some endpoints are in use but not all. Additionally, users may have added their own custom endpoints in Cart Ops that use the same endpoints in Cart, making Cart Ops the most straightforward placement for this configuration.

To disable each:

broadleaf:
  cartoperation:
    endpoint:
      cart-history:
        read-anonymous-customer-cart-enabled: false
        read-cart-by-order-number-for-anonymous-customer-enabled: false
        read-cart-by-order-number-for-anonymous-customer-hydrate-payments-enabled: false

Miscellaneous

  • Added CartProvider#retrieveHistoricalCartByOrderNumber for looking up both registered and anonymous historical carts by Order Number only. Additional ownership checks are handled in CartHistoryService to allow a more streamlined experience.

  • Added property to control whether CartProvider#retrieveHistoricalCartForAnonymousCustomer can retrieve only anonymous user carts or both registered and anonymous historical carts by email address and order number.

    • Previously the method returned both despite the name implying only anonymous carts being returned.

    • Recommended: Restrict it to only retrieve anonymous carts by setting the following property: broadleaf.cartoperation.cartprovider.readHistoricalCartForAnonymousCustomerEndpointVersion=2

  • All cart retrieval logic in CartHistoryEndpoint methods has been moved to methods in CartHistoryService to better consolidate business logic.

    • CartHistoryService centralizes handling of user access checks for retrieved all historical carts.

    • This enhances the capabilities of the endpoints so that Account Carts can be retrieved by either the owner or an Account Admin/Approver to streamline the behavior on the order confirmation page.

  • Avoid threadlocal context issues for access tokens on webclient

  • Do not throw an exception if a second request to transfer the guest cart to the customer is sent, but it has already been transferred

Checkout Payment Expectations API

  • Introduced a new REST API endpoint GET /checkout/{cartId}/payment-expectations returning a consolidated CheckoutPaymentExpectations DTO.

  • The expectations payload contains:

    • paymentRequired: Whether a payment is required immediately to successfully process checkout.

    • savedPaymentMethodRequired: Whether a saved payment method is required for future use (esp. for future subscription billing cycles).

    • paymentMethodOptions: Available payment method options for the cart.

  • Centralized checkout payment rules within CheckoutPaymentMethodService so that the expectations API and the CartPaymentMethodValidationActivity in the checkout workflow share identical logic.

  • Deprecated the GET /checkout/{cartId}/payment-method-options endpoint but preserved its execution paths.

Improved Support for $0 Authorizations during Checkout

  • Added improved support for $0.00 authorizations during checkout validation and processing.

  • This enables customers checking out with zero-dollar carts (such as subscription free trials) to securely tokenize and register new saved payment methods for future billing.

  • Coordinates a $0 Authorize (account verification check) transaction with the payment gateway to safely validate the payment details. On success, the token is stored in the BLC_SAVED_PAYMENT_METHOD table.

New PRICING_CHANGE CartAlert

  • The new CartAlert with PRICING_CHANGE type is added to the cart with updated payment information when the Cart price changes during repricing and the payment is updated.

    • This can be used to retrieve the latest payment version if you need to update it after the cart is repriced. If more information is needed, the DefaultCartOperationService#toPaymentUpdate method can be overridden.

CartAlert Example
{
  "type": "PRICING_CHANGE",
  "additionalAttributes": {
    "UPDATED_PAYMENTS": [
      {
        "paymentId": "ID of the updated payment",
        "amount": {
          "amount" : 3.99,
          "currency" : "USD"
        },
        "version": 2
      }
    ]
  }
}

Improved Inventory API Exception and Communication Error Handling

  • Added support for optionally throwing API exceptions from the inventory provider instead of silently catching them and returning false or empty availability results.

  • Added new configuration properties in ExternalInventoryProperties under the broadleaf.cartoperation.inventoryprovider prefix:

    • throw-is-inventory-available-exceptions: If true, exceptions from isInventoryAvailable methods are thrown rather than caught. Default: false.

    • throw-get-inventory-summaries-exceptions: If true, exceptions from getInventorySummaries and related methods are thrown rather than caught. Default: false.

    • message-keys-for-availability-errors: If true, returns message keys instead of human-readable messages for availability check failures. Default: false.

  • Enhanced checkout workflow error handling:

    • Introduced a new checkout failure type INVENTORY_CHECK_ERROR (mapping to the checkout.failure.inventory.error message key) to differentiate actual out-of-stock items (FAILED_INVENTORY_CHECK) from communication/API errors (e.g., connection errors or timeouts).

    • When communication errors occur, the checkout validation workflow captures the root cause (e.g., CONNECT_ERROR, READ_TIMEOUT, WRITE_TIMEOUT) or the inventory service’s response payload and includes it in the exception’s additionalInfo payload.

  • Refactored CartOperationExceptionAdvisor to handle request-level or empty API response errors (e.g., timeout, connection refused) from external service providers gracefully without exposing internal API details, mapping them to PROVIDER_API_ERROR with custom error payloads.

  • Introduced a new WebClientExceptionHelper utility to resolve root causes of connection issues (ConnectException, Netty read/write timeouts).

  • Added missing localizable error messages under messages.properties for cart quantity failures and communication failures.

WebClientRequestException Support for ProviderApiException

Previously, ProviderApiException only handled WebClientResponseException. Now, it also handles WebClientRequestException. These types of exceptions can be encountered in cases such as connection timeouts, connection refused, etc.

To support this, a potential breaking change was made to com.broadleafcommerce.cartoperation.exception.ProviderApiException#getReceivedException. This now returns the more generic WebClientException. This may cause compilation errors with custom exception handlers. A few helper methods were added to ProviderApiException to retrieve appropriate data depending on if the cause is a request or response exception. Refer to CartOperationExceptionAdvisor#handleProviderApiError for an example on how to handle this change.

Payment Lock Tokens When Removing Invalid Offer Codes

Add CartOperationService#removeOfferAndCampaignCodesFromCart(Cart, List, boolean, Map, ContextInfo), which accepts the payment lock tokens held by the calling flow. The checkout offer validation activity now passes its lock tokens through when it strips invalid offer codes, so the reprice that follows can act on payments the flow already holds locks for instead of failing to acquire them.

Stale Dependent Items and Attribute Choices No Longer Block Checkout or Edits

Previously, a cart item whose only config error was a NO_MATCHING_ALLOWED_VALUE mismatch (for example, an attribute value that was removed from the catalog) would hard-fail checkout validation or a cart edit request.

  • CartItemValidationActivity now identifies these invalid or mismatching dependent items as stale during checkout validation instead of mutating cart collections in place, and removes them (along with their nested dependent items and fulfillment items) via StaleCartItemsService rather than blocking the request.

  • When updating a cart item whose only config errors are unmatched-value mismatches and the request isn’t trying to set that attribute, the item is now removed as stale instead of the update hard-failing, keeping fulfillment/fee/COD cleanup consistent.

  • Fixed an issue where CartSubscriptionUtils#identifySubscriptionRootItems mutated the cart’s item collection while an alias to it was in use, which could throw a ConcurrentModificationException or duplicate items.

Bug Fixes

  • Fixed an issue where dependent item validation was not done for nested dependent items.

  • Fixed offer application for nested dependent cart items and optimized the lookup used to apply them.

  • Fixed properties not binding in CartStalePricingValidationActivityProperties because a @Fluent annotation was preventing correct binding, so broadleaf.cartoperation.checkout.activity.validation.cart-stale-pricing.should-reject-lower-price and …​use-real-time-cart-pricing behaved as if left at their defaults regardless of what was configured.

    • The fluent accessors shouldRejectLowerPrice() and useRealTimeCartPricing() are deprecated for removal. Use isShouldRejectLowerPrice()/setShouldRejectLowerPrice(boolean) and isUseRealTimeCartPricing()/setUseRealTimeCartPricing(boolean) instead.

  • Fixed a NullPointerException raised while pricing a cart when a merchandising product resolved to a price with no recurring price.

Extensibility & Deprecations

  • CartPaymentMethodValidationActivity Removals:

    • The protected method validatePayments(CheckoutProcessDto, ContextInfo) was removed. Its logic was split into validateAddToBillPaymentsIfNeeded and other cart payment vs saved payment method checks.

    • The protected method validatePaymentsForSubscription(CheckoutProcessDto, ContextInfo) was removed. Its logic was refactored and other cart payment vs saved payment method checks.

    • The protected method readCustomerActivePaymentMethods(ContextInfo) was removed. Its logic was migrated to DefaultCheckoutPaymentMethodService#readCustomerActivePaymentMethods as part of the centralized payment method logic in CheckoutPaymentMethodService.

  • Deprecated ULIDGuestTokenGenerator: Replaced by default by SecureRandomGuestTokenGenerator that generates a token with 128 bits of randomness to ensure cryptographic level randomness.

    • This is backwards compatible, only affecting the generation of the string and not lookups.

    • To revert to ULIDGuestTokenGenerator temporarily, set broadleaf.cartoperation.service.checkout.guest-token.generator-type=ULID.

  • Inventory Availability and Extensibility Improvements:

    • DefaultInventoryAvailabilityService has been substantially refactored to modularize inventory check workflows and simplify extension.

    • Added new overrideable helper methods in DefaultInventoryAvailabilityService:

    • verifyInventoryAvailability(CartItem, I, CatalogItemList<I>, List<InventoryAvailabilityRequest>, ContextInfo)

    • handleInventoryAvailabilityException(CartItem, I, CatalogItemList<I>, RuntimeException, ContextInfo)

    • findCartItemsWithSameSku(Cart, CartItem)

    • findSerializedItemsWithSameSku(CartItem, String, Cart)

    • findFulfillmentItemRefAndInventoryLocation(Cart, CartItem, String, ContextInfo)

    • Deprecated the method getInventoryLocationReference(String, Cart) in favor of getInventoryLocationReference(Cart, CartItem, String, ContextInfo).

    • Removed Spring @NonNull annotations from parameter definitions in the InventoryProvider interface to rely on standard JVM nullability checks.

Cart Version Validation & Resolution Refactor

This update introduces a unified, request-driven mechanism for validating Cart versions prior to read or write operations. Version validation is now handled directly during the resolution phase inside CartResolverService using ResolveCartRequest configuration, rather than being manually invoked by endpoints or downstream services.

  • Centralized version validation directly within CartResolverService driven by CartVersionValidationStrategy (READ, UPDATE, NONE) on ResolveCartRequest.

  • Deprecated manual CartVersionValidationService calls within DefaultCartResolverService.

  • Added handleCartBeforeProcessCheckout(CheckoutProcessDto, CheckoutProcessRequest, ContextInfo) to CheckoutCartEndpoint as an explicit extensibility hook prior to checkout processing.

Note

Extensibility Signature Change:

In CheckoutCartEndpoint, the legacy resolveCart(String, CustomerRef, ContextInfo) method has been removed. Additionally, CheckoutCartEndpoint#processCheckout now resolves the cart via a dedicated resolveCartForProcess(String, Integer, CustomerRef, ContextInfo) method (disabling automatic repricing on resolve, as pricing is handled within the checkout workflow itself).

Because resolveCartForProcess is a newly introduced method, any custom client subclasses that previously overrode resolveCart or resolveCartForUpdate to customize checkout resolution will compile successfully, but their overrides will go silently unused. You must migrate custom checkout resolution logic by overriding resolveCartForProcess or implementing custom logic inside the handleCartBeforeProcessCheckout hook.