Broadleaf Microservices
  • v1.0.0-latest-prod

Upgrade to 2.1.6

Table of Contents

Security

Important

This release contains several security-related fixes. It is strongly recommended that you review the security-related content for these releases at Broadleaf Security. You will need your login credentials originally provided for accessing the Broadleaf nexus.

Requirements

  • Java 17 is required since 2.0.0-GA.

Notable Changes

  • Added support for Caffeine and Ehcache as alternative caching providers for many microservices. See Caching Configuration for more details.

  • Updated scheduled jobs in Authentication Services to support user-friendly duration formats (e.g., 2d, 12h) and added execution tracking events.

  • This release also includes various bug and security fixes.

Frontend Compatibility and Release Notes

Unified Admin Release Notes for 1.10.13

Features & Enhancements

Support Retail Delivery Fee Refunds
  • Introduced the ability to optionally request the refund of order fees (esp. Retail Delivery Fees) when requesting creating a ReturnAuthorization.

Important Updates

  • Now supports Node 22 and 24. We recommend upgrading to Node 24 as soon as possible since Node 20 reaches end of life in April 2026.

    • Upgrading Node is not required to use this update.

Introduced Badges for Tile and List Grids

Added support for badges in both Tile and List grid views within the Unified Admin interface. This enhancement allows developers to define badges that can be displayed on individual items in these grids, providing additional context or status information at a glance.

Badges are rendered through BadgeColumn and BadgeTileComponent components, which can be configured in the metadata for the respective grid views. This feature enhances the visual representation of data and can be particularly useful for highlighting important attributes or statuses of items in a list or tile format. These badge components are specifically designed to pull from a hydration endpoint based on a field in the entity. The main current use case is to show AdvancedTags associated with a product in product grids.

Introduced a click event handler for links with href attributes matching the pattern modal(modalId). This handler intercepts such clicks and opens a modal dialog with the specified ID, allowing users to interact without leaving the current page. The handler searches both the current metadata and the new global components metadata for the modal definition and opens it if found.

This enhancement’s primary use case is to facilitate the opening of modals from links within a fields' help text, improving user experience by providing context-sensitive information without navigating away from the current view.

Introduced ModalFormView Component

A new ModalFormView component has been added to the Unified Admin interface. This component is designed to render forms within modal dialogs primarily triggered by links in help text or other interactive elements. These modal forms can handle both creation and editing of entities, providing a seamless user experience.

Introduced Divider Form Component

Introduced new Divider form component type to render a horizontal rule between fields. The divider component can be targeted using the .Divider css class. It takes a width attribute, indicating the width of the horizontal rule—default is sm indicating 1px. It also takes a spacing attribute indicating the spacing above and below the rule in rem—default is md indicating 2rem.

Tip
Other values are defined in metadata, see Divider#Width and Divider#Spacing enums.
Introduced CheckboxField Form Component

A new CheckboxField form component type has been added to render a checkbox input. This component is useful for boolean fields, where users want to have a simple checkbox instead of the default toggle switch.

Multi-line Truncation using line-clamp in LargeContentColumn

Multi-line truncation has been made available by including the @tailwindcss/line-clamp dependency in order to access the tw-line-clamp class name. The LargeContentColumn component has been updated to use tw-line-clamp to dictate the number of lines to truncate to for the column display value. The number of lines is expected to be set in the metadata for the colum via the lines attribute, and is set to 1 by default. By default, the available classes are tw-line-clamp-1 to tw-line-clamp-6 (numbers 1 through 6), and tw-line-clamp-none.

Introduced NavMenuFooterMenuItems Sub-Component

An overridable sub-component NavMenuFooterMenuItems has been created for the purpose of containing all menu items and links in the footer of the navigation menu. This sub-component can be overridden by registering a new component in the ComponentRegistrar with the ID blblNavMenuFooterMenuItems. By default, NavMenuFooterMenuItems contains the Developer Settings menu item.

Introduced ModalLinkColumn Component

A new component ModalLinkColumn has been created that renders a column with a link that when clicked, opens a modal containing fields and other components configured through the column metadata. If the ModalLinkColumn metadata has no configured sub-components such fields, groups, or grids, then the link rendered in the column will not open a modal when it is clicked. The modal also displays a Submit button and expects by default that the ModalLinkColumn metadata has a configured SUBMIT endpoint that it will submit the form data to.

This component also supports showing a confirmation message before invoking a "delete" submission action. When a "Delete" action is triggered the first time, this message will be displayed and must be acknowledged before actually invoking the endpoint.

private void example() {
    Externals.grid()
        .addColumn(SHARED_CODE, Columns.modalLink()
            .label("Modal Link Column")
            .addField("field1", Fields.string()
                .label("First Field")
                .order(1000))
            .closeButtonLabel("Close")
            .submitEndpoint(Endpoints.put()
                .uri("/my-endpoint")
                .scope("MY_SCOPE"))
            .submitLabel("Submit")
            .addEndpoint(EndpointTypes.DELETE, Endpoints.delete()
                .uri("/my-endpoint")
                .scope("MY_SCOPE")
                .attribute(ModalFormAction.Attributes.SUBMIT_COLOR,
                        ModalFormAction.SubmitColors.DANGER)
                .attribute(ModalFormAction.Attributes.SUBMIT_LABEL, "Delete")));
}
Introduced FormFieldColumn Grid component
  • Introduced a new FormFieldColumn component that allows for the columns in ActionListGrid to render a form field for inline editing of the row entity.

    • Added a separate form state context to external grids to allow modifying the row’s state inline and submitting updates to a separate endpoint from the main entity.

    • When the user clicks away from a field in the row after making changes, these changes are saved automatically via the update endpoint specified in the grid metadata.

      • Custom column types that seek similar behavior can expect the update submission to be triggered via an onBlur prop passed as a prop

    • Updated the components for the supported field types (BooleanField, DateField, DecimalField, EnumSelectField, IntegerField, LongField, LookupField, MoneyField, PhoneField, and StringField) to support calling the onBlur callback prop when available.

Tip
See the Metadata 2.0.8 release notes for an example of how to configure a grid with this new type of column.

A new click event handler has been added to the admin that listens for anchor tag clicks specifically targeting a href with the pattern href="modal(id)" where id maps to the id of a modal defined in metadata. This allows reusable modals to be defined and triggered from links on multiple pages.

Define a global component ModalView in the metadata
registry.addGlobalComponent("test-modal", Views.modalView()
       .label("Terms and Conditions")
       .addField("testField", Fields.string()
            .label("Test Field")));

...

form.addField("someField", Fields.string()
       .label("some-field.label")
       .hint("some-field.hint-text"));
Add a modal link in a hint text message
some-field.hint-text=Click <a href="modal(test-modal)">here</a> for more info.

The test-modal modal view will be triggered when the link on the hint is clicked.

Support alternative UPDATE endpoint to be configured for EntityView per EntityViewForm

Updated EntityFormView to be able to configure an UPDATE endpoint on the form itself that overrides the parent View’s UPDATE endpoint

Example usage of overriding the UPDATE endpoint per form
UpdateEntityView view = Views.entityViewUpdate()
        .label("Update View")
        .submitUrl("/main-entity", Scopes.SCOPE)
        // ...
        .addForm("separateEntityForm", Views.entityForm()
                .label("Form with External Related Entity")
                .updateUrl("/external-entity", Scopes.EXTERNAL_SCOPE);
Improved support for updating fields within an ExternalFieldGroup

This work was done in support of allowing a fields within an ExternalFieldGroup to be updated using a form’s override, update endpoint where the actual parent entity’s state wasn’t being modified and wouldn’t be returned from the submit endpoint, which was in a different microservice.

  • Added attributes map to Endpoints metadata with relevant helper methods

  • Added Endpoint attribute, responseIsPartialState: Indicates that this endpoint’s response will be a partial state that should be merged with the existing entity state, similar to a PATCH request. This is useful for APIs that do not support PATCH requests directly or that are backing external field groups on a different entity’s form. In those cases, the parent entity state should be merged with the new state returned by the endpoint to maintain the full view state.

  • Fixed Groups not getting their IDs set when using Form#addGroup(String type, Group<?> group)

  • Expanded javadocs on various metadata DSL interfaces

  • Added attribute to ExternalFieldGroup, useParentFormState. Indicates that the state for the fields in this group will be backed by the parent form’s.

  • If false, then a nested form state will be created to hold the field values in isolation from the parent. Note that this currently makes the group effectively read-only.

  • If true, then users should ensure that the field names are prefixed with the Group.getId() since this is used in the admin to ensure that the values do not collide with other fields in the parent form. TransformBody and MappingList can be used to map the form state to the appropriate structure expected by the form or entity submit endpoint (if any) and vice versa.

public void exampleUsage() {
    form.updateEndpoint(Endpoints.post()
            .responseIsPartialState()
            .uri("/dto-endpoint")
            .transformRequest(t -> t.mappings(transformEntityToRequestDto("externalGroupId")))
            .transformResponse(t -> t.mappings(transformEntityFromRequestDto("externalGroupId")))
            .scope("DTO"))
            .addGroup("externalGroupId", getExternalGroup());
}

public static MappingList transformEntityToRequestDto(String groupId) {
    return new MappingList(Arrays.asList(
            Mappings.mapValue("%s.%s".formatted(groupId, "field1"), "field1"),
            Mappings.mapValue("%s.%s".formatted(groupId, "field2"), "field2"),
            Mappings.mapValue("%s.%s".formatted(groupId, "field3"), "field3")));
}

public static MappingList transformEntityFromRequestDto(String groupId) {
    return new MappingList(Arrays.asList(
            Mappings.mapValue("field1", "%s.%s".formatted(groupId, "field1")),
            Mappings.mapValue("field2", "%s.%s".formatted(groupId, "field2")),
            Mappings.mapValue("field3", "%s.%s".formatted(groupId, "field3")));
}
Introduced TenantService to make interactions with Tenant Microservice extensible

This allows the API calls made by the Admin to Tenant Service to be overridden and customized.

  • Refactored code to use new Tenant Service

  • Introduced new TenantServiceContext to allow overrides by passing in custom TenantService object

Example Override:
// 1. Define your custom getApplications function
const customGetApplications = async (
  tenantId: string,
  applicationId: string
) => {
  console.log('Using custom getApplications with customParam!');
  const defaultService = DefaultTenantService;
  const applications = await defaultService.getApplications(
    tenantId,
    applicationId
  );
  // You can modify params or response here, for example:
  // const response = await axios.get(getTenantApplicationsUrl(), {
  //   ...restrictByTenant(tenantId, applicationId),
  //   params: {
  //     active: true,
  //     forward: true,
  //     offset: 0,
  //     size: getTenantApplicationsPageSize(),
  //     customParam: 'my-custom-value' // adding a custom parameter
  //   }
  // });
  return applications;
};

// 2. Create a custom TenantService implementation
const customTenantService: TenantService = {
  ...DefaultTenantService,
  getApplications: customGetApplications
};

// 3. Create a component that uses the TenantService
const MyComponent = () => {
  const tenantService = useTenantService();

  useEffect(() => {
    // Now this will call the custom getApplications function
    tenantService.getApplications('my-tenant-id', 'my-app-id');
  }, [tenantService]);

  return <div>My Component</div>;
};

// 4. Wrap your component with the TenantServiceProvider
const TenantServiceOverride = () => {
  return (
    <TenantServiceProvider service={customTenantService}>
      <MyComponent />
    </TenantServiceProvider>
  );
};

export default TenantServiceOverride;
Removed Bootstrap dependency

The dependency on Bootstrap CSS has been removed from the Unified Admin interface as it is no longer referenced in our styles. If you are relying on Bootstrap for custom code, or this removal results in any styling issues in your implementation, we recommend re-adding it as a dependency and importing it in your custom code to restore the previous styles.

Miscellaneous Improvements
  • Introduced new SimpleComponentTypeRenderer to handle simple components that do not fall into the existing classifiers like Field, Group, External, and View.

  • Allow for top-level menu items (menu items that have a configured URL without child menu items) to be rendered and displayed in the Navigation menu.

    • Additionally, if a parent menu item only has one child menu item visible, the menu items will be flattened so that the child menu item is displayed at the root level and the parent menu item is hidden. This behavior is controlled by the VITE_ENABLE_NAVIGATION_FLATTEN_SINGLE_MENU_ITEM environment variable, which is true by default.

  • Single-value fields were updated to be able to render raw data according to their types. If the field’s metadata has the displayOnly attribute set to true, then the field will be displayed as a plain or raw text representation. There is also a placeholder value to be displayed when there is no value for the field.

    • The following single-value field components can display fields as raw data:

      • BooleanField

      • DateField

      • DecimalField

      • IntegerField

      • LongField

      • MoneyField

      • PhoneField

      • StringField

      • TextAreaField

    • Updated FieldDecorations to not display change highlights for display-only fields

  • Added the ability to "Select All" tiles from the Product Browse Tile Grid similar to how it is supported on the list grid view. Used for bulk operations.

  • Handle pre-selected items in grids by looking for $selected on the row

  • Handle paginated results when using a transformMapper to map data from the response. Previously, it expected the response to be an array. Added support for checking the content if it exists.

  • This has no impact on any grids unless a transformResponse is added to the grids metadata

  • Introduced a MoneyTileComponent for TileGrid to display money fields

  • Introduced a ToggleTileComponent for TileGrid elements to display boolean fields as toggles.

  • Introduced a description prop to CollapsibleGroup components.

  • Introduced a overrideMaxWidth prop to SlideOver components to allow overriding the max width that is calculated by default.

  • Added mobile breakpoints for TileGrid components to allow for better responsiveness on smaller screens

  • Added ModalFormView that handles Update, Create and simple ModalViews

  • Support targeting Auth token claims in field conditionals

    • Auth claims can be targeted by prefixing $authClaims to the name of the claims, e.g., $authClaims.3pidp_client_registration_id

    • Example usage: Make an Admin User’s email read-only if they authenticated with Google.

  • Enhanced display of display-only Rule Builders so that they are more human-readable

    • This allows a FieldArrayBlock to be marked as displayOnly and for that to be inherited by its child field components.

    • This also improves the look of displayOnly RuleBuilderFields.

      Display-Only Rule Builder Example
  • Introduced support for Computed Dates in DateField component.

    • Takes in metadata-provided computedFromDate, computedFromDuration, and computedFromDurationUnit attributes to dynamically compute the value of the read-only date field.

  • Introduced a new DateRangeField component to display dates in a range format, e.g., "Start Date - End Date".

  • Introduced new DurationField and DurationColumn components to display duration values given specific base units, e.g., "2 weeks".

  • Added support for displaying a success toast notification message when a new entity is created. This is driven by the successNotificationOnCreate attribute. Additionally, a custom message can be set via the successNotificationMessage attribute, otherwise it will fall back to a default success message.

  • Updated the ActionListGridSelectAction to display a toast notification to indicate when the sort action is in process, and another to notify that the sort action was applied successfully.

  • Updated components to support displaying metadata-driven icons in action buttons:

    • Updated the ActionListGridAdvancedSearch component to display a button with a filter icon instead of the original "Filters" label. This icon can be modified via the filterIconName metadata attribute.

    • Updated the ActionListGridModalFormButton component to support displaying a button with a custom icon instead of the action definition’s label. This is driven by the iconName metadata attribute, and if it is not set, it will fall back to displaying the label as before.

    • Updated the custom Export and Import views to also display icons in their buttons and allow for customization via the iconName metadata attribute. By default, these views will display an upload icon and download icon, respectively.

  • Updated the BetterSearchInput component to display an explicit search button, instead of relying on the user to press enter after typing in their search query. This also allows for better accessibility.

  • Added a new selectableWhenMutableOnly metadata attribute to the ActionListGrid component. This is helpful to disable row selection and thus prevent the use of actions on entities that are not mutable.

  • Added a new forceCatalogSelector metadata attribute to Entity Forms that forces displaying the Catalog Selector, overriding the default behavior where it is only shown in Create forms.

  • The Rule Builder is now able to render lookups that are dependent upon the values from the parent form. To achieve this, the $parent prop is now being passed to the RuleBuilderQueryBuilder component.

  • The Grid Create Action now supports refetching on action success based on the new readOnSuccess metadata attribute.

  • Introduced components to support the new Interdependent Grid Concept

  • Implemented custom behaviors in the FieldArrayGrid component to support custom messages for Boolean Attribute Choices, defaulting the choice labels to "Yes" and "No".

  • Updated the main navigation to display the Application Logo instead of the Application Portrait and added environment properties to provide better control over this selection:

    • VITE_USE_PORTRAIT_ASSET_IN_MAIN_NAV: reverts to using the Application Portrait in the main navigation when set to true. This property is false by default.

    • VITE_USE_PORTRAIT_ASSET_IN_APPLICATION_SELECTOR: allows using the first letter of the Application Name instead of the portrait asset as the portrait in the application selector when set to false. This property is true by default.

  • Allowed metadata for entity forms to define a isCatalogOverrideFallbackHintField attribute that can be used as a fallback to determine if the current entity is a catalog override in the current context, even if its ContextState data does not indicate that it is an override.

    • The exemplifying use-case here is a Product from parentCatalog which has characteristics defined in childCatalog. If viewing the entity from the childCatalog context, Product.contextState may not have field changes and will not seem like an override, but the new characteristicsOverriddenHint field in CatalogServices will be used as a fallback to ensure the 'undo overrides' button still appears.

  • isProductionCatalogEntity is now exported as a public method out of CatalogUtils to allow its direct invocation in Delete.tsx

Bug Fixes

  • Fixed extra translations being submitted on entity forms where the values were the same as the default, untranslated values.

    • When in translation mode, an extra call will now be made to fetch the entity’s data without the language header in order to maintain in state the untranslated values for comparison when the TranslateModeService builds out the list of translations to submit to the backend APIs.

  • Added support for metadata attribute default_selected_component_id in TargetKeyLookup component.

    • When it is set, that value will be used to find a matching component and use it as a default selection if no component is found, the first component will be used.

  • Fixed typo on showInAdmin for badge columns/tile components (attribute name changed on the metadata)

  • Fixed TimeZoneProvider not making requests with appropriate scope and against the right endpoints.

    • Previously, this would not work for users without ALL_ADMIN_USER permissions.

  • Application selector will be hidden when no applications are available

  • Fixed mistakenly including the sandboxId in external grid requests when the grid isn’t sandboxable

  • Fixed an issue where the list grid rows are not selectable when they are displayed in a modal popup

  • Fixed an issue with validation for fields with multiple conditions

  • Fixed a bug where the 'Undo Overrides' action was being offered to users even when the entity was not specifically overridden in the current catalog context. This enabled the possibility of users making requests to undo overrides inherited from parent catalogs. Going forward, the action will only appear if the current catalog matches the entity’s override catalog.

  • Added handling in the FieldArrayGrid component to prevent modification of attribute choices that are derived from enum characteristics.

  • Fixed a bug where the 'Undo Overrides' action was being offered to users even when the entity was not specifically overridden in the current catalog context. This enabled the possibility of users making requests to undo overrides inherited from parent catalogs. Going forward, the action will only appear if the current catalog matches the entity’s override catalog.

  • Fixed a bug in LookupColumn where it failed to detect that the lookup value should be hydrated and instead displayed the entity id.

  • Added support for handling strings with single quotes in SpEL expressions, which were previously stripped or would result in errors at evaluation.

  • Replaced polling in the useSummaryGrid in favor of a refresh button.

    • This fixes an issue where continuous polling would clear the state and cause selected rows in the change summary grids to become unselected.


Auth JS SDK Release Notes for 1.6.5

Enhancements & Notable Features

  • Verified support for Node 22 and 24

  • Verified support for React 19

Added support for customizing access token cache key
  • Added new protected method to AuthClient, _saveAuthToken to allow easier customization of the token cache key

  • Added new protected method to AuthClient, _debugLog to allow adding debug logging.

    • To enable, pass in enableDebug as an option when instantiating the AuthClient

Example AuthClient Override
class MyAuthClient extends AuthClient {
  newParam?: string;

  constructor(options: { newParam?: string } & AuthClientOptions) {
    super(options);
    this.newParam = options.newParam;
  }

  // setter for newParam
  setNewParam(newParam: string) {
    this.newParam = newParam;
  }

  /**
   * Add new param to authorize request.
   */
  _buildAuthorizeUrl(
    params: { newParam?: string } & AuthorizeParams
  ): string {
    params.newParam = this.newParam;
    const authUrl = `${this.baseURL}/oauth/authorize?${qs.stringify(params, {
      skipNull: true,
      skipEmptyString: true,
    })}`;

    this._debugLog(`Built authorize URL: ${authUrl}`);

    return authUrl;
  }

  /**
   * Builds a token cache key.
   */
  _buildTokenCacheKey(scope?: string): DefaultTokenCacheKey {
    scope = scope || this.scope;
    if (this.useRefreshTokens && scope.indexOf('OFFLINE_ACCESS') === -1) {
      scope = `${scope} OFFLINE_ACCESS`;
    }
    const key = new DefaultTokenCacheKey({
      accountId: this.accountId,
      clientId: this.clientId,
      scope: scope || this.scope,
      additionalArguments: [this.newParam],
    });
    this._debugLog(
      `Building token cache key with newParam: ${key.stringify()}`
    );
    return key;
  }

  /**
   * Saves the auth token to the token cache.
   */
  _saveAuthToken(
    result: RequestAccessTokenResult,
    clientId?: string,
    scope?: string
  ): void {
    const args = {
      accountId: this.accountId,
      accessToken: result.accessToken,
      clientId: clientId || this.clientId,
      scope: scope ?? this.scope,
      session: result.session,
      additionalKeyArguments: [this.newParam],
    };
    this._debugLog(
      `Saving auth token with newParam: ${JSON.stringify(args)}`
    );
    this.tokenCache.save(args);
  }
}

const AuthProviderInner: FC<AuthProviderInnerProps> = props => {
  // ...truncated for example
  const { state } = useContext(MyContext);
  const myParamValue = state?.someValue;
  const initializeClient = useCallback(
    (options: AuthClientOptions) => {
      const client = new MyAuthClient({ ...options });
      setNewParam(client);
      if (myParamValue) {
        client.setNewParam(myParamValue);
      }
      return client;
    },
    [myParamValue]
  );

  return (
    <AuthProvider
      initializeClient={initializeClient}
    >
      <AuthSessionManager>{children}</AuthSessionManager>
    </AuthProvider>
  );
};

Commerce SDK Release Notes for 1.6.6

New Features & Notable Changes

  • Verified support for Node 22 and 24


Commerce Quote Microfrontend Release Notes for 1.0.2

Tip

This release is compatible with Release Trains in the 2.1.x line.

Features & Enhancements

  • Verified Node 22 and 24 support

  • Modified all usages of Customer Access Tokens to pass in limited scopes when fetching the access tokens.


Payment JS SDK Release Notes for 1.3.5

Features & Enhancements

  • Verified Node 22 and 24 support

  • Verified React 19 support

  • Modified all usages of Customer Access Tokens to pass in limited scopes when fetching the access tokens.


Commerce Next.js Starter Release Notes for 1.6.7

Note

Docker URL: repository.broadleafcommerce.com:5001/broadleaf/commerce-nextjs-starter:1.6.7

Features & Enhancements

Bug Fixes

  • Fixed bug where the Clone Cart button in the CSR Ribbon shown when impersonating a customer was being displayed even when the cart was already cloned or otherwise marked as a CSR cart.

Services

Admin Navigation Release Notes for 2.1.5-GA

Important Updates

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.1.6-GA, all microservices have been upgraded to support Spring Boot 3.3 & 3.5.


Admin User Release Notes for 2.1.5-GA

Requirements

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

Bug Fixes

  • Fixed a bug where the Admin UI would allow adding augmentations on the AdminUser Views despite the AdminUser domain not supporting them by default.


Admin Metadata Release Notes for 2.1.6-GA

Important Updates

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.1.6-GA, all microservices have been upgraded to support Spring Boot 3.3 & 3.5.


Asset Release Notes for 2.0.5-GA

Important Updates

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, all microservices have been upgraded to support Spring Boot 3.3 & 3.5.

Features & Notable Changes

  • Added support for Caffeine and Ehcache as Spring Cache options.

    • Deprecated AssetServiceCacheAutoConfiguration (Ignite cache auto-configuration) in favor of these standard Spring Cache implementations.

    • For more details, see the Caching documentation.

  • Updated ImageMagick detector to support a warning message when using deprecated commands.


Audit Services Release Notes 1.0.0-GA

1.0.0-GA

  • Initial release of the service.

Release Train Compatibility

Compatible with all Release Trains after 2.1.4 unless otherwise noted.


Auth Release Notes for 2.1.6-GA

Tip
The 2.x versions are Spring Boot 3 compatible.

Requirements

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

  • Spring Authorization Server 1.5.6+ is required for this version of AuthenticationServices, and beyond

New Features & Notable Changes

Spring Authorization Server Upgrade

AuthenticationServices is built upon and customizes various functionality from Spring Authorization Server.

In typical release cycles, the underlying version of Spring Authorization Server is upgraded via the standard Broadleaf base dependencies upgrades, and does not necessarily result in any changes to AuthenticationServices itself.

In this release, however, a multitude of classes in AuthenticationServices have been updated to reach full parity with the recently released Spring Authorization Server 1.5.6 version.

The overwhelming majority of changes around this are just simple internal refactorings to align with similar changes in Spring Authorization Server itself. From a functional perspective, there should be no significant differences in the behavior of the application.

With that being said, there are a handful of new features in Spring Authorization Server (SAS) such as OAuth2 Demonstrating Proof of Possession (DPoP) and Pushed Authorization Requests (PAR). While Broadleaf does not explicitly leverage or customize these flows, at the very least, the changes in this release give the relevant Broadleaf components the foundation for future support.

Below is a list of key affected classes. In all of them, there have been changes made to respond to SAS’s refactoring and eliminate redundant code.

  • OIDAwareOAuth2RefreshTokenAuthenticationProvider

    • DPoP support

  • PublicRefreshOAuth2AuthorizationCodeAuthenticationProvider

    • Updated comments/Javadocs to explain the customizations in context of the new SAS

    • DPoP support

  • ScopeNarrowingOAuth2AuthorizationCodeRequestAuthenticationProvider

    • PAR support

    • Native OIDC prompt support

  • ScopeNarrowingOAuth2ClientCredentialsAuthenticationProvider

    • DPoP support

    • The base SAS class introduced a new authenticationValidator concept to validate scopes, but our customizations require a different approach, so this is disabled by default.

  • PublicRefreshPublicClientAuthenticationProvider

    • Aligns with stricter PKCE enforcement around codeVerifier from newer SAS versions

  • PublicRefreshCodeVerifierAuthenticator

    • Aligns with stricter PKCE enforcement around codeVerifier from newer SAS versions

    • Aligns with fail-fast behavior from SAS when code was missing in an authorization_code flow

  • AdvancedOAuth2RefreshTokenConfigurerUtils

    • SAS introduced some new 'default' token customizers relate to DPoP and Token Exchange delegation, which are now successfully registered in addition to the standard token customizers from Broadleaf.

  • DefaultClientScopeAuthorizationCodeRequestConverter

    • PAR support

  • DefaultOAuth2AuthorizationCodeRequestAuthenticationValidator

    • Updated with new methods matching changes in SAS for use in other components

  • EmbeddedLoginCodeAuthenticationProvider

    • Updated to maintain full parity with updates in PublicRefreshOAuth2AuthorizationCodeAuthenticationProvider and the latest SAS

Miscellaneous
  • Property broadleaf.auth.token.support-refresh-token-rotation was removed and whether refresh token support is enabled is now solely based on AuthorizedClient/RegisteredClient grant types(REFRESH_TOKEN)

    • For example: registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN)

  • Property broadleaf.auth.token.support-refresh-token-cleanup removed.

  • Introduced the new property broadleaf.auth.token.enable-oauth2-authorization-cleanup. This property would default to true. This property controls whether a clean-up job to prune obsolete OAuth2Authorizations (runs periodically) is enabled. This property supersedes the now-removed broadleaf.auth.token.support-refresh-token-cleanup property.

  • Added an event listener that will prune the blc_password_token table as it can grow large over time.

  • Added official support for Caffeine and Ehcache as alternative caching providers for many microservices.

    • This includes new auto-configuration and properties for managing heap and off-heap budgets, as well as weights and estimated sizes for various service components.

    • For more details on configuring these providers, see the Caching Configuration documentation.

  • Updated scheduled jobs to support more user-friendly duration formats (e.g., 2d, 12h) in addition to ISO-8601.

    • Additionally, these jobs now emit started and completed events to provide better visibility into their execution status.

  • Introduced lots of new diagnostic trace logs in OAuth2 flows to make it easier to identify the root cause that failed a request. You can now enable TRACE logs in any of the following classes, and more detailed information will appear as the request moves through the flow.

    Note
    This is primarily intended only for use in lower environments, and in scenarios where testing a new integration may temporarily require extra diagnostic output. It’s not recommended to enable these logs in production, as they will be very noisy.
    Note
    The API responses returned to the external caller have not changed - the messages there still remain vague to prevent leaking information to potential attackers.
    • com.broadleafcommerce.auth.authorization.security.embedded.code.EmbeddedLoginCodeAuthenticationConverter

    • com.broadleafcommerce.auth.authorization.security.embedded.code.EmbeddedLoginCodeAuthenticationProvider

    • com.broadleafcommerce.auth.authorization.security.spring.OIDAwareOAuth2RefreshTokenAuthenticationProvider

    • com.broadleafcommerce.auth.authorization.security.spring.PublicRefreshCodeVerifierAuthenticator

    • com.broadleafcommerce.auth.authorization.security.spring.PublicRefreshOAuth2AuthorizationCodeAuthenticationProvider

    • com.broadleafcommerce.auth.authorization.security.spring.PublicRefreshPublicClientAuthenticationProvider

    • com.broadleafcommerce.auth.authorization.security.spring.ScopeNarrowingOAuth2AuthorizationCodeRequestAuthenticationProvider

    • com.broadleafcommerce.auth.authorization.security.spring.ScopeNarrowingOAuth2ClientCredentialsAuthenticationProvider

Bug Fixes

  • AuthServiceUserWebAutoConfiguration.addResourceHandlers was previously misconfigured with invalid resource paths, which caused failures starting in Spring Boot 3.5 due to stricter Spring validations. The resource configuration has been reworked with corrected syntax and more granular mappings. From an external perspective, nothing has changed, and resources can still be accessed at the same paths as before (so templates will be unaffected).

  • Fixed a compilation issue related to the Thymeleaf upgrade.

  • Fixed a channel name typo in PurgePasswordTokenJobListener.

  • Fixed an error when the AccountMemberRoleChangeRequest#userId or AccountMemberRestrictionUpdateEvent#userId is null.


Bulk Operations Release Notes for 1.0.3-GA

Important Updates

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, all microservices have been upgraded to support Spring Boot 3.3 & 3.5.

Notable Enhancements

  • Added DataRouteByKey annotation to BulkOperationsEndpoint


Cart Services Release Notes for 2.1.5-GA

Tip
The 2.x versions are Spring Boot 3 compatible.

Requirements

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

Bug Fixes

  • Fix issue where CartCrudEntityHelper was not sending out mutation events since it wasn’t configured properly as a spring bean in order to accept the autowire dependency for event publisher


Catalog Services Release Notes for 2.1.6-GA

Tip
The 2.x versions are Spring Boot 3 compatible.

Requirements

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

  • This version now requires DataTracking 2.0.7+

Bug Fixes

  • Fix a bug where products would go missing from search results if a product inherited from a tenant context had a related entity (ex: product tag) defined in an application context

    • DefaultConsolidatedProductPostProcessor was failing to calculate the right creatingApplicationId for synthetically generated ConsolidatedProduct instances during the indexing flow. The new implementation leverages the new ContextState.creatingApplicationId field made available in DataTracking 2.0.7 to accurately populate this value. All the consolidation contributors have also been updated to populate the new creatingApplicationId and overrideCatalogLevel fields on ContextState to ensure consistency.

  • Fixed an issue where immutable products from a child catalog are not disabled when reordering category products.

  • Added validation to ensure that active OptionTemplate entities that are directly referenced cannot be deleted.


Catalog Browse Release Notes for 2.0.8-GA

Tip
The 2.x versions are Spring Boot 3 compatible.

Requirements

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

New Features & Notable Changes

Add Ehcache and Caffeine cache support
  • Added support for Ehcache and Caffeine caches for dynamic customer segments.

  • For more information on configuring these caches, see the Caching Configuration guide.


Content Release Notes for 2.0.9-GA

Important Updates

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, all microservices have been upgraded to support Spring Boot 3.3 & 3.5.

New Features & Notable Changes

  • Added support for Caffeine and Ehcache caching implementations, including new auto-configurations and properties for fine-grained cache management.

  • Updated Content Item minification to properly handle nested content and clear unnecessary context state from model fields.

  • Updated the admin metadata to hide the translatable flag for Asset-typed Content Model Fields

Bug Fixes

  • Improved hydration validation to correctly account for custom fields that support multiple values.

  • Added defensive checks to prevent a potential NullPointerException when Content Field attributes are null during hydration.

  • Fixed a bug where the Admin UI would allow adding augmentations on the ContentItem Views despite the ContentItem domain not supporting them by default

  • Fixed a bug where the image field on a Content Item will show as changed any time any field on the Content Item is changed — updated the logic to consistently map the ContentField data for the image field so that the comparison logic can properly determine if the image field has actually changed or not

  • Added validation to prevent missing value for the custom CONTENT_FIELD, which will cause errors


Fulfillment Services Release Notes for 2.0.6-GA

Enhancements

  • Make name field on Fulfillment Destination and Fulfillment Origin required

Note

If the name fields are left blank, then it does not show up on the Admin listgrid, and cannot be selected in the fulfillment calculator configuration.

To help avoid this scenario, we’ve included a Liquibase script that will automatically populate these values with "UNNAMED_DESTINATION" or "UNNAMED_ORIGIN", if they’re currently blank. We recommend that you rename these fulfillment destinations & origins to give them a more meaningful name.


Inventory Release Notes for 2.0.6

Features & Notable Enhancements

Reintroduce Index on blc_sku_inventory.sku_code

The introduction of Serialized Inventory in Inventory Service 1.7.13-GA saw the removal of several indices including one on sku_code (id IDXk4k1x05sf4w59lia0c819pv20). Analysis since shows that the latter is an essential index to maintain for anyone not using Serialized Inventory. Therefore, we have reintroduced it by default, and it will be present for all new projects on the 2.1.x and subsequent release trains.

We advise all users to verify that this index is in place. If missing, we recommend adding it as it avoids table scans of the blc_sku_inventory table in typical usage.

CREATE INDEX IDXK4K1X05SF4W59LIA0C819PV20 ON BLC_SKU_INVENTORY (SKU_CODE);

…​ :leveloffset: 2

Menu Release Notes for 2.0.5-GA

Important Updates

Spring Boot Upgrade

  • As of Broadleaf Release Train 2.3.0-GA, all microservices have been upgraded to support Spring Boot 3.3 & 3.5.

Features & Notable Changes

  • Added support for Caffeine and Ehcache as Spring Cache options.

    • Standard Spring Cache implementations are now available alongside Apache Ignite.

    • For more details, see the Caching documentation.


Notification Release Notes for 2.1.3-GA

Tip
The 2.x versions are Spring Boot 3 compatible.

New Features & Notable Changes

  • Added support for Retail Delivery Fees

    • Included fee totals in order total breakdown of customer emails

Bug Fixes

  • Updated the FulfillmentStatusChange listeners to read Order and OrderFulfillment by ids, to accommodate the new message payload that only contains IDs to avoid RecordTooLargeException for large fulfillments

    • The listeners will still check for the full Order and OrderFulfillment payload in the message for the sake of backward compatibility, but the logic is subject to removal in a future release

Configuration Properties

Added Properties
  • broadleaf.notification.orderprovider.url

  • broadleaf.notification.orderprovider.order-uri

    • Description: The URI path for basic singular order retrieval

    • Default value: /orders

  • broadleaf.notification.orderprovider.fulfillment-uri

    • Description: The URI path for basic singular fulfillment retrieval

    • Default value: /order-fulfillments

  • broadleaf.notification.orderprovider.service-client

    • Description: The service client to use when calling order services

    • Default value: notificationclient


Offer Release Notes for 3.0.7

Important Updates

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.0.4-GA, all microservices have been upgraded to Spring Boot 3.3.

Bug Fixes

  • Fixed an issue where the discount is incorrect when maxSavingsPerOrder is set and two offers are stacked and applied to the same item

    • Previously, the discount for the offer that is applied second was calculated based on the item’s original price, rather than the price after applying the first discount, causing the final total discounts to be incorrect

  • Fixed a bug where the Admin UI would allow adding augmentations on the Campaign Views despite the Campaign domain not supporting them by default


Order Operation Release Notes for 2.0.6-GA

Miscellaneous

  • Updated existing and introduced new kafka bindings:

    • Added orderOperationsTaxHandlingOnOrderCreatedInput and orderOperationsVoucherCreationOnOrderCreatedInput for orderCreated topic

    • Added orderOperationsFulfillmentRefundTaxOnReturnConfirmedInput for returnConfirmed topic

    • Fixed FulfillmentRefundTaxHandler to subscribe to correct binding ReturnConfirmedFulfillmentRefundTaxConsumer.CHANNEL

    • Fixed VoucherCodeGenerationOrderCreatedListener to subscribe to OrderCreatedVoucherGenerationConsumer.CHANNEL

  • Fixed a bug where calculation of refund amounts didn’t include the parent order item’s quantity for Add-On Order Items, resulting in Add-On Order Items to only refund one quantity


Payment Transaction Release Notes for 2.0.9-GA

Requirements

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, all microservices have been upgraded to support Spring Boot 3.3 & 3.5.

New Features & Notable Changes

Subscription & Billing Support
  • Enhanced SavedPaymentMethod features to support Billing lifecycle

    • Added API functionality to read and execute payments for a SavedPaymentMethod to integrate with BillingServices.

      • Introduce endpoint for gathering SavedPaymentMethods for a set of owningUserIds.

      • Introduce endpoints to execute payment transactions based on a SavedPaymentMethod.

      • Introduce endpoints for looking up and recording SavedPaymentMethod transaction results by requestId.

    • Added SavedPaymentMethodTransactionExecutionRequest to handle transactions made against a SavedPaymentMethod.

    • Added validation ensuring that the request user matches the saved payment method

    • Updated logic creating a Payment based on a SavedPaymentMethod to declare the type & gatewayType from the SavedPaymentMethod.

    • Added logic to archive SavedPaymentMethods if a hard decline is encountered while using the payment method.

  • Added hook point in DefaultTransactionExecutionUtil to populate TransactionExecutionDetail#getAdditionalResponseAttributes.

  • Updated the Payment domain.

    • Added simple field, shouldArchivePaymentDueToFailedInitialTransaction, to optionally declare whether the payment should be archived when the initial Auth or AuthAndCapture transaction fails.

    • Added simple field, requestId, to track the request that created the payment.

      • Added Liquibase scripts to populate this field by default in the database.

  • Enhanced gateway error handling.

    • Added new transaction status, REQUEST_NOT_RECEIVED_BY_GATEWAY, to track transactions that failed before gateway connection.

    • Interpret InvalidCreatePaymentRequestException as InvalidTransactionExecutionRequestException for SavedPaymentMethodTransactionExecutionEndpoint interactions.

  • Added isShouldSavePaymentForFutureUse field to the payment summary.

  • Added new Payment Owner type, PAYMENT_ACCOUNT_PROCESSING_REQUEST, to represent a Billing event.

  • Added Payment#getAttributes to the PaymentRequest#getAdditionalFields during request creation.

Other Features
  • Fixed bug that allowed customers to create payments for submitted orders.

    • Added validation to prevent creating new Payments through the CustomerPaymentManagementEndpoint when an existing Payment for the same cart has a CUSTOMER_MUTABILITY_BLOCKED status.

  • Updated DefaultTransactionExecutionService#getTransactionReferenceId to invoke the new PaymentGatewayTransactionService#identifyTransactionReferenceIdOverrideForSubsequentTransactions method from PaymentGatewayCommon. This ensures transaction reference ID can be overridden for non-initial transactions.

  • Updated DefaultPaymentManagementService to populate PaymentInfo.addressByType from the equivalent field in Payment

  • Updated DefaultPaymentManagementService to invoke the new PaymentGatewayPaymentModificationService#modifyFullPaymentForCreate method from PaymentGatewayCommon. This allows gateway-specific overrides of all PaymentInfo fields, instead of being limited to PaymentGatewayPaymentModificationService#modifyPaymentMethodProperties like before.

  • Updated DefaultPaymentRequestService.createPaymentRequest to include a breakdown of order subtotal, adjustments total, shipping total, and tax total on the PaymentRequest, conditional on whether the new broadleaf.paymenttransaction.service.discriminated.include-transaction-amount-breakdown property is enabled.

  • In order to support OMS consolidated refunds, the PaymentTransaction domain, as well as TransactionExecutionRequest and similar DTOs have been modified to support multiple source entity IDs.

  • Added new PaymentCheckoutCompletionListener that will listen for checkout completion events, and sends out its own paymentPostCheckout events that can be listened to.

  • Added payment gateway reference to the payment attributes map.

  • Added new endpoints to support handling of payment gateway fulfillment callback responses.

  • Added property discriminated per payment gateway to determine whether or not to include the breakdown of transaction amounts.

  • Added isShouldSavePaymentForFutureUse field to the PaymentSummary


Pricing Release Notes for 2.0.7-GA

Tip
The 2.x versions are Spring Boot 3 compatible.

Bug Fixes

  • Fixed a bug where the Admin UI would allow adding augmentations on the PriceList Views despite the PriceList domain not supporting them by default.


Sandbox Release Notes for 2.1.5-GA

Requirements

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

New Features & Notable Changes

  • Track approver and deployer through sandbox transition lifecycle

Schema Changes
  • Added new column to the blc_change_summary table

    • APPROVER

Bugs Fixed

  • Added prevention for "Author cannot be null!" errors for the existing change summary events


Scheduled Job Release Notes for 2.1.5-GA

New Features & Notable Changes

Scheduled Job Execution Details cleanup
  • The cleanup functionality was added to keep only a configured number of execution details

    • You can configure it on a per-job basis - configuration property Execution Details to Keep was added in the admin view

      • It accepts values from 1 to 20 and indicates the last X number of execution details records to keep deleting the rest. The "last" is identified by the triggerTime column. The cleanup is happening when the job is executed and track execution details is enabled.

      • This requires the DB schema update to add a new column, check Upgrade Guide

Upgrade Guide

Note
If using liquibase to pull in base Broadleaf changelogs, then it is not necessary to manually run this script.
Add new column to the BLC_SCHEDULED_JOB table
ALTER TABLE blc_scheduled_job
ADD COLUMN number_of_exec_details_to_keep INT4;

UPDATE blc_scheduled_job
SET number_of_exec_details_to_keep = 10
WHERE number_of_exec_details_to_keep IS NULL;

ALTER TABLE blc_scheduled_job
ALTER COLUMN number_of_exec_details_to_keep SET DEFAULT 10;

Search Services Release Notes for 2.1.6-GA

Requirements

Important
After upgrading to this version, a full reindex is required for the changes to take effect.

New Features & Notable Changes

  • When a reindex triggered with "Index Filters" selected, you can see what filters were selected

Miscellaneous
  • Fixed an issue where the sort order of a Facet within a Facet Group was not honored by the search engine.

    • Any Facets that are sorted within a Facet Grouping will be returned by their specified sort order. Any Facets that are marked unsorted will default to the Facet’s global display order, if set.

  • Fixed issue where only one of the translations get indexed if there are multiple translations with the same entity field name, even if the translations are for separate entities

    • For example, consider a Product in a Category. If both the Product and Category have a "name" field that is translated, only one of those fields would be indexed. Now both will be indexed.

  • Increased specificity for the Product IndexableTypeDocumentBuilder

    • This fixes an issue that can arise when using @ConditionalOnMissingBean and its interpretation of interfaces, particularly when a class implements multiple interfaces. For example, a bean was not getting registered after introducing an IndexableTypeDocumentBuilder for a different indexable type altogether. Using the more specific concrete class as the return type of the bean method prevents ambiguity.

  • Update reindex logic so that reindex for the same indexable type can’t be running in parallel on the same node, potentially causing the index operation context to be polluted.

  • Fixed an issue where search entities didn’t delete their reference entities

    • For example, with this fix when a Facet is deleted, the FacetGroupFacet references will also be deleted removing the Facet from any FacetGroups it was assigned to.

    • This was implemented for Facets, SortOptions, RelevancyRules, FacetGroups, SortGroups, and RelevancyRuleGroups

  • Expose a new deleteByQuery method in ReindexProvider and update SolrReindexService.deleteAll() to use it for more efficient bulk write requests, improving performance of single and batch index flows.

  • Fixed SpringCloudStream binding misconfiguration that caused Kafka consumer lag even after multiple iterations of successful processing

    • Update SpringCloudStream bindings for singleIndexRequestInputProduct, batchIndexRequestInputProduct, and fullIndexMessageInputProduct indexing to each use their own groups

Upgrade Guide

Liquibase Change Sets

The database schema has changed as part of this version.

Creates and Updates

Create/update changes (new tables, new columns, etc) are automatically included in the updated *changelog-master.xml after you upgrade to the new Authentication Services JAR. The new changesets inside will run automatically to migrate existing data.

Database Platform Create/Update Changelog File Name

PostgreSQL

db/changelog/auth.postgresql.changelog-master.xml

MariaDB

db/changelog/auth.mariadb.changelog-master.xml

MySQL

db/changelog/auth.mysql.changelog-master.xml

Oracle

db/changelog/auth.oracle.changelog-master.xml and db/changelog/auth.oracle.short.changelog-master.xml


Tenant Services Release Notes for 2.1.6-GA :toc:

Tip
The 2.x versions are Spring Boot 3 compatible.

Important Updates

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, all microservices have been upgraded to support Spring Boot 3.3 & 3.5.

Requirements

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

Bug Fixes

  • Fixed an issue where ApplicationEndpoint would return results for applications when an admin user doesn’t have application access.

  • Fixed an issue where an implicit catalog’s currency would not get updated after updating its parent catalog.


Workflow Services Release Notes 1.0.0-GA

1.0.0-GA

  • Initial release of the service.

Main Components
  • com.broadleafcommerce.workflow.web.endpoint.WorkflowEndpoint

    • API for managing Workflow instances and execution

  • com.broadleafcommerce.workflow.service.WorkflowService

    • Main service-layer interface for all standard workflow related logic flows

  • com.broadleafcommerce.workflow.service.WorkflowLauncher

    • Management component that spawns SimpleWorkflow instances on a limited thread pool

  • com.broadleafcommerce.workflow.service.WorkflowRunner

    • Worker component (in a thread pool - see WorkflowLauncher) that handles calling SimpleWorkflow#start, or handles reconstitution of workflow state via replay

Release Train Compatibility

Compatible with all Release Trains after 2.2.0 unless otherwise noted.

Tax Provider Libraries


2.0.4-GA

Important Updates

  • Updated CybersourceTaxProvider to map back tax provider response to all tax-group items so response from the tax provider is fully used.

  • Fix issues where skuCode, taxCode, and isVat were not set onto taxInfo correctly

  • Fix the issue where OrderAcceptance and OrderOrigin were not getting set correctly

Payment Integration Libraries

Braintree Release Notes for 2.0.2-GA

Miscellaneous

  • Updated the partner BN code.


Checkout.com Release Notes for 2.0.3

New Features & Notable Changes

  • Enhanced webhook logging to include application and tenant IDs when there are exceptions around fetching and using the discriminated payment gateway properties.


Broadleaf PayPal Integration Release Notes for 3.0.3

New Features & Notable Changes

  • Upgraded PayPal to support new Complete Payment features including the Contact & Shipping Modules

    • Updated PayPal Order payload to include:

      • Venmo Payment Source

      • Order Update Callback Config

      • App Switch Preference

      • Contact Preference

      • Shipping Options

    • Added the BN code as a header to every PayPal API call

    • Added handling of shipping callbacks to the PayPalCheckoutHostedService

    • Added Assertion Header to the create PayPal Order API call

    • Added endpoints to create and fetch orders from PayPal

    • Added a HMAC security token on the callback config to verify the returned shipping callback

Upgrade Notes
Authentication Data

The calls to PayPal create and fetch order have been moved to the backend. To support the new endpoint, new authentication scripts have been added to the environment setup steps. Please review the new data in the environment setup.

PayPal Frontend Libraries

Additionally, to support the new functionality and backend PayPal v2 endpoint support, changes have been made to the paypal-checkout-js library and a new paypal-checkout-react library has been added.

See paypal-checkout-js and paypal-checkout-react documentation for more details.

Added Configuration Properties
  • broadleaf.paypal-checkout.api.merchant-id

    • Description: The Account ID, also known as the Partner-Merchant-Id or PayPal Merchant ID in the PayPal dashboard. Used when building PayPal Assertion headers.

  • `broadleaf.paypal-checkout.api.populate-shipping-on-order

    • Whether the shipping details should be populated if it’s already known when the PayPal Order is created or updated.

      • Default is false.

      • This should be true if setting the shipping_preference to SET_PROVIDED_ADDRESS in the frontend.

  • `broadleaf.paypal-checkout.api.populate-items-on-order

    • Whether the purchase unit items should be populated if they’re already known when the PayPal Order is created or updated.

      • Default is false.

      • This should be true if setting the shipping_preference to SET_PROVIDED_ADDRESS in the frontend.

  • broadleaf.paypal-checkout.gateway.callback-token-hmac-key

    • The private key used to generate an HMAC token for shipping callback validation.

  • broadleaf.paypal-checkout.gateway.callback-token-hmac-algorithm

    • The algorithm used to generate an HMAC token for shipping callback validation.

    • Default is HmacSHA256.

  • broadleaf.paypal-checkout.gateway.valid-order-callback-statuses

    • The PayPal Order statuses that are valid during shipping callback validation.

    • Default is ["CREATED", "SAVED", "APPROVED", "PAYER_ACTION_REQUIRED"].

  • broadleaf.paypal-checkout.gateway.gateway-reference-for-transaction-id

    • The name of the Payment attribute that the transaction reference ID should be saved as, mapped by transaction type.

    • Default is { AUTHORIZE: "PAYPAL_CUSTOM_ID", AUTHORIZE_AND_CAPTURE: "PAYPAL_CUSTOM_ID" }.

Bug Fixes

  • Updated the Authorize & Capture payment response to include the transactionReferenceId.


Common Libraries

Common Libraries

Cart Client Release Notes

2.0.5-GA

  • Introduced the RETAIL_DELIVERY_FEE cart item type

  • Add support for Cancellation Policy identification

  • Add new NON_CATALOG_ITEM to the DefaultCartItemTypes enum for generic non-catalog backed items that also aren’t fees

    • The NON_CATALOG_ITEM type is used for an item that does not exist in a catalog. This allows for custom usage of the CartItem domain and tracking of its instances as line items. These items are included in the cart subtotal and excluded from promotions.

  • Introduce CartItem#hasOverriddenSubtotal flag to support overriding the CartItem#getSubtotalWithDependentItems() calculation when portions of the subtotal don’t scale with the item quantity

  • Added CANCEL_CART to the DefaultCartActionTypes enum

Customer Client Release Notes

2.0.4-GA

Spring Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Features & Notable Changes
  • Added support for Caffeine and Ehcache as Spring Cache options.

    • For more details, see the Caching documentation.

  • Added support for specifying the X-Customer-Ref header in the service client.

Data Tracking Release Notes

Data Tracking Release Notes for 2.0.7-GA

  • The 2.x versions are Spring Boot 3 compatible.

Spring Boot Upgrade

  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Introduce Support for Optimized Catalog Hierarchy Propagation

When changes to a catalog-discriminated entity (ex: Product) are deployed to production, there is a 'propagation' process executed to cascade update any downstream catalog overrides with the changes within (unless the downstream record has already overridden the changed fields).

This is an expensive operation, and in projects with large numbers of child catalogs and child catalog overrides, this can become a performance hotspot.

With this release, we are introducing optional support for a different propagation design that can more efficiently propagate over large quantities of override records.

Please see Optimized Hierarchy Propagation documentation for more details.

  • Introduce a completely new alternative set of components called HierarchyPropagationHandler. Unlike PropagationHandler, which focuses on propagating a single record at a time (and relies on DefaultPropagationManager to do the work of recursing through the hierarchy), these implementations are capable of completing the full end-to-end propagation process for the entire hierarchy all on their own. This API contract enables much more powerful handler implementations that can batch propagate through entire ancestries much more quickly than the current flow.

  • Support for HierarchyPropagationHandler components is disabled by default. However, if enabled, DefaultPropagationManager will find the first such component which can handle the flow and delegate to it if available. If no HierarchyPropagationHandler is available, propagation falls back to the existing standard propagation flow.

  • Introduce a SimpleDeleteHierarchyPropagationHandler which delegates to a new method in JpaTrackableRepository to batch update entities as archived

  • Introduce a new SimpleCreateHierarchyPropagationHandler which short-circuits create propagation as a no-op

  • Introduce a new PerFieldUpdateHierarchyPropagationHandler which propagates changes for each field individually, delegating to FieldUpdatePropagator components to do so. By default, the only such propagator is SimpleFieldUpdatePropagator, which leverages new methods on JpaTrackableRepository to detect if a field is a simple field (can be easily compared and set in a single UPDATE statement) and execute an update statement to propagate changes on that field if it’s simple. If SimpleFieldUpdatePropagator is insufficient for a particular client’s needs, a new FieldUpdatePropagator can easily be registered with higher precedence to handle the specific field on the specific entity.

  • To support the simple field update propagation, JpaTrackableRepository was updated to now inject the NativeSqlStrategyManager to allow delegation to NativeSqlStrategy beans.

  • Defined new NativeSqlStrategy beans to implement the native SQL generation for the interesting fields. These are supported by new HibernateColumnResolverUtility for column mapping detection, as well as new methods in EntityUtils to detect entity field definition information, including any converter that might be being used for the field.

Bug Fixes

  • Updated JpaTrackableRepository.findByContextIdAndCatalog to detect if the current entity is sandbox-discriminated, and if so, add filters to ensure only production and non-sandbox-archived records are returned.

    • This fixes a bug with the default catalog propagation logic, which used this method to locate instances to propagate changes to. Without these additional filters, the result of the query was not deterministic and could result in propagation being applied to the wrong instance.

  • Fixed an issue where the incorrect tracking level causes the creation of a redundant notification state for the ChangeSummaryProducer#TYPE and an event with a null author and sandbox

    • NOTE: The method com.broadleafcommerce.data.tracking.core.mapping.TrackableDomainMapperMemberSupport.buildTracking is overloaded, and a new parameter is added. This may cause a breaking change if the method is overridden. The old method will no longer be called by the com.broadleafcommerce.data.tracking.core.transition.VendorSandboxPropagationHandler. If you have any customizations, please make sure to update them.

  • Added a cache invalidator to clear application cache to fix an issue where products from an unassigned and deleted catalog can still be searched and accessed on a storefront

  • Fixed an issue where methods in DefaultTrackablePolicyUtils that use Assert.notNull to check when catalogs are archived would throw an error instead of gracefully handling the policy validation failure

  • Fixed an issue where 'Undo Overrides' could be requested on an inherited entity and directly mutate the instance in the parent catalog

    • DefaultTrackableDomainMapperMemberSupport.handleDelete has been updated to reject 'clear override' requests if the target entity is not directly located in the catalog defined in the context request

Miscellaneous

  • Introduced a mechanism to allow the NotificationState for SingleIndexRequest messages to be built, even if SuppressNotificationContext is enabled

    • Previously, when SuppressNotificationContext was active for SingleIndexRequest during a CRUD flow, SingleIndexRequestNotificationStateMapperMember would always cease to build the NotificationState for it. This is still the default behavior, but now, there is a new SingleIndexRequestNotificationStateBuildContext ThreadLocal that can be activated to force the NotificationState to still be built in those flows. Using this will mean that on a CRUD operation, the NotificationState will still be built, but the first 'eager' send attempt of that message will not happen until the retry handler picks it up later.

    • Example of usage

      return SingleIndexRequestNotificationStateBuildContext.doWithForceBuildEnabled(() -> {
          return SuppressNotificationContext.exec(() -> {
              // invoke CRUD method that engages the mapping + persistence flows
              return replace(id, businessInstance, context);
          }, SingleIndexRequestProducer.TYPE);
      });
  • Updated various methods in CrudEntityHelper to be protected instead of private, improving extensibility of the class

  • Updated SortPositionRequest in accordance with Jackson library upgrade to enable seamless JSON deserialization

  • Enhanced performance of standard recursive catalog propagation flow

    • Introduced a net new PropagationCandidateFinderRepositoryFragment interface with a new bulk findByContextIdAndCatalogIn method.

    • Updated JpaTrackableRepository to implement that interface, and updated JpaTrackableRepositoryFactory to explicitly expose that interface on the final repository proxy instance

    • Updated DefaultPropagationManager to utilize the new batch query instead of querying for override records one child catalog at a time

      Note
      Please see Propagation Manager Properties for configuration options on the batch size.
  • Updated DefaultPropagationHandler to gate the emission of PERSISTENCE notifications on a new property. The default is still enabled for backward compatibility, but this feature now allows clients to disable that process for less noise and improved performance.

    Note
    Please see Default Propagation Handler Properties for configuration options.
  • Introduced new overrideCatalogLevel and creatingApplicationId fields to ContextState, and updated ContextStateBuilder to initialize them

    • overrideCatalogLevel is not serialized in API responses by default, but serves as a mechanism for internal service components to know the level of the catalog in overrideCatalogId, if set

    • creatingApplicationId is serialized in API responses and is also available for internal service components to know which application owns the entity (if the entity is in an application-owned catalog)

Fulfillment Common Release Notes

Extension Common Release Notes

Release Notes for 2.0.7

Ignite Metrics Collection Changes
  • Ignite metrics collection is resource-expensive and has been disabled by default. Previously, there was no mechanism available to disable this metrics collection. New properties have been introduced to control whether metrics collection is enabled.

  • Ignite metrics collection has been fully reworked with a new implementation.

    • This fixes a variety of bugs, including value miscalculations, overly aggressive metrics gathering in a looping structure, lazily instantiated caches being omitted from metrics, and large numbers of background tasks that continually run and consume resources. Hit percentage is no longer reported, as this can be calculated by the tooling gathering the data.

  • New Caffeine and Ehcache options for Spring Cache. See Caching for more information.

Tomcat Metrics Collection Enhancements

Import Consumer Release Notes

2.0.3

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Notable Changes
  • Fixed a bug that occurred when importing a product update with no changes, the product didn’t show up in the list grid.

  • Updated AbstractImportBatchHandler to replace usages of the deprecated property userSandboxPersistenceNotificationEnabled with the new property persistenceNotificationEnabled.

JPA Common Release Notes

Version 2.0.5-GA

Spring Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Features & Notable Changes
  • Improved memory efficiency during classpath scanning for Liquibase changelogs.

  • Fixed intermittent classloader collisions when reading YAML files during concurrent schema loading.

Metadata Release Notes

2.0.8-GA

Spring Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Features/Notable Changes
  • Added new attribute augmentable to Component that allows to disable form modification for views. Defaults to true.

    • This attribute cascades to child components overriding their settings.

  • Introduce Global Components to the registry

    • Global components are reusable components that can be shared across multiple containers. For instance, defining a modal once that can be triggered by multiple links in one or more forms.

      Example Usage of Global component
      registry.addGlobalComponent("test-modal", Views.modalView()
             .label("Terms and Conditions")
             .addField("testField", Fields.string()
                  .label("Test Field")));
  • Added new DSL for defining Modal Views.

    • Introduced ModalView interface and Views.modalView() builder method.

    • ModalView is a specialized form view designed for modal dialog presentations.

    • ModalViewCreate and ModalViewUpdate interfaces can be used for entity creation and update scenarios.

  • Introduced new DSL for CheckboxField component.

    • Introduced CheckboxField interface and Fields.checkbox() builder method.

    • CheckboxField is used to represent a boolean value as a checkbox in forms.

  • Added new DSL for BadgeColumn and BadgeTileComponent.

    • Introduced BadgeColumn interface and Columns.badge() builder method.

    • Introduced BadgeTileComponent interface and TileComponents.badge() builder method.

    • BadgeColumn and BadgeTileComponent are used to display badges in grid views.

  • Introduced new Simple classifier for components to handle simple components that don’t require or support all of the configuration options of Form Components, Groups, Views, Externals, etc.

    • Simple components can be added to other components using Component#addSimpleComponent, which will autogenerate the key to be in the form simple:{type}:{order}. Generally this will be sufficient, but they can also be added like normal components and supplied a manually defined key.

  • Introduced a Divider component to render a horizontal rule within forms or groups.

    • Takes a width attribute, indicating the width of the horizontal rule—default is sm indicating 1px.

    • Takes a spacing attribute indicating the spacing above and below the rule in rem—default is md indicating 2rem.

      Example usage of Simple component
      Groups.basic()
              .label("product.groups.basic-information")
              .addField(ProductProps.NAME, Fields.string()
                      .label("product.fields.name")
                      .required()
                      .translatable()
                      .readOnly(!isCreate)
                      .hidden(!isCreate)
                      .order(1000))
              .addSimpleComponent(SimpleComponents.divider()
                      .order(1500)
                      .width(Divider.Width.SMALL)
                      .spacing(Divider.Spacing.MEDIUM))
  • Added a new DSL for LargeContentColumn and its default implementation DefaultLargeContentColumn. This renders a column for the LARGE_CONTENT type with large contents like embedded collections, which displays the content as truncated strings. The column value is clickable, which will show a modal with the full contents formatted similar to YAML style.

    • This component can take a lines attribute to configure the number of lines to truncate to for the column value. Out of box, the default value is 1 and the maximum value is 6.

    • There is also a clearLines() method that will clear the lines attribute from the column.

      Example usage of LargeContentColumn
      Fields.residentGrid()
              .label("sandbox.grid.change-summaries")
              .addColumn(SandboxProps.DETAILS, Columns.largeContentColumn()
                      .label("sandbox.columns.details")
                      .lines()
                      .order(1000))
  • Added a new DSL for ModalLinkColumn and its default implementation DefaultModalLinkColumn. This renders a column for the MODAL_LINK type whose column value is clickable, and upon clicking will show a modal form with the fields and components configured via metadata.

    • Aside from being able to add fields and components, the endpoint to submit the modal form to can be configured via metadata as well.

      Example usage of ModalLinkColumn
      Externals.grid()
              .label("product.externals.promotional-product")
              .scope(ProductScopes.PRODUCT)
              .sandboxTrackable(CatalogChangeContainers.PROMOTIONAL_PRODUCT)
              .catalogTrackable()
              .sortable()
              .addColumn(ProductProps.Marketing.TYPE, Columns.modalLink()
                      .label("Update Promotional Product")
                      .order(1000)
                      .sandboxTrackable(CatalogChangeContainers.PROMOTIONAL_PRODUCT)
                      .catalogTrackable()
                      .submitEndpoint(Endpoints.put()
                              .uri(ProductPaths.PROMOTIONAL_PRODUCT)
                              .scope(ProductScopes.PRODUCT))
                      .addField(ProductProps.Marketing.TYPE, Fields.select()
                              .label("Type")
                              .required()
                              .defaultValue(PromotionalProductTypeOptionEnum.FEATURED)
                              .options(PromotionalProductTypeOptionEnum.toOptions())
                              .order(1000))
                      .addField(ProductProps.Marketing.RELATED_PRODUCT_ID,
                              ProductLookupHelpers.createProductIdLookup()
                                      .label("Select a Product")
                                      .required()
                                      .order(2000))
                      .addField(ProductProps.Marketing.PROMOTION_MESSAGE, Fields.string()
                              .label("Promotional Message")
                              .translatable()
                              .order(3000)));
  • Added displayOnly and displayOnly(boolean displayOnly) attribute methods to the Field DSL in order to display it as a plain or raw text representation of the field.

  • Introduce FORM_FIELD column type.

    • This column type allows for inline editing of the row entity by displaying an editable form field in the column.

    • Changes are submitted on blurring the field (moving focus away from it or just toggling for a boolean).

    • It supports the following field types:

      • BOOLEAN

      • DATE

      • DECIMAL

      • INTEGER

      • LONG

      • LOOKUP

      • MONEY

      • PHONE

      • SELECT

      • STRING

        Example Usage of FORM_FIELD column
        externalGrid
            // define an update endpoint to perform the save operation
            .updateEndpoint(endpoint -> endpoint
                .uri(EntityPaths.ENTITY)
                .scope(EntityScopes.ENTITY))
            // add a form field column
            .addColumn(EntityProps.DATE, Columns.formField()
                .label("Date")
                .field(Fields.bool()
                    .name("date")
                    // required to avoid displaying decorations inside the grid cell
                    .decorated(false))
                .order(3000))
  • Added new DSL for MoneyTileComponent to display monetary amount fields on tile grids

  • Added new DSL for CheckboxField component type.

  • Updated EntityFormView to be able to configure an UPDATE endpoint on the form itself that overrides the parent View’s UPDATE endpoint

    Example usage of overriding the UPDATE endpoint per form
    UpdateEntityView view = Views.entityViewUpdate()
            .label("Update View")
            .submitUrl("/main-entity", Scopes.SCOPE)
            // ...
            .addForm("separateEntityForm", Views.entityForm()
                    .label("Form with External Related Entity")
                    .updateUrl("/external-entity", Scopes.EXTERNAL_SCOPE);
  • Improved support for ExternalFieldGroup

    Note
    This work was done in support of allowing a fields within an ExternalFieldGroup to be updated using a form’s override update endpoint where the actual parent entity’s state wasn’t being modified and wouldn’t be returned from the submit endpoint, which was in a different microservice.
    • Added explicit DSL support for ExternalFieldGroup

    • Updated ExternalTypes & Externals to be able to expose the DefaultExternalFieldGroup DSL for metadata configuration

    • Added attributes map to Endpoints metadata with relevant helper methods

    • Added Endpoint attribute, responseIsPartialState: Indicates that this endpoint’s response will be a partial state that should be merged with the existing entity state, similar to a PATCH request. This is useful for APIs that do not support PATCH requests directly or that are backing external field groups on a different entity’s form. In those cases, the parent entity state should be merged with the new state returned by the endpoint to maintain the full view state.

    • Fixed Groups not getting their IDs set when using Form#addGroup(String type, Group<?> group)

    • Expanded javadocs on various metadata DSL interfaces

    • Added attribute to ExternalFieldGroup, useParentFormState. Indicates that the state for the fields in this group will be backed by the parent form’s.

    • If false, then a nested form state will be created to hold the field values in isolation from the parent. Note that this currently makes the group effectively read-only.

    • If true, then users should ensure that the field names are prefixed with the Group.getId() since this is used in the admin to ensure that the values do not collide with other fields in the parent form. TransformBody and MappingList can be used to map the form state to the appropriate structure expected by the form or entity submit endpoint (if any) and vice versa.

      Example Usage of ExternalFieldGroup
      public void exampleUsage() {
          form.updateEndpoint(Endpoints.post()  // <-- overrides the View's endpoint
                  .responseIsPartialState()
                  .uri("/dto-endpoint")
                  .transformRequest(t -> t.mappings(transformEntityToRequestDto("externalGroupId")))
                  .transformResponse(t -> t.mappings(transformEntityFromRequestDto("externalGroupId")))
                  .scope("DTO"))
                  .addGroup("externalGroupId", getExternalGroup());
      }
      
      public static MappingList transformEntityToRequestDto(String groupId) {
          return new MappingList(Arrays.asList(
                  Mappings.mapValue("%s.%s".formatted(groupId, "field1"), "field1"),
                  Mappings.mapValue("%s.%s".formatted(groupId, "field2"), "field2"),
                  Mappings.mapValue("%s.%s".formatted(groupId, "field3"), "field3")));
      }
      
      public static MappingList transformEntityFromRequestDto(String groupId) {
          return new MappingList(Arrays.asList(
                  Mappings.mapValue("field1", "%s.%s".formatted(groupId, "field1")),
                  Mappings.mapValue("field2", "%s.%s".formatted(groupId, "field2")),
                  Mappings.mapValue("field3", "%s.%s".formatted(groupId, "field3")));
      }
  • Added DateRangeColumn class to define a type of column that takes in a start date and end date to display a date range.

  • Added a DurationColumn class to define a type of column that takes in an integer value and displays it in a user-friendly format.

    • Includes a baseUnits attribute to specify the base units of the given duration.

    • Introduced DurationBaseUnits utility class to define the available base units:

      • DAY

      • WEEK

      • MONTH

      • YEAR

        Example Usage:
        grid
            .addColumn(DURATION, Columns.duration()
                    // The duration will be displayed in days
                    .baseUnits(DurationBaseUnits.DAY));
  • Added support for date fields to be computed based on another date field and a duration, e.g., allow active end date to be computed as the active start date plus 30 days.

    • Added computedFromDate, computedFromDuration, and computedFromDurationUnit attributes to the DateField, along with corresponding DSL methods.

      Example Usage:
      form
          // Add a duration field that will be used to compute the end date
          .addField(DURATION, Fields.duration())
          // Add a start date field
          .addField(ACTIVE_START_DATE, Fields.date())
          // Add an end date field that will be computed based on the start date and duration field
          .addField(ACTIVE_END_DATE, Fields.date()
                  .computedFrom(
                          ACTIVE_START_DATE,
                          OFFER_DURATION,
                          // Specify the base units for the duration field
                          DurationBaseUnits.DAY
                      )
                  );
  • Added new DSL methods to CreateEntityView to configure toast notifications to display on succesful create of an entity:

    • Introduced successNotificationOnCreate() method to configure a success notification with a default message.

    • Introduced successNotificationOnCreate(String message) method to configure a success notification with a custom message.

    • Introduced successNotificationOnCreate(InternationalizedMessage message) method to configure a success notification with a custom internationalized message.

  • Added new iconName DSL method to allow setting a custom icon to be displayed by the following components:

    • FilterAction

    • CommonStartExportAction

    • ExportGridAction

    • ImportGridAction

    • See Import Services 2.1.1 for StartImportAction component changes.

  • Added ComputedField & DefaultComputedField DSL support for Form components to allow defining fields whose values are computed based on other field values using a specified function. .Example Usage:

form
    .addField("shopPrice", Fields.money()
            .label("Shop Price")
            .validationSchema(ValidationSchemas.money()
                    .method(ValidationMethods.positive(
                            "Must be positive")))
            .order(1000))
    .addField("shopMarkup", Fields.money()
            .label("Shop Markup")
            .validationSchema(ValidationSchemas.money()
                    .method(ValidationMethods.positive(
                            "Must be positive")))
            .order(2000))
    .addField("productMarkup", Fields.money()
            .label("Product Markup")
            .validationSchema(ValidationSchemas.money()
                    .method(ValidationMethods.positive(
                            "Must be positive")))
            .order(3000))
    .addField("finalPrice", Fields.computed()
            .label("Final Price")
            .computationType(ComputedField.ComputationTypes.SUM)
            .fieldsToCompute(List.of("shopPrice", "shopMarkup", "productMarkup"))
            .order(4000));
  • Added ToggleTileComponent as a new type of TileComponent that represents a boolean value as a toggle switch on a tile grid. .Example Usage:

browseComponent.getDefaultGrid()
        .addTileComponent("thumbnail", TileComponents.thumbnail()
                .toggle(TileComponents.toggle()
                        .name("featured")
                        .label("product.browse.columns.featured")
                        .icon("star")
                        .submitEndpoint(endpoint -> endpoint
                                .uri(ProductPaths.TOGGLE_FEATURED_TAG)
                                .scope(ProductScopes.PRODUCT)
                                .param("toggleValue", "${toggleValue}"))
                        .order(1000)));
  • Added skipSandboxing attribute to GridExternal. This allows grids that pull data from external sources to opt out of sandboxing if the external source is not expected to be affected by sandboxing or if the grid is intended to show unsandboxed data for some reason.

  • Introduced InterdependentExternalGridsGroup concept to allow grouping together multiple instances of GridExternal that are related to each other and have interdependent data such that they should have their state changes tracked together in the admin and be displayed together in the UI.

    • For instance, this can be used for a group of grids that all pull from the same external source and should be tracked together in the admin since they will all be affected by the same external state changes, or if a change in one grid should trigger a refresh in the other grids since they are related and likely displayed together in the UI.

    • The following methods & attributes were added to support this feature:

      • listensFor(Map<String, List<String>>) & listensForGridsAndOperations: This method adds the listensForGridsAndOperations attribute and configures the other external grids within the InterdependentExternalGridsGroup that this grid will be listening for. This means that if a change is made to any of the configured grids, then this grid will be refreshed (i.e. the configured READ endpoint for the grid will be called). Operations can also be defined for each dependent grid to allow for conditional updates, but are not required. The operations are expected to be GridExternal.GridListenerOperations so that this grid is refreshed depending on the operation done on the grid being listened to. .Example Usage:

private Group<?> getPromotionsGroup() {
        return Groups.interdependentExternalGrids()
        .addExternal("CURRENT_PROMOTIONS", Externals.grid()
                .id("CURRENT_PROMOTIONS")
                .label("Current Promotions")
                ...
                .listensFor(Map.of("UPCOMING_PROMOTIONS", List.of())))
        .addExternal("UPCOMING_PROMOTIONS", Externals.grid()
                .id("UPCOMING_PROMOTIONS")
                .label("Upcoming Promotions")
                ...
                .listensFor(Map.of("CURRENT_PROMOTIONS", List.of(GridExternal.GridListenerOperations.ON_CREATE))));
}
  • Added the readOnSuccess attribute to ModalFormAction to specify whether a re-fetch should be executed after the modal form action is successfully executed. The read endpoint that is configured for the grid will be used to trigger this re-fetch.

Messaging Common Release Notes

2.0.5

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Notable Changes
  • Introduced RoundRobinRetryScheduler to manage retry handlers more efficiently.

    • Addresses resource exhaustion by using a fixed-size thread pool instead of creating a dedicated thread per handler.

    • In the past, thread counts for retry scheduling could get up to ~2600. This should now be reduced to a constant of 30 (the default).

    • Ensures fairness via a round-robin scheduling algorithm, preventing "noisy" handlers from monopolizing resources.

    • Implements a non-blocking design where the scheduler skips full pools and retries on the next cycle.

  • Added "Burst Mode" support for high-load scenarios.

    • Allows handlers to request immediate execution on a dedicated "Burst Pool" when a full page of records is processed.

    • Helps drain large backlogs quickly without starving other handlers in the main fair pool.

  • Added new configuration properties for tuning the retry scheduler and burst mode behavior.

Offer Client Release Notes

2.0.4-GA

  • Add support for offer targeting a specific subscription flow. See Subscription Offer Configuration.

  • Add Adjustment#isExistingAdjustment flag to indicate if it’s an existing adjustment for post-purchase subscription flows. Defaults to false.

  • Add new Dtos to support targeting former and active subscribers

  • Record discount method type and amount on OfferRef

Order Client Release Notes

2.0.4-GA

  • Introduced the RETAIL_DELIVERY_FEE order item type

  • Introduced fee refund concepts to the ReturnAuthorization domain

  • Forward-compatibility to support new concepts from Order Services 2.2.0, Order Operation Services 2.2.0

    • Introduced IncludedFee to represent a fee that is included in actions against an OrderFulfillment such as capturing funds or cancelling (refunding).

      • Stored as OrderFulfillment#includedExtraFees

  • Added CancellationPolicyRef to the OrderItem domain. See Subscription Cancellation for more information on cancellation policies.

  • Added support for the Spring boot 3.3/3.5

Order Common Release Notes

2.0.4-GA

  • Introduced the CancellationPolicyRef domain to represent the data structure describing a reference to a Cancellation Policy and where it came from

  • Added helper method to DefaultFreeTrialLengthUnits to convert FreeTrialLengthUnits to ChronoUnit

  • Added a Adjustment#isExistingAdjustment flag to indicate an existing offer

  • Introduced CurrencyConversionDetail domain to represent the adjustment details of the exchange rate used to convert a MonetaryAmount from one currency to another

  • Added the new attributes to the OfferRef domain to better describe the style of offer, its discount rate, & how it interacts with other offers

Payment Gateway Common Release Notes

2.0.5-GA

  • Introduced new fields on PaymentInfo

    • addressByType

    • displayAttributes

  • Introduced new method in PaymentGatewayPaymentModificationService

    • modifyFullPaymentForCreate: When a payment is being newly created, the request information will be copied to a PaymentInfo and passed into this method. The implementation can then customize the values as needed depending on the gateway-specific requirements. All values from the modified PaymentInfo will then be mapped back onto the payment, essentially as a full replacement. For backwards compatibility, this method is called after modifyPaymentMethodProperties. Default implementation in the interface is a no-op.

  • Introduced new method in PaymentGatewayTransactionService

    • identifyTransactionReferenceIdOverrideForSubsequentTransactions: Hook used to potentially gather a transactionReferenceId override value for the payment’s subsequent transactions after the initial Authorize or Authorize-Capture transaction. Default interface implementation returns null, effectively serving as a no-op.

  • Added new ShippingCallbackValidationException to handle fulfillment callback validation errors.

  • New interface methods in PaymentGatewayConfiguration for mapping a name to the gateway’s reference ID.

    • These methods determine the name of the attribute added to the Payment for the transaction reference ID. Typically an implementation of these methods would be used to name the attribute specific to the gateway’s naming convention, i.e. ORDER_ID or CUSTOM_ID.

Pricing Client Release Notes

2.0.4-GA

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Notable Changes
  • Forward-compatibility to support new concepts from PricingServices 2.2.0.

    • Added domain support for adjustment price details

    • Added support to store and summate adjustment data on price info

    • Added domain support to store the derived field type for price details, price info, and priceable targets

    • Added support for simpler access to tiered pricing information on price details and price info

    • Added support for pricing categories on priceable targets

    • Added a transient property to store requested currency on the PriceInfoContext domain to allow for better support of multi-currency use cases

    • Added a new price source for adjustment to a direct field

    • Added support for different frequencies each payment term

    • Added the DefaultPaymentStrategy enum which is the strategy used when paying for a target using a given price detail, whether the beginning or end of the billing period

    • Added a new domain ExchangeRateDetail to represent the details of the exchange rate used to convert a given amount from one currency to another, and added support to include this information on price details and price info when currency conversion is involved

    • Added a CancellationPolicy reference for price details and price info

    • Added priceTargetCurrencies to PriceContext

    • Allow for filtering price data by payment strategy via the PriceInfoContext

Security Common Release Notes

2.0.5-GA

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Notable Changes
  • Optimized the space efficiency of restrictions / restricted authorities in access tokens.

Tax Common Release Notes

2.0.4-GA

Spring Boot Upgrade
  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Notable Changes
  • Introduced the feeAmount field to the TaxInfo representation.

Translation Common Release Notes

2.0.5-GA

  • Extracted the default updateField translation-applying logic out of TranslationPostMapperMember into a new reusable TranslationHelper bean. The existing updateField method is marked deprecated and unused. Clients should move any overrides of the updateField-related methods out of their TranslationPostMapperMember customizations and into an extension of TranslationHelper.

  • Introduced a new EntityTranslationApplier concept that can be used to override the default translation-applying logic on a per-entity, per-field basis. TranslationPostMapperMember will delegate to these if available.

  • Introduced a new findByEntityTypeAndEntityFieldStartsWithAndEntityIdInAndLocaleIn method in TranslationRepository and TranslationEntityService to allow fetching translations matching a certain field

  • Introduced a new TranslationFieldTransformerHandler concept that can be used to override the default 'path transformation' logic executed in DefaultTranslationEntityService.bulkReplaceTranslationsForEntityInLocale on a per-entity, per-field basis

  • Updated various methods in DefaultTranslationEntityService to protected instead of private for the sake of extensibility in the rare circumstance a client may wish to directly extend that service

Workflow Client Release Notes

1.0.0-GA

  • Initial Release

Main Components
  • com.broadleafcommerce.orchestration.service.provider.external.WorkflowProvider

    • Support remote REST API calls to WorkflowServices

  • com.broadleafcommerce.orchestration.service.provider.domain.WorkflowRequest

    • Embodies data related to requesting a remote workflow execution

  • com.broadleafcommerce.orchestration.client.WorkflowInformation

    • Reference information about the currently executing workflow

  • com.broadleafcommerce.orchestration.client.SimpleWorkflow

    • Responsible for launching execution of activities at any point in the list

  • com.broadleafcommerce.orchestration.client.SimpleActivity

    • Prescribed interface to support initiation of a business task as part of an ordered/orchestrated workflow

Utility Services

Microservices Gateways Release Notes for 2.0.5

Features/Notable Changes

  • Added URIs, predicates, and filters for Audit and Workflow Services for Admin and Commerce Gateways.

  • Advance base dependencies version with the spring boot 3.5 upgrade

Bug Fixes

  • Rewrote OAuth2ClientCredentialsGatewayFilterFactory to use a fully non-blocking mechanism for all logic related to obtaining a new access token

    • Previously, this filter would defer to a worker thread and execute synchronized/blocking logic to fetch the access token. In scenarios where clients had attached the Elastic APM agent to the gateway for instrumentation, the agent would cause the blocking work to be executed in an event loop thread, which would throw an error on the blocking logic.

    • With the rewrite, the flow is now fully non-blocking, and the Elastic APM agent can be used with the gateway.

    • This change should also produce a positive impact on performance for all anonymous storefront requests, as a variety of inefficiencies have now been eliminated in this flow.

  • Fixed issue where caching could not be turned off in the commerce gateway due to a lack of null-checks against CacheStateManager

  • Fixed a bug where the commerce gateway’s default properties were setting the cache type to 'simple', even though the actual configuration uses and configures Ignite. The cache type property is now removed, preventing a confusing contradictory combination of defaults.

  • Rewrote the application token resolution logic in commerce gateway to fix a few different bugs

    • Since ThreadLocals are unsafe in reactive flows, removed the use of CacheContext and added a custom CacheStateConfigurer to force-set the cache enabled value to true for the relevant app token cache flow

    • Rewrote the ApplicationTokenGatewayFilterFactory and ExternalApplicationResolverService to move blocking cache interactions off of the event loop thread and into worker threads. Furthermore, added strong concurrency control to enforce only one thread at a time will make a request for any given application token, fixing a bug where multiple requests could have previously been fired off all at once to the downstream service.

  • Enabled ApplicationToken filter for services that were missing them

    • audit

    • billing

    • catalog

    • notification

    • workflow

  • Enabled Anonymous filter for services that were missing them

    • fulfillment

    • offer

    • orderoperation

    • pricing

Security

This release contains security updates. For more details, please visit Broadleaf Security and review the security advisories page.