Broadleaf Microservices
  • v1.0.0-latest-prod

Offer Release Notes for 3.1.1

Important Updates

Spring Boot Upgrade

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

  • This version includes all changes up to 2.0.9 Release Notes

New Features & Notable Changes

Updates to the Audit tab of Campaigns

  • The issue has been fixed where audit entries are missing from the list grid. The method for retrieving this data has been updated.

    • AlternateLifecycleSharedCodeAuditSummaryRepository#createOrUpdateAndIncrement(String, String, MonetaryAmount, ContextInfo) is deprecated

    • New column campaignId is added to BLC_SHARED_CODE_AUDIT_SUMMARY table

  • Add new otherMessagesMap and otherItemMessagesMap map fields to the MarketingMessageResponse.

  • Introduced logic in the DefaultMarketingMessageResolver populate the new map fields with any marketing messages that do not match the of the out-of-box LocationTypes.

  • Code generation now ensures uniqueness across all generators within a campaign, not just within individual batches/generators.

Offer Opt-In at the Application Level

This release introduces the ability for applications to opt-into Tenant-level offers. Tenant-level offers now include a new property, optInStatus, which can be set to one of the following options:

  • AUTO_ACCEPTED - The offer is automatically accepted by all applications.

  • REQUIRE_OPT_IN - The offer requires explicit opt-in by the application to be enabled.

  • ALLOW_OPT_OUT - The offer is enabled by default but can be explicitly disabled by the application.

This feature is enabled by default but can be disabled using the broadleaf.offer.metadata.enable-offer-opt-in property. When set to false, applications cannot opt-in or out of tenant-level offers, and all offers will be automatically accepted by default. At the application-level when enabled there will be two grids when browsing offers:

  • Application Only offers

    • This will read only the offers created in that Application’s context.

  • Tenant-level offers that can be opted-into or are opted-into automatically.

    • This will actually read the OfferOptIn domain instances with the original offer hydrated as a field.

Dynamic offers

This is an Order targeting discount whose amount is supplied externally. When used, the offer amount is fetched by the Cart Operation Service (See release notes for details). This information is stored in a DYNAMIC_OFFER_MAP in the Offer#attributes, and then used to apply the offer.

Payment offers

This is an Order-targeting discount that is applied base on the type of payment being used. Out-of-box, users can create offers targeting the types specified in the PaymentTypeEnum:

  • Visa

  • MasterCard

  • American Express

  • Discover

After the payment information is provided, the Cart Operation Service will store the payment type in a PAYMENTS_LIST in the Order#contextMap. (See release notes for details). The list of payments is then used to apply the offer upon cart repricing.

Note
The cart reprice must be triggered by the front-end when appropriate. Visit the Commerce Next.js Starter release notes for our recommendation on how to handle this. The back-end will not automatically handle applying offers of this type as payment information needs to have been supplied for them to be considered.

Content Marketing Messages

We now support the use of Content Items as marketing message content. To support this, we’ve made the following changes:

  • Added metadata to the marketing message form to create and update messages of type CONTENT.

    • Introduce content-related DSL components.

    • Add a searchable LookupField of type ContentItemSelect

      • Specify a modalComponent of type CONTENT_ITEM_BROWSE_MODAL to browse for existing content items in a folder structure.

  • Domain changes to MarketingMessage and MarketingMessageResponse.

  • New logic in DefaultMarketingMessageResolver to build an unhydrated map of content items. This is meant to be hydrated in Catalog Browse Services.

Miscellaneous

  • Method OfferOptInEndpoint#buildOptIn has been moved to OfferOptInService

  • Signature change in DefaultItemOfferProcessor#buildReducedFeeGiftDetail: the 3rd parameter Adjustment has been added. This is an itemAdjustment of the FreeGiftItem, used to determine appropriate currency.

All Domain Changes

  • Offer

    • optInStatus: Specifies the opt-in status of the offer at the application level. Possible values are AUTO_ACCEPTED, REQUIRE_OPT_IN, and ALLOW_OPT_OUT.

    • dynamicOffer: Determines whether the offer is dynamic, meaning that the discount amount is supplied externally.

    • dynamicOfferKey: The key used to supply the dynamic offer amount.

    • paymentOffer: Determines whether the offer applies based on the type of payment being used.

    • paymentType: The payment type for which a payment offer applies.

  • MarketingMessage

    • messageType: Determines the type of message to display. Out-of-box, this can be HTML or CONTENT.

    • contentItemId: The ID of the ContentItem to display. This is required for marketing messages of type CONTENT.

  • MarketingMessageResponse

    • contentItems: The content items used by any marketing messages of type CONTENT, mapped by their id

Data Migration

A new column - campaign_id was added to the blc_shared_code_audit_summary table, and it is now used to query data for the audit tab of the campaign. In order for the audit tab to work with historical data, you will need to populate it with data via a migration. You can use the following example script for postgres to populate the campaign_id column. Adapt the script for your DB. Depending on the amount of the data in the blc_shared_code_audit_summary it might be worth disabling index and enabling it after migration.

blc_shared_code_audit_summary

DO
$$
    DECLARE
        batch_size   INT  := 10000;
        last_id      TEXT := '';
        rows_updated INT;
    BEGIN
        LOOP
            WITH cte AS (
                SELECT s.id
                FROM offer.blc_shared_code_audit_summary s
                WHERE s.id > last_id
                ORDER BY s.id
                LIMIT batch_size
            )
            UPDATE offer.blc_shared_code_audit_summary s
            SET campaign_id = oc.campaign_id
            from offer.blc_offer_code oc, cte
            where oc.id = s.offer_code_id and s.id = cte.id;

            GET DIAGNOSTICS rows_updated = ROW_COUNT;
            EXIT WHEN rows_updated = 0;

            -- Advance last_id for next loop
            SELECT MAX(id)
            INTO last_id
            FROM (SELECT s.id
                  FROM offer.blc_shared_code_audit_summary s
                  WHERE s.id > last_id
                  ORDER BY s.id
                  LIMIT batch_size) as si;

            PERFORM pg_sleep(0.2); -- pause to reduce load
        END LOOP;
    END
$$;