Broadleaf Microservices
  • v1.0.0-latest-prod

Offer Release Notes for 3.1.0-GA

Important Updates

Spring Boot Upgrade

  • As of Broadleaf Release Train 2.0.0-GA, all microservices have been upgraded to Spring Boot 3.

New Features & Notable Changes

Subscription and Free Trial Discounts

Broadleaf Release Train 2.2.0 introduced new price types for Recurring (or Subscription) and Usage prices. Previously only upfront prices were supported out of box. Likewise, Offers now can discount recurring prices or provide free trial periods.

Domain Changes

  • Offer

    • freeTrial: Whether the offer applies a free trial for the targeted item(s).

    • freeTrialLength: How long the free trial lasts

    • freeTrialLengthUnits: The units for the free trial. Default values include: DAYS, WEEKS, and MONTHS.

    • subscriptionDiscount: Embedded object.

      • discountCurrentOrder: Deprecated as the new price fields make this flag unnecessary.

      • endPeriod: Is now nullable.

    • friendlyOfferType: Deprecated in favor of new offerTemplate that supports better localization of labels.

    • offerTemplate: A computed field to replace friendlyOfferType that indicates the template or pattern followed to create the offer. This primarily drives metadata to show or hide fields applicable to certain combinations of configuration flags.

DTO Changes

The following lists the changes to DTOs related to making requests and receiving responses from the Offer Engine.

  • Added new fields to Adjustment

    • type with the following options:

      • ORDER_DISCOUNT: Standard adjustment type. All out of box adjustments prior to 3.1.0 would have this type.

      • FUTURE_CREDIT: Indicates the discount should be applied to a future order as a credit. Future credits could be applied previously and used a separate isFutureCredit flag, although this feature was and is not fully implemented. This has been rolled into the new type field instead of using a separate flag.

      • RECURRING_DISCOUNT: Indicates the adjustment should be applied to the recurring (or subscription) price instead of the upfront price and should not affect the order subtotal at time of checkout.

      • FREE_TRIAL: Indicates that the subscription item should have its first billing period delayed for a period of time.

    • freeTrialLength: Indicates to the billing engine how long a free trial period is.

    • freeTrialLengthUnits: Indicates to the billing engine what the units are for freeTrialLength. Default options are: DAYS, WEEKS, and MONTHS.

    • beginPeriod: For recurring discounts, indicates when the discount should start being applied.

    • endPeriod: For recurring discounts, indicates when the discount should stop being applied. Null indicates never.

  • Added new fields to LineItem, LineItemDto, and EnhancedLineItem

    • standardRecurringPrice: Indicates the standard recurring price details including

      • price

      • periodFrequency: How often the price should be billed

      • periodType: The type of period. The default options are MONTHLY, QUARTERLY, and ANNUALLY.

      • periodLimit: The number of periods the price should be charged. Only applicable when the originating Price List was not STANDARD.

      • termDurationLength: If there are terms for the price, this is the length.

      • termDurationType: The type of duration. The Default options are DAYS, WEEKS, MONTHS, YEARS.

    • saleRecurringPrice: Indicates the sale recurring price details. Same structure as standardRecurringPrice. Important since not all offers may be applied to a sale price.

  • Added new fields to ItemResponse

    • baseRecurringPricePerItem: The price from which adjustments were calculated. This may be the originating LineItem’s standard or sale recurring price.

    • appliedToSalePrice: Whether the adjustments applied to the item used its sale or standard (non-recurring) price.

    • appliedToSaleRecurringPrice: Whether the adjustments applied to the item used its sale or standard recurring price. This is separate from appliedToSalePrice to allow mixing discounts for items with both recurring and upfront prices.

    • recurringAdjustedTotal: The final total recurring price after adjustments are applied.

    • recurringSavings: The total of all recurring price savings.

    • freeTrialApplied: Whether any of the adjustments applied were free trials.

  • Added new fields to ItemResponseDetail

    • appliedToSalePrice: Whether the adjustments applied to the item used its sale or standard (non-recurring) price.

    • appliedToSaleRecurringPrice: Whether the adjustments applied to the item used its sale or standard recurring price.

    • recurringSavings: The total of all recurring price savings.

    • recurringAdjustedTotal: The final total recurring price after adjustments are applied.

  • Deprecated fields on ItemResponseDetail

    • beginPeriod: No longer valid since more than one subscription discount may be applied. Instead each ItemAdjustment should be consulted by the caller.

    • endPeriod: No longer valid since more than one subscription discount may be applied. Instead each ItemAdjustment should be consulted by the caller.

Upgrade Notes if using Subscription Discounts before 3.1.0

Offers already had fields, hidden by default, that allowed configuring subscription discounts. However, the feature was incomplete and require customization to implement fully—such as setting the #isSubscription flag on OrderLineItemDto. Anyone upgrading who is using the old version of the feature should ensure that subscription OrderLineItemDtos sent to the Offer engine are updated to include the subscription price as part of the new #standardRecurringPrice and #saleRecurringPrice structures as applicable.

Also, expect that ItemResponseDetails will not populate #beginPeriod and #endPeriod since more than one subscription discount may be applied. Instead use the ItemAdjustments on the details, which are per discount.

Offer Templates

A new computed field has been introduced on the Offer domain to help drive the Admin UI to handle the variety of complex Offer configurations called offerTemplate. In the Admin this will be labeled as "Offer Type" and the existing field with that name will be changed to "Offer Target Type" to clarify the intent of each.

See Offer Types for more details.

Cache Invalidation

  • Added a OfferCachePropertiesEnvironmentPostProcessor to support automatically registering message binding properties if the cache invalidation enabled property is set as a JVM property, and has a value of true.

    • See Cache Invalidation in the Offer configuration docs for details on how to configure this feature and for the full list of configurable properties.

  • Additionally, this change removes and updates some of our Beans in the Order Services to better follow configuration patterns and resolve issues that prevented CamelClusterService from working correctly. The previous configuration pattern negatively affected message retries. See the table in the collapsed block below:

    Details
    Class Bean Change

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationDomainMapperManagerSupplier

    Removed as it was a supplier bean

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationNotificationManagerSupplier

    Removed as it was a supplier bean

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationIgnoredRepositoriesSupplier

    Removed as it was a supplier bean

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationNotificationStateRepositoriesSupplier

    Removed as it was a supplier bean

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationNotificationHandler

    Update arguments from ()

                (PromotionCacheInvalidationProducer producer,
                PromotionCacheInvalidationMessagingProperties properties,
                List<IgnoredNotificationStateRepository> ignoredRepositories,
                @Qualifier("promotionCacheInvalidationMessageFactory") MessageFactory<PromotionCacheInvalidationRemoteEvent> promotionCacheInvalidationMessageFactory,
                MessageSerializationHelper helper)

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationRetryClusterService

    Update arguments from ()

                (CamelClusterService camelClusterService,
                PromotionCacheInvalidationMessagingProperties properties,
                @Nullable List<NotificationStateRepository> repositories,
                @Qualifier("promotionCacheInvalidationNotificationHandler") NotificationHandler handler,
                List<IgnoredNotificationStateRepository> ignoredRepositories,
                @Nullable DataRouteReference reference)

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationHelper

    Update arguments from ()

                (PromotionCacheInvalidationMessagingProperties properties,
                ObjectProvider<DomainMapperManager> mapperManager)

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationNotificationStateMapperMember

    Update arguments from ()

                (NotificationStateService notificationStateService,
                @Qualifier("promotionCacheInvalidationNotificationHandler") NotificationHandler handler,
                PromotionCacheInvalidationHelper promotionCacheInvalidationHelper)

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationMessageFactory

    Update arguments from ()

                (PromotionCacheInvalidationHelper promotionCacheInvalidationHelper)

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationNotificationImmediateSender

    Update arguments from ()

                (@Qualifier("promotionCacheInvalidationMessageFactory") MessageFactory<PromotionCacheInvalidationRemoteEvent> promotionCacheInvalidationMessageFactory,
                PromotionCacheInvalidationMessagingProperties properties,
                PromotionCacheInvalidationProducer producer,
                @Qualifier("promotionCacheInvalidationNotificationStateMapperMember") PromotionCacheInvalidationNotificationStateMapperMember domainMapperMember,
                PromotionCacheInvalidationHelper promotionCacheInvalidationHelper,
                ObjectProvider<NotificationManager> notificationManager)

    PromotionCacheInvalidationMessagingConfiguration

    promotionCacheInvalidationEventListener

    Update arguments from ()

                (ObjectMapper objectMapper,
                ApplicationEventPublisher publisher)

External Adjustments API

  • Added first-class support for allowing third-party APIs to add and return external offers onto orders when they are being processed through the Offer Engine.

See the tutorial on adding a new external offer provider for more detailed documentation around this feature.

Additional New Features & Notable Changes

  • Added support for qualifying multiple voucher offers per order if it’s unlimited

  • Added support for cart subtotal threshold based Free Gift offers without any qualifier criteria

  • Allow the selection of BUNDLE typed products for Free Gift offers

    • This is to support a more dynamic setup for Free Gift offers, e.g. a bundle product that consists of 2 itemA and 3 itemB can be used solely for the purpose of being free gifts, while the bundle product itself cannot be individually sold nor searchable

  • Adds the option of an Offer which has an item associated with it. Unlike a Free Gift, this will have a cost but it should be at a reduced price from the original price.

Enhancements

  • Improve performance during the generation of offer codes in order to reduce the amount of processing needed to generate large amounts of codes.

    • This includes updating the ModelMapperMappable implementation of JpaOfferCode to perform mappings directly via a 'preconverter' instead of the previous TypeMap mappings-based approach.

    • The changes here also bypasses a slower merge() call for a faster persist() as the generated codes are always new and would not need any potential updates.

Bug Fixes

  • Several currency mismatch issues were addressed where the currency from the LineItem was not used to initialize computed prices, leading to the system default currency being used instead in some cases.

  • CombinabilityOverrides being incorrectly detected when an Offer was stackable and had no combinability overrides has been addressed.

  • Fixed an issue where subscription BOGO items would not correctly set dates and have the incorrect value for the applyToFuturePeriods flag.

  • Marketing message priority field is now honored(sorted by it) when fetching/showing messages

  • Fixed bug where 2 Free Gift offers can both be applied in the same order

    • Exposed the combinability fields for Free Gift offers and default it to OTHER_TYPES

  • Fixed issues around the usage and messaging for max usages on offers.

  • Fixed an issue where items with a sale price caused a NPE after attempting to grab information not needed for tiered candidate offers.