Development
7 min readTop-of-the-line eCommerce applications are distinguished by their ability to handle complex pricing and promotions, to meet modern business needs. It's never just a simple list price; it's about bundles, tiers, BOGOs, and dynamic adjustments based on user context. For developers and architects in the Spring ecosystem, the goal is to manage the various promotion possibilities and provide solutions to their challenges without writing mountains of brittle, custom code.
Broadleaf's Promotions Service and Pricing Service handle these requirements out of the box, and we continue to implement solutions for newfound needs. A multi-tenant environment may demand better control over which promotions appear on which storefronts; some platforms may benefit from integrating with external pricing systems, and others may benefit from the ability to influence promotion behavior based on payment methods.
Here are three new Offer features available in Broadleaf Release Train 2.2.1-GA that target these demands.
In multi-tenant environments, tenant-level promotions used to apply everywhere or require manual exclusions. There wasn't much middle ground.
Opt-In Offers introduce three modes for how tenant-level offers apply to applications:
AUTO_ACCEPTED - The offer applies universally to all applications. This maintains the previous behavior where tenant-level offers were automatically active everywhere.
REQUIRE_OPT_IN - Applications must explicitly opt-in to receive the offer. You can deploy a new tenant-level promotion without it accidentally going live across all storefronts.
ALLOW_OPT_OUT - The offer is enabled by default, but applications can explicitly disable it.
This is particularly useful when you're managing multiple brands under one tenant. A "Free Shipping Over $50" promotion might make sense for a budget brand but undermine a premium brand's positioning. With REQUIRE_OPT_IN, each brand's application decides whether to use it.
The opt-in behavior is enabled by default but can be disabled via the broadleaf.offer.metadata.enable-offer-opt-in property if you need universal application behavior.
When enabled, applications see two grids in the admin: one for application-specific offers, of which they have full control, and another for tenant-level offers, which they can consume and edit within the parent offer’s limitations.
How do you let external systems (like a proprietary loyalty engine or legacy pricing calculator) determine discount amounts within a Broadleaf transaction?
Dynamic Offers separate eligibility from amount. Broadleaf's offer rules determine whether a customer qualifies for a discount. But the actual discount amount now comes from an external service during cart repricing. This new kind of offer applies exclusively to Order-targeting discounts, meaning they apply to the entire order rather than specific items.
When creating a Dynamic Offer, you must provide the key by which this offer is identified in the external service. Internally, we refer to this as the dynamicOfferKey. When CartOperationService prices the cart, it fetches the offer amount from your external service for any Dynamic Offers the customer qualifies for. That amount gets stored in a DYNAMIC_OFFER_MAP in the offer's attributes, then applied to the cart. To utilize this feature, you need to define the API call to your designated service in the addDynamicOffersMap hook point of the ExternalOfferProvider.This is useful when you're dealing with legacy pricing systems you can't migrate yet, or loyalty programs that need to stay in their own infrastructure. You integrate with the pricing service without bottlenecking your core commerce platform.
When you build the external integration, response time matters since it's called during repricing. To address this challenge, we recommend common patterns such as caching frequently-accessed data like tier levels or point balances, and having fallbacks if your external system goes down.
Payment Offers let you apply Order-level discounts based on payment type. Out-of-box, you can create offers targeting:
After the customer provides payment information, the front-end should make a reprice request, including the new payment summary in a PAYMENTS_LIST. Out-of-box, the Cart Operation Service uses this front-end-supplied list of summaries to derive a list of payment types from the first word of their payment names. This list is then stored in the order's context map. When the cart is repriced, Broadleaf checks this list and applies any matching Payment Offers.
Important: Your front-end needs to make an additional request supplying the Payments List as a cart attribute that will also trigger a cart reprice once the payment information is available. Broadleaf doesn't automatically handle this. You control when repricing happens based on your checkout flow.
This is a highly customizable feature where you may introduce support for any additional payment methods by extending the PaymentTypeEnum to include your desired payment type, and ensuring that once added, payments of this type are included in the PAYMENTS_LIST attribute in your payment request. The Cart Operation service will take care of the rest.
This feature allows you to take control of your margins. Interchange fees differ significantly by card type. A premium credit card might cost 2.5-3% in processing fees, while a PIN debit transaction might be under 0.5%. Offering a 1% discount for lower-cost payment methods improves your net margins while giving customers a tangible benefit.
For B2B operations, Payment Offers can enforce contract compliance. If you've negotiated terms that include a 2% discount for ACH payment versus credit card, you can codify that in the offer system rather than handling it through manual invoice adjustments.
Here's where it gets interesting. Say you're running a multi-tenant B2B platform:
You end up with a flexible promotional setup without custom code at every integration point. Eligibility rules live in Broadleaf's offer engine, discount calculations live in your designated external system, payment preferences are handled through Payment Offers, and tenant offers are managed through opt-in controls.
These features are available in Broadleaf Release Train 2.2.1-GA, specifically in Offer Services 3.1.1-GA, and CartOperationService version 2.0.5-GA.
If you're currently using tenant-level offers, the Opt-In feature is enabled by default but maintains backward compatibility through AUTO_ACCEPTED mode. Existing offers will continue to work unless you explicitly change their optInStatus.
For Dynamic Offers, you'll need the supporting logic in CartOperationService version 2.0.5. You will need to extend the aforementioned addDynamicOffersMap hook point.
For the Payment Offer, you'll need the supporting logic in CartOperationService version 2.0.5. Additionally, the logic introduced there requires coordination with your front-end’s checkout flow in order to leverage the new functionality.. Check the Commerce Next.js Starter 1.6.6 release notes for details on how to trigger a cart reprice once the payment method has been applied. This is the most important step in determining the eligibility of this type of offer.
Full details are in the Offer Services 3.1.1 release notes and the Cart Operation Services 2.0.5 release notes.
By externalizing discount calculations where it makes sense (Dynamic Offers), providing better control over shared resources (Opt-In Offers), and making payment methods part of your promotional strategy (Payment Offers), we're making it easier to build complex platforms on a Java/Spring foundation.
We'd love to hear which of these you're planning to implement first. Reach out to your account team or connect with us in the community forums.