eCommerce Integration Framework

You are reading the AEM 5.6 version of eCommerce Integration Framework.
This documentation is also available for the following versions: CQ 5.5 

eCommerce, together with Product Information Management (PIM), handles the activities of a website focused on selling products via an online store:

  • Creation, lifetime, and obsolescence of a product
  • Price management
  • Transaction management
  • Live and centralized storage records
  • Web interfaces

AEM eCommerce helps marketers deliver branded, personalized shopping experiences across web, mobile, and social touchpoints. The AEM authoring environment allows you to customize pages and components based on target visitor context and merchandising strategies; for example:

  • product pages
  • shopping cart components
  • checkout components

The implementation allows real-time access to product information. This can be used to enforce:

  • product information integrity
  • pricing
  • stock-keeping inventory
  • variations in state of a shopping cart

AEM eCommerce provides:

  • The integration framework, this provides the API used for eCommerce implementations.

    file
  • Using this framework, the eCommerce implementations of the API provided by AEM can be either:

    • AEM native (CRX / JCR)
      A standalone, AEM native eCommerce implementation of the API. This can be used to control product data, shopping carts and checkout in conjunction with the existing data display and marketing campaigns. In this case the product database is stored in CRX (Adobe's implementation of JCR).
    • AEM eCommerce implemented with an eCommerce engine
      The eCommerce integration framework has been built to allow you to easily integrate eCommerce systems with AEM. This allows you to connect with a purpose built eCommerce system to control product data, shopping carts, checkout and order fulfillment, while AEM controls the data display and marketing campaigns.
      A reference site has already been implemented using hybris.
  • A number of out-of-the-box AEM components:

    • a product display component
    • a shopping cart
    • check-out
    file

    Note

    The integration framework provided by AEM also allows you to build additional AEM components for commerce capabilities independent of your specific eCommerce engine.

  • Search - using either the AEM search, the search of the eCommerce system, a third party search (such as Search&Promote) or a combination thereof.

    file
  • Uses the AEM ability to present your content in format needed by your visitors, be that full browser window or mobile device.

    file
  • The ability to develop your own integration implementation based on the AEM eCommerce framework.

    The two implementations currently available are both built on the same basis - on top of the general API (the framework).

    Building another integration means implementing the feature that your integration needs.

    Note

    Front end components can be used by any new implementation (they use interfaces, so they are independent from the implementation).

  • The possibility to develop experience-driven commerce based on shopper data.

    This allows you to realize many scenarios. One example allows you to provide seasonal offers that use profile data (e.g. location). These can then be highlighted, again depending on other factors when necessary.

    In the example below one teaser is shown as the contents of the cart are less than $75:

    file

    This can be changed when the contents of the cart exceed $75:

    file

Deploying AEM native eCommerce

AEM native eCommerce is available as part of a standard installation and provides you with the full functionality of the eCommerce framework.

Concepts of AEM native eCommerce

AEM Native eCommerce:

  • Provides:
    • User views (provided by out-of-the-box AEM components) for Product Information, Shopping Cart and Checkout.
    • Shopping cart and checkout information.
    • Search Engine Optimization (SEO).
    • Community functionality.
    • Unstructured marketing interactions.
    • Product Information from the internal database (JCR); located under:
          /etc/commerce/products
    • Product variant management.
    • Search within the product information.
    • Promotions and Vouchers for personalized shopping.
  • Processes:
    • The Shopping Cart.
    • The Checkout.

This means that:

  • Shoppers can register and shop without waiting.
  • Price changes will be seen by shoppers without delay.
  • Products can be added as required.
  • Campaigns (whether promotions, vouchers or teasers) provide personalized shopping.

Page and Components (native)

The following components and pages can use eCommerce data:

  • Landing page
    Rendered by AEM (Commerce Category).
    This provides primarily static information, for example, an introduction and overview with links to the underlying product pages.
  • Product
    Rendered by AEM (Commerce Product).
    Dynamic information about individual products; for example, price changes, special offers. Updates from live data are reflected. Product catalogs contain both hierarchical section pages and the individual product pages.
    The product component can be added to any page where the parent page delivers the required metadata (i.e. the paths to cartPage and cartObject). In Geometrixx Outdoors this is supplied by UserInfo.jsp.
  • Search results / product lists (cached)
    See search; this component can be added to any page.
  • myAccount
    Transaction data is combined with personal information about the shopper. AEM uses some of this data as profile data.
  • Checkout
    Checkout is implemented with standard AEM forms. This allows the marketing manager to customize the experience with marketing content.
  • Shopping cart
    AEM renders this information using the appropriate components.
  • Promotions and Vouchers
    You can create vouchers and promotions that customers can then use in their shopping cart to claim the appropriate discount.

Roles (native)

AEM eCommerce caters for the following roles to maintain the data:

file
  • Product Information Management (PIM) User who maintains:
    • Product information.
    • Taxonomy, categorization, approval.
    • Interacts with digital asset management.
    • Pricing - often this comes from an ERP system and is not explicitly maintained in the commerce system.
  • Author / Marketing Manager who maintains:
    • Marketing content for all channels.
    • Promotions.
    • Vouchers.
    • Campaigns.
  • Surfer / Shopper who:
    • Views your product information.
    • Places items into the shopping cart.
    • Checks out their orders.
    • Expect order fulfillment.

Products and Product Variants (native)

Products (native)

With AEM native eCommerce product data is maintained in CRX:

    /etc/commerce/products

and made available in AEM.

Note

Product images in geometrixx-outdoors are served from:

    /etc/commerce/products/...

This means that, by default, they are blocked by the dispatcher, so configure as required.

Product Variants (native)

For appropriate products information about variants can also be held. For example, for items of clothing the different colors available are held as variants:

file

Promotions and Vouchers (native)

Vouchers are a tried and tested method of offering discounts to either attract customers into making a purchase and/or rewarding customer's loyalty.

Promotions, together with vouchers, allow you to realize scenarios such as:

  • A company provides custom prices for employees, which is a handcrafted list of users.
  • Long-term customers receive discounts on all orders.
  • A sale price offered over a well-defined time period.
  • A customer receives a voucher when their previous order exceeded a specific amount.
  • A customer who buys product-X is offered a discount on product-Y (pair products).

With AEM native eCommerce you can create vouchers and promotions that customers can then use in their shopping cart to claim the appropriate discount.

  • Vouchers:
    • A Voucher is a page-based component that is created / edited with the Websites console.
    • Vouchers supply:
      • A voucher code (to be typed into the cart by the shopper).
      • A voucher label (to be displayed after the shopper has entered it into the cart).
      • A promotion path (which defines the action the voucher applies).
    • External commerce engines can also supply vouchers.
    • The Voucher component provides:
      • A renderer for voucher administration; this shows any vouchers currently in the cart.
      • The edit dialogs (form) for administrating (adding/removing) the vouchers.
      • The actions required for adding/removing vouchers to/from the cart.
    • Vouchers do not have their own on and off date/times, but use those of their parent campaigns.
  • Promotions:
    • A Promotion is a page-based component that is created / edited with the Websites console.
    • Promotions supply:
      • A priority
      • A promotion handler path
    • You can connect promotions to a campaign to define their on/off date/times.
    • You can connect promotions to an experience to define their segments.
    • Promotions not connected to an experience will not fire on its own, but can still be fired by a Voucher.
    • The Promotion component contains:
      • renderers and dialogs for promotion administration
      • sub-components for rendering and editing configuration parameters specific to the promotion handlers

In AEM:

  • a campaign specifies the on/off times
  • experiences within the campaign are used to group assets (teaserpages, promotions, etc) according to the audience segment they correspond to

A promotion can be held either in an experience or directly in the campaign:

  • If a promotion is held in an experience, then it can be automatically applied to an audience segment.
    For example, in the geometrixx-outdoors sample site, the promotion:
         /content/campaigns/geometrixx-outdoors/big-spender/ordervalueover100/free-shipping
    is in an experience, and so fires automatically whenever the segment (ordervalueover100) resolves.
  • If a promotion does not appear within an experience (only in the campaign), then it cannot be automatically applied to an audience.  However, it can still be fired if the shopper enters a voucher into their cart and that voucher references the promotion.
    For example, the promotion:
         /content/campaigns/geometrixx-outdoors/article/10-bucks-off
    is outside an experience and so never fires automatically (ie: based on segmentation).  It is, however, referenced by the vouchers which can be found in several of the experiences within the article campaign.  Entering those voucher codes into the cart will result in the promotion firing.

Note

AEM uses the term Voucher, this is synonymous with the term Coupon.

Search (native)

Since the AEM native implementation uses standard pages for products, you can use the standard search component to create a search page.

If you require a more thorough implementation, you can either:

  • Extend the default search component with the functionality you need.
  • Implement the search method in your CommerceService and then use the eCommerce search component on your search page.

Payment Security (native)

Payment details, including credit card information, is managed by AEM, then forwarded to a payment processing system.

Payment Card Industry (PCI) complicance can be achieved.

Catalogs in Multiple Languages (native)

AEM supports product content in multiple languages. When requesting data from the database, the integration framework retrieves the language from the current tree (for example, en_US for pages under /content/geometrixx-outdoors/en_US).

For a multi-lingual store, you can import your catalog in each language tree individually (or copy it by means of MSM).

Product Catalog Sections (native)

The product catalog sections provide you with, for example:

  • an introduction (image and/or text) to the category; this can also be used for banners and teasers to promote special offers
  • links to the individual products in that category
  • links to the other categories
file

Product Information with Color Variants (native)

An AEM page (for example, using the Commerce Product template) can provide:

  • general product information; text and images
  • pricing

And allow the shopper to select:

  • color and size variants
  • quantity
  • add to basket
file

Shopping Cart Content Overview (native)

The shopping cart provides:

  • an overview of items selected
  • links to the individual product pages
  • updates to quantity
  • removal of the item

AEM native stores the cart in a cookie so items stay in the cart across log-in/log-out. Price changes are reflected as they occur.

file

Customer Sign-Up (native)

Often sign-up is required for the shopper to have access to the shopping cart. If so, this requires registration so that a customer-specific account can be created.

file

Note

An anonymous shopping cart and checkout is also supported.

Customer Sign-In (native)

After sign-up the shopper must login with their account so that their actions can be tracked and their orders fulfilled.

file

Administering AEM native eCommerce

Creating a Promotion (native)

Note

The following example deals with a promotion held directly in a campaign, this is used for vouchers.

A promotion can also be in an experience within a campaign.

For more information see Promotions and Vouchers (native).

  1. Open the Websites console of your author instance.

  2. In the left-hand pane select your required Campaign.

  3. Click on New, select the Promotion template, then specify a Title (and Name if required) for your new voucher.

  4. Click Create. The new promotion page will be shown in the right-hand pane.

  5. Edit the Properties by either:

    • opening the page, then clicking the Edit button to open the Properties dialog
    • selecting the page in the Websites console, then using the context menu (usually the right mouse button) to select Properties... and open the properties dialog

    Specify the Promotion Type, Discount Type, Discount Value and any other fields as required.

  6. Click OK to save.

  7. You can now activate your promotion, so that shoppers will see it on the publish instance.

Creating a Voucher (native)

  1. Open the Websites console of your author instance.

  2. In the left-hand pane select your required Campaign.

  3. Click on New, select the Voucher template, then specify a Title (and Name if required) for your new voucher.

  4. Click Create. The new voucher page will be shown in the right-hand pane.

  5. Open your new voucher page with a double-click, then click on Edit to configure the information as required.

  6. Click OK to save.

  7. You can now activate your voucher, so that shoppers can use it in their carts on the publish instance.

Removing Vouchers (native)

In order to make a voucher unavailable to customers, you can either:

  • Deactivate the voucher - it will remain available on the author environment so you can re-activate it at a later time.
  • Delete it completely.

Both actions can be done from the Websites console.

Modifying Vouchers (native)

To change the properties of a voucher or promotion, you can double-click on it on the Websites console and click Edit. After saving it, you should activate it so that the changes get pushed to the publish instance(s).

Adding Vouchers to a Cart (native)

To allow users to add vouchers to their carts, you can use the built-in Vouchers component (Commerce category). You need to add this to the same page as where the cart is displayed (but is not mandatory). The vouchers component is merely a form in which the user can enter a voucher code, it is the shopping cart component that actually shows the list of applied vouchers and their discount.

In the demo site (Geometrixx Outdoors - English) you can see the voucher form on the cart page, under the actual shopping cart.

Generating a Catalog (native)

Note

The catalogue will reference your Product Data.

  1. Using the Websites console, navigate to your Catalog Blueprint, then the Base Catalog.

    For example:

    http://localhost:4502/siteadmin#/content/catalogs/geometrixx-outdoors/base-catalog

  2. Create a new page using the Section Blueprint template.

    For example, Swimwear.

  3. Open the new Swimwear page, then click Edit Blueprint to open the Properties dialog, where you can set up the Products selection. 

    For example, open the Tags/Keywords field to select Activity, then Swimming from the Geometrixx-Outdoors section.

  4. Click OK to save your properties; example products will be shown under the Product Selection Criteria on the blueprint page.

  5. Click on Rollout Changes..., select Rollout page and all sub pages, then click Next then Rollout. Once the rollout is completed successfully the Status indicator will be shown as green. 

  6. You can now click Close and check the new catalog section; for example, on and under:

    http://localhost:4502/cf#/content/geometrixx-outdoors/en/swimwear.html

  7. Again from the blueprints page click Edit Blueprint and in the Properties dialog open the Generated Page tab. In the Banner list field select the image you want to show; for example, summer.jpg

  8. Click OK to save your properties; banner information will be shown under the Product Selection Criteria on the blueprint page.

  9. Rollout these new changes. Click on Rollout Changes..., select Rollout page and all sub pages, then click Next then Rollout. Once the rollout is completed successfully the Status indicator will be shown as green. 

  10. You can now click Close and see the changes applied to your catalog section; for example:

    http://localhost:4502/cf#/content/geometrixx-outdoors/en/swimwear.html

Developing for AEM native eCommerce

Note

API documentation is also available for download.

The integration framework includes an integration layer with an API. This allows you to build AEM components for eCommerce capabilities (independent of your specific eCommerce engine). It also allows you to use the internal CRX database or to plug in an eCommerce system and pull product data into AEM.

A number of out-of-the-box AEM components are provided to use the integration layer. Currently these are:

  • A product display component
  • A shopping cart
  • Promotions and vouchers
  • Catalog and section blueprints
  • Check-out
  • Search

For search an integration hook is provided that allows you to use the AEM search, a third party search (like Search&Promote) or a combination thereof.

eCommerce Engine Selection (native)

The eCommerce framework can be used with any eCommerce solution, the engine being used needs to be identified by AEM - even when using the AEM native engine:

  • eCommerce Engines are OSGi services supporting the CommerceService interface
    • Engines can be distinguished by a commerceProvider service property
  • AEM supports Resource.adaptTo() for CommerceService and Product
    • The adaptTo implementation looks for a cq:commerceProvider property in the resource's hierarchy:
      • If found, the value is used to filter the commerce service lookup.
      • If not found, the highest-ranked commerce service is used.
    • A cq:Commerce mixin is used so the cq:commerceProvider can be added to strongly-typed resources.
  • The cq:commerceProvider property is also used to reference the appropriate commerce factory definition.
    • For example, a cq:commerceProvider property with the value geometrixx will correlate to the OSGi configuration for Day CQ Commerce Factory for Geometrixx-Outdoors (com.adobe.cq.commerce.hybris.impl.GeoCommerceServiceFactory) - where the parameter commerceProvider also has the value geometrixx.
    • Here further properties can be configured (when appropriate and available).

In a standard AEM installation a specific implementation is required, for example:

cq:commerceProvider = geometrixx geometrixx example; this includes minimal extensions to the generic API
Example
/etc/commerce/products/geometrixx-outdoors 
+ cq:commerceProvider = geometrixx 
  + adobe-logo-shirt 
    + cq:commerceType = product 
    + price = 12.50 
  + adobe-logo-shirt_S 
    + cq:commerceType = variant 
    + size = S 
  + adobe-logo-shirt_XL 
    + cq:commerceType = variant 
    + size = XL 
    + price = 14.50
        

Note

Using CRXDE Lite you can see how this is handled in the product component for the AEM native implementation:

   /apps/geometrixx-outdoors/components/product

Session Handling (native)

A session to store information related to the customer's shopping cart.

The CommerceSession:

  • Owns the shopping cart
    • performs add/remove/etc
    • performs the various calculations on the cart;
      commerceSession.getProductPriceInfo(Product product, Predicate filter)
  • Owns persistance of the order data:
        CommerceSession.getUserContext()
  • Can retrieve/update delivery details by using updateOrder(Map<String, Object> delta)
  • Also owns the payment processing connection
  • Also owns the fulfillment connection

Architecture (native)

Architecture of Product and Variants (native)

A single product can have multiple variations; for instance, it might vary by color and/or size. A product must define which properties drive variation; we term these variant axes.

However, not all properties are variant axes. Variations can also affect other properties; for example, the price might be dependant on size. These properties cannot be selected by the shopper and therefore are not considered variant axes.

Each product and/or variant is represented by a resource, and therefore maps 1:1 to a repository node. It is a corollary that a specific product and/or variant can be uniquely identified by its path.

Any product resource can be represented by a Product API. Most calls in the product API are variation specific (although variations might inherit shared values from an ancestor), but there are also calls which list the set of variations (getVariantAxes(), getVariants(), etc.).

Note

In effect a variant axes is determined by whatever Product.getVariantAxes() returns:

  • for the AEM-native implementation AEM reads it from a property in the product data (cq:productVariantAxes)

While products (in general) can have many variant axes, the out-of-the-box product component only handles two:

  1. size
  2. plus one more
    This additional variant is selected via the variationAxis property of the product reference (usually color for Geometrixx Outdoors).

Product References and PIM Data (native)

In general:

  • PIM data is located under /etc
  • Product references under /content.

There must be a 1:1 map between product variations and product data nodes.

Product references must also have a node for each variation presented - but there is no requirement to present all variations.  For instance, if a product has S, M, L variations, the product data might be:

etc
  commerce
    products
      shirt
        shirt-s
        shirt-m
        shirt-l
        

While a "Big and Tall" catalog might have only:

content
  big-and-tall
    shirt
      shirt-l
        

Finally, there is no requirement to use product data.  You can place all product data under the references in the catalog; but then you cannot really have multiple catalogs without duplicating all the product data.

API

com.adobe.cq.commerce.api.Product interface
public interface Product extends Adaptable {

    public String getPath();            // path to specific variation
    public String getPagePath();        // path to presentation page for all variations
    public String getSKU();             // unique ID of specific variation

    public String getTitle();           // shortcut to getProperty(TITLE)
    public String getDescription();     // shortcut to getProperty(DESCRIPTION)
    public String getImageUrl();        // shortcut to getProperty(IMAGE_URL)
    public String getThumbnailUrl();    // shortcut to getProperty(THUMBNAIL_URL)

    public <T> T getProperty(String name, Class<T> type);

    public Iterator<String> getVariantAxes();
    public boolean axisIsVariant(String axis);
    public Iterator<Product> getVariants(VariantFilter filter) throws CommerceException;
}
        
com.adobe.cq.commerce.api.VariantFilter
/**
 * Interface for filtering variants and AxisFilter provided as common implementation
 *
 * The <code>VariantFilter</code> is used to filter variants,
 * e.g. when using {@link Product#getVariants(VariantFilter filter)}.
 */
public interface VariantFilter {
    public boolean includes(Product product);
}

/**
 * A {@link VariantFilter} for filtering variants by the given
 * axis and value. The following example returns a list of
 * variant products that have a value of <i>blue</i> on the
 * <i>color</i> axis.
 * 
 * <p>
 * <code>product.getVariants(new AxisFilter("color", "blue"));</code>
 */
public class AxisFilter implements VariantFilter {
    
    private String axis;
    private String value;

    public AxisFilter(String axis, String value) {
        this.axis = axis;
        this.value = value;
    }

    /**
     * {@inheritDoc}
     */
    public boolean includes(Product product) {
        ValueMap values = product.adaptTo(ValueMap.class);

        if(values != null) {
            String v = values.get(axis, String.class);

            return v != null && v == value;
        }

        return false;
    }
}
        
  • General Storage Mechanism
    • Product nodes are nt:unstructured.
    • A product node can be either:
      • A reference, with the product data stored elsewhere:
        • Product references contain a productData property, which points to the product data (typically under /etc/commerce/products).
        • The product data is hierarchical; product attributes are inherited from a product data node's ancestors.
        • Product references can also contain local properties, which override those specified in their product data.
      • A product itself:
        • Without a productData property.
        • A product node which holds all properties locally (and does not contain a productData property) inherits product attributes directly from its own ancestors.
  • AEM-native Product Structure
    • Each variant must have its own leaf node.
    • The product interface represents both products and variants, but the related repository node is specific about which it is.
    • The product node describes the product attributes and variant axes.
Example
+ banyan_shirt
    - cq:commerceType = product
    - cq:productAttributes = [jcr:title, jcr:description, size, price, color]
    - cq:productVariantAxes = [color, size]
    - jcr:title = Banyan Shirt
    - jcr:description = Flowery, all-cotton shirt.
    - price = 14.00
    + banyan_shirt_s
        - cq:commerceType = variant
        - size = S
        + banyan_shirt_s_red
            - cq:commerceType = variant
            - color = red
        + banyan_shirt_s_blue
            - cq:commerceType = variant
            - color = blue
    + banyan_shirt_m
        - cq:commerceType = variant
        - size = M
        + banyan_shirt_m_red
            - cq:commerceType = variant
            - color = red
        + banyan_shirt_m_blue
            - cq:commerceType = variant
            - color = blue
    + banyan_shirt_l
        - cq:commerceType = variant
        - size = L
        + banyan_shirt_l_red
            - cq:commerceType = variant
            - color = red
        + banyan_shirt_l_blue
            - cq:commerceType = variant
            - color = blue
    + banyan_shirt_xl
        - cq:commerceType = variant
        - size = XL
        - price = 18.00
        

Architecture of the Shopping Cart (native)

Components

  • The shopping cart is owned by the CommerceSession:
    • The CommerceSession performs add, remove, etc.
    • The CommerceSession also performs the various calculations on the cart.
    • The CommerceSession also applies vouchers and promotions that have fired to the cart.
  • While not directly cart-related, the CommerceSession must also provide catalog pricing information (since it owns pricing)
    • Pricing might have several modifiers:
      • Quantity discounts.
      • Different currencies.
      • VAT-liable and VAT-free.
    • The modifiers are completely open-ended with the following interface:
      • int CommerceSession.getQuantityBreakpoints(Product product)
      • String CommerceSession.getProductPrice(Product product)

Storage

  • Storage
    • In the AEM-native case carts of are stored in the ClientContext

Personalization

  • Personalization should always be driven through the ClientContext.
  • A ClientContext /version/ of the cart is created in all cases:
    • Products should be added by using the CommerceSession.addCartEntry() method.
  • The following illustrates an example of cart information in the ClientContext cart:
file

Architecture of Checkout (native)

Cart and Order Data

The CommerceSession owns the three elements:

  1. Cart contents
  2. Pricing
  3. The order details
  1. Cart contents

    The cart contents schema is fixed by the API:

        public void addCartEntry(Product product, int quantity);
        public void modifyCartEntry(int entryNumber, int quantity);
        public void deleteCartEntry(int entryNumber);
            
  2. Pricing

    The pricing schema is also fixed by the API:

        public String getCartPreTaxPrice();
        public String getCartTax();
        public String getCartTotalPrice();
        public String getOrderShipping();
        public String getOrderTotalTax();
        public String getOrderTotalPrice();
            
  3. Order Details

    However, order details are not fixed by the API:

        public void updateOrderDetails(Map<String, String> orderDetails);
        public Map<String, String> getOrderDetails();
        public void submitOrder();
            

Shipping Calculations

  • Order forms often need to present multiple shipping options (and prices).
  • The prices might be based on items and details of the order, such as weight and/or delivery address.
  • The CommerceSession has access to all the dependencies, so it can be treated in a similar manner as product pricing:
    • The CommerceSession owns shipping pricing.
    • Use updateOrder(Map<String, Object> delta) to retrieve/update delivery details.

Search Definition (native)

Following the standard service API model, the eCommerce project provides a set of search-related APIs that can be implemented by individual commerce engines.

Note

Currently, only the hybris engine implements the search API out-of-the-box.

However, the search API is generic and can be implemented by each CommerceService individually.

So although the native implementation provided out-of-the-box does not implement this API, you can extend it and add the search functionality.

The eCommerce project contains a default search component, located in:

    /libs/commerce/components/search

file

This makes use of the search API to query the selected commerce engine (see eCommerce Engine Selection):

Search API (native)

There are several generic / helper classes provided by the core project:

  1. CommerceQuery
    Is used to describe a search query (contains information about the query text, current page, page size, sort and selected facets). All eCommerce services that implement the search API will receive instances of this class in order to perform their search. A CommerceQuery can be instantiated from a request object (HttpServletRequest).
  2. FacetParamHelper
    Is a utility class that provides one static method - toParams - that is used for generating GET parameter strings from a list of facets and one toggled value. This is useful on the UI side, where you need to display a hyperlink for each value of each facet, such that when the user clicks on the hyperlink the respective value is toggled (i.e. if it was selected it is removed from the query, otherwise added). This takes care of all the logic of handling multiple/single-valued facets, overriding values, etc.

The entry point for the search API is the CommerceService#search method which returns a CommerceResult object. See the API Documentation for more information on this topic.

Developing Promotions and Vouchers (native)

  • Vouchers:
    • A Voucher is a page-based component that is created / edited with the Websites console and stored under:
           /content/campaigns
    • Vouchers supply:
      • A voucher code (to be typed into the cart by the shopper).
      • A voucher label (to be displayed after the shopper has entered it into the cart).
      • A promotion path (which defines the action the voucher applies).
    • Vouchers do not have their own on and off date/times, but use those of their parent campaigns.
    • External commerce engines can also supply vouchers; these require a minimum of:
      • A voucher code
      • An isValid() method
    • The Voucher component (/libs/commerce/components/voucher) provides:
      • A renderer for voucher administration; this shows any vouchers currently in the cart.
      • The edit dialogs (form) for administrating (adding/removing) the vouchers.
      • The actions required for adding/removing vouchers to/from the cart.
  • Promotions:
    • A Promotion is a page-based component that is created / edited with the Websites console and stored under:
           /content/campaigns
    • Promotions supply:
      • A priority
      • A promotion handler path
    • You can connect promotions to a campaign to define their on/off date/times.
    • You can connect promotions to an experience to define their segments.
    • Promotions not connected to an experience will not fire on its own, but can still be fired by a Voucher.
    • The Promotion component (/libs/commerce/components/promotion) contains:
      • renderers and dialogs for promotion administration
      • sub-components for rendering and editing configuration parameters specific to the promotion handlers
    • Two promotion handlers are supplied out of the box:
      • DiscountPromotionHandler, which applies a cart-wide absolute or percentage discount
      • PerfectPartnerPromotionHandler, which applies a product absolute or percentage discount if the partner procduct is also in the cart
    • The ClientContext SegmentMgr resolves segments and the ClientContext CartMgr resolves promotions. Each promotion that is subject to at least one resolved segment will be fired.
      • Fired Promotions are sent back to the server via an AJAX call to re-calculate the cart.
      • Fired Promotions (and added Vouchers) are also shown in the ClientContext panel.

Adding/Removing a voucher from a cart is accomplished via the CommerceSession API:

/**
 * Apply a voucher to this session's cart.
 * 
 * @param code the voucher's code
 * @throws CommerceException
 */
public void addVoucher(String code) throws CommerceException;

/**
 * Remove a voucher that was previously added with {@link #addVoucher(String)}.
 * 
 * @param code the voucher's code
 * @throws CommerceException
 */
public void removeVoucher(String code) throws CommerceException;

/**
 * Get a list of vouchers that were added to this cart via {@link #addVoucher(String)}.
 * 
 * @throws CommerceException
 */
public List<Voucher> getVouchers() throws CommerceException;
        

This way, the CommerceSession is responsible for checking whether a voucher exists and if it can be applied or not. This might be for vouchers that can only be applied if a certain condition is met; for example, when the total cart price is greater than $100). If a voucher cannot be applied for any reason, the addVoucher method will throw an exception. Also, the CommerceSession is responsible for updating the cart's price(s) after a voucher is added / removed.

The Voucher is a bean-like class that contains fields for:

  • Voucher code
  • A short description
  • Referencing the related promotion that indicates the discount type and value

The AbstractJcrCommerceSession provided can apply vouchers. The vouchers returned by the class getVouchers() are instances of cq:Page containing a jcr:content node with the following properties (amongst others):

  • sling:resourceType (String) - this needs to be commerce/components/voucher
  • jcr:title (String) - for the voucher's description
  • code (String) - the code the user has to enter to apply this voucher
  • promotion (String) - the promotion to be applied; e.g. /content/campaigns/geometrixx-outdoors/article/10-bucks-off

Promotion handlers are OSGi services which modify the shopping cart. The cart will support several hooks that will be defined in the PromotionHandler interface.

/**
 * Apply promotion to a cart line item. The method returns a discount
 * <code>PriceInfo</code> instance or <code>null</code> if no discount
 * was applied.
 * @param commerceSession The commerce session
 * @param promotion The configured promotion
 * @param cartEntry The cart line item
 * @return A discounted <code>PriceInfo</code> or <code>null</code>
 */
public PriceInfo applyCartEntryPromotion(CommerceSession commerceSession, 
                                         Promotion promotion, CartEntry cartEntry) 
    throws CommerceException;

/**
 * Apply promotion to an order. The method returns a discount
 * <code>PriceInfo</code> instance or <code>null</code> if no discount
 * was applied.
 * @param commerceSession The commerce session
 * @param promotion The configured promotion
 * @return A discounted <code>PriceInfo</code> or <code>null</code>
 */
public PriceInfo applyOrderPromotion(CommerceSession commerceSession, Promotion promotion) 
    throws CommerceException;

public PriceInfo applyShippingPromotion(CommerceSession commerceSession, Promotion promotion) 
    throws CommerceException;

/**
 * Allows a promotion handler to define a custom, author-oriented message for a promotion.
 * The {@link com.adobe.cq.commerce.common.promotion.PerfectPartnerPromotionHandler}, for instance,
 * uses this to list the qualifying pairs of products in the current cart.
 * @param commerceSession
 * @param promotion
 * @return A message to display
 * @throws CommerceException
 */
public String getMessage(SlingHttpServletRequest request, CommerceSession commerceSession, Promotion promotion) throws CommerceException;

/**
 * Informs the promotion handler that something under the promotions root has been edited, and the handler
 * should invalidate any caches it might be keeping.
 */
public void invalidateCaches();
        

Three promotion handlers are provided out of the box:

  • DiscountPromotionHandler applies a cart-wide absolute or percentage discount
  • PerfectPartnerPromotionHandler applies a product absolute or percentage discount if the product partner is also in the cart
  • FreeShippingPromotionHandler applies free shipping

Deploying eCommerce with hybris

Deploying the necessary eCommerce packages will provide the full functionality of the eCommerce framework, together with a reference implementation of eCommerce functionality as provided with a hybris implementation (including a demonstration catalog)

This is available under the English (US) branch (/content/geometrixx-outdoors/en_US) of the Geometrixx Outdoors site:

Packages Needed for eCommerce with hybris

To install eCommerce functionality you need the following packages, available from Package Share:

  • AEM eCommerce framework:
    • this is part of a standard AEM installation
  • AEM hybris implementation:
    • cq-hybris-content
    • hybris-specific API implementation
    • a reference implementation to illustrate use of hybris (geometrixx-outdoors/en_US)
  • Embedded, self-installing hybris server:
    • cq-hybris-server
    • this can be used for POCs, demos, etc.; it is not suitable for production

Caution

Use of this hybris server requires a separate hybris license.

Note

For developers API documentation is also available for download.

Installation of eCommerce with hybris

To deploy a fully-fledged configuration the basic steps are:

  1. Install AEM.
  2. Install the packages using the package manager:
    1. cq-hybris-content
    2. cq-hybris-server
  3. Install your eCommerce engine (for this example, hybris).
  4. Construct your catalog in your eCommerce engine.
  5. Use the importer to import the catalog into a specific location in AEM.
  6. Author any supplementary pages that you need in AEM.

Configuring the Catalog Version (hybris)

The Catalog version (hybris.catalog.version) that is imported can be configured for:

Day CQ Commerce Factory for Hybris
(com.adobe.cq.commerce.hybris.impl.HybrisServiceFactory)

Catalog version is usually set to either Online or Staged (the default).

When working with AEM there are several methods of managing the configuration settings for such services; see Configuring OSGi for full details.  Also see the console for a full list of configurable parameters and their defaults.

The log output provides feedback on the created pages and components and reports potential errors.

Configuring the Import Structure (hybris)

The following listing shows a sample structure (of assets, pages and components) that is created by default:

+ /content/dam/path/to/images
  + 12345.jpg (dam:Asset)
    + ...
  + ...
+ /content/site/en
  - cq:commerceProvider = "hybris"
  - cq:hybrisBaseStore = "basestore"
  - cq:hybrisCatalogId = "catalog"
  + category1 (cq:Page)
    + jcr:content (cq:PageContent)
      - jcr:title = "Category 1"
    + category11 (cq:Page)
      + jcr:content (cq:PageContent)
        - jcr:title = "Category 1.1"
      + 12345 (cq:Page)
        + jcr:content (cq:PageContent)
          + par
            + product (nt:unstructured)
              - cq:hybrisProductId = "12345"
              - sling:resourceType = "commerce/components/product"
              + image (nt:unstructured)
                - sling:resourceType = "commerce/components/product/image"
                - fileReference = "/content/dam/path/to/images/12345.jpg"
              + 12345.1-S (nt:unstructured)
                - cq:hybrisProductId = "12345.1-S"
                - sling:resourceType = "commerce/components/product"
                + image (nt:unstructured)
                  - sling:resourceType = "commerce/components/product/image"
                  - fileReference = "/content/dam/path/to/images/12345.1-S.jpg"
              + ...
        

Such a structure is created by the OSGi service DefaultImportHandler that implements the ImportHandler interface. An import handler is called by the actual importer to create products, product variations, categories, asset, etc.

The structure to be generated when importing can be configured for:

Day CQ Commerce Hybris Default Import Handler
(com.adobe.cq.commerce.hybris.importer.DefaultImportHandler)

When working with AEM there are several methods of managing the configuration settings for such services; see Configuring OSGi for full details.  Also see the console for a full list of configurable parameters and their defaults.

Configuring the Product Properties to Load (hybris)

The configuration of the response parser defines which properties are loaded for (variant) products.

If you need to change the properties loaded from hybris, you need to update this list.

The response handler can be configured for:

Day CQ Commerce Hybris Response Parser
(com.adobe.cq.commerce.hybris.impl.importer.HybrisResponseParserImpl)

When working with AEM there are several methods of managing the configuration settings for such services; see Configuring OSGi for full details.  Also see the console for a full list of configurable parameters and their defaults.

Configuring the Synchronization Interval (hybris)

The interval for the importer to synchronize can be for:

Day CQ Commerce Hybris Catalog Importer
(com.adobe.cq.commerce.hybris.impl.importer.HybrisImporterImpl)

When working with AEM there are several methods of managing the configuration settings for such services; see Configuring OSGi for full details.  Also see the console for a full list of configurable parameters and their defaults.

Concepts of eCommerce with hybris

The integration framework provides the mechanisms and components for:

  • connection to an eCommerce system
  • pulling data into AEM
  • displaying that data and collecting the shopper's responses
  • returning transaction details
  • search over the data from both systems

This means that:

  • shoppers can register and shop without waiting
  • price changes will be seen by shoppers without delay
  • products can be added as required

Note

The eCommerce framework can be used with any eCommerce solution. Certain specifics and examples dealt with here will refer to the hybris solution.

To optimize operation each application concentrates on its own area of expertise with information being transferred between the two in real time; for example:

  • AEM:
    • Requests:
      • Product Information from hybris.
    • Provides:
      • User views for Product Information, Shopping Cart and Checkout.
      • Shopping cart and checkout information to hybris.
      • Search Engine Optimization (SEO).
      • Community functionality.
      • Unstructured marketing interactions.
  • hybris:
    • Provides:
      • Product Information from the database.
      • Product variant management.
      • Search within the product information.
    • Processes:
      • The Shopping Cart.
      • The Checkout.
      • Order fulfillment.

A number of out-of-the-box AEM components are provided to use the integration layer. Currently these are:

  • Product display component
  • Shopping cart
  • Check-out

Various search options are also available.

Page and Components (hybris)

The following components and pages can use eCommerce data:

  • Landing page
    Rendered by AEM (Commerce Category).
    This provides primarily static information, for example, an introduction and overview with links to the underlying product pages.
  • Product
    Rendered by AEM (Commerce Product).
    Dynamic information about individual products; for example, price changes, special offers. Updates from live data are reflected.
    The product component can be added to any page where the parent page delivers the required metadata (i.e. the paths to cartPage and cartObject). In Geometrixx Outdoors this is supplied by UserInfo.jsp.
  • Search results / product lists (cached)
    See search below. This component can be added to any page.
  • myAccount
    Transaction data in hybris is combined with personal information about the shopper. AEM uses some of this data as profile data. A forms action in AEM is used to write information back to hybris.
  • Checkout
    Checkout is implemented with standard AEM forms. This allows the marketing manager to customize the experience with marketing content.
    The checkout process is a very complex process that is hybris owned.
  • Shopping cart
    hybris provides all relevant data (xml). AEM renders this information using the appropriate components.

Roles (hybris)

The integrated system caters for the following roles to maintain the data:

file
  • Product Information Management (PIM) User who maintains:
    • Product information.
    • Taxonomy, categorization, approval.
    • Interacts with digital asset management.
    • Pricing - often this comes from an ERP system and is not explicitly maintained in the commerce system.
  • Author / Marketing Manager who maintains:
    • Marketing content for all channels.
    • Promotions.
    • Vouchers.
    • Campaigns.
  • Surfer / Shopper who:
    • Views your product information.
    • Places items into the shopping cart.
    • Checks out their orders.
    • Expect order fulfillment.

Single Sign-On (hybris)

Single-sign-on (SSO) is provided, so that authors are known in both systems without having to login twice.

Products and Product Variants (hybris)

Products (hybris)

Product data is maintained in hybris and can be made available in AEM.

Actual product information imported from hybris is held in the CRX repository under:

    /etc/commerce/products

The following properties indicate the link with hybris:

  • commerceProvider
  • cq:hybrisCatalogId
  • cq:hybrisProductID

This data is synchronized as necessary.

Note

The hybris implementation (i.e. geometrixx-outdoors/en_US) only stores product IDs and other basic information under /etc/commerce.

The hybris server is referenced every time information about a product is requested.

Product Variants (hybris)

For appropriate products information about variants can also be held. For example, for items of clothing the different colors available are held as variants:

file

Data Synchronization (hybris)

Some of the product data that is maintained in hybris needs to be available in AEM. As the data can be very dynamic (new products, price changes, special offers, etc) a periodic synchronization is used together with a data feed of changes.

Search (hybris)

The eCommerce search API is fully implemented in the hybris solution, so you can use the eCommerce search component that is provided out-of-the-box:

file

Promotions (hybris)

hybris promotions cover everything that influences the shopping cart and is related to pricing. Promotion specific marketing content (such as banners, etc) is not part of the hybris promotion.

Promotions are not usually maintained by product information managers, but by marketing managers. The promotions are also integrated into the Campaign Management.

Customer Registration and Accounts (hybris)

When a shopper registers, the account details need to be synchronized between AEM and hybris. Sensitive data is held independently, but profiles are shared:

file

Note

When using hybris, you need to ensure that accounts created for users who log into an AEM instance are replicated (e.g. via workflows) to any other AEM instances that communicate with hybris.

Otherwise, these other AEM instances will also try to create accounts for these users in hybris. These actions will fail with a DuplicateUidException coming from hybris.

Customer-specific Pricing (hybris)

hybris uses the context (essentially the shopper information) to determine the price on the hybris side then provide the correct information back to AEM.

Payment Security (hybris)

Payment details, including credit card information, is managed by hybis. AEM forwards such transactional information to hybris (from where it is then forwarded to a payment processing service).

Payment Card Industry (PCI) complicance can be achieved.

Order Fulfillment and Tracking (hybris)

Order fulfillment and tracking is managed by hybris. Information can be displayed by AEM.

Catalogs in Multiple Languages (hybris)

hybris supports product content in multiple languages, this can be used by AEM.

When requesting data from hybris, the integration framework retrieves the language from the current tree (for example, en_US for pages under /content/geometrixx-outdoors/en_US).

For a multi-lingual store, you can import your catalog in each language tree individually (or copy it by means of MSM).

Product Catalog Sections (hybris)

The product catalog sections provide you with, for example:

  • an introduction (image and/or text) to the category; this can also be used for banners and teasers to promote special offers
  • links to the individual products in that category
  • links to the other categories
file

Product Information with Color Variants (hybris)

A AEM page (for example, using the Commerce Product template) can provide:

  • general product information; text and images
  • pricing

And allow the shopper to select:

  • color and size variants
  • quantity
  • add to basket
file

Shopping Cart Content Overview (hybris)

The shopping cart provides:

  • an overview of items selected
  • links to the individual product pages
  • updates to quantity
  • removal of the item

Hybris stores the cart in a session so items are lost across log-in/log-out.

Price changes are reflected in both systems as they occur.

file

Customer Sign-Up (hybris)

Often sign-up is required for the shopper to have access to the shopping cart. This requires registration so that a customer-specific account can be created.

file

Note

An anonymous shopping cart and checkout is also supported.

Customer Sign-In (hybris)

After sign-up the shopper must login with their account so that their actions can be tracked and their orders fulfilled.

file

Access to the hybris Management Console

The hybris console is used for managing your product information; see the hybris documentation for more information.

The local instance included in the demonstration packages can be accessed using:

    https://localhost:9002/hmc/hybris

Login is required, the default details are:

  • Account name:
    admin
  • Password:
    nimda
file

Catalog Importer (hybris)

The hybris package comes with a catalog importer for setting up the initial page structure.

This is available from:

    http://localhost:4502/etc/importers/hybris.html

file

The following information has to be provided:

  • Base store
    The identifier of the base store configured in hybris.
  • Catalog
    The identifier of the catalog to import.
  • Root path
    The path where the catalog should be imported into.

Developing eCommerce with hybris

Note

The eCommerce framework can be used with any eCommerce solution. Certain specifics and examples dealt with here will refer to the hybris solution.

The integration framework includes an integration layer with an API. This allows you to:

  • plug in an eCommerce system and pull product data into AEM
  • build AEM components for commerce capabilities independent of the specific eCommerce engine
file

Note

API documentation is also available for download.

A number of out-of-the-box AEM components are provided to use the integration layer. Currently these are:

  • a product display component
  • a shopping cart
  • check-out

For search an integration hook is provided that allows you to use the AEM search, the search of the eCommerce system, a third party search (like Search&Promote) or a combination thereof.

eCommerce Engine Selection (hybris)

The eCommerce framework can be used with any eCommerce solution, the engine being used needs to be identifiable by AEM:

  • eCommerce Engines are OSGi services supporting the CommerceService interface
    • Engines can be distinguished by a commerceProvider service property
  • AEM supports Resource.adaptTo() for CommerceService and Product
    • The adaptTo implementation looks for a cq:commerceProvider property in the resource's hierarchy:
      • If found, the value is used to filter the commerce service lookup.
      • If not found, the highest-ranked commerce service is used.
    • A cq:Commerce mixin is used so the cq:commerceProvider can be added to strongly-typed resources.
  • The cq:commerceProvider property is also used to reference the appropriate commerce factory definition.
    • For example, a cq:commerceProvider property with the value hybris will correlate to the OSGi configuration for Day CQ Commerce Factory for Hybris (com.adobe.cq.commerce.hybris.impl.HybrisServiceFactory) - where the parameter commerceProvider also has the value hybris.
    • Here further properties, such as Catalog version can be configured (when appropriate and available).

See the following in the example below:

cq:commerceProvider = jcr generic API
cq:commerceProvider = hybris hybris implementation
Example
/content/store 
+ cq:commerceProvider = hybris 
  + mens 
    + polo-shirt-1 
    + polo-shirt-2 
    + employee 
+ cq:commerceProvider = jcr 
  + adobe-logo-shirt 
    + cq:commerceType = product 
    + price = 12.50 
  + adobe-logo-shirt_S 
    + cq:commerceType = variant 
    + size = S 
  + adobe-logo-shirt_XL 
    + cq:commerceType = variant 
    + size = XL 
    + price = 14.50
        

Note

Using CRXDE Lite you can see how this is handled in the product component for the hybris implementation:

   /apps/geometrixx-outdoors/components/hybris/product/product.jsp

Session Handling (hybris)

hybris uses a user session to store information such as the customer's shopping cart. The session id is returned from hybris in a JSESSIONID cookie that needs to be sent on subsequent requests to hybris. To avoid storing the session id in the repository it is encoded in another cookie that is stored in the shopper's browser. The following steps are performed:

  • On the first request no cookie is set on the shopper's request; so a request is sent to the hybris instance to create a session.
  • The session cookies are extracted from the response, encoded in a new cookie (for example, hybris-session-rest) and set on the response to the shopper. The encoding in a new cookie is required, because the original cookie is only valid for a certain path and would otherwise not be sent back from the browser in subsequent requests. The path information must also be added to the cookie's value.
  • On subsequent requests, the cookies are decoded from the hybris-session-<xxx> cookies and set on the HTTP client that is used to request data from hybris.

Note

A new, anonymous session is created when the original session is no longer valid.

CommerceSession (hybris)

  • This session "owns" the shopping cart
    • performs add/remove/etc
    • performs the various calculations on the cart;
      commerceSession.getProductPrice(Product product)
  • Owns the storage location for the order data
    CommerceSession.getUserContext()
  • Also owns the payment processing connection
  • Also owns the fulfillment connection

Product Synchronization and Publishing (hybris)

Product data that is maintained in hybris needs to be available in AEM. The following mechanism has been implemented:

  • An initial load of IDs is provided by hybris as a feed. There can be updates to this feed.
  • hybris will supply update information via a feed (which AEM polls).
  • When AEM is using product data it will send requests back to hybris for the current data (conditional get request using last modified date).
  • On hybris it is possible to specify feed contents in a declarative way.
  • Mapping the feed structure to the AEM content model happens in the feed adapter on the AEM side.
file
  • The importer (b) is used for the initial setup of the page tree structure in AEM for catalogs.
  • Catalog changes in hybris are indicated to AEM via a feed, these then propagate to AEM (b)
    • Product added/deleted/changed with respect to catalog version.
    • Product approved.
  • The hybris connector provides a polling importer ("hybris" scheme"), which can be configured to import changes into AEM at a specified interval (for example, every 24 hours where the interval is specified in seconds):
    • http://localhost:4502/content/geometrixx-outdoors/en_US/jcr:content.json
      {
      * "jcr:mixinTypes": ["cq:PollConfig"],
      * "enabled": true,
      * "source": "hybris:outdoors",
      * "jcr:primaryType": "cq:PageContent",
      * "interval": 86400
      }

  • The catalog configuration in AEM recognizes Staged and Online catalog versions.
  • Syncing products between catalog versions will require a (de-)activation of the corresponding AEM page (a, c)
    • Adding a product to an Online catalog version requires activation of the product's page.
    • Removing a product requires deactivation.
  • Activating a page in AEM (c) requires a check (b) and is only possible if
    • The product is in an Online catalog version for product pages.
    • The referenced products are available in an Online catalog version for other pages (e.g. campaign pages).
  • Activated product pages need to access the product data's Online version (d).
  • The AEM publish instance requires access to hybris for the retrieval of product and personalized data (d).

Architecture (hybris)

Architecture of Product and Variants (hybris)

A single product can have multiple variations; for instance, it might vary by color and/or size. A product must define which properties drive variation; we term these variant axes.

However, not all properties are variant axes. Variations can also affect other properties; for example, the price might be dependant on size. These properties cannot be selected by the shopper and therefore are not considered variant axes.

Each product and/or variant is represented by a resource, and therefore maps 1:1 to a repository node. It is a corollary that a specific product and/or variant can be uniquely identified by its path.

The product/variant resource does not always hold the actual product dataIt might be a representation of data actually held on another system (such as hybris). For example, product descriptions, pricing, etc, are not stored in AEM, but retrieved in real-time from the eCommerce engine.

Any product resource can be represented by a Product API. Most calls in the product API are variation specific (although variations might inherit shared values from an ancestor), but there are also calls which list the set of variations (getVariantAxes(), getVariants(), etc.).

Note

In effect a variant axes is determined by whatever Product.getVariantAxes() returns:

  • hybris defines it for the hybris implementation

While products (in general) can have many variant axes, the out-of-the-box product component only handles two:

  1. size
  2. plus one more
    This additional variant is selected via the variationAxis property of the product reference (usually color for Geometrixx Outdoors).

Product References and Product Data (hybris)

In general:

  • product data is located under /etc
  • and product references under /content.

There must be a 1:1 map between product variations and product data nodes.

Product references must also have a node for each variation presented - but there is no requirement to present all variations.  For instance, if a product has S, M, L variations, the product data might be:

etc
  commerce
    products
      shirt
        shirt-s
        shirt-m
        shirt-l
        

While a "Big and Tall" catalog might have only:

content
  big-and-tall
    shirt
      shirt-l
        

Finally, there is no requirement to use product data.  You can place all product data under the references in the catalog; but then you cannot really have multiple catalogs without duplicating all the product data.

API

com.adobe.cq.commerce.api.Product interface
public interface Product extends Adaptable {

    public String getPath();            // path to specific variation
    public String getPagePath();        // path to presentation page for all variations
    public String getSKU();             // unique ID of specific variation

    public String getTitle();           // shortcut to getProperty(TITLE)
    public String getDescription();     // shortcut to getProperty(DESCRIPTION)
    public String getImageUrl();        // shortcut to getProperty(IMAGE_URL)
    public String getThumbnailUrl();    // shortcut to getProperty(THUMBNAIL_URL)

    public <T> T getProperty(String name, Class<T> type);

    public Iterator<String> getVariantAxes();
    public boolean axisIsVariant(String axis);
    public Iterator<Product> getVariants(VariantFilter filter) throws CommerceException;
}
        
com.adobe.cq.commerce.api.VariantFilter
/**
 * Interface for filtering variants and AxisFilter provided as common implementation
 *
 * The <code>VariantFilter</code> is used to filter variants,
 * e.g. when using {@link Product#getVariants(VariantFilter filter)}.
 */
public interface VariantFilter {
    public boolean includes(Product product);
}

/**
 * A {@link VariantFilter} for filtering variants by the given
 * axis and value. The following example returns a list of
 * variant products that have a value of <i>blue</i> on the
 * <i>color</i> axis.
 * 
 * <p>
 * <code>product.getVariants(new AxisFilter("color", "blue"));</code>
 */
public class AxisFilter implements VariantFilter {
    
    private String axis;
    private String value;

    public AxisFilter(String axis, String value) {
        this.axis = axis;
        this.value = value;
    }

    /**
     * {@inheritDoc}
     */
    public boolean includes(Product product) {
        ValueMap values = product.adaptTo(ValueMap.class);

        if(values != null) {
            String v = values.get(axis, String.class);

            return v != null && v == value;
        }

        return false;
    }
}
        
  • General Storage Mechanism
    • Product nodes are nt:unstructured.
    • A product node can be either:
      • A reference, with the product data stored elsewhere:
        • Product references contain a productData property, which points to the product data (typically under /etc/commerce/products).
        • The product data is hierarchical; product attributes are inherited from a product data node's ancestors.
        • Product references can also contain local properties, which override those specified in their product data.
      • A product itself:
        • Without a productData property.
        • A product node which holds all properties locally (and does not contain a productData property) inherits product attributes directly from its own ancestors.
  • AEM-native Product Structure
    • Each variant must have its own leaf node.
    • The product interface represents both products and variants, but the related repository node is specific about which it is.
    • The product node describes the product attributes and variant axes.
Example
+ banyan_shirt
    - cq:commerceType = product
    - cq:productAttributes = [jcr:title, jcr:description, size, price, color]
    - cq:productVariantAxes = [color, size]
    - jcr:title = Banyan Shirt
    - jcr:description = Flowery, all-cotton shirt.
    - price = 14.00
    + banyan_shirt_s
        - cq:commerceType = variant
        - size = S
        + banyan_shirt_s_red
            - cq:commerceType = variant
            - color = red
        + banyan_shirt_s_blue
            - cq:commerceType = variant
            - color = blue
    + banyan_shirt_m
        - cq:commerceType = variant
        - size = M
        + banyan_shirt_m_red
            - cq:commerceType = variant
            - color = red
        + banyan_shirt_m_blue
            - cq:commerceType = variant
            - color = blue
    + banyan_shirt_l
        - cq:commerceType = variant
        - size = L
        + banyan_shirt_l_red
            - cq:commerceType = variant
            - color = red
        + banyan_shirt_l_blue
            - cq:commerceType = variant
            - color = blue
    + banyan_shirt_xl
        - cq:commerceType = variant
        - size = XL
        - price = 18.00
        

Architecture of the Shopping Cart (hybris)

Components

  • The shopping cart is owned by the CommerceSession:
    • The CommerceSession performs add/remove/etc.
    • The CommerceSession also performs the various calculations on the cart.
  • While not directly cart-related, the CommerceSession must also provide catalog pricing information (since it owns pricing)
    • Pricing might have several modifiers:
      • Quantity discounts.
      • Different currencies.
      • VAT-liable and VAT-free.
    • The modifiers are completely open-ended with the following interface:
      • int CommerceSession.getQuantityBreakpoints(Product product)
      • String CommerceSession.getProductPrice(Product product)

Storage

  • Storage
    • In the hybris case, the hybris server owns the cart.
    • In the AEM-native case carts of are stored in the ClientContext

Personalization

  • Personalization should always be driven through the ClientContext.
  • A ClientContext /version/ of the cart is created in all cases:
    • Products should be added by using the CommerceSession.addCartEntry() method.
  • The following illustrates an example of cart information in the ClientContext cart:
file

Architecture of Checkout (hybris)

Cart and Order Data

The CommerceSession owns the three elements:

  1. Cart contents
  2. Pricing
  3. The order details
  1. Cart contents

    The cart contents schema is fixed by the API:

        public void addCartEntry(Product product, int quantity);
        public void modifyCartEntry(int entryNumber, int quantity);
        public void deleteCartEntry(int entryNumber);
            
  2. Pricing

    The pricing schema is also fixed by the API:

        public String getCartPreTaxPrice();
        public String getCartTax();
        public String getCartTotalPrice();
        public String getOrderShipping();
        public String getOrderTotalTax();
        public String getOrderTotalPrice();
            
  3. Order Details

    However, order details are not fixed by the API:

        public void updateOrderDetails(Map<String, String> orderDetails);
        public Map<String, String> getOrderDetails();
        public void submitOrder();
            

Shipping Calculations

  • Order forms often need to present multiple shipping options (and prices).
  • The prices might be based on items and details of the order, such as weight and/or delivery address.
  • The CommerceSession has access to all the dependencies, so it can be treated in a similar manner as product pricing:
    • The CommerceSession owns shipping pricing.
    • Can retrieve/update delivery details by using updateOrder(Map<String, Object> delta)

Note

You could implement a shipping selector; for example:

yourProject/commerce/components/shippingpicker:

  • Essentially this could be a copy of foundation/components/form/radio, but with callbacks to the CommerceSession for:
    • Checking if the method is available
    • Adding pricing information
    • To enable shoppers to update the order page in AEM (including the superset of shipping methods and the text describing them), while still having the control to expose the relevant CommerceSession information.

Payment Processing

  • The CommerceSession also owns the payment processing connection.
  • Implementors need to add specific calls (to their chosen payment processing service) to the CommerceSession implementation.

Order Fulfillment

  • The CommerceSession also owns the fulfillment connection.
  • Implementors will need to add specific calls (to their chosen payment processing service) to the CommerceSession implementation.

Search Definition (hybris)

Following the standard service API model, the eCommerce project provides a set of search-related APIs that can be implemented by individual commerce engines.

Note

Currently, only the hybris engine implements the search API out-of-the-box.

However, the search API is generic and can be implemented by each CommerceService individually.

The eCommerce project contains a default search component, located in:

    /libs/commerce/components/search

file

This makes use of the search API to query the selected commerce engine (see eCommerce Engine Selection):

Search API (hybris)

There are several generic / helper classes provided by the core project:

  1. CommerceQuery
    Is used to describe a search query (contains information about the query text, current page, page size, sort and selected facets). All eCommerce services that implement the search API will receive instances of this class in order to perform their search. A CommerceQuery can be instantiated from a request object (HttpServletRequest).
  2. FacetParamHelper
    Is a utility class that provides one static method - toParams - that is used for generating GET parameter strings from a list of facets and one toggled value. This is useful on the UI side, where you need to display a hyperlink for each value of each facet, such that when the user clicks on the hyperlink the respective value is toggled (i.e. if it was selected it is removed from the query, otherwise added). This takes care of all the logic of handling multiple/single-valued facets, overriding values, etc.

The entry point for the search API is the CommerceService#search method which returns a CommerceResult object. See the API Documentation for more information on this topic.

User Integration (hybris)

Integration is provided between AEM and various eCommerce systems. This requires a strategy for synchronizing shoppers between the various systems so that AEM-specific code only has to know about AEM and vice-versa:

  • Authentication
    AEM is presumed to be the only web front-end and therefore performs all authentication.
  • Slave Accounts
    AEM creates a slave account in hybris for each shopper.  The username of the slave account is the same as the AEM username. A cryptographically-random password is auto-generated and stored (encrypted) in AEM.

Pre-existing Users (hybris)

A AEM front-end can be positioned in front of an existing hybris implementation. Also a hybris engine can be added to an existing AEM installation. To do this, the systems must be able to gracefully handle existing users in either system:

  • AEM -> hybris
    • When logging in to hybris, if the AEM user does not already exist:
      • create a new hybris user with a cryptographically random password
      • store the hybris username in the user directory of the AEM user
    • See: com.adobe.cq.commerce.hybris.impl.HybrisSessionImpl#login()
  • hybris -> AEM
    • When logging in to AEM, if the system recognizes the user:
      • attempt to log in to hybris with supplied username/pwd
      • if successful, create the new user in AEM with the same password (AEM-specific salt will result in AEM-specific hash)
    • The above algorithm is implemented in a Sling AuthenticationInfoPostProcessor
      • See: com.adobe.cq.commerce.hybris.impl.user.LazyUserImporter.java

Customizing the Import Process (hybris)

To build upon existing functionality your custom import handler:

  • has to implement the ImportHandler interface
  • can extend the DefaultImportHandler
/**
 * Services implementing the <code>ImportHandler</code> interface are
 * called by the {@link HybrisImporter} to create actual commerce entities
 * such as products.
 */
public interface ImportHandler {

    /**
     * Not used.
     */
    public void createTaxonomie(ImporterContext ctx);

    /**
     * Creates a catalog with the given name.
     * @param ctx   The importer context
     * @param name  The catalog's name
     * @return Path of created catalog
     */
    public String createCatalog(ImporterContext ctx, String name) throws Exception;

    /**
     * Creates a product from the given values.
     * @param ctx                The importer context
     * @param values             The product's properties
     * @param parentCategoryPath The containing category's path
     * @return Path of created product
     */
    public String createProduct(ImporterContext ctx, ValueMap values, String parentCategoryPath) throws Exception;

    /**
     * Creates a variant product from the given values.
     * @param ctx             The importer context
     * @param values          The product's properties
     * @param baseProductPath The base product's path
     * @return Path of created product
     */
    public String createVariantProduct(ImporterContext ctx, ValueMap values, String baseProductPath) throws Exception;

    /**
     * Creates an asset for a product. This is usually a product
     * image.
     * @param ctx             The importer context
     * @param values          The product's properties
     * @param baseProductPath The product's path
     * @return Path of created asset
     */
    public String createAsset(ImporterContext ctx, ValueMap values, String productPath) throws Exception;

    /**
     * Creates a category from the given values.
     * @param ctx           The importer context
     * @param values        The category's properties
     * @param parentPath    Path of parent category or base path of import in case of root category
     * @return Path of created category
     */
    public String createCategory(ImporterContext ctx, ValueMap values, String parentCategoryPath) throws Exception;
}
        

For your custom handler to be recognized by the importer, it must specify the service.ranking property with a value higher than 0; for example:

@Component
@Service
@Property(name = "service.ranking", value = 100)
public class MyImportHandler extends DefaultImportHandler {
    ...
}
        

API Documentation

The eCommerce API is provided by the packages:

    com.adobe.cq.commerce.*

See the API documentation for further information.

Additional Points To Note

  1. For all implementations the following points can be kept in mind:

    • As product, stock-keeping units and sometimes categories are numerous, try to use the least number of nodes possible to model the content.
      The more nodes you have, the more flexible your content is (e.g. parsys), but everything is a trade-off and do you need individual flexibility (by default) when manipulating (for example) 30K Products?
    • Avoid duplication as much as you can (see localization), or when you do, think about how many nodes your duplication will lead to.
    • Try to tag your content as much as you can in order to prepare the query optimization.
      For example, /content/products/france/fr/shoe/reebok/pump/46 SKU should have one tag per content level (i.e. country, language, category, brand, product). Searching for
          //element(*,my:Sku)[@country=’france’ and @language=’fr’ and @category=’shoe’ and @brand=’reebok’ and @product=’pump’]
      will be drastically quicker than searching for
        /jcr:root/content/france/fr/shoe/reebok/pump/element(*,my:Sku)
    • In your technical stack plan very factorized content access model and services. This is general best practice, but even more here as you can, in optimization phases, add some application caches for data that is read really often (and that you do not want to fill the bundle cache with).
      For example, attributes management is very frequently a good candidate for caching as it concerns data that is updated through products import.
  2. If:

    • structural categories (the category tree defining what is a product; for example, /products/mens/shoes/sneakers)
    • marketing categories (all other categories a product can belong to; for example /special-offers/christmas/shoes)

    Can be differentiated, then this allows you to make clear URLs with fully meaningful cq:Page trees (therefore, very close to classical AEM content management).

  3. This following terms are often used in eCommerce:

    • Editorial content: content that is managed by websites users.
    • PIM content: content that is managed by e-merchandizers.
    • Product: group of content (PIM and editorial) related to a generic product.
    • SKU: or stock-keeping unit, specifies the variant of a product that can directly be related to the stock, and a price. A SKU is always tightly related to its product, a product can have one or more SKUs.
    • Attribute: an attribute is a sku property (color, size, etc).
    • Catalog: the vendor’s hierarchical set of products he offers.
    • Category: a catalog item, that behaves like a PIM tag.
  4. Performance testing is something to take in consideration even more in AEM eCommerce implementations on:

    • Author environment:
      A lot of backend activity arises at the same time as normal user activity, users manipulate bunches of data more than invidual pages. Even if front-end performance are (in general) given higher priority, bad performance of the author environment can lead to frustration capable of blocking a go-live decision.
    • Publication environment:
      Replication is a critical process to ensure that the content is published quickly and reliably. This can be impacted by the author grouping content to be published.
    • Front-end:
      The mixture of front-end and cache invalidations can lead to performance surprises, testing helps avoid these.

    Please note that this performance testing requires:

    • target volumetry
      • assets
      • localized, I18ned products and SKUs
    • target user activity:
      • bulk edition
      • bulk publication
      • intense search requests
    • target back-end processes activity
      •  imports
    • maintenance (backup, Tar PM optimization, datastore garbage collection, etc)

Scaling eCommerce

Importing a large number of products (usually more than 100,000) from an eCommerce system (PIM) can slow down the authoring instance if the products have associated assets (eg product images). This is due to the fact that the post-processing of these assets is CPU and memory intensive.

There are various strategies you can choose to work around this:

Offload asset post processing to a dedicated instance

This scenario involves setting up two author instances:

  1. Master author instance that imports product data from PIM, on which post-processing for the asset paths is disabled.
  2. Dedicated DAM author instance that imports and post-processes product assets from the PIM, and replicates these back to the master author instance for use.
Architecture diagram

Only import product data

For cases when products do not contain assets (images) to be imported, you can import the product data without being affected by asset post-processing.

Architecture diagram

Your comments are welcome!
Did you notice a way we could improve the documentation on this page? Is something unclear or insufficiently explained? Please leave your comments below and we will make the appropriate changes. Comments that have been addressed, by improving the documentation accordingly, will then be removed.

COMMENTS

  • By marouanenet - 11:08 AM on Apr 02, 2013   Reply
    I wanna import a catalog from hybris to cq5, I fill the form when I click import catalog; it gives me this error:
    Error while processing /libs/commerce/content/import.html
    thanks for your help;
    • By Satish - 4:21 PM on Apr 08, 2013   Reply
      Hi,

      First of all check whether you jars are correctly loaded and installed.
      Try to give correct basestore, catalogid, rootpath(where you want to import the catalog), languagecode (you can leave as empty)
    • By Satish - 4:24 PM on Apr 08, 2013   Reply
      Hi Team,

      Loaded catalog from hybris to cq successfully.
      I am not able to add product to cart for geometrix outdoors site???? any setting needs to be done???
      where we have to configure restful API' for adding to cart, placing order?????? Please let me know....
      • By zumbrunn - 8:40 AM on Apr 11, 2013   Reply
        Hi Satish, if you do not get a more helpful response here, I suggest to ask about his in the AEM forum at http://forums.adobe.com/community/digital_marketing_suite/cq5
        • By marouanenet - 11:11 AM on Apr 11, 2013   Reply
          can you give us what it gives ou as an error; (go to file cq/ logs/error.log) and tell us;
          • By Anonymous - 12:16 PM on Apr 22, 2013   Reply
            Hi,

            I have successfully loaded catalog, able to add product successfully, checkout and order successfully.........
        • By amine.elharrak - 11:32 AM on Apr 23, 2013   Reply
          Hello,

          Can you give me more information about this field root path in cq 5.6 i can't see ? when a used importers link

          http://localhost:4502/etc/importers/hybris.html

          Please see this picture is from cq5.5

          <a href="http://www.hostingpics.net/viewer.php?id=1626381336121352000.png"><img src="http://img15.hostingpics.net/thumbs/mini_1626381336121352000.png" alt="Heberger image" /></a>

          thanks your
          • By Anonymous - 11:33 AM on Apr 23, 2013   Reply
            http://img15.hostingpics.net/pics/1626381336121352000.png
            • By aheimoz - 11:02 AM on May 14, 2013   Reply
              The root path is the parent page of the imported catalog pages; ie imported pages will be located below this page.

              Hope that helps.
          • By amir - 1:28 PM on Apr 23, 2013   Reply
            Hi,
            I have been trying to work out the steps provided in http://dev.day.com/docs/en/cq/current/ecommerce/eCommerce-framework.htm

            when i am at Hybris importer i can't see field root path in version 5.6 ?
            • By Freek - 1:38 PM on Apr 23, 2013   Reply
              Hi Amir,
              Seems you have the same issue as I have. Do you see any Hybris related bundles in your system console apart from the Adobe CQ Embedded Hybris Ecommerce Server bundle?

              Cheers,
              Freek
              • By aheimoz - 11:04 AM on May 14, 2013   Reply
                There might be various reasons for this, it is difficult to tell from the information given.
                To try and determine the core issue we suggest that you post all details (what you're trying to achieve, what you've implemented/configured so far, any log output) to our dedicated AEM forum:
                http://forums.adobe.com/community/digital_marketing_suite/cq5
                Hope that helps.
            • By Freek - 1:34 PM on Apr 23, 2013   Reply
              I installed the two packages from Package Share (cq-hybris-content-5.6.2 and cq-hybris-server-5.6.0)
              I see that a Hybris server is started but I miss the whole Hybris Commerce implementation. No Hybris related OSGI bundles or configs except "Adobe CQ Embedded Hybris Ecommerce Server".
              What could be the cause of this?
              Thanks in advance.
              • By Freek - 2:41 PM on Apr 23, 2013   Reply
                Hi,
                It works for me now. It seems it required a restart after installing the two packages.
                (Don't restart too soon though because the package installation takes some time. Even after it finishes in the Package Manager.)

                Cheers,
                Freek
              • By hybris - 6:43 PM on Apr 23, 2013   Reply
                Hi,

                i use hybris importer

                A /etc/commerce/products/apparel-uk/apparelProductCatalog/en
                Catalog imported successfully in 2690 milliseconds

                But in /etc/commerce/products/apparel-uk/apparelProductCatalog/en nothing imported !!

                you have an answer to my question ?

                thanks
                • By aheimoz - 3:16 PM on May 13, 2013   Reply
                  There might be various reasons for this, it is difficult to tell from the information given.
                  To try and determine the core issue we suggest that you post all details (what you're trying to achieve, what you've implemented/configured so far, any log output) to our dedicated AEM forum:
                  http://forums.adobe.com/community/digital_marketing_suite/cq5
                  Hope that helps.
                • By Anonymous - 6:54 PM on Apr 25, 2013   Reply
                  I have the same problem as hybris;
                  nothing imported!!!!
                  • By aheimoz - 3:18 PM on May 13, 2013   Reply
                    As above, there might be various reasons for this, it is difficult to tell from the information given.
                    To try and determine the core issue we suggest that you post all details (what you're trying to achieve, what you've implemented/configured so far, any log output) to our dedicated AEM forum:
                    http://forums.adobe.com/community/digital_marketing_suite/cq5
                    Hope that helps.
                  • By Karthikeyan - 10:58 AM on May 09, 2013   Reply
                    Getting the following error when I tried to import a catalogue from hybris.


                    com.adobe.cq.commerce.hybris.impl.importer.HybrisImporterImpl Importing catalog "telcoProductCatalog" from Hybris failed: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[5,16]
                    Message: expected start or end tag
                    at com.sun.xml.internal.stream.XMLEventReaderImpl.nextTag(Unknown Source)
                    at com.adobe.cq.commerce.hybris.impl.importer.HybrisImporterImpl.importProducts(HybrisImporterImpl.java:233)
                    • By aheimoz - 3:19 PM on May 13, 2013   Reply
                      There might be various reasons for this.
                      You can either open a support ticket or post all details (what you're trying to achieve, what you've implemented/configured so far, any log output) to our dedicated AEM forum:
                      http://forums.adobe.com/community/digital_marketing_suite/cq5
                      Hope that helps.

                    ADD A COMMENT

                     

                    In order to post a comment, you need to sign-in.

                    Note: Customers with DayCare user accounts need to create a new account for use on day.com.

                    ***