Announcement: You can find the guides for Commerce 7.5 and later on the new Elastic Path Documentation site. This Developer Center contains the guides for Commerce 6.13.0 through 7.4.1.Visit new site

This version of Elastic Path Commerce is no longer supported or maintained. To upgrade to the latest version, contact your Elastic Path representative.

What's new for Commerce Engine 6.10.0

What's new for Commerce Engine 6.10.0

Elastic Path Commerce Engine 6.10.0 includes bug fixes and performance improvements.

If you have any questions, contact support or go to the Community for the latest information and access to support bulletins, forums, and other Elastic Path resources.

New Features

Customer Segments

Customer Segments are the functionality which enables customer to be grouped together. Once available, customer segments can then be used to outline conditions for delivering price lists, dynamic content and cart promotions. In Elastic Path Commerce, Customer Segment tags are used to determine whether or not a customer belongs to a segment and resulting in content, prices, or promotions to be delivered to the current customer in the storefront.

More information about this feature can be found in the 6.10.0 Documentation.

Digital Returns

This adds the ability for a CSR to initiate a return of digital goods via the CM Client. The refactoring also adds server-side validation of returns to support future development of API-based CSR initiated returns and/or customer self-service returns.

Note that returns of subscription products are not included. Typically these would be done via the downstream subscription/billing system.

In order to support caches for both storefront and Cortex, a new pluggable Caching API was created in the ep-cache bundle. It supports the following capabilities:

  1. Pluggable implementations, including JSR-107 caches and Ehcache with future support for distributed caches (e.g. memcached) envisioned.
  2. Threadsafe operation with OpenJPA entities.
  3. Pub/Sub cache invalidation (Future)

In an additional note, ep-cache is now the first module in Commerce Engine which uses mockito for unit tests instead of JMock.

Thread safe, in-memory Category Caching

The overall goal of this change is to add thread safe, in-memory caching for Categories to both Cortex and Storefront. Accomplishing this goal required some substantive changes to the domain model, which can also be considered a non-trivial sub-goal. The domain model changes were: adding a true guid field to the Category object and severing the Category.getParent() and Category.getChildren() relationships.

Tag Definition Caching

Caching has been introduced for for TagDefinitions using ehcache and roughly aligns with the new caching strategy for other objects such as Product and Category. TagDefinitionService has been split into TagDefinitionService for writes and TagDefinitionReader for reads.

In addition, a handful of homegrown simple timeout caches in the tagging subsystem have been replaced with the ehcache version.

Enhancements

Better Event Messaging System

Event Message Consumption Configurability

Changes were made to the bean definitions and configuration of Event Message consumption to make it significantly more configurable, which facilitates making the settings needed to consume Event Messages reliably in production.

Default JMS type changed to Pooled

The default JMS configuration previously had a default type of ActiveMQConnectionFactory. This creates a new tcp connection for every call, which can cause some machines to crash. Consequently, this default was changed to be AmqJNDIPolledConnectionFactory so that a connection pool is used instead. This requires your application server to have the libraries activemq-pool and commons-pool.

Messaging as a fundamental part of Commerce Engine

The new ep-core-customer-messaging and the existing ep-core-order-messaging modules are now compile-scoped, not optional, dependencies of ep-core. Previously the ep-core-order-messaging module was an optional dependency, as this was only required when performing a checkout, and therefore omitted from applications such as Import/Export, DST, ep-core-tool, etc. Now that much more prevalent, the model has been reversed from an opt-in approach, in which adding the relevant dependency would overwrite the no-op messaging implementation, to an opt-out model, in which messaging is expected to be present and must explicitly be disabled if not desired. This more clearly documents of the intent and behaviour of each component.

Reliable Email Delivery

Email delivery in Elastic Path Commerce Engine is triggered by messages sent within the Event Messaging framework. Certain Event Messages will trigger the publishing of a corresponding Email message which contains the contents and metadata regarding the email message. For example, when a new Order is created, an ORDER_CREATED event message is published. One of the consumers of this message is the component that generates an Order Confirmation Email.

Payment Gateway API ExternalAuth capability

The Payment Gateway API was enhanced to support ExternalAuth capabilities for payment-gateways.

Programatic Access to Import/Export Configuration

The method getImportConfiguration() has been added to Import/Export's ImportController, allowing programatic access to the Import/Export configuration.

Configurable Import/Export Configuration Location

When using the Import/Export tool, the operator is now able to supply an external importexporttool.config file, so he does not have to invade the deployment to configure database and search server configuration. For example,

importexport.bat -e searchconfiguration.xml -p [filepath]\importexporttool.config

If the argument is not specified, then the default config file is used so it is backwards compatible.

Tax Details

The storefront Order History page, Order Confirmation (Receipt), and the Order Confirmation Email now display all tax details instead of a summary.

Checkout failure rollback

Previously, when an order was created, the new order is filled with details right away before it is saved to the context. So if anything goes wrong while filling in the order details, the created order can't be rolled back. The CreateNewOrderCheckoutAction was changed to split this into 2 steps, saving the order in the context for rollback action after the order is created but before details are filled.

Publish event for changesets

This included adding capabilities to trigger event to the CM Client

Upgraded maven tomcat plugin to tomcat7

For developers running tomcat from the command line via maven: where before you would have used mvn tomcat:run or mvn tomcat:run-war, you should now do mvn tomcat7:run or mvn tomcat7:run-war. The plugin configuration was also set to disable http-only cookies due to compatibility issues with DWR.

Import Export System Tests

Automated end-to-end testing has been added to Import/Export. In particular, a Java process builder is used to run the Import/Export CLI and ensure it can be used successfully.

New ep-core-tool command

The EP Core Tool has had a new command added to update the Store URL:

set-store-url <storecode>=<url> 

SKU Level Tax Code

ProductSku now has its own optional tax code field. If not set, the tax code is obtained from the parent product. The tax code inheritance now lives in a new TaxCodeRetriever service. The old get/setTaxCode methods on Product have been renamed to get/setTaxCodeOverride to more clearly convey the field's intended use and have also been added to ProductSku.

Product Association Search Criteria

Additional fields have been added to ProductAssociationSearchCriteria to allow inclusion of Start Date and End Date in the query. The query building logic in ProductAssocationServiceImpl was extracted out into a separate class, ProductAssociationQueryBuilder.

Default Sku Behaviour in multi-sku bundles

When you view a product bundle with a multi-sku product constituent and the multi-sku constituents' default sku is not available for purchase, the entire bundle becomes unavailable for purchase even when the multi-sku constituent has other skus still available for purchase.

This premature marking of bundles as out of stock in this scenario was addressed by adding a step to the process of wrapping a product into a storeProduct. This extra step traverses a bundle's constituents and checks whether a product constituent's default sku is available. If it is not, then the product constituent's default sku is set to an available sku if one can be found.

Tax Journal Entries for Zero Shipping Cost

Previously when a shipment is processed and has a zero-amount shipping cost, no tax journal entries are recorded for the shipping cost. These tax journal entries will now be craeted. Note that this applies to physical shipments but not electronic shipments, because electronic shipments are always free. This means there is different treatment for "zero-cost" shipping and an absence of shipping.

Expose the applied rule discount records on the cart with a DiscountRecordContainer.

Previously, discounts applied to the shopping cart were stored in a private Map field in the cart. Applications such as Cortex may want to use this information, so the private Map of Maps was changed to be a new DiscountRecordContainer class, and this is exposed on the shopping cart via getDiscountRecordContainer().

New pluggable Product Caching API

Methods which read Product and ProductSku entities by immutable unique keys were moved from the ProductService and ProductSkuService to the new ProductLookup and ProductSkuLookup interfaces. These new lookups have the following characteristics:

  1. To reduce confusion, both the ProductService and ProductLookup interfaces and ProductSkuService and ProductSkuLookup interfaces are completely disjoint. The services do not share any methods with the lookups.
  2. Lookup interfaces do not support any FetchGroup or LoadTuner arguments. The expected contract is that an entity returned from a lookup will always be "fully loaded"

The following methods were moved from ProductService to ProductLookup:

ProductService ProductLookup
get(long) findByUid(long)
getObject(long) findByUid(long)
getWithCategories(long) findByUid(long)
load(long) findByUid(long)
findByGuid(String) findByGuid(String)
findByGuid(String, ProductLoadTuner) findByGuid(String)
getProductWithSkus(Product) findByUid(long) or findByGuid(String)
findByGuids(Collection<String>) findByUids(Collection<Long>)

The following methods were moved from ProductSkuService to ProductSkuLookup:

ProductSkuService ProductSkuLookup
get(long) findByUid(long)
getObject(long) findByUid(long)
getTuned(long) findByUid(long)
getWithProduct(long) findByUid(long)
load(long) findByUid(long)
findByUids(Collection<Long>, FetchGroupLoadTuner) findByUids(Collection<Long>)
findByUids(Collection<Long>, ProductSkuLoadTuner) findByUids(Collection<Long>)
findByGuid(String) findByGuid(String)
findBySkuCode(String) findBySkuCode(String)
findBySkuCodeWithAll(String) findBySkuCode(String)
findBySkuCodes(Collection<String>) findBySkuCodes(Collection<String>)

Breaking the relationships from ShoppingItem and OrderSku to ProductSku

One of the preconditions for caching ProductSkus was to remove the CascadeType.MERGE annotations from ShoppingItem and OrderSku to ProductSku. While removing only the annotation was necessary for thread-safety, removing the relationship entirely also gives us much better integration possibilities with non-OpenJPA catalog data sources. As a result, the direct ShoppingItem->ProductSku and OrderSku->ProductSku relationships were replaced with indirect relationships using the sku guid.

So, callers which previously called:

shoppingItem.getProductSku()
orderSku.getProductSku()

now call

productSkuLookup.findByGuid(shoppingItem.getSkuGuid())
productSkuLookup.findByGuid(orderSku.getSkuGuid())

In addition, instead of linking TSHOPPINGITEM and TORDERSKU to TPRODUCTSKU via the TPRODUCTSKU.uidPk column, TSHOPPINGITEM and TORDERSKU are now linked to TPRODUCTSKU via the TPRODUCTSKU.guid column.

Note:

The associated database conversion requires mandatory down time, as well as a mandatory database backup before the conversion!

Caching ProductLookup and ProductSkuLookup

Caching implementations of the ProductLookup and ProductSkuLookup were added to a new ep-core-caching bundle. ep-core-caching is imported as a jar dependency by storefront and as a standalone bundle dependency in cortex.

When wired in, the caching ProductLookup and ProductSkuLookups are automatically made available to the spring/blueprint contexts.

In other changes, the ProductLookup and ProductSkuLookup caches are configured using EP System Settings instead of maven properties.

ep-core-caching also uses mockito for unit testing purposes instead of jmock.

Thread safe, in-memory Category Caching

Category Guid

Previously, category.getGuid() and category.setGuid() would delegate to category.getCode() and setCode() respectively, where the category code was a business key which is guaranteed to be unique only within a single Catalog). This is no longer true!. The Category code and Category guid are now two distinct properties with different values. Using the "compound" category guid which was constructed by combining a category's code with its catalog's code, delimited with a | (e.g. 'category-code|catalog-code') should now be considered deprecated (although it is still in use in Promotion Rules).

Category now has a true guid, which is stored in a separate database column and domain property and is guaranteed to be unique across the entire system. New Categories will be created using UUID style guids. Existing categories have their guid's initialized to their pre-existing compound guid during the database conversion.

Data Sync Tool

Initializing the guid of existing categories to their old compound guid preserves compatibility with pre-existing changesets and also ensures that pre-existing Categories receive the same guid in staging and production post-conversion. As a result, no changes should be required for users of the DST, and changesets created before the database upgrade should still be syncable post upgrade.

XML Import/Export

The XML DTO for categories now has additional columns for the new guid field in both the Category DTO and the linked category sub-object. Therefore XML category exports created before this version cannot be imported post upgrade.

The new guid field has also required another change to how XML import/export works with linked categories. Assume a category tree, with a (master) root category A, and two children B and C. Previously, importing an XML category document with a new linked category for category A would automatically create the linked categories for categories B and C, regardless of whether or not B and C were included in the document. Post upgrade, importing an XML category document with a new linked category for category A will NOT automatically create the linked categories for categories B and C. Linked categories for B and C will only be created if they are explicitly included in the document. This change is necessary because otherwise there is no way for import/export to determine the guid's for the linked B and C categories.

CSV Import

For users of CSV import there is no change to the CSV import format. However, there is also no way to specify a categories GUID using CSV import/export - only the code can be specified with CSV import. Users who require control of the category guids on import should use XML import/export instead.

Category.getParent() and Category.getChild()

Although Categories still exist in a tree structure, both Category.getParent() and Category.getChild() have been removed. Callers of the following domain object methods should now use the following alternatives:

Method Replacement
category.getParent() CategoryLookup.findParent(category)
category.getParent() != null category.hasParent()
category.setParent() No Change
category.setParentOnly() category.setParent()
category.getChildren() CategoryLookup.findChildren(category)
category.setChildren Use category.setParent() instead
category.getPathAsList() CategoryService.findAncestorCategoryUidsByCategoryUid() + CategoryLookup.findByUids()
category.getHasSubCategories() CategoryService.hasSubCategories()
product.isInCategory() ProductService.isInCategory()
CategoryService

Many methods in CategoryService have either been moved, renamed, or removed. In general, finders that retrieved categories by a unique key or keys have been moved to CategoryLookup. In addition, several older methods that were no longer being called have been removed from CategoryService.

CategoryService Method Replacement
findByCompoundGuid( * ) CategoryLookup.findByCompoundCategoryAndCatalogCodes()
findByGuid(String) CategoryService.findByCode()
findByGuid(String, Catalog) CategoryLookup.findByCategoryCodeAndCatalog()
findByGuid(String, Catalog, FetchGroupLoadTuner) CategoryLookup.findByCategoryCodeAndCatalog()
findByGuid(String, String) CategoryLookup.findByCategoryAndCatalogCode()
findByGuid(String, String, CategoryLoadTuner) CategoryLookup.findByCategoryAndCatalogCode()
findByUids( * ) CategoryLookup.findByUids()
findByUidsWithFetchGroupLoadTuner() CategoryLookup.findByUids()
findDirectDescendantCategories(long) CategoryService.findDirectDescendantCategories(String guid)
get() CategoryLookup.findByUid()
getCategoryWithAttribute() CategoryLookup.findByUid()
getCategoryWithSubCategories() CategoryLookup.findByUid()
getObject() CategoryLookup.findByUid()
getSubcategories() CategoryLookup.findChildren()
guidExists(String) CategoryService.isCodeInUse() / CategoryService.isGuidInUse()
load( * ) CategoryLookup.findByUid()
loadWithAllChildren() CategoryLookup.findByUid()
listRootCategories(Catalog, availableOnly, FetchGroupLoadTuner) CategoryService.listRootCategories(Catalog, availableOnly)
listRootCategoriesWithTree( * ) CategoryService.listRootCategories(Catalog, availableOnly)
populateChildrenCategory() Removed. Call is no longer necessary.
updatePosition() Removed
CategoryLookup

A new CategoryLookup interface containing finders by unique key has been added. The contract for the new finders in CategoryLookup is that they should always return a "fully loaded" version of the Category. As a result, most clients should no longer have a need to use FetchGroupLoadTuners and/or CategoryLoadTuners when loading categories.

Spring

Consumers of ep-core will be able to obtain a CategoryLookup in the spring context via two bean ids - "nonCachingCategoryLookup" and "categoryLookup". "nonCachingCategoryLookup" guarantees a non-caching implementation. By default, the "categoryLookup" is proxied to the non-caching implementation unless ep-core-caching is also in the classpath, in which case "categoryLookup" is proxied to the "cachingCategoryLookup" implementation.

OSGI

Consumers of the ep-core bundle will be able to obtain a non-caching version of the CategoryLookup from the blueprint by importing a "com.elasticpath.service.catalog.CategoryLookup" with filter "(caching=false)". If the ep-core-caching bundle is available, then a caching version of the CategoryLookup can be obtained via the filter "(caching=true)". Note that while cached implementations have a higher rank than non-cached implementations, bundle starting order can mean that non-cached services are selected at start up time even if cached services become available later on. For that reason, using the filter is preferred if your bundle requires a caching version.

Event Messaging System

New Event Messages are published by Commerce Engine that will trigger email delivery:

  • Commerce Manager User Events
    • CM User created
    • CM User password changed
    • CM User password reset
  • Customer Events
    • Anonymous Customer registered
    • Customer registered
    • Customer password changed
    • Customer password forgotten
    • Wish List shared
  • Data Import Events
    • Import job completed
  • Gift Certificate Events
    • Gift Certificate purchased
  • Order Events
    • Order exchanged
    • Order shipment created
    • Order shipment release failure
    • Order shipment shipped
    • Order returned

Solr Upgrade

Solr was upgraded from version 1.4.1 to 4.5.1. This resolves problems that some customer have encountered with replication of large indexes, fuzzy matching, as well as various other Solr bugs, including:

  • SOLR-309: A solr.StrField that has analyzers configured should emit warning to log
  • SOLR-1846: Remove support for (broken) abortOnConfigurationError
  • SOLR-2591: Remove commitLockTimeout option from solrconfig.xml
  • SOLR-5227: attempting to configured a dynamicField as required, or using a default value, should fail.
  • SOLR-2015: add a config hook for autoGeneratePhraseQueries\
  • SOLR-1261: Lucene trunk renamed RangeQuery & Co to TermRangeQuery
  • LUCENE-995: Add open ended range query syntax to QueryParser
  • LUCENE-4024: FuzzyQuery should never do edit distance > 2
  • LUCENE-2458: queryparser makes all CJK queries phrase queries regardless of analyzer

If you have made customizations to any of the index schema files, solr indexing code or querying code you should review the out-of-the-box changes made in these areas to see if similar changes will be required for your customizations.

OpenJPA Upgrade

OpenJPA was upgraded from version 1.2.1 to 2.3.0. This means we now support the JPA 2.0 standard for persistence. Some changes made to support this:

  • No private setters
    • A handful of classes had property setter methods marked as private. JPA 2.0 doesn't support this for persistent fields so the setters were changed to protected
  • Non-standard Join syntax
    • We previously used a non-standard join syntax for joins to TLOCALIZEDPROPERTIES. This is no-longer supported, and has been replaced by use of the @ElementClassCriteria annotation
  • Persistence Entity Listeners
    • The old PersistenceEngineEntityListener which was attached to the PersistenceEngine has been replaced by two separate listener interfaces. OpenJPA LifecycleListeners can now be added to the EntityManagerFactory via the spring context. The EntityManagerFactory takes responsibility for attaching these listeners to each EntityManager created by the factory at creation time. This means that OpenJPA Lifecycle listeners now receive all lifecycle events exposed by OpenJPA.
    • The PersistenceEngine specific events in PersistenceEngineEntityListener have been moved to PersistenceEngineOperationListener. These events were only used by the AuditEntityListener. PersistenceEngineOperationListeners are attached directly to the PersistenceEngine singleton. Of course, individual listeners like AuditEntityListener are free to listen to both sets of events, but are not required to do so.
  • ORM file changes
    • The *-orm.xml files have been changed to update the persistence schema version as well as removing the <package> and <entity> elements - basically they now only hold the named queries. Customers no longer need to duplicate the file and suppress the OOTB version in order to override entity persistence annotations - they can just introduce a new file with their entity definitions. The OOTB orm files only need to be duplicated and changed if OOTB named queries are being replaced.
  • jpa-persistence.xml changes
    • Customers overriding the jpa-persistence.xml need to ensure that the following properties are present:
    • <property name="openjpa.jdbc.FinderCache" value="false”/>
    • <property name="openjpa.Compatibility" value="convertPositionalParametersToNamed=true,ignoreDetachedStateFieldForProxySerialization=true"/commerce-legacy/> <property name="openjpa.MetaDataRepository" value="Preload=true”/>
    • The schema version has been updated to 2.0
    • In a new or overriding jpa-persistence.xml file you may also need to include the following element to ensure JSR-303 validation is not performed during persistence: <validation-mode>NONE</validation-mode>

RFC-4180 Compliant CSV Encoding/Decoding (Multi-Valued Attributes)

Previously, multi-valued attribute data became corrupted if the values contained a comma because delimitting of these attributes were handled by manually calling StringUtils.split() or split() on a comma..

There are now 2 formats of encoding and decoding of multi-value attribute:

1) RFC-4180 compliant encoding using SuperCSV 2.1 library (link).

Note: SuperCSV is our candidate encoder because it is licensed under Apache v2 and it has a release. We did not use Opencsv because it is not fully RFC compliant and it returns the entire row as the first element when parsing.

2) Legacy encoding (delimit on commas) for existing multi-valued attribute data

The reason for having legacy encoding is that the legacy data are not properly formatted and may result in data corruption.

For example, consider the encoded string,

3" DVD-R, 3" DVD-L

RFC-complaint encoding will treat the double-quotes as escape characters. The result after decoding is,

{ "3 DVD-R, 3 DVD-L" } a list of 1 element

Thus, the "multi-valueness" of an attribute is no longer a boolean state, but of three modes: 1) a single-value; 2) legacy encoded; 3) rfc-4180 encoded.

All existing data is kept in legacy encoding. All newly created attributes will be in RFC 4180 encoding.

New CustomerSessionService Method

The method changeFromAnonymousToRegisteredCustomer(CustomerSession customerSession, Customer customer, String storeCode) has been added to CustomerSessionService. This will change the Customer associated with the session to a new registered Customer, create a new Shopper and handle updates (such as merging ShoppingCarts and WishLists and updating the CustomerSession. This functionality was previously spread across private methods.

New ProductAssociationService Methods

Two new methods have been added to ProductAssociationService:

  • findByCriteria(ProductAssociationSearchCriteria criteria, int startIndex, int maxResults) - Searches the product associations by given search criteria, at the starting index with a result limit
  • findCountForCriteria(ProductAssociationSearchCriteria criteria) - Finds the count of product associations by the given search criteria.

New Promotions/Coupons Service Methods

Validation logic that was previously within private methods in the shopping cart has been moved to new methods on the appropriate services:

  • RuleService. isRuleValid(Rule rule, String storeCode) will check if the given rule is valid in the given store
  • CouponUsageService. isValidCouponUsage(String customerEmailAddress, String couponCode) will check that the coupon usage is valid for the given coupon code and email address

CartDirectorService.reApplyCatalogPromotions

A new method reApplyCatalogPromotions has been added to CartDirectorService that re-applies the catalog promotions to the ShoppingCart so that the applied rules are tracked on the cart.

Money

The Money interface and MoneyFactory class have been replaced with a single Money implementation. This implementation is final, and contains factory methods that can be used to create new Monies, making it analogous to core JRE datatypes such as BigDecimal or Long. As with the core JRE datatypes, a correct Money implementation is critical to the correct functioning of Commerce Engine and therefore it should not be possible nor necessary to replace this object with a different implementation.

As a result of this change it is no longer possible to create or encounter Monies in invalid states (ie. missing a currency or amount), and therefore it should be more difficult to introduce bugs. Any defects or shortcomings with the Money implementation should be reported and remedied in the platform.

Implementation Details

Money now resides in the ep-base module, and it's package has changed from com.elasticpath.domain.misc to com.elasticpath.money. MoneyFactory is no longer used to create new Money objects, so code of the form:

MoneyFactory.createMoney(BigDecimal.ZERO, CURRENCY_USD)

must to be changed to the following:

Money.valueOf(BigDecimal.ZERO, CURRENCY_USD)

CustomerRegistrationService

A CustomerRegistrationService was added which houses customer registration related logic. This currently has two methods:

  • registerAnonymousCustomer(Customer) - Performs field validation on the customer, and updates it to registered status and sends a confirmation email. Systems using Commerce Engine will no longer have to do these operations separately by calling into different services, making integration less brittle. Returns a CustomerRegistrationResult object which holds any field constraint violations that were found during validation, as well as the updated Customer object.
  • registerCustomerAndSendPassword(Customer) - was moved from CustomerService to this new service. This method is currently used by Commerce Manager Client only.

Removed BeanFactory references, AttributeService and CustomerService calls from CustomerImpl

The domain class CustomerImpl was invoking service methods on AttributeService and CustomerService to load metadata and settings values respectively. These values were lazy loaded at run-time when setters were invoked.

This has several problems:

  • It makes CustomerImpl make unexpected calls to the service/persistence layer at run time. This is made worse by the fact that CustomerImpl can be serialized to the Commerce Manager Client.
  • Invoking reads in the middle of a transaction can cause unexpected flushes of partially changed objects
  • CustomerImpl requires static access to the ElasticPath singleton and the bean factory.
  • Calling services from domain objects is not best practice.

This change does three main things:

  • It adds a generic OpenJPA post-load listener to the EntityManagerFactory. This post-load listener handles distribution of PostLoad events to PostLoadStrategies, configured with spring. The new listener provides a place to hang spring-configured post load handlers.
  • It removes the calls in CustomerImpl which lazy-loaded data from the AttributeService and CustomerService. Instead, CustomerImpl objects are eagerly loaded with all the configuration they require to execute properly. Existing CustomerImpl instances retrieved from the database have their metadata populated with a PostLoadStrategy. New CustomerImpl instances created by the spring bean factory have their metadata populated from spring.
  • It removes CustomerProfileImpl and CustomerProfileValueImpl from the bean factory. Extension projects can still override these classes if they need to by overriding protected factory methods in CustomerImpl and CustomerProfileImpl respectively.

Promotion Logging

Logging of applied rule codes & checksums during order creation has been changed from being at level INFO to level TRACE.

Recording Applied Rules on Shipping Service Level

A transient field has been added to ShippingServiceLevel to record any applied promotion Rule ids. The ShoppingCart.fireRules() lifecycle governs the lifecycle of the applied promotions on a ShippingServiceLevel. The following two methods were added to ShippingServiceLevel:

  • void recordAppliedRule(long ruleId, long actionId, Money discountAmount);
  • Set<Long> getAppliedRules();

Save rule description, and display name on TAPPLIEDRULE

In order to be able display promotion information that was captured at the time of purchase (e.g. for Cortex) we need to save the display name (in the shopper's locale at the time of purchase), and the description into TAPPLIEDRULE. In addition, to retrieve a promotion applied to a purchase an Applied Rule must be distinguishable from other Applied Rules so a Guid has been added to AppliedRule (and consequently to the TAPPLIEDRULE table).h3.

Database Changes

  • New table TTAXJOURNAL was added.
  • TAX_DOCUMENT_ID column was added to TORDERSHIPMENT and TORDERRETURN
  • SHIPPING_TAX column was added to TORDERRETURN
  • New table TCARTORDERCOUPON was added
  • TCUSTOMERGROUP table had the columns DESCRIPTION and ENABLED added
  • New Customer Segment tags were added: new data in TTAGVALUETYPE, TTAGVALUETYPEOPERATOR, TTAGDEFINITION, TLOCALIZEDPROPERTIES, TTAGDICTIONARYTAGDEFINITION tables
  • TCARTITEM and TORDERSKU tables both had the column SKU_GUID added as a non-nullable foreign key to TPRODUCTSKU. The value is automatically computed in the Liquibase script.
  • TCARTITEM and TORDERSKU tables both had the SKU_UID column removed
  • A GUID column was added to TCATEGORY. For upgrades, liquibase will automatically populate this with "master category code|catalog code" which was previously the "effective" guid.
  • A PARENT_CATEGORY_GUID column was added to TCATEGORY. For upgrades, Liquibase finds the category linked to by the PARENT_CATEGORY_UID and puts its GUID in the new field
  • After the above change, the PARENT_CATEGORY_UID column was dropped from TCATEGORY
  • A TAX_CODE_UID column was added to TPRODUCTSKU
  • Columns RULE_DESCRIPTION, RULE_DISPLAY_NAME and GUID were added to TAPPLIEDRULE.

The following Setting definitions were added to the database via Liquibase:

Setting Definition Path Purpose Default Value

COMMERCE/SYSTEM/CHANGESETS/enablePublishWorkflow

Enable the publish workflow for changesets. true

COMMERCE/SYSTEM/notificationsEnabled

Specifies whether notifications are enabled. If set to true will attempt to notify when new orders are created, and shipped. If false, will not notify. true
COMMERCE/SYSTEM/CACHING/CATEGORY/timeToLive The max number of seconds a category should live in cache before it is evicted. 1
COMMERCE/SYSTEM/CACHING/CATEGORY/timeToIdle The max number of seconds a category should live in cache without being touched before it is evicted. 1
COMMERCE/SYSTEM/CACHING/CATEGORY/maxEntriesLocalHeap The max number of category entries to store in the local heap (0 = no limit). 0
COMMERCE/SYSTEM/CACHING/PRODUCT/timeToLive The max number of seconds a product should live in cache before it is evicted. 1
COMMERCE/SYSTEM/CACHING/PRODUCT/timeToIdle The max number of seconds a product should live in cache without being touched before it is evicted. 1
COMMERCE/SYSTEM/CACHING/PRODUCT/maxEntriesLocalHeap The max number of entries to store in the local heap (0 = no limit). 5000
COMMERCE/SYSTEM/CACHING/PRODUCTSKU/timeToLive The max number of seconds a product sku should live in cache before it is evicted. 1
COMMERCE/SYSTEM/CACHING/PRODUCTSKU/timeToIdle The max number of seconds a product sku should live in cache without being touched before it is evicted. 1
COMMERCE/SYSTEM/CACHING/PRODUCTSKU/maxEntriesLocalHeap The max number of product sku entries to store in the local heap (0 = no limit). 10000
COMMERCE/SYSTEM/EMAIL/smtpScheme The protocol scheme of the SMTP server used to send emails. Expected values are 'smtp' and 'smtps'. smtp
COMMERCE/SYSTEM/EMAIL/channelUri The URI of the channel on which Email messages are sent and received jms:ep.emails
COMMERCE/SYSTEM/EMAIL/deadLetterChannelUri The URI of the channel on which Email messages are stored if email submission is unsuccessful jms:ep.emails.dlq
COMMERCE/SYSTEM/MESSAGING/GIFTCERTIFICATES/channelUri The URI of the channel on which Gift Certificate Event messages are sent and received jms:topic:ep.giftcertificates
COMMERCE/SYSTEM/MESSAGING/CUSTOMERS/channelUri The URI of the channel on which Customer Event messages are sent and received jms:topic:ep.customers
COMMERCE/SYSTEM/MESSAGING/CMUSERS/channelUri The URI of the channel on which CM User Event messages are sent and received jms:topic:ep.cmusers
COMMERCE/SYSTEM/MESSAGING/DATAIMPORT/channelUri The URI of the channel on which Data Import Event messages are sent and received jms:topic:ep.dataimport

Setting Definitions and Values with a path starting with "COMMERCE/SYSTEM/ASYNC" were removed as they are not used.

Code Changes

Code Moves

  • ImageService was moved from ep-core to ep-common-web
  • Shopping Cart Refresh functionality was moved from storefront to core.
  • getWebInfPath() was removed from ElasticPath/ElasticPathImpl. You should now use getConfigurationRootPath() on EnvironmentInfoService.
  • All *-cucumber-tests modules have been renamed *-acceptance-tests to better reflect what they are

Refactoring

  • Refactored Customer Tagging logic into reusable modules
  • Extracted PriceListStack setup logic from WebCustomerSessionService
  • The Product Association type constants on ProductAssociation have been removed, and a ProductAssociationType extensible enum is now used instead.
  • Payment Handlers now throw a consistent error message if an authorization is attempted for a zero amount
  • Coupon validation logic has been moved into a ValidCouponUseSpecification class.
  • Coupon auto-apply logic has been moved into a CouponAutoApplierService class.
  • PaymentType was changed to be an extensible enum.
  • Incorrectly spelled method setResour eDirectory in EsapiSecurityConfig was renamed to setResourceDirectory
  • Previously in checkout.xml , abstractCheckoutServiceDelegate had three properties for defining the checkout actions to run. Only the reversibleActionList property was a reference value. The other two checkout actions list are now also reference values. This enables extension projects to override the list beans to define their own checkout actions for setupCheckoutActions and finalizeCheckoutActions.

Code Removal

  • Removed fncLoader from ElasticPathImpl
  • Removed ctxEp from velocity
  • Removed unused getAllRegions method from ShippingRegionService
  • Removed DST dependency on ElasticPathImpl
  • AsyncService was unused and has been removed.
  • MessageSource was removed from ElasticPath & ElasticPathImpl. Classes requiring this can just have coreMessageSource injected or get it from the bean factory.
  • The EpService interface and AbstractEpServiceImpl class were removed. Classes that used this to get access to ElasticPath for bean creation now use an injected BeanFactory instead.
  • Removed unused methods getCountry() and setCountry() from ShoppingCartDto
  • Removed unused methods getElasticPath() and setElasticPath() from EventOriginatorHelper.

3rd Party Library Changes and Upgrades

Updated Dependencies:

  • Solr has been upgraded from 1.4.1 to 4.5.1
  • OpenJPA has been upgradded from 1.2.1 to 2.3.0

New Dependencies:

  • Google Guava 16.0.1