API-Dokumentation ist ebenfalls verfügbar.
Das Integrations-Framework enthält eine Integrationsebene mit einer API. Dies ermöglicht es Ihnen, AEM-Komponenten für eCommerce-Funktionen (unabhängig von einer bestimmten eCommerce-Engine) zu erstellen. Außerdem können Sie die interne CRX-Datenbank verwenden oder ein eCommerce-System einbinden und Produktdaten in AEM ziehen.
Eine Reihe vorkonfigurierter AEM-Komponenten wird zur Verwendung der Integrationsebene bereitgestellt. Derzeit sind folgende Komponenten verfügbar:
Für die Suche wird ein Integrations-Hook zur Verfügung gestellt, mit dem Sie die AEM-Suche, eine Suche von Drittanbietern oder eine Kombination daraus verwenden können.
Das eCommerce-Framework kann mit jeder eCommerce-Lösung verwendet werden, die verwendete Engine muss von AEM identifiziert werden - auch bei Verwendung der generischen AEM-Engine:
eCommerce-Engines sind OSGi-Dienste, die die CommerceService
-Schnittstelle unterstützen.
commerceProvider
-Service-Eigenschaft identifiziert werden.AEM unterstützt Resource.adaptTo()
für CommerceService
und Product
.
Die adaptTo
-Implementierung sucht nach einer cq:commerceProvider
-Eigenschaft in der Hierarchie der Ressource:
Ein cq:Commerce
-Mixin wird verwendet, um cq:commerceProvider
zu stark typisierten Ressourcen hinzuzufügen.
Die cq:commerceProvider
-Eigenschaft wird auch als Verweis auf die geeignete Commerce-Factory-Definition verwendet.
cq:commerceProvider
mit dem Wert mit der OSGi-Konfiguration für Day CQ Commerce Factory für Geometrixx-Outdoors (com.adobe.cq.commerce.hybris.impl.GeoCommerceServiceFactory
) - wobei der Parameter commerceProvider
auch den Wert geometrixx
geometrixx hat.In einer Standard-AEM-Installation wird eine spezifische Implementierung benötigt, zum Beispiel:
cq:commerceProvider = geometrixx |
Geometrixx-Beispiel; dies umfasst minimale Erweiterungen der generischen API |
/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
Mit CRXDE Lite können Sie sehen, wie dies in der Produktkomponente für die generische AEM-Implementierung gehandhabt wird:
/apps/geometrixx-outdoors/components/product
Eine Sitzung zum Speichern von Informationen über den Warenkorb des Kunden.
Die CommerceSession:
Besitzt den Warenkorb
Sie führt Hinzufügen/Entfernen-Aktionen aus.
Sie führt diverse Berechnungen im Hinblick auf den Warenkorb aus,
commerceSession.getProductPriceInfo(Product product, Predicate filter)
Besitzt Persistenz der Bestelldaten:
CommerceSession.getUserContext()
Kann Versanddetails über updateOrder(Map<String, Object> delta)
abrufen oder aktualisieren.
Sie steuert auch die Verbindung für die Zahlungs verarbeitung.
Sie steuert ebenfalls die Verbindung für die Auftragserfüllung.
Ein einzelnes Produkt kann mehrere Varianten aufweisen, z. B. unterschiedliche Farben und/oder Größen. Für ein Produkt müssen so genannte Variantenachsen definiert werden, die angeben, welche Eigenschaften die Variante bestimmen.
Es sind jedoch nicht alle Eigenschaften Variantenachsen. Varianten können sich auch auf andere Eigenschaften auswirken, z. B. kann der Preis größenabhängig sein. Diese Eigenschaften können vom Kunden nicht ausgewählt werden und werden daher nicht als Variantenachsen angesehen.
Jedes Produkt bzw. jede Variante steht für eine Ressource und ist daher im Verhältnis 1:1 einem Repository-Knoten zugeordnet. Folglich kann ein spezifisches Produkt bzw. eine spezifische Variante eindeutig anhand des Pfads identifiziert werden.
Jede Produktressource kann durch eine Product API
dargestellt werden. Die meisten Aufrufe in einer Produkt-API beziehen sich auf spezifische Varianten (obwohl Varianten gemeinsame Werte von einem Vorgänger erben können). Bei manchen Aufrufen wird jedoch ein Variantensatz (getVariantAxes()
, getVariants()
usw.) aufgelistet.
Eine Variantenachse wird letztendlich von dem bestimmt, was der Product.getVariantAxes()
-Aufruf zurückgibt:
cq:productVariantAxes
)Zwar können Produkte (im Allgemeinen) viele Variantenachsen haben, vorkonfigurierte Produktkomponenten jedoch nur zwei:
size
und eine zusätzliche Variante
Diese zusätzliche Variante wird von der variationAxis
-Eigenschaft des Produktverweises (in der Regel color
für Geometrixx Outdoors) ausgewählt.
Im Allgemeinen
befinden sich PIM-Daten unter /etc
und Produktverweise unter /content
.
Die Knoten für die Produktvarianten und Produktdaten müssen 1:1 zugeordnet sein.
Produktverweise müssen außerdem einen Knoten für jede präsentierte Variante haben, es müssen jedoch nicht alle Varianten präsentiert werden. Wenn ein Produkt beispielsweise die Varianten S, M und L hat, können die Produktdaten wie folgt aussehen:
etc
commerce
products
shirt
shirt-s
shirt-m
shirt-l
Im Katalog „big-and-tall“ sind möglicherweise nur diese Daten enthalten:
content
big-and-tall
shirt
shirt-l
Es ist nicht zwingend erforderlich, Produktdaten zu verwenden. Sie können alle Produktdaten unter den Verweisen im Katalog speichern. Allerdings müssen Sie dann alle Produktdaten duplizieren, wenn Sie mehrere Kataloge verwenden möchten.
API
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;
}
/**
* 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;
}
}
Allgemeine Speichermethode
Produktknoten weisen die Eigenschaft „nt:unstructured“ auf.
Ein Produktknoten kann Folgendes sein:
Ein Verweis, wenn die Produktdaten an anderer Stelle gespeichert sind:
productData
-Eigenschaft, die auf die Produktdaten verweist (in der Regel unter /etc/commerce/products
).Ein Produkt als solches:
productData
-Eigenschaft.AEM-generische Produktstruktur
+ 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
Komponenten
Der Warenkorb wird von der CommerceSession:
gesteuert:
CommerceSession
führt Hinzufügen, Entfernen usw. durch.CommerceSession
nimmt auch die diversen Berechnungen des Warenkorbs vor.CommerceSession
wendet auch Gutscheine und Aktionen an, die auf den Warenkorb ausgeführt werden.Obwohl dies nicht direkt mit dem Warenkorb zusammenhängt, muss die CommerceSession
auch Kataloginformationen angeben (da sie die Preise steuert).
Für Preise können mehrere Modifikatoren gelten:
Die Modifikatoren sind bei folgenden Schnittstellen vollständig offen:
int CommerceSession.getQuantityBreakpoints(Product product)
String CommerceSession.getProductPrice(Product product)
Speicher
Speicher
Personalisierung
Die Personalisierung sollte immer mithilfe von ClientContext erfolgen.
In allen Fällen wird eine ClientContext-Version (/version/
) des Warenkorbs erstellt:
CommerceSession.addCartEntry()
-Methode hinzugefügt werden.Nachstehend sehen Sie ein Beispiel für Warenkorbinformationen in einem ClientContext-Warenkorb:
Warenkorb- und Auftragsdaten
Die CommerceSession
steuert die drei folgenden Elemente:
Inhalt des Warenkorbs
Das Inhaltsschema des Warenkorbs wird von der API festgelegt:
public void addCartEntry(Product product, int quantity);
public void modifyCartEntry(int entryNumber, int quantity);
public void deleteCartEntry(int entryNumber);
Preise
Das Preisschema wird ebenfalls von der API festgelegt:
public String getCartPreTaxPrice();
public String getCartTax();
public String getCartTotalPrice();
public String getOrderShipping();
public String getOrderTotalTax();
public String getOrderTotalPrice();
Auftragsdetails
Die Auftragsdetails werden jedoch nicht von der API festgelegt:
public void updateOrderDetails(Map<String, String> orderDetails);
public Map<String, String> getOrderDetails();
public void submitOrder();
Versandberechnungen
Auftragsformulare müssen häufig mehrere Versandoptionen (und Preise) enthalten.
Die Preise können auf Elementen und Details des Auftrags, wie Gewicht und/oder Lieferadresse, basieren.
CommerceSession
hat Zugriff auf alle Abhängigkeiten und kann daher ähnlich wie Produktpreise behandelt werden:
CommerceSession
steuert die Versandkosten.updateOrder(Map<String, Object> delta)
, um Lieferdetails abzurufen / zu aktualisieren.Nach dem standardmäßigen Dienst-API-Modell stellt das Commerzbank-Projekt einen Satz suchbezogener APIs bereit, die in einzelnen Commerce-Engines implementiert werden können.
Derzeit wird die vorkonfigurierte Such-API nur von der Hybris-Engine implementiert.
Die Such-API ist jedoch generisch und kann von jeder CommerceService-Suche einzeln implementiert werden.
Obwohl die standardmäßig bereitgestellte generische Implementierung diese API nicht implementiert, können Sie sie erweitern und die Suchfunktionalität hinzufügen.
Das eCommerce-Projekt enthält eine Standardsuchkomponente in:
/libs/commerce/components/search
Dabei wird die Such-API zum Abfragen der ausgewählten Commerce-Engine (siehe Auswahl der eCommerce Engine) verwendet:
Vom Kernprojekt werden mehrere generische bzw. Helper-Klassen bereitgestellt:
CommerceQuery
Wird zum Beschreiben einer Suchabfrage verwendet (enthält Informationen zu Abfragetext, aktueller Seite, Seitengröße, Sortierung und ausgewählten Facetten). Alle eCommerce-Services, die die Such-API implementieren, erhalten Instanzen dieser Klasse, um die Suche durchführen zu können. Es kann eine CommerceQuery
-Instanz anhand eines Anfrageobjekts (HttpServletRequest
) erstellt werden.
FacetParamHelper
Eine Hilfsprogramm-Klasse, die eine statische Methode (toParams
) zum Erzeugen von GET
-Parameterzeichenfolgen aus einer Facettenliste und einen umgeschalteten Wert bereitstellt. Dies ist in der Benutzeroberfläche nützlich, wenn Sie einen Hyperlink für jeden Wert einer Facette anzeigen möchten, damit beim Klicken eines Benutzers auf den Hyperlink der entsprechende Wert umgeschaltet wird (z. B. aus der Abfrage entfernt wird, falls er ausgewählt war, oder andernfalls hinzugefügt wird). Damit wird die gesamte Logik zur Verarbeitung von Facetten, einschließlich Facetten mit einzelnen oder mehreren Werten, das Überschreiben von Werten usw., abgedeckt.
Einstiegspunkt für die Such-API ist die CommerceService#search
-Methode, die ein CommerceResult
-Objekt zurückgibt. Weitere Informationen zu diesem Thema finden Sie in der API-Dokumentation.
Gutscheine:
Ein Gutschein ist eine seitenbasierte Komponente, die mit der Website-Konsole erstellt/bearbeitet und unter folgendem Ordner gespeichert wird:
/content/campaigns
Gutscheine umfassen:
Gutscheine haben keine eigenen Datums-/Zeitangaben für Aktivierung und Deaktivierung, sondern nutzen die der übergeordneten Kampagnen.
Externe Commerce-Engines können ebenfalls Gutscheine bereitstellen; diese erfordern mindestens:
isValid()
-MethodeDie Gutschein-Komponente (/libs/commerce/components/voucher
) bietet:
Promotions:
Eine Promotion ist eine seitenbasierte Komponente, die mit der Website-Konsole erstellt/bearbeitet und unter folgendem Ordner gespeichert wird:
/content/campaigns
Promotions umfassen:
Sie können Promotions mit einer Kampagne verbinden, um ihre Datums-/Zeitangaben für Aktivierung und Deaktivierung zu definieren.
Sie können Promotions mit einem Erlebnis verbinden, um ihre Segmente zu definieren.
Promotions, die nicht mit einem Erlebnis verbunden sind, starten nicht von selbst, können aber durch einen Gutschein ausgelöst werden.
Die Promotion-Komponente (/libs/commerce/components/promotion
) umfasst:
Zwei Promotion-Handler sind im Lieferumfang enthalten:
DiscountPromotionHandler
, der einen absoluten oder prozentualen Rabatt auf den gesamten Warenkorb anwendetPerfectPartnerPromotionHandler
, der einen absoluten oder prozentualen Rabatt auf ein Produkt anwendet, wenn das Partnerprodukt ebenfalls im Warenkorb istDer ClientContext SegmentMgr
löst Segmente auf und der ClientContext CartMgr
löst Promotions auf. Jede Promotion, die mindestens einem aufgelösten Segment unterliegt, wird ausgelöst.
Das Hinzufügen/Entfernen eines Gutscheins aus einem Warenkorb erfolgt über die 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;
Auf diese Weise ist CommerceSession
für die Überprüfung verantwortlich, ob ein Gutschein existiert und ob er angewendet werden kann oder nicht. Dies könnte Gutscheine betreffen, die nur angewendet werden können, wenn eine bestimmte Bedingung erfüllt ist; zum Beispiel, wenn der gesamte Warenkorbpreis größer als 100 € ist). Wenn ein Gutschein aus irgendeinem Grund nicht angewendet werden kann, löst die addVoucher
-Methode eine Ausnahme aus. Außerdem ist die CommerceSession
für die Aktualisierung der Preise im Warenkorb verantwortlich, nachdem ein Gutschein hinzugefügt/entfernt wurde.
Der Voucher
ist eine Bean-ähnliche Klasse, die Felder enthält für:
Die bereitgestellte AbstractJcrCommerceSession
kann Gutscheine beantragen. Die von der Klasse getVouchers()
zurückgegebenen Gutscheine sind Instanzen von cq:Page
, die einen jcr:content-Knoten mit folgenden Eigenschaften enthalten (unter anderem):
sling:resourceType
(String) - dieser muss commerce/components/voucher
sein
jcr:title
(String) - für die Beschreibung des Gutscheins
code
(String) - der Code, den der Benutzer eingeben muss, um den Gutschein anwenden
promotion
(String) - die anzuwendende Promotion; z. B. /content/campaigns/geometrixx-outdoors/article/10-bucks-off
Promotion-Handler sind OSGi-Dienste, die den Warenkorb verändern. Der Warenkorb unterstützt mehrere Hooks, die in der PromotionHandler
-Schnittstelle definiert werden.
/**
* 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();
Drei Promotion-Handler stehen zur Verfügung:
DiscountPromotionHandler
wendet einen absoluten oder prozentualen Rabatt auf den gesamten Warenkorb anPerfectPartnerPromotionHandler
wendet einen absoluten oder prozentualen Rabatt auf ein Produkt an, wenn sich das Partnerprodukt ebenfalls im Warenkorb befindetFreeShippingPromotionHandler
wendet kostenlosen Versand an