aem (cq) ecommerce framework
DESCRIPTION
As part of Adobe Experience Manager, CQ 5.6 provides a new Commerce Framework to build Experience Driven Commerce websites on top of a 3rd party Commerce Platform. This session provides an overview of the framework from an architectural perspective and presents some details of the reference implementation, based on the JCR repository.TRANSCRIPT
eCommerce Integration Framework
Paolo Mo!adelliAdobe Technical Marketing
Adobe® Marketing Cloud
Adobe® Experience Manager
CQ Gems
Commerce Integrated Platform
JCR repo product DB
Experience Manager PIM/ecommerce
surfer
content editor PIM editor
1 2
PIM synch
3
4
dynamic PIM
Commerce Integrated Platform
surfer
content editor PIM editor
1. Product display component2. Shopping cart3. Promotions and vouchers4. Catalog blueprints5. Check-out6. Search
1. Product information integrity2. Pricing3. Stock-keeping inventory4. Variations on shopping cart
AEM eCommerce Integration Modules
1. !e integration framework (API used for eCommerce implementations)
2. AEM native (JCR) implementation
3. hybris implementation
4. A number of out-of-the-box AEM components
5. Search (AEM, eCommerce, 3rd party)
6. Catalog management
7. Promotions management
8. Client context cart storeJCR repo product DB
Experience Manager PIM/ecommerce
Architecture of the Commerce Framework
AEM Commerce API
Implementation
AEM Commerce Components
AEM native impl
JCR Repository
hybris impl
hybris DB
other impl
other
eCommerce Engine Selection
CommerceService commerceService = resource.adaptTo(CommerceService.class);
CommerceSession session = commerceService.login(slingRequest, slingResponse);
Product baseProduct = resource.adaptTo(Product.class);
GeoImpl(geometrixx) hybrisImpl
(hybris)
otherImpl(xyz)
Site Component
OSGi container
bundle
bundlebundle
cq:commerceProvider = geometrixx
1
2
3
CommerceSession
• addCartEntry(Product product, int quantity);• modifyCartEntry(int entryNumber, int quantity);• deleteCartEntry(int entryNumber);
•updateOrderDetails(Map<String, String> orderDetails);•getOrderDetails();•submitOrder();
cart content
pricing
order details
•updateOrderDetails(Map<String, String> orderDetails);•getOrderDetails();•submitOrder();
CommerceSession is RESTful style (1)
CommerceSession is RESTful style (2)
ORDER%3a%3dorderId%253d9c1346bf-3813-4205-80ec-2fdfd1644143%7cCART%3a%3dquantity3%253d1%252cquantity0%253d1%252cquantity1%253d1%252cpromotionCoun
t%253d2%252cquantity2%253d1%252cvoucherCount%253d0%252cpromotion1%253d%252fcontent%252fcampaigns%252fgeometrixx-outdoors%252fcosy-up-to-winter%252fwinter-female%252fcosy-companions%252cpromotion0%253d%252fcontent
%252fcampaigns%252fgeometrixx-outdoors%252!ig-spender%252fordervalueover100%252ffree-shipping%252cproduct3%253d%252fcontent
%252fgeometrixx-outdoors%252fen%252fequipment%252fskiing%252#alifax-winter%252$cr%253acontent%252fpar%252fproduct%252cproduct0%253d%252fcontent
%252fgeometrixx-outdoors%252fen%252fwomen%252fcoats%252fcalgary-winter%252$cr%253acontent%252fpar%252fproduct%252f397122-s%252cproduct2%253d%252fcontent
%252fgeometrixx-outdoors%252fen%252fseasonal%252fwinter%252fequipment%252%amloops-snow%252$cr%253acontent%252fpar%252fproduct
%252f37924450-7%252centryCount%253d4%252cproduct1%253d%252fcontent%252fgeometrixx-outdoors%252fen%252fequipment%252fskiing%252%elowna-snow
%252$cr%253acontent%252fpar%252fproduct%7c
Name: CommercePersistence, Host: geometrixx.com, Path: /
CommerceSession is RESTful style (3)
public class AbstractJcrCommerceSession implements CommerceSession {
...
cartStore = ContextSessionPersistence.getStore(request, "CART", CommerceConstants.COMMERCE_COOKIE_NAME);
...
}
Products and Variants architecture:
- variant - color: purple- id: 397122.1
- variant - size: S
- variant - size: L
- variant - size: M
- variant - size: XL
- variant - color: purple-id: 397122.2- price: 199
- variant - size: S
- variant - size: L
- variant - size: M
- variant - size: XL
- type: product- axes: color, size - id: 397122- title: Saskatoon- price: 299
11
1
1 1
1 1
1 1
1 1
PIM Data & Product References
11
1
1 1
1 1
1 1
1 1
1 /etc/commerce/products 2 /content
Product interface
public interface Product extends Adaptable { public String getPath(); // path to speci!c variation public String getPagePath(); // path to presentation page for all variations public String getSKU(); // unique ID of speci!c 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 get"umbnailUrl(); // 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 !lter) throws CommerceException;}
AxisFilter implements VariantFilter
public class AxisFilter implements VariantFilter { ...
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; }}
Shopping Cart architecture (CommerceSession)
"e CommerceSession performs add, remove, etc."e CommerceSession also performs the various calculations on the cart."e CommerceSession also applies vouchers and promotions that have !red to the cart.
Pricing modi&ers:- Quantity discounts. - Different currencies.- VAT-liable and VAT-free.
session.calcCart()
protected void calcCart() { ... for (int i = 0; i < cart.size(); i++) { ... for (Promotion p : promotions) { try { PromotionHandler ph = p.adaptTo(PromotionHandler.class); PriceInfo discount = ph.applyCartEntryPromotion(this, p, entry); if (discount != null && discount.getAmount().compareTo(BigDecimal.ZERO) > 0) { ... entry.calcPrices(); ... } ... cartTotalPrice = cartTotalPrice.add(entry.getPriceInfo(new PriceFilter("POST_TAX", currencyCode)).get(0).getAmount()); } setPrice(new PriceInfo(cartPreTaxPrice, currency), "CART", "PRE_TAX"); setPrice(new PriceInfo(cartTax, currency), "CART", "TAX"); setPrice(new PriceInfo(cartTotalPrice, currency), "CART", "POST_TAX"); ... }
Shopping Cart architecture (Storage)
In AEM-native carts are stored in the ClientContext
Personalization should always be driven through the ClientContext.CommerceSession.addCartEntry()
Checkout architectureCart and Order Data
"e CommerceSession owns the three elements:
Cart contents Pricing "e order details
Cart contents
"e cart contents schema is !xed by the API: public void addCartEntry(Product product, int quantity); public void modifyCartEntry(int entryNumber, int quantity); public void deleteCartEntry(int entryNumber);
Pricing
"e pricing schema is also !xed by the API: public String getCartPreTaxPrice(); public String getCartTax(); public String getCartTotalPrice(); public String getOrderShipping(); public String getOrderTotalTax(); public String getOrderTotalPrice();
Checkout architecture (order details)
Order details are not !xed by the API: updateOrderDetails(Map<String, String> orderDetails);
Shipping options (and prices) depend on weight, delivery address, etc...
"e CommerceSession owns shipping pricing; to retrieve and update delivery details:updateOrder(Map<String, Object> delta)
Hands on
De!ning the scope
1. Build a new Commerce Implementation: “training”
2. Apply the new implementation to Geometrixx Outdoors
3. Store the cart data in the repository (/home/users/a/admin/commerce/cart)
adobe.com/go/gems@CQDev