Skip to main content
Version: 8.8.x

Self-Managed Commerce 8.8.x Release Notes

Learn about changes to Self-Managed Commerce for this release. Fixes since the release are summarized in the changelog.

Changelog​

The changelog contains the list of fixes and improvements made to Self-Managed Commerce 8.8 since its release date. To learn how to consume the updates, see Consuming Support Fixes.

CommitDescriptionBadgesRelease Date
de900961 Fixed an issue where application containers would unnecessarily wait for additional services to be ready before starting the application. Now they only confirm that the database is available.5‑Nov‑2026
95121da4 Upgraded Tomcat from 10.1.60 to 10.1.61 to address CVE-2026-101296, CVE-2026-101356, CVE-2026-88041, CVE-2026-74048, CVE-2026-93446, CVE-2026-74049.Security4‑Nov‑2026
5e435eef Upgraded Jetty from 12.1.12 to 12.1.13 to address CVE-2026-19863, CVE-2026-77711, CVE-2026-76182, CVE-2026-19864Security3‑Nov‑2026
1adce8e2 Fixed a Cortex performance issue where api-platform was dispatching LINK and ADVISE operations to resource families already cached as not allowed.Performance3‑Nov‑2026
d6bc7b4b Fixed a performance issue with inefficient localized attribute key parsing by caching parsed results and eliminating repeated regex compilation per call.Performance3‑Nov‑2026
9bbf188a Fixed an issue where Cortex calculated the same product SKU price up to three times per search or navigation request.Performance2‑Nov‑2026
575197c2 Upgraded the PostgreSQL JDBC driver from 42.7.13 to 42.7.14 to address CVE-2026-107314 and CVE-2026-107315.Security2‑Nov‑2026
c88119ca Fixed a security and relevance issue where shopper keyword searches passed input directly to Solr unescaped, allowing Lucene query syntax operators to inflate search cost or prevent literal product name matches.Security Data model changes2‑Nov‑2026
f97246a7 Fixed an issue where Tomcat-based Commerce containers shut down immediately on SIGTERM, interrupting in-progress heap dumps instead of allowing the Java process to finish gracefully.Build Tools29‑Oct‑2026
0be57532 Upgraded the Google Guava library from 32.0.1 to 33.7.2 to address a high-severity security vulnerability (CVE-2026-102554).Security29‑Oct‑2026
7c93bcd3 Fixed an issue where a malformed or unresolvable entry in extensions.json or plugins.json was silently ignored, causing all configured extension overrides to be discarded at startup.27‑Oct‑2026
a9f6a796 Fixed a performance issue where the outbox message relay job lacked an optimized database index, causing inefficient queries against the outbox message table.Performance Data model changes27‑Oct‑2026
5e01b2fd Fixed an issue where a single failing or repeatedly duplicated search index notification could permanently stall the index update queue, causing indexes to go stale and eventually run out of memory during rebuilds.Data model changes27‑Oct‑2026
a79e36a1 Upgraded Jackson from 2.22.3 to 2.22.4 to address three security vulnerabilities (CVE-2026-104895, CVE-2026-106554, CVE-2026-110879).Security26‑Oct‑2026
d8ed74d4 Search Server's in-memory cache entry limit is now capped during index rebuilds, preventing out-of-memory errors on large catalogs.26‑Oct‑2026
6972df50 Fixed an issue where concurrent reads of cached product attributes caused threads to spin indefinitely, driving CPU usage up until the service was restarted.23‑Oct‑2026
0ea5490d Updated the ActiveMQ container image to allow tuning ActiveMQ storeUsage and tempUsage limits and totals. Default values are set in the image but can be overridden with new container environment variables.Build Tools23‑Oct‑2026
b6d1ce8d Fixed an intermittently failing deadlock retry integration test that could exhaust its retry budget due to a livelock, and added a missing error log when all retry attempts are exhausted.22‑Oct‑2026
a3f1c4a5 Fixed an issue where upgrading across a major Lucene version permanently broke search indexes, causing all storefront and Commerce Manager searches to return no results.21‑Oct‑2026
fcb759a5 Fixed an issue where orders with three or more partial captures against the same payment reservation failed with a duplicate key error, leaving orders partially charged and requiring manual intervention.21‑Oct‑2026
eff081f1 The Operational Insights report now includes OpenJPA level 2 data caches alongside application caches, giving operators visibility into the memory footprint of the persistence cache tier.21‑Oct‑2026
0082d418 Removed msgpack-core dependency to address CVE-2026-90472.Security20‑Oct‑2026
c3d33f9c Upgraded Logback from 1.6.3 to 1.6.5 and SLF4j from 2.0.18 to 2.0.19 to address CVE-2026-104721.Security20‑Oct‑2026
afaee13f Updated the Cortex Studio CSS compiler dependency to address 8 Javascript vulnerablilities.20‑Oct‑2026
a2062159 Product-developer-only AI agent guidance, including upgrade recipe review requirements, have been removed from what is distributed.19‑Oct‑2026
a768bf94 Fixed an issue where keyword searches with long multi-word phrases returned no results due to the search server rejecting queries that exceeded its maximum clause count.Data model changes14‑Oct‑2026
9087b227 Fixed an issue where Commerce Manager failed to load extension classes that used the Log4j 2 API directly.15‑Oct‑2026
22927c38 The Operational Insights Data Shape section now includes a record count for the index notification table (TINDEXNOTIFY).14‑Oct‑2026
e974f4a0 @ResourceRepository and @ResourceService annotations can now be used in non-prototype classes such as permission parameter strategies without requiring a configurePrototypes workaround.14‑Oct‑2026
212833dd Fixed an issue where eight Cortex storefront resources evaluated every promotion rule twice per request, causing redundant pricing calculations when rendering cart totals, discounts, and applied promotions.14‑Oct‑2026
e3c589b8 Upgraded certified Java version from 21.0.9 to 21.0.12.Security9‑Oct‑2026
2f4f5101 Fixed an issue where the Search Server threw OutOfMemoryError during index rebuilds because queued index notifications were loaded entirely into memory before deletion.8‑Oct‑2026
23a96f4d Fixed XML external entity injection vulnerabilities in the Import/Export module that allowed crafted import payloads to read server files or trigger outbound requests from the server.Security7‑Oct‑2026
eb5c6210 Replaced the unmaintained com.github.java-json-tools:json-schema-validator library with com.networknt:json-schema-validator 2.0.7 to resolve three security vulnerabilities (CVE-2026-86321, CVE-2026-86511, CVE-2026-86513).Security7‑Oct‑2026
1d8b7592 Updated AI guidance documentation to require JUnit Jupiter (JUnit 6) and AssertJ for new test classes.6‑Oct‑2026
be49a81b Fixed multiple reliability issues in Operational Insights report generation.6‑Oct‑2026
6f475688 Upgraded Extension Point Framework connectivity library build to Java 21.Security6‑Oct‑2026
c562d0ad Upgraded Tomcat from 10.1.59 to 10.1.60 to address CVE-2026-86350, CVE-2026-77762, CVE-2026-78383, CVE-2026-78437, CVE-2026-75973, CVE-2026-73581, CVE-2026-77756.Security2‑Oct‑2026
fae6d679 Upgraded Jackson from 2.22.1 to 2.22.3 to address CVE-2026-83557, CVE-2026-19032, CVE-2026-68497, CVE-2026-89425, CVE-2026-89407, CVE-2026-91776, CVE-2026-91777.Security2‑Oct‑2026
b60d5f33 Trimmed the AI agent instructions file (AGENTS.md) by removing content that can be inferred from the repository.1‑Oct‑2026
97acee0b Fixed an issue where importing an order with a mixed-case store code failed with a foreign key violation.1‑Oct‑2026
dba71e21 Fixed an issue where scenarios with escaped pipe characters in feature files were silently skipped during parallel test runs due to a parsing error in the cucable plugin.1‑Oct‑2026
313556cb Upgraded ActiveMQ from 5.19.10 to 5.19.11 to address CVE-2026-74761.Security Build Tools29‑Sep‑2026
6d8b9cfb Fixed a security defect where an account cart was incorrectly accessible under a different account's URI when the buyer was associated with both accounts.Security29‑Sep‑2026
cbf810e7 Fixed an issue where Cortex permission checks bypassed a required pre-check and passed resource identifiers from unrelated resource types to parameter resolution strategies.28‑Sep‑2026
da338e1d Operational Insights cache sizing now uses a custom heap estimator that requires no JVM flags, replacing the previous engine that failed or silently under-reported on modern JVMs.27‑Sep‑2026
31dadfcd Upgraded Spring Framework from version 6.2 to 7.0, along with Spring Security, Spring Data, Apache Camel, and related dependencies, resolving 15 CVE vulnerabilities.Security27‑Sep‑2026
3be1ffbb Upgraded ant from 1.10.14 to 1.10.18 to address CVE_2026-78254.27‑Sep‑2026
0ae8c273 Removed unused t-digest 3.3 dependency to address CVE-2026-87822, CVE-2026-87962.Security27‑Sep‑2026
60c49d8c Upgraded the Node.js version used to build Cortex Studio from 6.x to 26.x.26‑Sep‑2026
b3af26f5 Removed unused snappy-java 1.1.10.8 dependency to address CVE-2026-90559.Security26‑Sep‑2026
838b22d0 Upgraded Zookeeper from 3.9.5 to 3.9.6 to address CVE-2026-79993, CVE-2026-59969, CVE-2026-59739, CVE-2026-84439, CVE-2026-84501.Security26‑Sep‑2026
5cfbac5d Upgraded the certified PostgreSQL 16 Amazon Aurora version from 16.10 to 16.14.26‑Sep‑2026
0942eae5 Upgraded the certified MySQL 8.4 RDS version from 8.4.8 to 8.4.11.26‑Sep‑2026
d1e704ae Upgraded the certified MySQL 8.0 RDS version from 8.0.43 to 8.0.46.Security26‑Sep‑2026
c3e96f1c Upgraded Jetty from 12.1.10 to 12.1.12 to address CVE-2026-19203, CVE-2026-12611.Security25‑Sep‑2026
1b02f049 Upgraded JUnit 5.x to JUnit 6.x; all existing JUnit 4 and 5 tests continue to work without modification.Security24‑Sep‑2026
a65728b3 Build stability improvements.21‑Sep‑2026
01363b73 Added ability for Import/Export to convert an existing product to a bundle, or a bundle to a product.21‑Sep‑2026
7a01f5eb Cleaned up Cortex Studio npm dependencies by dropping unused packages and bringing package-lock.json back in sync with package.json.19‑Sep‑2026
b2dd9f9b Fixed an issue where completing a physical shipment paid with a retried charge incorrectly marks the order as failed and throws an unhandled exception.17‑Sep‑2026
68a4234b Banned BouncyCastle dependencies in the build enforcer due to the number of vulnerabilities that they constantly raise.Security17‑Sep‑2026
d2168a8b Fixed an issue where upgrading Logback to 1.6.x caused JLine stack traces to appear in the Cortex startup logs and silently broke colorised console output for local development.17‑Sep‑2026
0d1188f9 Fixed an issue where PromoIQ REST endpoints return a generic "Invalid JSon payload." error with no diagnostic detail when a malformed or incomplete JSON body is submitted.16‑Sep‑2026
8594ec7a Removes MySQL 5.7 (RDS and Aurora) entries from the certified database configuration file so the database support report accurately reflects supported technologies.16‑Sep‑2026
c225a65b Upgraded OpenTelemetry from 1.56.0 to 1.62.0 to address CVE-2026-45292Security16‑Sep‑2026
f84b5f3d Renames the Tomcat build tools configuration file from server9.xml to server.xml to remove a misleading version suffix.Build Tools15‑Sep‑2026
abca53f0 Upgraded Camel from 4.18.3 to 4.18.4 to address CVE-2026-59230.Security15‑Sep‑2026
e61f6c44 Upgraded jsoup from 1.15.3 to 1.23.1 to address CVE-2026-71497.Security15‑Sep‑2026
ecfb5459 Removed the unused metrics-graphite dependency from the search module, eliminating the vulnerable RabbitMQ client library (CVE-2026-63337, CVSS 9.0).Security15‑Sep‑2026
b96ddd97 Upgraded Tomcat from 10.1.55 to 10.1.59 to address multiple high-severity vulnerabilities.Security15‑Sep‑2026
d207c842 Upgraded Apache ActiveMQ from version 5.19.6 to 5.19.10 to address 8 vulnerabilities with scores from 5.9 to 8.8.Build Tools14‑Sep‑2026
56767344 Upgraded Postgresql JDBC driver from 42.7.11 to 42.7.13 to address CVE-2026-54291.Security14‑Sep‑2026
628f192d Upgraded Netty from 4.1.136.Final to 4.1.137.Final to address CVE-2026-75595 and CVE-2026-75596.Security14‑Sep‑2026
b3a1794e Upgraded Spring Data from 3.4.5 to 3.5.13 to address four security vulnerabilities (CVE-2026-41695, CVE-2026-41716, CVE-2026-41711, CVE-2026-41721).Security11‑Sep‑2026
86f14b7a Upgraded Logback from 1.5.35 to 1.6.3 to address CVE-2026-19880.Security11‑Sep‑2026
a6e60d09 Fixed an issue where zooming into account sub-resources silently drops the zoomed section from the response due to an UnsupportedOperationException thrown during permission resolution.10‑Sep‑2026
71fa3f3d Fixed an issue where multiple Commerce Manager instances can claim and execute the same CSV import job concurrently, causing duplicate data.Data model changes10‑Sep‑2026
6ea5ff7d Replaces the unmaintained org.fusesource.jansi:jansi 1.18 library with org.jline:jansi 4.3.1.8‑Sep‑2026
0ccefc48 Upgraded Apache Solr from version 9.x to 10.x, resolving several security vulnerabilities and removing the need for the Jakarta EE compatibility wrapper.Security1‑Sep‑2026
874ce4ee Fixed an issue where transacted JMS consumers open and tear down a real TCP connection to the ActiveMQ broker on every receive cycle, causing significant connection churn at idle and under load.1‑Sep‑2026
c014cb7d Fixed an issue where MySQL upgrade tests on 8.5.x fail with a datetime truncation error caused by test price list assignments being created with a start date at or too close to the Unix epoch.31‑Aug‑2026
74803f6c Fixed an issue where Camel JMS request-reply (InOut) routes fail with an IllegalArgumentException after connection pooling changes removed a required connection factory property.28‑Aug‑2026
35718876 Fixed an issue where OpenID Connect token exchange requests send a malformed scope parameter, causing sign-in to fail with Microsoft Entra ID.27‑Aug‑2026
e13653c9 Upgraded httpclient5 from 5.6.2 to 5.6.4 to resolve CVE-2026-71290, CVE-2026-64607.Security25‑Aug‑2026
3f1ab672 Build stability improvements.21‑Aug‑2026
b89c1d6d Updated the ActiveMQ container entrypoint to ensure signals reach the broker JVM process.Build Tools21‑Aug‑2026
ca934ad1 Fixed an issue where importing a registered customer whose username already exists in the target store causes the entire import batch to fail with a raw duplicate key database error.Data model changes20‑Aug‑2026
fe33d60d Removed the Spring Batch dependency from Commerce Manager by replacing the price list CSV export with a direct opencsv-based implementation, resolving CVE-2026-41710.Security19‑Aug‑2026
5a0017e4 Upgraded Tomcat from 10.1.56 to 10.1.57 to address CVE-2026-59084, CVE-2026-59083.Security19‑Aug‑2026
4bc232ed Fixed an issue where a Software Composition Analysis security scan falsely reports Bouncy Castle vulnerabilities by excluding unused Shiro crypto dependencies from the Maven dependency graph.Security19‑Aug‑2026
6f9d0055 Fixed an intermittent cache eviction error during search indexing caused by several Ehcache cache key classes not implementing Serializable.18‑Aug‑2026
9db1f23f Upgraded Log4j from 2.25.4 to 2.26.1 to address CVE-2026-49844.Security18‑Aug‑2026
3fc9d45a Upgraded Jackson from 2.21.4 to 2.22.1 to address CVE-2026-59889, CVE-2026-54515.Security17‑Aug‑2026
fb15b3b8 Upgraded Netty from 4.1.135.Final to 4.1.136.Final to address CVE-2026-59901.Security17‑Aug‑2026
368e6640 Fixed an issue where Cucumber test suites silently pass when step definitions are missing or unimplemented, by enabling strict mode across all 17 Java runners and 7 parallel runner templates.13‑Aug‑2026
e7fbcb47 Fixed spurious "Unrecognized collection class" warnings logged by StrictDetachmentStrategyImpl in Cortex whenever an entity with a null collection-valued association is detached before caching.13‑Aug‑2026
cc68ef64 Fixed a bug where transacted JMS routes built on CRSCEnabledRouteBuilder consume only one message and stall permanently, by removing the onCompletion hook that deadlocks the consumer thread on Camel 3 and later.13‑Aug‑2026
8f7accc8 Fixed a bug in Commerce Manager where saving a customer record after adding a new address caused the address to appear duplicated in the address list.13‑Aug‑2026
795ab4d4 Fixed an issue where the coupon table migration generates random GUID values, causing the same coupon records to have different identifiers across environments, breaking data synchronization and import/export matching.13‑Aug‑2026
171d0bf7 Replaces bespoke advanced time condition tags and operators with evaluation using a new iCalMatch operator and the ical4j library, with no changes to the user interface.Data model changes12‑Aug‑2026
1fd95675 Fixed intermittent test failures where the ORDER_CREATED message assertion fails because the message is consumed before the listener is fully initialized.7‑Aug‑2026
0069d251 Fixed an issue where Selenium tests intermittently fail with a stale element reference error when calling click, doubleClick, or setChecked on a RAPTable row, resolved by adding retry logic to each method.7‑Aug‑2026
83bbd46f Parallelizes previously serial isolated Cucumber regression tests by scoping test data and configuration to unique stores, catalogs, and scenarios per test run, reducing pipeline duration by approximately 20–30 minutes.6‑Aug‑2026
0ad9d939 Fixed issue with Cortex Studio issuing a redundant GET request after a followlocation form POST.4‑Aug‑2026
558814fe Improves Commerce Manager Selenium test reliability by removing broken stale-element wait methods, consolidating redundant wait call stacks, introducing stale-safe RAP widget wrappers, and cleaning up dialog handling.4‑Aug‑2026
8305f60d Fixed incorrect equality, hash code, and string representation behavior due to missing annotation parameters in the XPFHttpCookie class.4‑Aug‑2026
efce6c2b Fixed incorrect @EqualsAndHashCode and @ToString annotations in the XPFDeliveryPolicy class.29‑Jul‑2026
91e74ff6 Removed unused Cortex bundles wrapped-spring-security-config, wrapped-spring-security-data, wrapped-spring-data-commons.Security28‑Jul‑2026
fb4945a3 Fixed an issue where the XPFOrderHold default constructor fails to initialize the non-null holdDescription and orderHoldStatus fields.28‑Jul‑2026
e5c62d57 Upgraded parsson from 1.1.7 to 1.1.9 to address CVE-2026-9563.Security28‑Jul‑2026
0382c7cc Upgraded Camel from 4.18.2 to 4.18.3 to address CVE-2026-42527, CVE-2026-43866, CVE-2026-46584.Security27‑Jul‑2026
26663b0e Upgraded httpcore5 from 5.3.6 to 5.4.3 and httpclient5 from 5.5 to 5.6.2 to address CVE-2026-54399 and CVE-2026-54428.Security24‑Jul‑2026
9bb0fad2 Adds a new downloadChecksumWithAlgorithm field to ops-spec.json for all four tool entries (Java, Maven, Tomcat, ActiveMQ), enabling vendor-published SHA-256/SHA-512 hashes to be used directly instead of manually calculated MD5 values.Build Tools23‑Jul‑2026
9eb03b9a Fixed intermittent parallel Maven build failures with "Could not acquire write lock" on a cold local cache by increasing the artifact lock acquisition timeout from 30 to 120 seconds.23‑Jul‑2026
9a1981c9 Fixed a race condition in CustomerCreationFilter where simultaneous customer creation across multiple Cortex instances could result in an error instead of returning the existing customer record.23‑Jul‑2026
4c9c070b Upgraded Tomcat from 10.1.55 to 10.1.56 to address CVE-2026-55276, CVE-2026-53404, and CVE-2026-55956.Security22‑Jul‑2026
87a74cb8 Operational Insights revenue metrics now only count completed orders, using the order completion date instead of the creation date, preventing historical revenue figures from changing retroactively.17‑Jul‑2026
2cb2ee60 JMS message consumers now use dedicated, non-pooled connections instead of shared pooled connections, preventing consumers on low-traffic queues from becoming stranded when a broker connection fails silently.16‑Jul‑2026
893a077a Upgraded Jackson from 2.21.2 to 2.21.4 to address CVE-2026-54513, CVE-2026-54512, CVE-2026-54516, CVE-2026-54514, CVE-2026-54517.Security15‑Jul‑2026
cd029d1b Fixed issue with bundle price list cache using excessive memory due to holding entire ProductBundle in the cache key.14‑Jul‑2026
959d32be Improved resolution of agreements icons in Commerce Manager.14‑Jul‑2026
20159017 Added an upgrade recipe that removes obsolete wrapped-antlr-runtime Maven dependencies.14‑Jul‑2026
9bb64cce The promotion rule recompilation trigger interval has been reduced from 5 minutes to 10 seconds by default, and the delay and interval are now configurable via the ep.rule.compilation.delay and ep.rule.compilation.interval properties.14‑Jul‑2026
09ec2074 The Create/Edit Price List Assignment wizard in Commerce Manager now correctly shows 6 steps instead of 5, and the Advanced Time Conditions page heading is now consistent with the other wizard steps.14‑Jul‑2026
2c0da4c6 Fixed an issue where unit tests failed with a missing class error when run from IntelliJ by restoring the Hamcrest Core transitive dependency in JUnit 4 and upgrading it to version 2.x.14‑Jul‑2026
0036352b Upgraded Logback from 1.5.32 to 1.5.35 to address CVE-2026-9828, CVE-2026-10532, and CVE-2026-13006 (fix for previous commit).Security14‑Jul‑2026
e14ad733 Upgraded Logback from 1.5.32 to 1.5.35 to address CVE-2026-9828, CVE-2026-10532, and CVE-2026-13006.Security14‑Jul‑2026
77e11435 Upgraded Spring Security from 6.5.10 to 6.5.11 to address multiple vulnerabilities (fix for previous commit).Security8‑Jul‑2026
850213a6 Upgraded Spring Security from 6.5.10 to 6.5.11 to address multiple vulnerabilities.Security7‑Jul‑2026
e3c80bbe Upgraded Netty from 4.1.133.Final to 4.1.135.Final to address CVE-2026-45416, CVE-2026-50010, and CVE-2026-44249.Security7‑Jul‑2026
5d650e53 Upgraded Spring from 6.2.18 to 6.2.19 to address multiple vulnerabilities.Security6‑Jul‑2026
331817be Upgraded Shiro from 1.13.0 to 2.2.1 to address CVE-2026-23901, CVE-2026-43828, and CVE-2026-49268.Security2‑Jul‑2026
bec9ba83 Upgraded certified PostgreSQL version from 16.10 to 16.14.Security27‑Jun‑2026
52fdd9b7 Upgraded certified Oracle version from 19.0.0.0.ru-2025-10.rur-2025-10.r1 to 19.0.0.0.ru-2026-01.rur-2026-01.r3.Security27‑Jun‑2026
0fedf2f2 Validation warnings now appear in the promotion wizard for currency, shipping service level, product attribute, SKU attribute, and cart item modifier fields when an unrecognized code is entered.26‑Jun‑2026
78bb2094 Fixed an issue where cart recurring cost totals were calculated incorrectly when multiple subscription items with different agreement lengths had overlapping billing periods, including rollover scenarios.26‑Jun‑2026
d2b076c8 The Commerce Manager test-util module no longer uses PhantomJS to run JavaScript tests, fixing build failures on systems with OpenSSL 3.x (such as Debian Trixie); tests now run via HtmlUnit and JUnit.26‑Jun‑2026

Badge legend​

  • Security: Indicates that the patch includes security fixes.
  • Performance: Indicates that the patch improves system performance.
  • Data model changes: Indicates that the patch includes Liquibase scripts that make changes to the data model.
  • Requires downtime: Indicates that the Self-Managed Commerce services should be shut down while the Data Population Tool is executed.
  • Build Tools: Indicates that the patch includes changes to Build Tools.

8.8.0​

Released: June 2026

Release highlights​

Recurring pricing​

Support has been added to allow business users to define subscription-style pricing — such as weekly, monthly, quarterly, or annual billing — alongside existing one-time (up-front) pricing. Shoppers can be given the option to choose from different recurring billing options or to pay up front when adding an item to their cart. New Cortex APIs have been added to return the estimated recurring charges for all items in the shopping cart.

A new Agreement domain model has been introduced to enable recurring pricing for products on the Self-Managed Commerce platform. Each Agreement captures key contract details including interval type, billing frequency, agreement length, end behaviour (ROLLOVER or EXPIRE), and whether the subscription may be paused or cancelled.

Agreements can be optionally associated with both products and price lists. Price list base amounts have been extended with two new fields — recurring_list_price and recurring_sale_price — which are only valid when an agreement is linked to the price list. Recurring prices support context-based variation just like up-front prices, allowing flexible selling scenarios.

Cortex now exposes recurring pricing information on cart line items and on the overall cart total. For each line item, both the unit recurring list price and purchase price are displayed. For the cart total, recurring costs are aggregated across all applicable line items. Prices are organized by billing interval (for example, monthly or every three months) and broken down into period ranges with start and end points. Prices that apply beyond the end of an agreement term are flagged as rollover and estimated prices.

Commerce Manager users can create new Agreements using a dedicated Create Agreement wizard. The wizard is accessible via a Create Agreement button in both the main Price List Management toolbar and the Agreements search results view pane toolbar. Users can also associate Agreements with Products and assigned Product Bundles through a new Agreement Association tab in the Product and Product Bundle editors.

For more information see Recurring Pricing.

note

Currently, shoppers will be blocked from completing checkout if their cart contains line items associated with an agreement. When such items are detected, the purchase form will display a structured error message with the ID cart.contains.line.item.associated.to.agreement. This is a temporary safeguard put in place because recurring/subscription billing fulfillment is not yet fully supported. For businesses with a backend billing system, the AgreementLineItemShoppingCartValidatorImpl validator can be disabled.

A future release of Self-Managed Commerce will provide support for recurring billing of purchases with line items associated to agreements.

Optional dependent items​

Merchants can now configure Optional Dependent Item product associations, allowing suggested dependent products to be presented to shoppers during add-to-cart operations. Unlike the existing "Auto Dependent Item" association (which adds items to the cart automatically), optional dependent items are displayed as choices that shoppers can explicitly add or remove. This gives merchants greater flexibility in cross-sell and upsell scenarios without forcing unwanted items into the cart.

Bundle products are not supported as the source product for optional dependent associations. This restriction is enforced in the Commerce Manager UI (the "Optional Dependent Item" tab is hidden when editing a bundle product) and during data import.

For more information see Optional Dependent Items.

Deferred customer and shopper record creation for single-session users​

Previously, every public access token request resulted in the immediate creation of a single-session customer record in the database. This allowed bots and web scrapers that only checked product availability to generate millions of customer records per day, overwhelming the scheduled cleanup jobs. Customer and shopper records for single-session (anonymous/public) users are now created lazily — only when a resource that actually requires them (such as a cart or profile) is first accessed. Users who only browse navigations, offers, categories, or prices will no longer have database records created on their behalf.

note

Any client lookup request to the /carts/{scope}/default resource will result in a customer and shopping cart record being created. Since many eCommerce sites include a cart icon that shows the number of items in the cart, your front-end may be making this request on every page load. Therefore, we recommend that you add logic on your front-end to avoid making this call for anonymous shoppers until a known add-to-cart operation has been done. A flag could be stored in browser local storage to determine if the cart count lookup is required.

New promotion conditions for cart item modifiers​

Two new promotion conditions have been added to the Self-Managed Commerce promotion engine, enabling merchants to create promotions that trigger based on cart item modifier fields and their values.

The cart-level condition (Line item with cart item modifier [] having value [] is in the shopping cart) evaluates whether any line item in the shopping cart has a specific cart item modifier field set to a specified value.

The item-level condition (Line item cart item modifier [] has value []) evaluates individual line items, enabling per-item discounts to be applied only to those line items that have the specified modifier field and value.

For more information see Promotion Rule Conditions.

Support for nested AND/OR condition groups in promotion configuration​

Promotion rules can now use nestable AND/OR condition groups to express complex boolean logic for conditions. Previously, all conditions on a promotion were evaluated using a single flat AND or OR operator. With this change, conditions can be organized into a tree structure — for example, a promotion can fire when (Brand is X AND quantity > 2) OR (Brand is Y AND quantity > 2 AND (Color is Red OR Color is Yellow)). This unlocks significantly more expressive and targeted promotional logic without requiring custom extensions.

The Commerce Manager promotions editor also now supports these more complex nested promotion conditions. Merchants can create condition groups with AND/OR operators, nest groups within groups, add or remove conditions at any level of the hierarchy, and switch operators between AND and OR using drop-down controls. The hierarchical structure is displayed using indented, bordered containers with alternating background colors to make nesting depth easy to read. An error is shown if a group is left empty, preventing the rule from being saved in an invalid state.

Import/export support has been updated to handle condition groups. Promotions exported from or imported into the system will reflect the full condition group tree using nested <and> and <or> XML elements.

For more information see Promotion Rules.

Advanced time conditions for promotions and price list assignments​

Merchants can now create promotions and price list assignments that activate only during specific, recurring time windows — going well beyond simple start/end date ranges. Supported patterns include hour-of-day windows (e.g., happy hours from 5–7 PM), day-of-week restrictions (e.g., weekend-only sales), day-of-month targeting (e.g., payday specials on the 1st and 15th), specific date inclusion or exclusion (e.g., Black Friday, excluding holidays), and custom interval-based recurrence (e.g., every 3 days from a given start date).

To support this, Commerce Manager now provides a dedicated Time Conditions configuration page for both promotions and price list assignments. Merchants can choose between keeping a promotion or price list assignment active throughout its entire date range (the default behavior) or restricting activity to specific time windows. When specific time windows are selected, merchants can add one or more windows using an intuitive dialog that supports scheduling by days of the week, days of the month, specific dates, or recurring intervals, combined with flexible time-of-day ranges. Exceptions such as excluded weekdays or specific blackout dates can also be added to each window. Configured windows are displayed as at-a-glance summary cards.

For more information see Promotion Rules.

Ability for Buyers to view and edit shared account carts​

Buyers associated with the same account can now view and edit all shopping carts belonging to that account, enabling collaborative purchasing workflows within B2B account hierarchies. Access is governed by role-based permissions: users with the OWNER Shiro role can read and browse account carts, while the new MODIFY_CARTS Shiro role grants full create, read, update, and delete access to carts within an account.

A new carts sub-resource has been added to the accounts API ({account}/carts), allowing buyers to list and access all active carts associated with their account. Cart descriptor responses now include an owner field containing the email address of the buyer who originally created the cart, making it easier to identify cart ownership in multi-buyer scenarios.

For more information see Read carts from account.

Peak Mode: Pause non-critical batch jobs during high-traffic events​

A new "peak mode" capability has been introduced that allows operators to temporarily disable non-critical background batch jobs during peak transactional periods (e.g., product launches or promotional events). This ensures that system resources are fully available for order processing rather than being consumed by cleanup and maintenance tasks. When active, non-critical jobs such as abandoned cart cleanup, anonymous customer purge, OAuth2 token cleanup, import job cleanup, data point processing, and others are skipped automatically. Critical jobs — including shipment release ( releaseShipmentsJob), inventory journal rollup (inventoryJournalRollupJob), and outbox message relay (relayOutboxMessagesJobInvoker) — are never paused and continue to run normally.

A Job Pause Settings screen has been added to the Configuration section of Commerce Manager, enabling administrators to enable and pre-schedule the job pause functionality. The UI supports pausing immediately for a preset duration (15 minutes, 30 minutes, 1 hour, 2 hours, 4 hours, or 8 hours), scheduling a pause to begin at a future date and time, pausing indefinitely until manually resumed, and cancelling or modifying an active or scheduled pause. Current pause status, start time, and expiration time are displayed in the user's local timezone, and the screen auto-refreshes every 60 seconds to reflect the latest state.

Access to the Job Pause Settings screen is controlled by a new permission, ADMIN_JOBS_PAUSE_MANAGE. Administrators who should be able to manage job pauses must be assigned a role that includes this permission. Teams that define their own Commerce Manager user roles should review these roles to determine whether ADMIN_JOBS_PAUSE_MANAGE should be granted.

Integration Server REST API for Shipping Notifications​

A new REST endpoint has been added to the Integration Server to allow external systems to notify Self-Managed Commerce when a shipment has been shipped. Previously, the only supported mechanism for completing a shipment — which triggers payment capture and updates the order status to COMPLETE — was through Commerce Manager, which was impractical for enterprise-scale operations and typically led customers to build custom integrations. The new POST /shipping/v1/shipments/complete-shipment endpoint accepts a shipment number and an optional carrier tracking number, and is secured with HTTP Basic authentication.

The API is designed with idempotency in mind: if a shipment has already been completed (e.g., due to a duplicate or concurrent request), the endpoint returns a 409 Conflict response rather than an error, allowing calling systems to safely retry without risk. Standard error responses are returned for invalid requests (400), shipment not found (404), and unexpected failures (500). An OpenAPI/Swagger specification is available at /shipping/v1/shipments/api-docs.

For more information see Shipment Completion API.

AI coding assistant context​

An AGENTS.md file and a suite of supplementary AI context guides have been added to the ep-commerce repository to help AI coding tools (such as GitHub Copilot, Claude, and similar assistants) understand the platform's structure, conventions, and best practices. The guides cover coding standards, extension approaches (Extension Modules and the Extension Point Framework), Cortex REST API patterns, performance guidelines, testing practices, and how to search the codebase effectively.

For customer implementation teams, the documentation reinforces which areas of the codebase are safe to modify and how to use extension mechanisms to maintain upgrade compatibility. It also provides quick-reference patterns for entities, services, Spring configuration, data mappings, Liquibase schema changes, and more. These files are intended to reduce onboarding friction, improve AI-assisted code generation quality, and promote consistent implementation patterns across both core and extension development.

Automatic IntelliJ IDEA resolution of Eclipse P2 plugin dependencies for Commerce Manager​

Developers working on Commerce Manager customizations in IntelliJ IDEA no longer need to manually configure Tycho/Eclipse P2 dependencies so that Commerce Manager dependencies are resolved. Previously, this required a complex and error-prone setup process documented in a separate support article. Eclipse RAP and other P2 plugin classes are now resolved automatically when the project is opened in IntelliJ.

To support this, three new Maven modules have been added under commerce-manager/cm-modules/eclipse-p2-platform: a feature module declaring all required Eclipse P2 plugins, a repository module that packages them into a P2 repository ZIP, and an intellij-support module that unpacks those plugin JARs and aggregates their classes into a single Uber JAR. This Uber JAR is wired into the project using a Maven profile (activeInIdea) that activates automatically in IntelliJ IDEA environments, using system scope for reliable resolution.

Developers who have customized Commerce Manager plugins (including extensions under ext-cm-modules) will benefit from this change automatically, as the activeInIdea profile has been applied to both the core cm-plugins and the ext-plugins modules. No changes to existing customizations are required, and the standard Maven build is unaffected.

Customizable Checkstyle suppressions for extensions modules​

A new Checkstyle suppressions file has been introduced specifically for code under the extensions folder (extensions/code-checking-rules/src/main/resources/rulesets/suppressions/checkstyle-elasticpath-extensions.xml). This separates the code quality enforcement between the core Elastic Path Product team and project team customizations, allowing the Product team to introduce stricter Checkstyle rules in the platform without inadvertently breaking builds for extension code.

Project teams can now tailor Checkstyle enforcement for their custom code by modifying this suppressions file — adding suppressions to relax rules or removing them to enforce stricter standards. To minimize upgrade conflicts, custom suppressions should be added in the designated section of the file, below the comment marked for project team use.

Added ast-grep recipes for structured search and replace during patching and upgrades​

The Self-Managed Commerce source code repo now includes a new folder structure for automated ast-grep upgrade recipes. These recipes are designed to automatically transform customer customization code when upgrading between platform versions, significantly reducing the manual and AI effort required when breaking changes are introduced — such as migrations to Jakarta EE, Spring 6, or JUnit 5.

The new upgrade/recipes/<version>/ directory structure organizes transformation recipes by target version, with each recipe defined as a flat YAML file. An AI recipe authoring guide (ai/ast-grep-recipes.md) has also been added, documenting tested patterns for Java and XML code transformations, critical authoring rules (e.g., uppercase metavariable names, atomic single-line fix templates), design principles, and debugging techniques.

These recipes are read and executed by the Self-Managed Commerce Upgrader Tool when running in AI Assist Mode. These transformations are executed before Claude attempts to fix any issues, so that relatively simple transformations can be completed without unnecessary AI token use.

PromoIQ: Externalized promotions APIs​

New REST API endpoints have been introduced in the ep-promoiq-api Integration Server module to expose the PromotionsCalculator extension point. These APIs enable external promotion engines to integrate with the Self-Managed Commerce platform by delegating promotion evaluation, rule retrieval, and coupon management operations over HTTP.

The following capabilities are now available via REST:

  • Evaluate promotions for catalog items and shopping carts
  • Retrieve promotion rules by GUID
  • Look up coupons by GUID or coupon code
  • Retrieve applicable coupon codes for a customer and store
  • Validate coupon rule and usage for checking suspension status and remaining uses
  • Trigger actions at checkout for executing actions on applied promotions during the checkout process
  • Disable coupon auto-apply for a customer's cart

An OpenAPI specification (v1.0) is available for all PromoIQ REST APIs, accessible by calling the GET /promoiq/v1/promotions/api-docs endpoint.

A new embedded Extension Point Framework extension, PromoIQPromotionsCalculator, has been introduced to support delegating promotion evaluation to the PromoIQ APIs running on a separate instance. This extension implements the PromotionsCalculator extension point and handles all key promotion operations. This enables merchants to offload complex promotion logic to a separate Self-Managed Commerce environment rather than relying on the built-in promotion engine.

A new system configuration setting COMMERCE/SYSTEM/PROMOIQ/enable (defaulting to false) has been introduced to gate access to the PromoIQ promotion evaluation REST APIs. When disabled, all PromoIQ API requests return an HTTP 403 with the message PromoIQ feature is disabled.

For more information see PromoIQ API.

note

Use of the PromoIQ APIs requires a separate license for production use — contact your Customer Success Manager for details.

Java 21​

Self-Managed Commerce now requires a Java 21 JDK for builds and a Java 21 JRE at runtime.

Supporting Java 21 provides several benefits:

Additionally, the Java 21 upgrade required us to update many library dependencies to newer versions that provide Java 21 support. These upgrades further improve security and stability of the application.

For more information about upgraded dependencies, see Dependency Changes.

Multiple extension point framework improvements​

See the Extension Point Framework release notes.

Fixed issues​

Core​

Replaced deprecated ServiceMix dependencies with Elastic Path-maintained wrapped bundles​

The Apache ServiceMix project has been retired and will no longer release new versions. To ensure long-term supportability of the Self-Managed Commerce platform, the ServiceMix bundle dependencies have been removed and replaced with custom OSGi-wrapped bundles created and maintained by Elastic Path. These new bundles are published under the Maven group ID com.elasticpath.wrappedbundles and cover key libraries including Spring Framework modules, AspectJ, EhCache, ANTLR, and Commons Collections.

Improved promotion category exclusion handling for products in overlapping category hierarchies​

When configuring a promotion condition such as "at least 1 item from category A, excluding items from subcategory B," products assigned to both the parent category A and the excluded subcategory B are now correctly treated as eligible for the promotion. Previously, such products were incorrectly excluded, preventing the promotion from applying even though the product was directly assigned to the intended included category. Products that belong to an excluded category that is not part of the included category hierarchy remain ineligible as expected.

For example:

Given the following category structure:

,--------------.
|Category T1_L1|
|--------------|
`--------------'
|
,--------------. ,--------------.
|Category T1_L2| |Category T2_L1|
|--------------| |--------------|
`--------------' `--------------'
| |
,--------------. ,--------------.
|Category T1_L3| |Category T2_L2|
|--------------| |--------------|
`--------------' `--------------'

Assume that we have the following products:

  • ProductX which belongs to categories T1_L1 and T1_L3.
  • ProductY which belongs to category T1_L3 only.
  • ProductZ which belongs to categories T1_L3 and T2_L2.

And assume we have the following cart promotions:

  • ExcludedCategoryTestPromotion:
    • Condition: [At Least] [1] items of category [T1_L1] are in the shopping cart, excluding items of category [T1_L2]
    • Action: Get [50]% off [1] items in category [T1_l1], excluding items of category [T1_L2]
  • ExcludedCategoryTestPromotion2:
    • Condition: [At Least] [1] items of category [T1_L1] are in the shopping cart, excluding items of category [T2_L1]
    • Action: Get [10]% off [1] items in category [T1_l1], excluding items of category [T2_L1]

Then the promotions will apply as follows:

  • ExcludedCategoryTestPromotion promotion applies to ProductX because it is assigned to included category T1_L1, and the excluded T1_L3 category is ignored because it is a descendent.
  • ExcludedCategoryTestPromotion promotion does not apply to ProductZ because it is assigned to category T1_L3, which is a descendent of excluded category T1_L2.
  • ExcludedCategoryTestPromotion2 promotion applies to ProductY because it is assigned to category T1_L3, which is a descendent of category T1_L1.
  • ExcludedCategoryTestPromotion2 promotion does not apply to ProductZ because it is assigned to category T2_L2, which is a descendent of excluded category T2_L1.
Fixed several issues that were causing InvalidStateException to be thrown​

Intermittent InvalidStateException: The context has been closed exceptions were being thrown in several Self-Managed Commerce services, especially under high load.

One cause was that several JPA query executor classes (NamedQueryWithListExecutor, NamedQueryExecutor, DynamicQueryExecutor, and JpaPersistenceEngineImpl) were casting JPA Query objects to OpenJPAQuery via OpenJPAPersistence.cast() in order to use the setParameters() convenience method. This cast forced Spring's DeferredQueryInvocationHandler to immediately materialize the underlying EntityManager. When no transaction-bound EntityManager was available, Spring created a temporary one, used it to create the query, then closed it — leaving the query referencing a closed broker and causing the subsequent setParameter() call to fail. This was fixed by removing all uses of OpenJPAPersistence.cast() from query executor classes and replaces OpenJPAQuery.setParameters(Object[]) and OpenJPAQuery.setParameters(Map) with standard JPA positional and named parameter binding via Query.setParameter(int, Object) and Query.setParameter(String, Object). A new utility method, JPAUtil.setQueryParameters(), centralizes this logic. By retaining the standard JPA Query proxy, Spring defers EntityManager materialization until getResultList() or executeUpdate() is called, at which point a transaction-bound or freshly allocated (and properly scoped) EntityManager is used for the full query lifetime.

Another cause was that StrictDetachmentStrategyImpl, which detaches entities before storing them in the cache, was not replacing OpenJPA proxy collections and maps with plain Java equivalents. These proxy objects retained internal references to the JPA StateManager and Broker, which became invalid after the transaction closed. When property change listeners (e.g., ProductImpl.propertyChange) later operated on these proxy collections, OpenJPA would assert the broker was still open and throw the exception. To fix this, StrictDetachmentStrategyImpl was updated to replace all OpenJPA proxy Collection and Map fields with standard Java collections (ArrayList, HashSet, or HashMap) via the corresponding setter methods during the detachment process.

The third cause was that JPA entities were being placed into EhCache while still attached to an OpenJPA state manager. When the database transaction ended and the underlying broker was closed, any subsequent read of those cached entities would fail. The fix ensures that entities are detached from the OpenJPA persistence context before being stored in any EhCache-backed cache.

Simplified EhCache Spring XML configuration via custom ep-caches:cache namespace​

A new custom Spring XML namespace (ep-caches:cache) has been introduced to streamline the declaration of EhCache-backed caches. Previously, each cache required two separate Spring bean definitions — one to configure the underlying EhCache instance (EhCacheDefaultConfigurationFactoryBean) and one to create the EP cache wrapper via localCacheFactory. These can now be replaced with a single, concise XML element, for example:

<ep-caches:cache id="taxCodeByCodeCache" timeToLive="3600" timeToIdle="3600" maxEntries="10000"/>

For more information, see the related upgrade notes.

JDBC drivers removed from webapps​

The H2 database driver JAR (h2-2.2.224.jar) was unintentionally included in the ext-integration-webapp and ext-sync-webapp web assembly files. This occurred because the ep-sync-message-listener-email and ep-sync-message-listener-camel modules declared the H2 dependency with the default compile scope rather than test scope. JDBC drivers should be provided at the container (Tomcat) level rather than bundled inside the webapp, so this represents both a security concern and a packaging issue.

The H2 dependency in the affected modules has been corrected to test scope, ensuring it is no longer included in the packaged webapp artifacts. Additionally, all supported JDBC drivers (H2, MySQL, Oracle, PostgreSQL) are now explicitly provided on the Tomcat classpath via the Cargo container configuration in the root POM.

A Maven enforcer rule (enforce-banned-dependencies-for-webapp) has been added to all webapp modules to prevent JDBC drivers from being accidentally bundled into webapp assemblies in the future.

Cortex​

Zoom graph builder removed from Cortex Studio​

The Zoom Graph Builder tab and all associated functionality have been removed from Cortex Studio. This feature allowed developers to visually explore Cortex API zoom paths via an interactive graph, but it contained known bugs and was rarely used.

Custom request header support in Cortex Studio​

Cortex Studio now allows users to define custom HTTP headers that are sent with every API request. A new Custom Headers section has been added to the Request Headers tab, where users can add headers by providing a header name and value, clear individual header values, or remove headers entirely.

Custom header definitions and their values are persisted in the browser's local storage, so they are retained across browser sessions — consistent with how standard header values are already preserved. This makes it easier for developers and testers to work with APIs that require non-standard or environment-specific headers without needing to re-enter them each session.

Added limited Shopping Cart caching for improved performance​

A new cache has been introduced for some shopping cart operations with values that are not expected to change frequently.

The findOrCreateDefaultCartGuidByShopper method in ShoppingCartServiceImpl is now cached using a shopper GUID → shopping cart GUID cache ( defaultCartGuidByShopperGuidCache). This eliminates redundant database queries for default cart lookups on every shopper session interaction, providing measurable performance improvements under load. The cache has a default TTL of 60 minutes and is invalidated automatically through message-based events. Cache invalidation is triggered when a shopping cart is created, deactivated, or deleted — including the new deactivateAllShoppingCartsByShopperGuid method, which replaces the now-deprecated deactivateAllShoppingCartsByShopperUid. Cart events now carry a shopperGuid field in their event data to enable targeted cache invalidation. A new CacheEventType.SHOPPER_DEFAULT_CART event type and a corresponding ShopperDefaultCartCacheInvalidationProcessorImpl have been introduced to handle invalidation across nodes.

Additionally, the findAccountGuidByCartGuid method in ShoppingCartServiceImpl is now cached using a shopping cart GUID → account GUID cache ( accountGuidByCartGuidCache). This eliminates redundant database queries for account resolution operations. The cache has a default TTL of 60 minutes and is invalidated automatically through message-based events.

Promotion rule base cache now avoids unnecessary database reloads​

Previously, the Drools promotion rule base cache had a 5-minute TTL, causing the full rule base to be reloaded from the database on every cache expiry — even if nothing had changed. Because rule base records can be very large, this resulted in costly and unnecessary database reads that degraded promotion evaluation performance.

This fix introduces a two-tier caching strategy: the rule base itself is now cached eternally, while a separate, shorter-lived "freshness indicator" cache tracks when the last-modified date was verified. When the freshness indicator expires, a lightweight query fetches only the last-modified date for the rule base. The full rule base blob is reloaded from the database only if the date has actually changed.

Promotion selling context conditions evaluated when adding coupon codes to cart​

Previously, shoppers could add coupon codes to their cart even if they did not meet the promotion's selling context conditions (such as belonging to a required customer segment). The coupon would be silently accepted but would never apply, providing no feedback to the shopper. With this change, the platform now validates selling context conditions at the time a shopper adds a coupon code to the cart and returns a clear error if the shopper does not qualify.

When a coupon code is rejected due to unmet selling context conditions, the API returns a structured error response with the coupon.not.valid error ID, the coupon code, and a validation-failure-code of ERROR_SELLING_CONTEXT_CONDITIONS_NOT_SATISFIED. Only Groovy selling context conditions are evaluated during this check; Drools conditions are not. If a coupon code is associated with multiple promotions, each promotion's selling context is evaluated independently.

Commerce Manager​

Commerce Manager platform modules can now access ext-core services directly​

Commerce Manager modules have been updated to allow direct access to ext-core classes and services at runtime and compile-time. Previously, developers who needed Commerce Manager modules to interact with custom ext-core services were forced to copy entire Commerce Manager modules into extensions/cm/ext-cm-modules and modify the configuration to use those copies. This workaround is no longer supported since an upgraded version of Tycho causes build-time failures ("Duplicate reactor project IUs" errors) when multiple modules share the same artifact ID.

With this fix, customers can integrate ext-core customizations directly into the standard commerce-manager/cm-modules/cm-plugins modules without needing extension copies. Customers who have previously applied the copy-module workaround must migrate their customizations back into the corresponding platform CM modules and delete the copied modules from extensions/cm/ext-cm-modules as part of the upgrade process.

Technically, this was achieved by adding DynamicImport-Package: com.elasticpath.extensions.* to all CM bundle manifests, explicitly declaring platform package imports in ext-cm-libs, adding Require-Bundle wiring for platform OSGi bundles, and enforcing build-time reactor ordering to ensure ext-cm-libs is built before Tycho resolves plugin dependencies. A Maven enforcer rule was also added to prevent ep-messaging-camel from entering the ext-cm-libs dependency tree, which can cause Commerce Manager startup delays of several minutes.

"Not Set" option added for optional boolean customer profile attributes​

Commerce Manager now supports distinguishing between an unset boolean customer profile attribute and one that has been explicitly set to a value. Previously, optional boolean fields (such as HTML Email and Newsletter preferences) displayed "No" regardless of whether the value was absent or had been explicitly set to false, making it impossible to tell the difference.

Optional boolean fields now render as a dropdown with three choices: "Not Set", "Yes", and "No". When a customer profile is loaded, fields with no stored value will display "Not Set". When a user saves a record with "Not Set" selected, the underlying customer profile attribute value record is removed entirely, ensuring a clean and accurate data state.

Attribute value editor now accessible in read only mode for locked products, SKUs, and categories​

When changesets are enabled (COMMERCE/SYSTEM/CHANGESETS/enable=true), Commerce Manager previously prevented users from opening the attribute value editor for products, SKUs, or categories that had not yet been added to a changeset (i.e., items in a "locked" state). Users are now able to open the attribute value editor in read-only mode by double-clicking an attribute value in the Attributes tab, making it easier to review attribute data without needing to add the item to a changeset first. Note that simply selecting (highlighting) an attribute row will not enable the Edit Attribute Value… button.

When the editor is opened in read-only mode, all controls are appropriately restricted: the OK button is disabled; Boolean fields display a disabled combo box; text-based fields (Short Text, Long Text, Integer, Decimal, File, and Image) are read-only but allow text selection and copying; Date and Date/Time fields are read-only with the calendar icon disabled; and for multi-value attributes (Short Text Multi-Value, Long Text Multi-Value), the Add Value, Edit Value, and Remove Value buttons are all disabled.

New DRL Code tab added to promotion editors in Commerce Manager​

A new read-only DRL Code tab is now available in both cart promotion and catalog promotion editors in Commerce Manager. The tab displays the underlying Drools rule language code that is generated from the promotion's configured conditions and actions, with syntax highlighting applied for readability. A Copy to Clipboard button is included so developers can easily extract the code for further analysis.

This feature is primarily useful for developers who are debugging custom promotion conditions or actions, as it allows them to inspect the generated rule code directly within Commerce Manager without requiring access to backend systems or logs. The Drools rule language code is generated from the current saved state of the promotion; unsaved promotions will display a message indicating that the promotion must be saved before code can be shown.

Promotion conditions and actions editable without catalog data in database​

Promotion conditions, actions, and exclusions in Commerce Manager can now be viewed and modified even when the associated catalog data — such as products, product SKUs, categories, brands, currencies, attributes, and shipping service levels — is not present in the Promotions database. This is particularly relevant for deployments where catalog data is managed separately from the Promotions service.

Fields that previously relied on database-backed dropdowns or combo boxes now present a text input alongside a [select] link. Users can either type the identifier code directly into the text field or use the [select] link to open a new generic list selection dialog, which displays available options and supports filtering by code or name. Category code fields require the compound format categoryCode|catalogCode, and validation provides a specific error message if the format is incorrect.

Inline validation warnings for invalid promotion condition codes​

When building promotion rules in Commerce Manager, users can now see an immediate inline warning when a condition references a product, SKU, category, or brand code that does not exist in the database. The warning appears as an amber icon next to the condition field as soon as the user moves focus away, and a tooltip displays the full message (for example, "Product 'INVALID_PROD_001' was not found in the database"). The warning is non-blocking, meaning users can continue editing and saving the promotion without any extra steps.

This change helps prevent promotions that silently fail to apply due to typos or references to deleted catalog items, making it easier to diagnose promotion configuration issues before they reach customers.

Brand is now optional on products and product bundles​

Previously, a brand was required when creating or editing a product or product bundle. This requirement has been removed — brand is now an optional field. Commerce Manager wizards and editors have been updated to include an empty option in the brand selection dropdown, allowing merchants to create products and bundles without specifying a brand, and to remove a brand from existing products or bundles.

Import/export has also been updated to support products where no brand is specified. An empty <brand> element in an import file is now treated as no brand, rather than causing an error. Search indexing already handled null brand values and required no changes.

A database migration is included that removes any existing brand records with the code "None" (case-insensitive) and sets the brand field to null on any products that previously referenced those records. Customers who have used a "None" brand as a placeholder should be aware that this migration will remove those records automatically on upgrade.

Export search results to CSV from Commerce Manager list views​

Commerce Manager now includes an Export List button on the following search result list views: shopping cart promotions, catalog promotions, price lists, price list assignments, products, SKUs, orders, customers, and accounts. Clicking the button downloads a CSV file containing all rows that match the current search criteria, not just the items visible on the current page. The exported file includes a UTF-8 byte order mark so that it opens correctly in Microsoft Excel without character encoding issues.

Ability to switch shopping cart promotion activation mode without recreating the promotion​

Merchandisers can now change the activation mode of an existing shopping cart promotion — between no coupon, public coupon, and private coupon — directly from the promotion editor, without needing to delete and recreate the promotion. Previously, the "Activation Rules" and "Coupon Codes" tabs were only visible on promotions that already had a coupon configuration, making it impossible to add coupon activation to a promotion after it was created.

The "Activation Rules" tab is now always visible and presents all three activation options as radio buttons. If a promotion already has coupon codes associated with it, switching directly between public and private coupon modes is not permitted; users must first switch to "not activated by coupons" and save, which will delete all related coupon codes. A confirmation dialog is shown before any coupon codes are deleted, and the save is blocked if any coupon codes are currently in use on active shopping carts or orders.

Batch Server​

Batch server job schedules can now be configured via properties​

The scheduled batch jobs on the batch server previously had fixed run schedules defined in the Spring XML configuration file (quartz.xml). Operators who needed to adjust when jobs ran — for example, to avoid peak traffic periods or align with maintenance windows — had to override the XML configuration directly.

Cron expression schedule overrides can now be set for each batch job using properties in ep.properties, following the naming pattern ep.batch.job.<jobName>.cronExpression (for example, ep.batch.job.cleanupAbandonedCarts.cronExpression). If a property is not set, the job continues to run on its existing default schedule.

For more information, see Batch Server Properties.

Import/Export​

GUID Filtering added to Import/Export EPQL queries​

The Import/Export feature supports an optional EPQL query clause that allows users to filter which records are included in an export. Previously, most object types did not expose a GUID field as a filterable option, limiting operators to filtering by other attributes such as name or code. GUID fields have now been added as supported filter fields across a wide range of exportable object types, including Price Lists, Price List Assignments, Promotions, Categories, Products, Customers, CM Users, Shipping Service Levels, Shipping Regions, Warehouses, Gift Certificates, and CM Import Jobs.

This enhancement allows operators to export a specific, known record by its GUID using queries such as FIND PriceListAssignment WHERE GUID = '492c9662-7b9b-4223-afea-da5b12024e6b', which is particularly useful when integrating with external systems or automating data migration workflows where GUIDs are the primary reference identifiers.

Fixed issue with duplicate TCARTTYPE records created during store imports​

Repeated imports of stores via the Import/Export feature were incorrectly creating duplicate TCARTTYPE records in the database instead of updating existing ones.

The root cause was in StoreDtoAssembler#populateCartTypesForDomain, which always instantiated new transient CartType objects (with no database identity) during import, causing JPA to issue INSERT statements instead of UPDATEs. Additionally, a flawed equals() implementation on CartType that compared modifier collections could prevent deduplication from working correctly. The fix updates the assembler to look up and reuse existing CartType entities by GUID before falling back to creating new ones, and removes the problematic equals()/hashCode() implementation in favor of identity-based comparison.

A Liquibase migration is included that removes orphaned duplicate TCARTTYPE records from affected databases and adds a unique constraint on the TCARTTYPE.GUID column to prevent this issue at the database level. Missing indexes and foreign keys on the TSTORECARTTYPE and TCARTTYPEMODIFIERS tables are also added as part of this migration.

Improved Import/Export error and warning log messages​

Previously, warnings and errors logged during Import/Export operations — including during Data Population execution — were output as raw internal representations such as Message[jobType=<null>,code=IE-10103,params={MobileCatalog},exception=null], which were difficult to interpret without cross-referencing internal message property files. Example:

[EP-DataPopulation] [INFO] Begin importing CATEGORY
[EP-DataPopulation] [ERROR] Message[jobType=<null>,code=IE-10103,params={MobileCatalog},exception=null]

Import/Export log messages now display fully resolved, human-readable text by leveraging the existing MessageResolver to translate message codes and parameters at log time. Example:

[EP-DataPopulation] [INFO] Begin importing CATEGORY
[EP-DataPopulation] [ERROR] Catalog with code MobileCatalog does not exist

The Message.toString() method has been updated to use the resolver when available, and LogAppenderUtil has been updated with a setMessageResolver() method that is called at the start of import and export jobs.

Named import configurations via query parameter​

The Import/Export API now accepts an optional configuration query parameter on import requests, allowing clients to select different import configuration files at runtime. For example: POST integration/api/importexport/import?configuration=insertonly. When specified, the API will use a configuration file named {configuration}-importconfiguration.xml instead of the default importconfiguration.xml. If the specified configuration file does not exist, the API will return an error.

This enhancement gives operators greater flexibility when importing data, as different import scenarios may require different behaviors — such as using an INSERT-only strategy to prevent updates to existing records, or adjusting dependent element handling between CLEAR_COLLECTION and RETAIN_COLLECTION for elements like product associations or SKU pricing.

Custom import configuration files must be created in advance and placed in the extensions/importexport/ext-importexport-api/src/main/resources folder.

For more information, see Import endpoint parameters.

Tests​

New functionality for interacting with RAP widgets in Selenium test step definitions​

Several new RAP test wrapper components — including RAPTable, RAPCombo, RAPText, RAPButton, and others — have been added to the Commerce Manager test utilities, alongside a new AbstractRAPWidget base class to reduce code duplication across the growing library of test widgets. These additions provide a consistent and simplified API for interacting with UI elements in automated tests.

The new WidgetBy and WidgetLocator factory classes provide a fluent API (e.g., WidgetBy.byWidgetId("Store").parentCSS(...).combo()) to locate and work with RAP widgets without needing to know their internal document object model structure.

A number of existing Dialog page objects and Cucumber step definitions have been refactored to use the new widgets. Notably, several verify* and action methods have had unused attributeName parameters removed, payment configuration step definitions now correctly distinguish between select and deselect actions, and checkbox state detection in RAP tables has been improved via client-side JavaScript (EPTest.isChecked) with a fallback image-comparison mechanism.

Fixed intermittent Selenium test failures caused by ambiguous RAP Widget selector lookups​

The findRwtIdForSelector function in ep-test-support.js previously used querySelector, which silently returned only the first matching element when multiple elements match a given CSS selector. This non-deterministic behavior caused intermittent and difficult-to-diagnose test failures in the Commerce Manager UI automation suite.

The function has been updated to use querySelectorAll combined with a new _assertSingleElement helper that throws a detailed, descriptive error — including element IDs, widget types, and automation IDs — when more than one element matches the selector. This makes selector ambiguity immediately visible rather than silently producing unreliable results. Additionally, CSS selectors in several page objects (StoresResultPane, ProductEditor, CreateCategoryWizard, and CreateEditShippingRegionDialog) have been tightened with more specific attribute constraints (e.g., adding parent context selectors, [seeable='true'], or [widget-type='Shell']) to ensure only the intended element is targeted.

JPQL Query Test console now shows generated SQL queries​

The JPQL Query Test interactive console has been enhanced to capture and display the native SQL statements that OpenJPA generates when executing queries. Previously, the console only showed the results of a query without revealing the underlying SQL, limiting its usefulness for debugging and performance analysis. Now, each query execution displays the generated SQL statements, the total number of queries executed, and the overall execution time.

ActiveMQ broker now runs as a Cargo container to support concurrent integration test execution​

Previously, ActiveMQ was started during integration tests using an embedded Maven plugin (activemq-maven-plugin). This approach prevented multiple ActiveMQ brokers from running within the same Java Virtual Machine, causing build failures with errors such as "A local broker is already running" or "Address already in use" when integration test modules were executed concurrently.

ActiveMQ is now started and stopped as a Cargo-managed web application container, consistent with how other test infrastructure components (such as Cortex and Search) are managed. The TCP and STOMP ports used by ActiveMQ are dynamically reserved at build time from module-specific port ranges, preventing conflicts between concurrently running test modules. The activemq.xml configuration now reads the ports from the ep.activemq.tcp.port and ep.activemq.stomp.port system properties, with default values of 61616 and 61613 respectively.

Build Tools​

Optional in-cluster proxy cache for Eclipse plugin downloads​

Build scripts (build_deployment_package.sh, build_source_tree.sh, build_container_layout.sh, run_extensions_tests.sh, and run_cortex_system_tests.sh) now accept additional Maven arguments that are passed directly to the underlying Maven command. This allows operators to supply options such as proxy configuration or mirror overrides without modifying the scripts themselves.

This change also introduces support for an optional reverse-proxy service that caches Eclipse plugin repository (P2) files within the cluster. When enabled, subsequent builds retrieve Eclipse plugins from the local cache instead of reaching out to external Eclipse mirror servers, reducing intermittent download failures and improving build reliability. The proxy can be enabled by setting use_p2_proxy: true in the Maven settings configuration, and the proxy base URL can be overridden via the p2_proxy_base_url variable to support non-standard environments.

New container layout module simplifies Commerce container image builds​

A new Maven module, ext-container-layout, has been introduced to streamline the process of building Commerce container images. Previously, the build pipeline produced an intermediate deployment package (a zip archive) that was then unpacked and rearranged before container images could be built. This unnecessary step has been eliminated: the container layout file structure and per-application Dockerfiles are now produced directly by the Maven build and consumed directly by the image build tools.

The build tools have been updated to reflect this change. The previous build_deployment_package.sh script has been split into two new scripts: build_source_tree.sh, which compiles the full source tree, and build_container_layout.sh, which produces the container layout. The Ansible playbooks used to build images have also been simplified, with much of the file-rearrangement logic removed.

Additional build process enhancements​

  • SLF4j was upgraded from 1.7.x to 2.0.x and Logback from 1.2.x to 1.5.x to remediate security vulnerabilities CVE-2024-12798, CVE-2024-12801, and CVE-2025-11226. Log4j was also been upgraded from 2.17.x to 2.24.x and the SLF4j bridge artifact updated from log4j-slf4j-impl to log4j-slf4j2-impl.
  • Eclipse Sisu has been upgraded from version 0.3.5 to 0.9.0.M4 to resolve a build-time compatibility failure caused by Sisu's previously embedded, outdated ASM library being incompatible with Java bytecode 15+. As part of this change, ASM and several Jakarta API dependencies are now explicitly included in the runtime bundle.
  • Resolved a failure in the boms module during Maven deploy operations by explicitly configuring maven-deploy-plugin version 2.8 with deployAtEnd=true.
  • Fixed a duplicate maven-dependency-plugin declaration in the performance-cucumber-tests POM file that generated warnings during the Maven build process (mvn clean install).
  • Fixed an issue where building the com.elasticpath.cmclient.core Eclipse plugin module would fail with an unresolved com.elasticpath.ep-base OSGi bundle dependency when Maven goals such as checkstyle:check were run without a preceding install phase.
  • Eliminated spurious Maven build warnings caused by the ext-plugin-config assembly descriptor attempting to include its own POM artifact and defining an exclusion filter that never matched. The fix adds <useProjectArtifact>false</useProjectArtifact> to the dependency set and removes the unnecessary exclusion, resulting in a cleaner build output.
  • Resolved requireUpperBoundDeps violations in the extensions module by upgrading ASM libraries (asm, asm-analysis, asm-commons, asm-tree) from version 7.2 to 9.3, removing stale dependency exclusions, and enabling strict enforcement of upper-bound dependency rules across all modules.
  • Removed unnecessary Apache Geronimo spec dependencies (geronimo-jpa_2.2_spec, geronimo-jta_1.1_spec, geronimo-stax-api_1.0_spec) from multiple modules, replacing them with standard Jakarta/javax API equivalents and reducing transitive dependency noise in built artifacts.
  • Synchronized the Maven dependency exclusions between ep-core and ext-core in ext-commerce-engine-wrapper to ensure the Cortex "fat bundle" does not embed JARs (e.g., Spring, Jackson, slf4j, OpenJPA, EhCache) that are already deployed as independent OSGi bundles, preventing duplicate class problems, version conflicts, Bundle-Activator errors, and unnecessary bundle bloat.
  • Updated ci-settings.xml to remove the obsolete eclipse-p2-updates mirror and replace it with the eclipse-p2-birt-updates mirror targeting BIRT release 4.19.0, ensuring Maven CI mirror configuration aligns with cm-rap.target locations.
  • Updated .gitignore configuration to exclude the .claude/ directory from source control, preventing AI assistant configuration files from being accidentally committed.
  • The Maven Enforcer Plugin has been updated to fail the build when duplicate POM dependency version declarations are detected, ensuring build stability and encouraging clean dependency management across.
  • Removed the unused org.apache.felix.webconsole dependency and the felix.webconsole.version property from the bill-of-materials POM, reducing unnecessary dependency management overhead.
  • The camel-direct component has been embedded in ep-camel-bundle, resolving an issue where customers using direct: endpoint references in their custom Camel routes would encounter failures due to the component not being exported by the bundle.
  • Per-module JaCoCo code coverage threshold overrides have been removed across all Cortex REST resource Maven modules, so builds will no longer fail due to unmet coverage ratios. Code coverage metrics are still reported, but no minimum thresholds are enforced.
  • Removed duplicate checkstyle-cmclient-suppressions.xml files from the Commerce Manager modules, consolidating all Checkstyle suppression rules into the code-checking-rules project. This eliminates the need for developers to manually add CHECKSTYLE:OFF/CHECKSTYLE:ON annotations in Commerce Manager JUnit test code, as the centralized suppressions now include the full set of expected suppression configurations.
  • Fixed an issue where the code-checking-rules JAR was unnecessarily included in Commerce Manager (cmclient.libs) and ext-commerce-engine-wrapper assembly files. This was resolved by removing the code-checking-rules dependency from the grandparent POM, reducing assembly bloat and preventing unintended packaging of build-time tooling into runtime artifacts.
  • Cleaned up redundant and duplicate .gitignore files across the repository by consolidating entries into the root .gitignore. These changes prevent build-generated files from appearing as untracked files in git status.
  • The Maven Checkstyle plugin has been upgraded from version 2.17 (using Checkstyle 6.11.2) to version 3.6.0 (using Checkstyle 9.3), improving code quality enforcement with an up-to-date ruleset. Elastic Path's code-checking rules configuration has been updated for compatibility, including adjustments to Javadoc, suppression filter, and modifier rules.
  • Removed all OWASP ESAPI dependencies from the platform, eliminating several vulnerable transitive dependencies (including bsh-core, commons-configuration, commons-fileupload, and commons-lang). ESAPI was not actively filtering or protecting any API endpoints, so its removal has no impact on runtime security behavior.
  • Upgraded the Maven Compiler Plugin from version 3.9.0 to 3.14.1, resolving an issue where Java compilation warnings that caused build failures did not display their root cause in the build output, making failures difficult to diagnose.
  • Fixed the assembly enforcer so that database-specific driver JARs (MySQL, PostgreSQL, Oracle, and H2) are no longer included in expected assembly list files and are filtered out during validation. This means running the assembly enforcer reset or validate steps will no longer fail due to a mismatched or missing database driver, regardless of which database profile was used during the build.
  • Fixed an issue where feature.xml files referenced locally built Commerce Manager plugins with version="0.0.0", causing the build system to resolve the highest available version from the local Maven repository instead of the locally built snapshot. This could result in unexpected errors and required developers to manually delete the local P2 repository cache when switching between platform versions.
  • The deprecated hamcrest-core and hamcrest-library test dependencies have been replaced with the consolidated hamcrest 2.2 dependency across the platform; the older artifacts contain no classes in version 2.2 and exist only for backwards compatibility.
  • Updated the compiler configuration to add the -Xlint:-serial flag, which suppresses Java 18+ compiler warnings for non-serializable fields in serializable classes.
  • Updated the compiler configuration to add the -Xlint:-this-escape flag, which suppresses warnings raised by Java 21 about possible this escape before a subclass is fully initialized. This flag is applied only when running Java 21, as it is not compatible with Java 17.
  • Fixed a missing distribution management configuration in boms/pom.xml that caused the boms module to fail during Maven deploy operations, preventing accelerator builds from completing successfully.
  • Duplicate Maven distribution management blocks (defining release and snapshot repository URLs) have been removed from 13 submodule POM files across the codebase, as these settings are now inherited from the root POM.
  • The Helix Maven plugin validation process for Cortex modules, which was disabled after the Jakarta migration broke dependency injection in the Maven plugin framework, has been re-enabled by refactoring the validator to use direct instantiation instead of injection.
  • Reconciled mismatched version property names for JAXB dependencies between /pom.xml and /bill-of-materials/pom.xml, replacing com.sun.xml.bind.jaxb-core.version and com.sun.xml.bind.jaxb-impl.version with jaxb.version and jaxb-impl.version respectively.

Additional core enhancements​

  • Fixed a bug where the "Line item product is from category" promotion condition always evaluated to true, causing promotions targeting a specific category to incorrectly apply to products in any category. The fix ensures PromotionRuleDelegateImpl#lineItemProductCategory now properly validates that the line item's product belongs to the specified category before applying the promotion.
  • Fixed an issue where promotions using product or SKU attribute value conditions (e.g., lineItemProductAttributeValueCondition, cartProductSkuAttributeValueCondition) silently failed to apply when the attribute key contained any lowercase characters. Attribute value comparisons are now also case-insensitive, so promotions will correctly evaluate regardless of the case used in attribute keys or values.
  • Stacked discounts no longer exceed line item subtotal: Fixed a bug where applying multiple stacked promotions to a cart line item could result in a total discount amount greater than the item's subtotal, causing over-discounting on orders. The fix moves subtotal cap enforcement into AbstractShoppingItemImpl so that each successive discount is limited to the remaining undiscounted value of the line item.
  • Fixed a bug in the credit/refund processing logic where the presence of REVERSE_CHARGE payment events would incorrectly cause refund operations to fail, even when a valid approved charge was available to refund against. The fix ensures that reverse-charged amounts are correctly accounted for when calculating refundable balances, allowing refunds to proceed as expected.
  • Fixed an incorrect exception message in CreditProcessorImpl that displayed a cancel reservation failure message instead of a refund failure message when a refund could not be processed.
  • Fixed a bug where attempting to check out after a previous payment failure would throw a database unique constraint violation (TORDERSKU_GUID_UNIQUE). Order SKU GUIDs are now generated using a combination of the order ID and the cart line item GUID, ensuring uniqueness across multiple order attempts for the same cart.
  • Fixed incompatible-configuration warnings that appeared in logs during service startup when using the EhCache OpenJPA data cache manager, by updating the openjpa.DataCache property value from true to ehcache and removing the incompatible openjpa.RemoteCommitProvider property.
  • Fixed product and SKU reindexing after updating SKU option values: index notifications (TINDEXNOTIFY records) are now correctly created for only the products and SKUs affected by the changed SKU option value, and product last-modified dates are no longer incorrectly updated as a side effect.
  • Fixed an issue where services started locally with mvn cargo:run had a maximum JVM heap size of only 500MB, which was insufficient for large data sets and could cause OutOfMemoryErrors (e.g., in Search Server). The default max heap size has been increased to 2048MB.
  • Fixed a bug where SKU, product, and category exclusions on shopping cart promotion conditions (line item product, line item product category, and product-in-cart conditions) were being ignored, causing excluded items to incorrectly receive promotion discounts.
  • Fixed an issue where promotion actions were limited to a maximum of 10 parameters due to the use of Map.of() in AbstractRuleActionImpl#createRuleCode. The method has been refactored to use Map.ofEntries(), allowing an unlimited number of promotion action parameters. Promotions with more than 10 action parameters will now function correctly.
  • The InventoryDtoCacheKey held a full ProductSku object in memory, causing excessive EhCache memory consumption. The cache key has been refactored to store only the SKU code string, with ProductSkuLookup (which is itself cached) used to retrieve the ProductSku when needed.
  • Updated all MySQL JDBC driver class references from the deprecated com.mysql.jdbc.Driver to the current com.mysql.cj.jdbc.Driver across the platform.
  • Resolved an issue where Order objects passed between methods within a context object but not refreshed after database updates, which could cause subsequent operations to overwrite changes made by previous operations. This affected gift certificate creation during checkout ( CreateGiftCertificatesCheckoutAction) and several batch job processes.
  • The default Cargo container startup timeout has been increased from 120 to 180 seconds to prevent local services from timing out due to taking too long to start. The timeout is now configurable via the ep.cargo.prop.startupTimeout Maven property.
  • Fixed a NullPointerException that occurred when checking availability of a product bundle containing "Always available" constituent products or nested empty bundles (bundles with no constituents), which previously resulted in a server error during item lookups in Cortex. Null safety was added to the constituent inventory details sorting logic in ProductInventoryShoppingServiceImpl, and empty bundles are now correctly treated as not available.
  • Removed the unused CartHasItemsServiceImpl class, its related interface, and associated tests.
  • Removed deprecated shopping cart deletion methods (deleteShoppingCartsByGuid and deleteAllShoppingCartsByShopperUid) and their associated named queries from ShoppingCartService, enforcing that all cart deletions are handled exclusively by the PurgeCartsBatchProcessor.
  • Removed unused fields (codeValid, mergedNotification, itemWithNoTierOneFromWishList, giftCertificateService, discountCalculator) and methods (getSubtotalOfShippableItems, getCustomerEmailAddress, getCustomerBusinessNumber, isCustomerAnonymous) from ShoppingCartImpl and the ShoppingCart interface.
  • The deprecated com.elasticpath.commons.util.Collections utility class has been removed from ep-core.
  • Removed the unused greenmail (com.icegreen) test dependency from the bill-of-materials and all affected module POMs, including ep-email, ep-test-application, and ep-core-fittests.
  • Removed the unused ActiveRule interface and ActiveRuleImpl class from com.elasticpath.domain.rules. These classes were legacy Drools rule ID wrappers that were no longer in use.
  • Removed the unused PropertyService interface and PropertyServiceImpl class, along with the associated propertyService Spring bean definition and the PROPERTIES_SERVICE constant from ContextIdNames.
  • Removed unused fields (promotionRuleDelegate, ruleEngineSessionFactory, ruleEngineRuleStrategy, couponConfigDao, productSkuConverter, shoppingCartConverter) along with their getters, setters, and Spring bean injections from AbstractRuleEngineImpl.
  • The caching configuration for Performance Insights tests has been separated into a dedicated ehcache-performance-insights.xml file (generated from ehcache-fast-updates.xml) with infinite time-to-live and unlimited cache sizes, ensuring query counts are consistent between runs so that genuine performance regressions are easier to identify.
  • Fixed a regression where cached tax results from cart pricing were not being reused during checkout, causing unnecessary recalculation. This was resolved by introducing a new cache key class (XPFTaxCalculationContextAlternateKey) and updating the OrderSku GUID format to {order_id}|{cart-item-guid}, allowing the cache to correctly match cart and order SKUs while avoiding database unique key constraint violations.
  • The allConditions and allActions lists are now autowired extensible Spring lists, so custom RuleCondition and RuleAction beans are automatically discovered and registered.
  • All internal usages of org.drools.core.util.StringUtils have been replaced with org.apache.commons.lang3.StringUtils, and the Drools class has been added to the Checkstyle IllegalImport list to prevent future use.
  • Fixed a memory inefficiency in StoreProductSkuFactoryImpl where every cached StoreProductSku proxy unnecessarily held a reference to the StoreProductSkuFactoryImpl Spring singleton. This was caused by a lambda capturing this due to hashCode(ProductSku, PerStoreProductSkuAvailability) being declared as an instance method despite using no instance state; converting it to static resolves the unintended object retention.
  • Dozens of private methods, fields, and constants across the Commerce platform core, services, search, checkout, tax, promotions, and Commerce Manager UI layers have been changed to protected (or public where necessary), and new protected getters/setters have been added, significantly reducing the need for workarounds when customizing platform behavior.
  • Spring XML configuration files across the platform have been updated to declare beans using id instead of name, standardizing bean definition practices and ensuring bean identifiers are unique within the Spring container.
  • A new ShoppingItemDtoBuilder interface and ShoppingItemDtoBuilderImpl implementation have been introduced to replace the multi-method ShoppingItemDtoFactory pattern for constructing ShoppingItemDto objects. The existing ShoppingItemDtoFactoryImpl has been refactored to use the new builder internally.
  • The eager JPA fetch from CustomerGroupImpl to CustomerRoleImpl (via the TCUSTOMERGROUPROLEX table) has been eliminated, reducing the number of database queries executed when loading customers. The ROLE_CUSTOMER Spring Security authority is now hardcoded directly in CustomerImpl.getAuthorities().
  • Improved shopping cart performance by refactoring ShoppingCartImpl to retrieve cart items directly from the flat cart memento list instead of performing a costly recursive tree-flattening operation. This change affects several cart methods, and a null-pointer issue in CartDirectorImpl when processing bundles with missing parent items has also been resolved.
  • A performance optimization prevents an unnecessary database query when calculating available coupon discount quantities for shopping carts that have no applied coupon codes, reducing database load during cart and checkout processing.
  • Fixed an issue where promotion carrots were not displayed for products belonging to a category referenced by a shopping cart promotion condition. The root cause was incorrect category identifier comparison logic, which has been resolved by converting CategoryGuidUtil from a standalone class to a Spring-managed bean and refactoring RuleParameterUtility to use the promotion rule delegate for category matching.
  • The EnumLoader class has been updated to use wildcard generic type parameters, making it easier to work with extensible enum implementations. This reduces the complexity of custom code, such as unit tests, that references EnumLoader methods like getEnums and setEnums.
  • Several extension point framework converter classes that convert extension point entities back into domain objects have been moved to the new com.elasticpath.xpf.converters.output package. Any customizations that reference these classes (including StructuredErrorMessageConverter, OrderHoldConverter, InventoryDtoConverter, and others) must update their Java imports and Spring XML bean definitions accordingly. Upgrade recipes are provided to assist with this migration.
  • Fixed an issue where promotion rule validity checks ignored the SHOPPING_CONTEXT_DATE_OVERRIDE request header, causing coupons belonging to future-dated promotions to be incorrectly rejected when a shopper used a date override trait.
  • Removed an obsolete reference to a non-existent method (getCurrentLupNumber) from the sync service merge filter bean configuration.
  • The non-functional hot-deploy-sling, felix-deploy, and osgi-deploy Maven build profiles and their associated Apache Sling plugin configuration have been removed from all modules, as these profiles did not work reliably and provided no practical value.

Additional Cortex enhancements​

  • Fixed a race condition where two simultaneous checkout requests for the same cart (e.g., from a double-click or network retry) could cause a duplicate order constraint violation to be silently swallowed, resulting in shoppers receiving a misleading "Payment method must be present" error and a failed cart requiring retry. The fix ensures unrecognized persistence exceptions are re-thrown rather than ignored, and improves duplicate constraint detection to handle varying OpenJPA exception nesting structures across MySQL, Oracle, PostgreSQL, and H2.
  • Fixed issue with Cortex logging in deployed environments. After applying the Logback 1.5 upgrade patch, Cortex produced no log output when deployed via Tomcat (while local Cargo deployments were unaffected). This was caused by a syntax change in Logback 1.5's conditional configuration; the fix replaces the deprecated if/then conditional blocks with Logback's native property default syntax (e.g., ${ep.logback.console.threshold:-ALL}).
  • A non-fatal BundleException (Bundle symbolic name and version are not unique: jakarta.el-api:5.0.1) was logged as an ERROR during every Cortex startup. This was resolved by moving jakarta.el-api to the correct dependency scope and removing the duplicate bundle from the OSGi bundle load path.
  • Checkout payment instrument reliability improvement: Cart order payment instruments and the customer's default payment instrument are now loaded once at the start of checkout and stored as transient fields on the ShoppingCart object, eliminating redundant database calls and preventing intermittent checkout failures (e.g., "Payment method must be present" errors) that could occur if payment instruments changed mid-checkout.
  • Fixed an issue where Cortex returned a 500 Internal Server Error when loading a shopper's profile if the customer record contained a Date-type profile attribute with a null value; the profile resource now loads normally in this scenario.
  • Resolved an issue where the autocomplete dropdown in the Cortex Studio Zoom field was incorrectly displayed at the top of the page rather than beneath the input field. This was caused by a jQuery UI incompatibility and was fixed by upgrading jQuery UI from version 1.11.4 to 1.13.2.
  • Resolved an issue where XPFTaxableShoppingItem generated a new GUID on every tax calculation call, causing the ElasticPathTaxCalculator cache to always miss and redundantly recalculate taxes for identical requests. The GUID is now derived from the shopping cart line item GUID, ensuring consistent cache hits for repeated tax lookups on the same cart items.
  • Fixed a NoSuchElementException ("No value present") server error in Cortex that occurred when a new SKU option value was added and assigned to a new product SKU before the SKU option cache (default 60-minute TTL) had expired. When the missing option value is detected, the stale SKU option entry is now evicted from the cache and reloaded from the database.
  • Fixed spurious "Invalid cookie header" warnings appearing in logs during OpenID Connect authentication handshakes by updating the HttpClient in OidcHttpRequestUtil to use the RFC-compliant standard cookie specification (CookieSpecs.STANDARD).
  • A new cortex.headers.ignore JVM parameter has been added to Cortex, allowing administrators to specify a comma-separated list of HTTP request headers to unconditionally remove before processing. Unlike headers configured via the OSGi "Headers to Remove" list, headers specified in this parameter are stripped in all circumstances, including when trusted header mode is enabled or when requests target the authentication endpoint.
  • Fixed an intermittent Cortex startup failure where the Spring JMS bundle could not find a required Spring Transactions class during startup. This was caused by an unpredictable bundle load order; the fix moves the Spring Transactions bundle to load at an earlier stage (bundles-level4) to guarantee it is available before Spring JMS needs it.
  • A warning logged when the auth.mode property is missing from authentication.properties now appears only once per session instead of on every Cortex request; additionally, the default configuration now includes auth.mode=OAUTH_PASSWORD to prevent the warning from appearing in standard deployments.
  • Product SKU availability validation errors now return available-date and expiry-date fields in ISO 8601 format (e.g., 2026-09-04T00:00:00) instead of a localized US short date format (e.g., 9/4/26 12:00 AM).

Additional Commerce Manager enhancements​

  • Fixed an issue in Commerce Manager where performing a new Price List Assignment search that returns no results would fail to clear the previous search results if the user had navigated away from the first page, leaving stale results visible alongside the "No results found" message.
  • Removed unused BouncyCastle (bcprov and bcutil) plugins from Commerce Manager to remediate three security vulnerabilities: CVE-2026-0636 (CVSS 5.3), CVE-2026-5598 (CVSS 10.0), and CVE-2025-14813 (CVSS 9.0).
  • Fixed broken JMX get/setLogLevel operations in Commerce Manager that were failing with a NoClassDefFoundError. The ep-jmx-logging-api and ep-jmx-logging-log4j libraries are now explicitly packaged as part of the Commerce Manager webapp rather than relying on transitive dependency resolution.
  • Fixed an issue where coupon codes created in Commerce Manager with leading or trailing whitespace (including Unicode whitespace characters) would fail validation when used by customers; the coupon service now automatically strips whitespace from coupon codes on both create and update operations, including via Import/Export.
  • Fixed an issue in Commerce Manager where clearing customer profile fields (e.g., Business Number, Tax Exemption ID) would not save correctly, causing values to revert to their previous entries. The fix ensures that setting a short-text customer profile attribute to blank removes the corresponding database record rather than retaining the old value.
  • Resolved an issue in Commerce Manager that caused a NoSuchBeanDefinitionException when attempting to copy a shopping cart promotion that contained rule exclusions (e.g., category, SKU, or product exclusions); the DuplicateShoppingCartPromotionWizard now correctly resolves the bean using the exception's type rather than a hardcoded bean name.
  • Fixed an issue in the Commerce Manager promotion editor (both Catalog and Cart Promotions) where changes to Store or Catalog assignments made after an initial save would not be persisted — the editor now correctly reads assignment state from the current editor model rather than a stale reference captured at editor open time.
  • Fixed an issue in Commerce Manager where the shipping service level dropdown for a Shipping Discount promotion action retained stale options after the store selection was changed. If the newly selected store has no applicable shipping service levels, the dropdown is cleared and disabled, and an error is displayed to prevent saving an invalid promotion.
  • Descender characters (g, p, y, j, q) were being visually clipped at the bottom of column headings in Commerce Manager lists and grids. This was resolved by injecting a client-side JavaScript override that adds padding to the RAP GridColumnLabel cell height, and updating the $table_header_padding variable.
  • Removing a product or SKU attribute from a product type no longer incorrectly deletes attribute values for products in other product types that share the same attribute — only attribute values belonging to products of the modified product type are now removed.
  • In Commerce Manager, required boolean customer profile attributes were missing the required field (red !) icon and displayed a raw exception message instead of a user-friendly error when left unset on save. Both issues are now resolved, bringing behavior in line with other required attribute types.
  • Fixed an issue in AbstractCmClientFormEditor where a CancelSaveException during a save operation (e.g., saving a cart promotion with no stores assigned) would cause an unwanted system error dialog to appear alongside the validation error dialog. The save operation now correctly handles this exception, displaying only the relevant validation message and keeping the editor open without triggering a spurious system error.
  • The PromotionRulesWidgetUtil class has been made extendable by removing the final modifier and changing the constructor and LayingOutMouseAdapter inner class to protected, enabling custom implementations of promotion rules widget behavior.
  • When editing an existing cart promotion, switching between "Define cart level rules" and "Define line item level rules" in the Promotion Rules tab now properly displays only the relevant conditions and actions for the selected level, and removes incompatible rule elements when the promotion is saved — matching the behavior already present in the Create Shopping Cart Promotion wizard.
  • BaseConditionalExpressionAction has been renamed to AbstractConditionalExpressionAction and made abstract, with the placeholder getTargetIdentifier() implementation removed.
  • Fixed an error that occurred when opening a newly created master catalog configured with all available languages. The root cause was that certain locales returned by the JVM could not be round-tripped through their string representation, causing a persistence exception; these incompatible locales are now filtered out.
  • The changeset icon in the Commerce Manager top menu has been updated to reflect the current visual style and now displays a text label beneath the icon.
  • Fixed a bug where copying a shopping cart promotion in Commerce Manager caused the copy to share the original promotion's shopper conditions (selling context), meaning edits to one promotion's conditions would unexpectedly affect the other. A database migration script runs automatically on upgrade to separate any previously affected promotions.
  • Validation dialogs shown when saving shopping cart or catalog promotions with missing store or catalog assignments now display as standard warning dialogs consistent with the Commerce Manager interface, including a proper title and warning icon instead of a plain, untitled message box.

Additional Search Server enhancements​

  • Fixed an issue where the Search Server query cache (configured via openjpa-querycache in ehcache.xml) was preventing index update notifications from being processed for up to an hour; the cache timeout has been reduced from 3600 seconds to 5 seconds, ensuring near-real-time index updates.
  • Resolved a date truncation error that occurred during Search Server startup when the TRULESTORAGE table was empty. A timezone transformation in the MySQL driver caused an epoch-based date (Date(0)) to shift before the Unix epoch (1969-12-31), producing an invalid datetime value that prevented the TJOBEXECUTION record from being written and blocked promotion rule compilation. The fix replaces the epoch date write with a delete operation on the job execution record.

Additional Batch Server enhancements​

  • Fixed a bug in the AbandonedCartsCleanupJob where cart UIDs were incorrectly passed to a service method expecting shopper UIDs, causing abandoned shopping carts to remain active instead of being deactivated. The job now correctly fetches cart GUIDs and uses the appropriate deactivateShoppingCartsByGuid service method.
  • Fixed an issue where shopping cart line items soft-deleted via Cortex only permanently removed from the database when the underlying shopping cart expired. A new InactiveCartItemsCleanupJob now runs hourly (at 20 minutes past the hour) to purge these records, respecting the existing COMMERCE/SYSTEM/INACTIVECARTSCLEANUPJOB/minAge setting (default: 60 minutes) before deletion.
  • Fixed an issue where the "Order Cleanup" jobs failed with a foreign key constraint error when attempting to delete orders that had associated order hold records. This was resolved by updating theFK_TORDERHOLD_TORDER foreign key constraint on the TORDERHOLD table to use cascade deletion via a Liquibase database migration.
  • The PurgeExpiredCompletedOrdersBatchProcessor and PurgeExpiredFailedOrdersBatchProcessor classes have been consolidated into a single PurgeOrdersBatchProcessor class, which is now shared by both the expired completed and expired failed order cleanup Quartz jobs.
  • Fixed intermittent promotion compilation failures where some promotions were not recompiled properly after edits. The ruleUpdate.properties and catalogPromo.properties files used by the Search Server to track rule compilation and catalog promotion check timestamps were vulnerable to race conditions from concurrent access and could be lost during deployments. These files have been replaced with a new TJOBEXECUTION database table, ensuring reliable, consistent state tracking across all nodes.

Additional Data Sync enhancements​

  • Fixed unnecessary product reindexing when publishing new SKU option values. Publishing a new SKU option value via the Data Sync Tool no longer incorrectly creates TINDEXNOTIFY records for all products associated with the SKU option, preventing unnecessary reindexing of unaffected products in the live environment.

Additional Import/Export enhancements​

  • Performance improvement for inventory imports: Redundant calls to the expensive getInventory method (which queries both TINVENTORY and TINVENTORYJOURNAL) have been eliminated during inventory import processing, improving import time by about 3X.
  • Fixed a NullPointerException in the Import/Export API's SummaryAggregationStrategy that caused the API to return an unhelpful 500 Internal Server Error when an import failed (e.g., when an invalid changeset GUID was provided); the API now correctly returns a 400 Bad Request with a meaningful error message.
  • Fixed a spurious Error during type conversion stack trace that appeared in Integration Server logs after every Import/Export Export API request. The error was caused by Apache Camel's OnCompletion processor attempting to cache a PipedInputStream whose write end had already been closed; the fix configures onCompletion() to use the original message instead, avoiding the closed-stream read. Export API functionality was unaffected, but the noise in logs could obscure real errors.
  • Fixed a bug in ImportRouteBuilder where super.configure() was called twice, which could cause duplicate route registration and unexpected behavior during Import/Export operations.
  • Removed unused productService and productLoadTuner fields, associated setter methods, and the productTunerForPricing Spring bean definition from PricingExporterImpl.
  • When an import fails due to an invalid attribute value (e.g., a value exceeding the maximum length), the error message now identifies the specific attribute key responsible, such as Invalid attribute 'catName' with validation error message 'AttributeValue length must be less than or equal to 255', replacing the previous generic error that required log inspection to diagnose.
  • Importing a new catalog through the Import/Export API was failing with a pcStateManager is null exception. The issue was resolved by changing the default OpenJPA detachment strategy from StrictDetachmentStrategyImpl to NonDetachingDetachmentStrategyImpl, while retaining strict detachment for Cortex.

Additional performance enhancements​

  • Fixed a critical performance issue where Cortex became unresponsive due to a slow-running database query against the TCOUPONUSAGE table when looking up automatically applicable coupons. A new index (I_TCOUPONUSAGE_CUSTOMEREMAILADDRESS) on the CUSTOMER_EMAIL_ADDRESS column has been added via a Liquibase changeset to resolve this.
  • The saveShoppingCart method now skips pricing snapshot evaluation (which triggers the promotion rule engine) when no active free-item promotions ( e.g., "buy N, get M free") exist for the store. The result is cached per store with a 10-minute TTL, reducing unnecessary rule engine overhead on every cart save in stores without such promotions.

Additional test enhancements​

  • Fixed an issue where the JaCoCo Maven plugin was silently skipping test coverage report generation and threshold enforcement because the Surefire plugin's argLine was not using late-binding (@{jacocoArgLine}) for the JaCoCo agent argument. As a result, JaCoCo execution data was never written and coverage checks were bypassed entirely.
  • Fixed an intermittent failure in the Create Catalog Selenium tests where the default language dropdown would not finish populating in time, causing test failures. A retry mechanism now replaces the previous fixed sleep delay, making the test more reliable.
  • Fixed an intermittent test failures caused by a race condition where shipment line item tax values were being checked before asynchronous post-capture checkout actions (such as tax application) had finished writing to the order. A new ORDER_READY event type has been introduced, which is fired by PostCaptureCheckoutServiceImpl only after all post-capture actions have completed, providing a reliable signal that order data is fully populated.
  • Fixed a duplicate FACET_GUID value in the Mobee demo data (liquibase-changelog.xml), which caused intermittent test failures. The duplicate GUID for the "Rental Days" facet entry has been replaced with a unique value.
  • Removed the Mockito.reset-based tearDown method and eliminated unnecessary mock stubs in PromotionRuleDelegateImplTest, ensuring that Mockito's strict stubbing checks are no longer suppressed and unused stubs are properly detected. This improves test reliability and prevents false confidence from silently ignored stub violations.
  • Fixed an intermittent integration test failure caused by a missing teardown in MergeEngineImplITest, which left a CacheManager instance running and prevented subsequent Data Sync Tool tests from initializing correctly. The fix ensures the Spring application context is properly closed after each test run.
  • Created new Cucumber functional tests for Import/Export functional scenarios in commerce-engine/importexport/ep-importexport-acceptance-tests. These tests include validating idempotent imports, selling context conditions, and INSERT/UPDATE/INSERT_OR_UPDATE import strategies. A shared readZipEntryAsString utility method was also refactored into the base test class for reuse across step definitions.
  • Resolved intermittently failing AddToAndRetrieveItemsFromWishlist test scenarios where search retry logic incorrectly fell back to searching by product name only instead of maintaining the original name-and-code criteria, causing intermittent false test failures.
  • The Cucumber test EhCache default cache time-to-live has been updated from 60 seconds to 1 second to align with the production EhCache configuration, preventing stale data from causing intermittent test failures when values are changed in Commerce Manager and accessed via Cortex.
  • Updated TokenStoreStrategyImplTest, OAuth2AccessTokenTransformerTest, and AccessTokenDtoTransformerTest to generate random UUID-based tokens instead of static hardcoded token values, improving test isolation and reducing potential false positives in authentication token testing.
  • Fixed an invalid Scenario Outline (missing its examples table) in gift-certificate-payment-instruments.feature by converting it to a standard Scenario. This resolves warnings raised by the Cucable plugin and IntelliJ, and allows the test to execute correctly.
  • Fixed an intermittent race condition in automated tests where the "Move item" button was incorrectly reported as disabled when splitting an order shipment, causing tests to fail unpredictably. The fix adds retry logic around the item selection and button click in the order editor test helper.
  • Fixed intermittent automated test failures in the Manage Virtual Catalog scenarios, specifically when adding or removing linked categories and deleting a virtual catalog. The failures were caused by menu-dismissal side effects in the test framework's click logic, which have been resolved by introducing a dedicated menu item click method.
  • Fixed an intermittent failure in the catalog syndication category flow test where a randomly generated category name could land on a second page of search results, causing the category finder dialog's pagination logic to never execute due to catching the wrong exception type.
  • Fixed a test reliability issue in FatalExceptionCheckerTest where the ignoreFatalJsExceptions flag was being reset after each test run rather than before, which could cause tests to behave incorrectly if a previous test left the flag in a modified state.
  • Retry logic in retryFunction and retryAttempts has been updated to more precisely classify which exceptions should trigger a retry versus fail immediately. InvalidElementStateException and NotFoundException (including NoSuchElementException) are now retried, while InvalidSelectorException is treated as a fatal error and will stop retrying immediately. These changes reduce false negatives from transient element state issues and prevent unnecessary retries when a locator is fundamentally broken.
  • Selenium automated tests now support a fail-fast mechanism for critical JavaScript errors: exceptions with a FATAL: prefix in their message will immediately break the retry loop instead of being silently retried. This is disabled by default (lenient/legacy behaviour) and can be enabled by setting the ep.selenium.ignore.fatal.js.exceptions property to false. The assertSingleElement() helper in ep-test-support.js has been updated to emit a FATAL:-prefixed error when an ambiguous element selector matches more than one element.
  • Corrected automated test column references throughout the Commerce Manager test suite to use precise column names (such as "Display Name", "Product Code", "Order #", and "SKU Configuration"), ensuring compatibility with strict table column matching and improving test reliability.
  • Fixed intermittent Selenium test failures caused by nested retryFunction() calls, where inner retry exhaustion was incorrectly wrapped in a timeout exception that the outer retry could not handle. A new retryAttempts() method has been introduced as a safe alternative for inner retry logic, re-throwing the original assertion error on exhaustion rather than wrapping it.
  • Resolved intermittent failures in wishlist management automated tests by replacing unreliable element-existence checks with a direct negative assertion method. As part of this fix, the test widget library was refactored to use a new fluent .as("description") pattern for supplying custom failure messages, replacing the previous approach of passing message strings as method parameters.
  • Commerce Manager system tests now explicitly log out at the end of each test scenario to release server-side sessions, preventing memory exhaustion caused by session accumulation when tests complete faster than the configured session timeout.
  • Fatal JavaScript exception checking in system tests is now strict by default; tests will immediately fail when a fatal JavaScript exception is detected rather than treating it as a retryable error. To restore the previous lenient behavior, set the property ep.selenium.ignore.fatal.js.exceptions to true.
  • Fixed intermittent Performance Insights test failures by removing code that reset the database between test scenarios. This reset was dropping all database tables while applications were still running, leaving them in an unknown state and causing unpredictable failures.
  • Fixed an intermittent automated test failure caused by a page element becoming detached from the document between being located and clicked. The fix moves the element lookup, scrolling, and focus steps inside the retry loop so all actions are retried together if a stale element is encountered.
  • Fixed an intermittent automated test failure where creating a return in the Order editor would occasionally throw a stale element reference error. The fix removes redundant viewport-checking logic in the test definition that was re-querying a page element after it had already been refreshed or replaced by the browser.
  • Fixed an intermittent error where order shipment release failed emails could not be sent due to duplicate test execution listener registration in Cucumber tests, causing the entity manager factory to close twice and resulting in a null pointer exception during transaction commits.
  • Improved reliability of Selenium test infrastructure by adding automatic retry logic (up to 3 attempts) when initializing a remote Chrome browser session, and ensuring the WebDriver session is always properly cleaned up even if an error occurs during shutdown.
  • Fixed intermittent test failures in the "Move Object between Changesets" test scenarios caused by multiple scenarios competing for the same product when tests ran concurrently; each scenario now uses a distinct product to avoid conflicts, since an object can only belong to one changeset at a time.
  • Fixed an issue where browser HTML snapshots captured during Selenium test failures were partially rendered in test reports, making them unreadable. The HTML source is now properly escaped before being embedded, allowing developers to inspect the state of page elements at the time of failure.
  • Fixed a race condition in the Utils.uniqueCode() test utility method that could generate duplicate codes when multiple threads ran concurrently, causing intermittent database unique constraint violations during integration test execution. The fix replaces a non-thread-safe static integer with an atomic integer and incorporates the process ID into the generated code to ensure uniqueness across parallel test forks.
  • Fixed intermittent failures in order payment modification test scenarios caused by race conditions during parallel test execution. The test payment provider plugin was updated to use thread-safe data structures, ensuring that call counts per order number and transaction type are tracked correctly across concurrent tests.
  • Fixed a resource leak in programmatic test data generation by converting TestEpCoreProvider to a singleton with proper shutdown handling, resulting in lower memory usage, reduced CPU load, and fewer peak database connections during test suite execution.
  • Commerce Manager automated test steps for search result validation have been updated with retry logic to handle cases where search results take longer to load, resolving intermittent test failures that were most commonly seen on Oracle databases but could also affect MySQL and PostgreSQL environments.
  • Fixed an intermittent issue where clearAndTypeText() would silently accept a partially entered text string as successful, causing automated tests to fail unexpectedly. The validation check now confirms the full text value was entered into the field, rather than only checking that the field is non-empty.
  • Fixed intermittent failures in the automated tests for the promotion SKU search and account search features in Commerce Manager. The failures were caused by timing issues where tests checked for results before the UI had finished loading them. Retry logic and proper result-waiting behavior have been added to make these tests more reliable.
  • Fixed an intermittent test failure in the Customer Data Policy feature caused by a JavaScript error when attempting to move focus to a page element; the automated test framework's retry logic now ignores JavascriptException and retries the action automatically.
  • Separate port ranges are now assigned during integration test builds to prevent port conflicts: cargo web applications use ports 30000–39999 and the embedded ActiveMQ broker uses ports 40000–49999. Previously, the two port reservation steps could accidentally reserve the same port, causing intermittent build failures.
  • Improved debugging output in Commerce Manager automated test step definitions, providing more detailed error messages when payment transaction verifications or payment reservation assertions fail, making it easier to diagnose intermittent test failures.
  • Upgraded the Cucable plugin from version 1.9 to 1.15.2 and expanded parallel test execution support across multiple system test modules by adding runner templates, parallel-runners build profiles, and custom report/rerun output directory placeholders. Several test feature files had their isolation tags (@runIsolated) added or removed to improve reliability when tests run concurrently.
  • Fixed an intermittent failure in the Tags System where concurrent automated test scenarios modifying the same tag dictionary simultaneously caused database unique constraint violations, preventing tag definitions from being saved in Commerce Manager.
  • Improved the Cortex API automated test suite by enhancing assertion failure messages to include more diagnostic detail, making test failures easier to investigate. Validation and order-related error message step definitions have been consolidated into a single AdvisorSteps class, and cart-related steps have been moved to ConfigurableCartSteps.
  • Duplicate feature path entries have been removed from Cucumber test runner configurations, and duplicate columns have been removed from feature tables. These changes eliminate warning messages during test runs and fix an incompatibility that prevented scenarios from being parallelized correctly.
  • Selenium tests for the Commerce Manager now enforce exact table column name matching, throwing a clear error message that identifies the invalid column name and lists the available columns when a mismatch occurs. This improves test reliability and makes failures easier to diagnose and debug.
  • Fixed intermittent automated test failures in Commerce Manager caused by ambiguous element selectors that could match multiple widgets; the test support library now throws a descriptive error when a selector matches more than one element, and several selectors have been made more specific to target the correct element reliably.
  • Added support for programmatic commerce data generation in Cucumber test step definitions, allowing new isolated stores to be created per test scenario. This replaces slow UI-driven store creation and prevents intermittent test failures caused by concurrent scenarios sharing and conflicting over the same store's payment configurations.
  • Fixed a race condition that caused intermittent test failures when Commerce Manager user creation tests were run in parallel. The previous implementation used direct SQL inserts to create users in the database, which could produce unique constraint violations; it has been replaced with a proper service-layer approach using CmUserTestPersister and the TestEmbeddedEpCore framework.
  • Updated payment configuration automated tests to create a unique store for each test scenario, preventing intermittent test failures caused by shared store state when tests run concurrently.
  • Fixed intermittently failing pre-order and back-order automated tests where inventory was incorrectly being added to the wrong warehouse, causing order allocation to fail.
  • Fixed an intermittent failure in the catalog batch integration test (CatalogBatchIntegrationTest) caused by an incorrect expected message count. The fix corrects the count from 1 to 2 (since both the cleanup and build batch jobs send messages) and moves the message listener setup to run before test data is persisted, ensuring all relevant messages are captured. Messages are also now filtered by option code to avoid interference from unrelated test activity.
  • Fixed intermittently failing catalog syndication integration tests. The tests previously relied on counting an exact number of messaging events within a time window, which was inherently fragile; they now assert directly against database state instead. The expiry projection job tests were also fixed by invoking the job directly rather than sleeping for 125 seconds and waiting for the scheduler to run it.
  • Fixed an intermittent test failure in the Order Item Detail automated tests where the cleanup hook would fail to locate the Merchandising tab element because the correct product editor pane was not explicitly activated before interacting with it. The cleanup logic was updated to close the order pane and navigate to the correct product editor tab before proceeding.

Additional Build Tools enhancements​

  • The ActiveMQ container startup script (start-activemq.sh) now validates that required and optional environment variables are set to valid values before starting the broker. If an invalid value is detected, the script exits with a descriptive error message rather than starting with a misconfigured state.
  • Fixed an issue where property files from a secure configuration repository were not being applied during data population, causing the tool to run without the expected environment-specific configuration.
  • The ext-container-layout build has been updated to fail immediately if any declared artifacts are missing, rather than issuing a warning and continuing. This prevents broken container images — where missing dependencies such as messaging client libraries would only cause errors at runtime — from being produced silently.
  • Build log files generated during pipeline jobs are now saved as artifacts when those jobs fail, restoring previously removed behavior and making it easier to diagnose build failures.
  • The explicit reserved code cache size setting of 128 MB has been removed from Maven build options, allowing Java 21 to use its default of 240 MB and enabling proper segmented code cache allocation, which improves build reliability.
  • Added a run_cortex_system_tests.sh script and updated the Maven settings configuration playbook to support a CI-specific settings template, enabling the branch validation job to use centralized build tools instead of inline commands in the pipeline definition.
  • Build Tools now support MySQL 8.4 container images, which is now the default version built by the build_base_images.yml playbook. MySQL 8.0 remains supported and can be selected by overriding the database_id variable at runtime (e.g., ansible-playbook -e database_id='mysql-8.0' build_base_images.yml).
  • The MySQL live (DST target) database connection parameters in the build tools and Commerce containers were missing the allowPublicKeyRetrieval parameter, causing them to be out of sync with the author database parameters. Both EP_DST_TARGET_PARAMS and EP_DST_TARGET_URL have been updated to include this parameter, ensuring consistent database connection configuration across author and live environments.
  • The Tomcat connector (port 8080) in Build Tools now has a default maxThreads value of 250, aligning the self-managed commerce platform with Operational Insights recommendations for optimal performance.

Additional database enhancements​

  • Fixed three Liquibase changesets (2021-09-create-FK-BATCH_JOB_EXECUTION-index, 2021-09-create-FK-BATCH_JOB_EXECUTION_PARAMS-index, 2021-09-create-FK-BATCH_STEP_EXECUTION-index) that were incorrectly configured with runAlways="true", causing duplicate entries to be inserted into the DATABASECHANGELOG table on every data population run. This could cause failures for databases that have a primary key or unique constraint on the DATABASECHANGELOG table's ID, AUTHOR, and FILENAME columns.
  • Fixed data type mismatches in the TRMAGENERATOR and TORDERNUMBERGENERATOR tables where sequence number columns were incorrectly typed as VARCHAR instead of BIGINT, and the identifier column was misaligned with OpenJPA expectations. A new ID column has been added to each table as the JPA identifier, while the existing UIDPK column is retained for backwards compatibility. This fix resolves failures on PostgreSQL, which does not perform the implicit casts that other databases use to work around these inconsistencies.
  • Fixed a failure in the reset-db step for local Oracle database setup. The Oracle reset script was reworked to drop and recreate the Pluggable Database (orclpdb1) instead of attempting to drop the default permanent tablespace, and the oracle-dev-db Maven settings profile was updated with corrected defaults (username COMMERCEDB, tablespaces COMMERCE/COMMERCETEMP). Developers using a local Oracle database will need to update their settings.xml to match the new profile configuration.
  • The FACET_GUID column in the TFACET database table has been renamed to GUID and a unique constraint has been added to enforce data integrity. The Facet interface and FacetImpl now extend Entity instead of Persistable, and the getFacetGuid()/setFacetGuid() methods have been replaced with the standard getGuid()/setGuid() methods.
  • Fixed a failure during Liquibase updates where duplicate GUID values in the TCARTTYPE table caused a unique constraint violation ( I_CARTTYPE_GUID_UNQ) when applying the 2026-03-carttype-guid-unique-constraint changeset; the Liquibase changeset now resolves pre-existing duplicates by reassigning their GUIDs before applying the constraint, and the Import/Export assembler has been corrected to no longer retain cart types that are absent from the import data, which could previously result in duplicate GUIDs being persisted.
  • A CREATION_DATE column has been added to the TSHOPPINGCART table, and ShoppingCartMementoImpl now implements the DatabaseCreationDate interface so the creation timestamp is automatically populated for new shopping carts. Existing cart records will have a null creation date.
  • The TORDERAUDIT.DETAIL database column has been converted from a CLOB type to VARCHAR(20000), reducing potential performance overhead associated with large object storage for order audit detail records. A database migration will run automatically via Liquibase; note that if any existing DETAIL values exceed 20,000 characters, the migration will halt and must be resolved before upgrading.
  • A Liquibase changeset has been added that automatically runs ANALYZE on PostgreSQL databases during each data population run, ensuring the query planner has up-to-date table statistics. This prevents significant query performance degradation that can occur after a major PostgreSQL version upgrade, which clears existing table statistics.

Supported technology updates​

Self-Managed Commerce 8.8.0 is compatible with the following Elastic Path releases:

Elastic Path ComponentCompatibility
Extension Point FrameworkExtension Point Framework compatibility matrix
CloudOps for KubernetesCloudOps for Kubernetes compatibility matrix
Self-Managed Commerce DockerSelf-Managed Commerce Docker compatibility matrix

Additionally, the following changes have been made to the Supported Technologies:

  • Removed support for MySQL 5.7. MySQL 5.7 reached its end-of-life on October 31, 2023. Customers should upgrade to MySQL 8.0 or MySQL 8.4.

Dependency changes​

Many dependencies were updated as part of Self-Managed Commerce 8.8.0. The highlights are shown below:

  • Upgraded ASM from 7.x to 9.x.
  • Upgraded commons-lang from 3.10.x to 3.18.x.
  • Upgraded Drools from 7.x to 8.x.
  • Upgraded Jackson from 2.19.x to 2.21.x.
  • Upgraded Log4j from 2.17.x to 2.25.x.
  • Upgraded Logback from 1.2.x to 1.5.x.
  • Upgraded okhttp from 3.x to 4.x.
  • Upgraded SLF4j from 1.7.x to 2.0.x.
  • Upgraded SOLR from 9.8.x to 9.10.x.
  • Upgraded Eclipse Sisu from 0.3.5 to 0.9.0.M4.
  • Upgraded Eclipse Remote Application Platform from 4.2 to 4.6.

Database changes​

  • Added new setting definition records:
    • COMMERCE/SYSTEM/PROMOIQ/enable
    • COMMERCE/SYSTEM/JOBS/PAUSENONCRITICAL/enabled
    • COMMERCE/SYSTEM/JOBS/PAUSENONCRITICAL/startsAt
    • COMMERCE/SYSTEM/JOBS/PAUSENONCRITICAL/expiresAt
  • Added new setting value context records:
    • COMMERCE/SYSTEM/MESSAGING/SHOPPINGCARTS/channelUri with context shoppingCartCacheHandler
  • Added TAGREEMENT table:
    • UIDPK: BIGINT
    • CODE: VARCHAR(50)
    • NAME: VARCHAR(255)
    • DESCRIPTION: VARCHAR(1024)
    • INTERNAL_TYPE: VARCHAR(50)
    • BILLING_FREQENCY: INT
    • AGREEMENT_LENGTH: INT
    • END_BEHAVIOUR: VARCHAR(50)
    • CANCEL_ALLOWED: BOOLEAN
    • PAUSE_ALLOWED: BOOLEAN
  • Added TORDERAGREEMENT table:
    • UIDPK: BIGINT
    • ORDER_UID: BIGINT
    • CODE: VARCHAR(50)
    • NAME: VARCHAR(255)
    • DESCRIPTION: VARCHAR(1024)
    • INTERNAL_TYPE: VARCHAR(50)
    • BILLING_FREQENCY: INT
    • AGREEMENT_LENGTH: INT
    • END_BEHAVIOUR: VARCHAR(50)
    • CANCEL_ALLOWED: BOOLEAN
    • PAUSE_ALLOWED: BOOLEAN
    • Added index I_ORDERAGREEMENT_ORDERUID on ORDER_UID column.
    • Added foreign key constraint FK_ORDERAGREEMENT_ORDERUID on ORDER_UID column (referencing TORDER.UIDPK).
  • Added TORDERLOCALIZEDPROPERTIES table:
    • UIDPK: BIGINT
    • OBJECT_UID: BIGINT
    • LOCALIZED_PROPERTY_KEY: VARCHAR(255)
    • VALUE: VARCHAR(255)
    • TYPE: VARCHAR(50)
    • Added index I_ORDERLOCALIZEDPROPERTIES_OBJECTUID on OBJECT_UID column.
    • Added index I_ORDERLOCALIZEDPROPERTIES_LOCALIZEDPROPERTYKEY on LOCALIZED_PROPERTY_KEY column.
    • Added index I_ORDERLOCALIZEDPROPERTIES_TYPE on TYPE column.
  • Added TORDERSKURECURRINGPRICEPERIOD table:
    • UIDPK: BIGINT
    • ORDERSKU_UID: BIGINT
    • RECURRING_PRICE_TYPE: VARCHAR(50)
    • PAYMENT_FREQUENCY_AMOUNT: INT
    • PAYMENT_FREQUENCY_UNIT: VARCHAR(50)
    • PAYMENT_START: INT
    • PAYMENT_END: INT
    • AMOUNT: DECIMAL(19,2)
    • ROLLOVER: BOOLEAN
    • Added index I_ORDERSKURECURRINGPRICEPERIOD_ORDERSKUUID on ORDERSKU_UID column.
    • Added foreign key constraint FK_ORDERSKURECURRINGPRICEPERIOD_ORDERSKUUID on ORDERSKU_UID column (referencing TORDERSKU.UIDPK).
  • Modified TPRICELIST table:
    • Added AGREMENT_CODE: VARCHAR(50) column.
    • Added index I_PRICELIST_AGREEMENTCODE on AGREMENT_CODE column.
    • Added foreign key constraint FK_PRICELIST_AGREEMENTCODE on AGREMENT_CODE column (referencing TAGREEMENT.CODE).
  • Modified TBASEAMOUNT table:
    • Added RECURRING_LIST: DECIMAL(19,2) column.
    • Added RECURRING_SALE: DECIMAL(19,2) column.
  • Added TPRODUCTAGREEMENT table:
    • UIDPK: BIGINT
    • PRODUCT_UID: BIGINT
    • AGREEMENT_CODE: VARCHAR(50)
    • ORDERING: INT
    • Added index I_PRODUCTAGREEMENT_PRODUCTUID on PRODUCT_UID column.
    • Added foreign key constraint FK_PRODUCTAGREEMENT_PRODUCTUID on PRODUCT_UID column (referencing TPRODUCT.UIDPK).
    • Added index I_PRODUCTAGREEMENT_AGREEMENTCODE on AGREEMENT_CODE column.
    • Added foreign key constraint FK_PRODUCTAGREEMENT_AGREEMENTCODE on AGREEMENT_CODE column (referencing TAGREEMENT.CODE).
  • Modified TCARTITEM table:
    • Added AGREEMENT_CODE: VARCHAR(50) column.
    • Added index I_CARTITEM_AGREEMENTCODE on AGREEMENT_CODE column.
    • Added foreign key constraint FK_CARTITEM_AGREEMENTCODE on AGREEMENT_CODE column (referencing TAGREEMENT.CODE).
  • Modified TORDERSKU table:
    • Added AGREEMENT_CODE: VARCHAR(50) column.
    • Added index I_ORDERSKU_AGREEMENTCODE on AGREEMENT_CODE column.
    • Added foreign key constraint FK_ORDERSKU_AGREEMENTCODE on AGREEMENT_CODE column (referencing TAGREEMENT.CODE).
  • Modified TSTORECARTTYPE table:
    • Added index I_STORECARTTYPE_STOREUID on STORE_UID column.
    • Added foreign key constraint FK_STORECARTTYPE_STOREUID on STORE_UID column (referencing TSTORE.UIDPK).
    • Added index I_STORECARTTYPE_CARTTYPEUID on CARTTYPE_UID column.
    • Added foreign key constraint FK_STORECARTTYPE_CARTTYPEUID on CARTTYPE_UID column (referencing TCARTTYPE.UIDPK).
  • Modified TCARTTYPEMODIFIERS table:
    • Added index I_CARTTYPEMODIFIERS_MODIFIERUID on MODIFIER_UID column.
    • Added foreign key constraint FK_CARTTYPEMODIFIERS_MODIFIERUID on MODIFIER_UID column (referencing TMODIFIERGROUP.UIDPK).
    • Added index I_CARTTYPEMODIFIERS_CARTTYPEUID on CARTTYPE_UID column.
    • Added foreign key constraint FK_CARTTYPEMODIFIERS_CARTTYPEUID on CARTTYPE_UID column (referencing TCARTTYPE.UIDPK).
  • Modified TCARTTYPE table:
    • Added unique constraint index I_CARTTYPE_GUID_UNQ on GUID column.
  • Modified TORDERNUMBERGENERATOR table:
    • Added ID: VARCHAR(50) column.
  • Modified TRMAGENERATOR table:
    • Added ID: VARCHAR(50) column.
  • Modified TFACET table:
    • Renamed FACET_GUID column to GUID.
  • Modified TCOUPONUSAGE table:
    • Added index I_TCOUPONUSAGE_CUSTOMEREMAILADDRESS on CUSTOMER_EMAIL_ADDRESS column.
  • Modified TORDERAUDIT table:
    • Changed DETAIL column type from CLOB to VARCHAR(20000).
  • Modified TORDERHOLD table:
    • Added cascade delete on FK_ORDERHOLD_TORDER foreign key.
  • Modified TSHOPPINGCART table:
    • Added CREATION_DATE: DATETIME column.
  • Modified TOAUTHACCESSTOKEN table:
    • Dropped foreign key constraint FK_OAUTH_CUSTOMER.
  • Created TJOBEXECUTION table:
    • UIDPK: BIGINT
    • NAME: VARCHAR(255)
    • LAST_EXECUTION_DATE: TIMESTAMP
  • Dropped TCUSTOMERGROUPROLEX table.