Show Menu
ARGOMENTI×

Sviluppo con SAP Commerce Cloud

Il framework eCommerce può essere utilizzato con qualsiasi soluzione eCommerce. Alcune specifiche ed esempi qui trattati faranno riferimento alla soluzione ibrida .
Il framework di integrazione include un livello di integrazione con un'API. Questo consente di:
  • plug-in in un sistema eCommerce ed estrazione di dati di prodotto in AEM
  • creazione di componenti AEM per funzionalità di eCommerce, indipendentemente dallo specifico motore di eCommerce
Per usare il livello di integrazione, sono disponibili diversi componenti AEM forniti con il prodotto. Attualmente questi sono:
  • un componente di visualizzazione del prodotto
  • un carrello
  • check-out
Per la ricerca viene fornito un gancio di integrazione che consente di utilizzare la ricerca AEM, la ricerca del sistema eCommerce, una ricerca di terze parti (come Search&Promote) o una combinazione di tali metodi.

Selezione motore eCommerce

Il framework eCommerce può essere utilizzato con qualsiasi soluzione eCommerce. Il motore utilizzato deve essere identificabile da AEM:
  • I motori di eCommerce sono servizi OSGi che supportano l' CommerceService interfaccia
    • I motori possono essere distinti da una proprietà commerceProvider del servizio
  • AEM supporta Resource.adaptTo() per CommerceService e Product
    • L' adaptTo implementazione cerca una cq:commerceProvider proprietà nella gerarchia della risorsa:
      • Se trovato, il valore viene utilizzato per filtrare la ricerca del servizio commerce.
      • Se non viene trovato, viene utilizzato il servizio di commercio di livello più elevato.
    • Viene utilizzato un cq:Commerce mixin per cq:commerceProvider aggiungere risorse fortemente tipizzate.
  • La cq:commerceProvider proprietà viene utilizzata anche per fare riferimento alla definizione di fabbrica commerciale appropriata.
    • Ad esempio, una cq:commerceProvider proprietà con il valore hybris sarà correlata alla configurazione OSGi per Day CQ Commerce Factory for Hybris (com.adobe.cq.commerce.hybris.impl.HybrisServiceFactory), dove commerceProvider anche il parametro ha il valore hybris .
    • In questo caso è possibile configurare ulteriori proprietà, ad esempio la versione del catalogo (se appropriato e disponibile).
Vedere gli esempi seguenti:
cq:commerceProvider = geometrixx
in un’installazione standard di AEM è richiesta un’implementazione specifica; ad esempio, l'esempio geometrixx, che include estensioni minime per l'API generica
cq:commerceProvider = hybris
implementazione di hybris

Esempio

/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

Utilizzando CRXDE Lite potete vedere come questo viene gestito nel componente prodotto per l'implementazione hybris:
/apps/geometrixx-outdoors/components/hybris/product/product.jsp

Sviluppo per hybris 4

L'estensione hybris di eCommerce Integration Framework è stata aggiornata per supportare Hybris 5, mantenendo al contempo la compatibilità con Hybris 4.
Le impostazioni predefinite nel codice sono sintonizzate per Hybris 5.
Per sviluppare per Hybris 4 è necessario quanto segue:
  • Quando si richiama l'area di visualizzazione, aggiungere al comando il seguente argomento della riga di comando
    -P hybris4
Scarica la distribuzione preconfigurata di Hybris 4 e la incorpora nel pacchetto:
cq-commerce-hybris-server

  • In Gestione configurazione OSGi:
    • Disattivate il supporto di Hybris 5 per il servizio Parser risposte predefinito.
    • Verificate che il servizio Gestore autenticazione di base Hybris abbia una classificazione di servizio inferiore a quella del servizio Gestore OAuth di Hybris.

Gestione sessione

hybris utilizza una sessione utente per memorizzare informazioni come il carrello acquisti del cliente. L'ID sessione viene restituito da hybris in un JSESSIONID cookie che deve essere inviato in seguito a richieste successive ad hybris. Per evitare di memorizzare l’ID sessione nell’archivio, questo viene codificato in un altro cookie memorizzato nel browser dell’acquirente. Vengono eseguiti i seguenti passaggi:
  • Alla prima richiesta non viene impostato alcun cookie sulla richiesta dell'acquirente; viene quindi inviata una richiesta all’istanza hybris per creare una sessione.
  • I cookie di sessione vengono estratti dalla risposta, codificati in un nuovo cookie (ad esempio hybris-session-rest ) e impostati sulla risposta dell'acquirente. La codifica in un nuovo cookie è necessaria, perché il cookie originale è valido solo per un determinato percorso e in caso contrario non viene inviato dal browser nelle richieste successive. Le informazioni sul percorso devono essere aggiunte al valore del cookie.
  • Su richieste successive, i cookie vengono decodificati dai hybris-session-<*xxx*> cookie e impostati sul client HTTP utilizzato per richiedere i dati da hybris.
Viene creata una nuova sessione anonima quando la sessione originale non è più valida.

CommerceSession

  • Questa sessione "possiede" il carrello
    • esegue add/remove/etc
    • esegue i vari calcoli sul carrello;
      commerceSession.getProductPrice(Product product)
  • Possiede la posizione di archiviazione per i dati dell' ordine
    CommerceSession.getUserContext()
  • Possiede anche la connessione di elaborazione pagamento
  • Possiede anche la connessione di evasione

Sincronizzazione e pubblicazione dei prodotti

I dati di prodotto mantenuti in hybris devono essere disponibili in AEM. È stato attuato il seguente meccanismo:
  • Un carico iniziale di ID è fornito da hybris come feed. Possono essere presenti aggiornamenti a questo feed.
  • hybris fornirà informazioni di aggiornamento tramite un feed (che verrà controllato da AEM).
  • Quando AEM utilizza i dati di prodotto, invia le richieste ai hybris per i dati correnti (richiesta di ottenimento condizionale con data dell’ultima modifica).
  • In hybris è possibile specificare il contenuto di feed in modo dichiarativo.
  • La mappatura della struttura del feed al modello di contenuto AEM avviene nella scheda del feed sul lato AEM.
  • L’importazione (b) viene utilizzata per l’impostazione iniziale della struttura ad albero delle pagine in AEM per i cataloghi.
  • Le modifiche al catalogo negli ibridi sono indicate ad AEM tramite un feed, che quindi si propaga ad AEM (b)
    • Prodotto aggiunto/eliminato/modificato rispetto alla versione del catalogo.
    • Prodotto approvato.
  • L’estensione hybris fornisce un importatore polling ("schema hybris"), che può essere configurato per importare le modifiche in AEM a un intervallo specificato (ad esempio, ogni 24 ore in cui l’intervallo è specificato in secondi):
    ```
          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
           }
          ```
    
    
  • La configurazione del catalogo in AEM riconosce le versioni del catalogo in fase e online .
  • La sincronizzazione di prodotti tra versioni catalogo richiederà una (disattivazione)attivazione della pagina AEM corrispondente (a, c)
    • L'aggiunta di un prodotto a una versione di catalogo online richiede l'attivazione della pagina del prodotto.
    • La rimozione di un prodotto richiede la disattivazione.
  • L’attivazione di una pagina in AEM (c) richiede un controllo (b) ed è possibile solo se
    • Il prodotto si trova in una versione catalogo online per le pagine dei prodotti.
    • I prodotti di riferimento sono disponibili in una versione catalogo online per altre pagine (ad esempio, pagine di campagna).
  • Le pagine di prodotto attivate devono accedere alla versione online (d) dei dati del prodotto.
  • L’istanza di pubblicazione AEM richiede l’accesso agli ibridi per il recupero di dati di prodotto e personalizzati (d).

Architettura

Architettura di prodotti e varianti

Un singolo prodotto può presentare più varianti; ad esempio, può variare in base al colore e/o alla dimensione. Un prodotto deve definire quali proprietà determinano la variazione; chiamiamo questi assi ** varianti.
Tuttavia, non tutte le proprietà sono assi variabili. Le variazioni possono interessare anche altre proprietà; ad esempio, il prezzo potrebbe dipendere dalle dimensioni. Queste proprietà non possono essere selezionate dall'acquirente e pertanto non sono considerate assi di variante.
Ciascun prodotto e/o variante è rappresentato da una risorsa e pertanto viene mappato 1:1 su un nodo del repository. È un corollario che un prodotto e/o una variante specifica possa essere identificato in modo univoco dal suo percorso.
La risorsa prodotto/variante non contiene sempre i dati effettivi del prodotto. Può trattarsi di una rappresentazione dei dati effettivamente contenuti in un altro sistema (ad esempio gli ibridi). Ad esempio, le descrizioni dei prodotti, i prezzi e così via non vengono memorizzati in AEM, ma recuperati in tempo reale dal motore eCommerce.
Qualsiasi risorsa prodotto può essere rappresentata da un Product API . La maggior parte delle chiamate nell'API del prodotto sono specifiche per le varianti (anche se le variazioni possono ereditare valori condivisi da un predecessore), ma ci sono anche chiamate che elencano il set di variazioni ( getVariantAxes() , getVariants() ecc.).
In effetti, gli assi di una variante sono determinati da qualsiasi Product.getVariantAxes() risultato:
  • hybris lo definisce per l'implementazione hybris
Mentre i prodotti (in generale) possono avere molti assi di variante, il componente prodotto out-of-the-box gestisce solo due:
  1. size
  1. più uno
    Questa variante aggiuntiva viene selezionata tramite la variationAxis proprietà del riferimento prodotto (in genere color per Geometrixx Outdoors).

Riferimenti prodotto e dati prodotto

In generale:
  • i dati del prodotto si trovano in /etc
  • e i riferimenti ai prodotti in /content .
Deve essere presente una mappa 1:1 tra le varianti di prodotto e i nodi dati del prodotto.
Anche i riferimenti ai prodotti devono avere un nodo per ogni variante presentata, ma non è necessario presentare tutte le varianti. Ad esempio, se un prodotto ha varianti S, M, L, i dati del prodotto potrebbero essere:
etc
  commerce
    products
      shirt
        shirt-s
        shirt-m
        shirt-l

Mentre un catalogo "Big and Tall" può contenere solo:
content
  big-and-tall
    shirt
      shirt-l

Infine, non è previsto l'uso di dati di prodotto. È possibile inserire tutti i dati di prodotto sotto i riferimenti nel catalogo; ma non è possibile avere più cataloghi senza duplicare tutti i dati del prodotto.
API

com.adobe.cq.comCommerce.api.Interfaccia prodotto

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;
    }
}

  • Meccanismo di storage generale
    • I nodi di prodotto non sono:non strutturati.
    • Un nodo prodotto può essere:
      • Un riferimento, con i dati del prodotto memorizzati altrove:
        • I riferimenti ai prodotti contengono una productData proprietà che fa riferimento ai dati del prodotto (in genere sotto /etc/commerce/products ).
        • I dati del prodotto sono gerarchici; gli attributi del prodotto vengono ereditati dagli predecessori di un nodo di dati di prodotto.
        • I riferimenti ai prodotti possono anche contenere proprietà locali, che ignorano quelle specificate nei relativi dati di prodotto.
      • Un prodotto:
        • Senza una productData proprietà.
        • Un nodo di prodotto che contiene tutte le proprietà localmente (e non contiene una proprietà productData) eredita gli attributi di prodotto direttamente dai propri predecessori.
  • Struttura di prodotto generica AEM
    • Ogni variante deve avere un proprio nodo foglia.
    • L'interfaccia del prodotto rappresenta sia prodotti che varianti, ma il nodo del repository correlato è specifico sul quale si trova.
    • Il nodo product descrive gli attributi del prodotto e gli assi delle varianti.

Esempio

+ 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

Architettura del carrello

Componenti
  • Il carrello è di proprietà del CommerceSession:
    • Consente di CommerceSession eseguire operazioni di aggiunta, rimozione e così via.
    • Vengono CommerceSession inoltre eseguiti i vari calcoli sul carrello. "
  • Anche se non direttamente correlati al carrello, il CommerceSession cliente deve anche fornire informazioni sui prezzi del catalogo (dal momento che possiede i prezzi)
    • La determinazione prezzi può avere diversi modificatori:
      • Sconti sulla quantità.
      • Valute diverse.
      • IVA e IVA.
    • I modificatori sono completamente aperti con la seguente interfaccia:
      • int CommerceSession.getQuantityBreakpoints(Product product)
      • String CommerceSession.getProductPrice(Product product)
Archiviazione
  • Archiviazione
    • Nel caso hybris, il server hybris possiede il carrello.
    • In AEM i carrelli di maiuscole e minuscole generici sono memorizzati in ClientContext .
Personalizzazione
  • La personalizzazione deve sempre essere guidata da ClientContext .
  • ClientContext /version/ del carrello viene creato in tutti i casi:
    • I prodotti devono essere aggiunti utilizzando il CommerceSession.addCartEntry() metodo .
  • Esempio di informazioni sul carrello nel carrello ClientContext:

Architettura del Checkout

Dati carrello e ordine
La proprietà CommerceSession possiede i tre elementi:
  1. Contenuto del carrello
  2. Prezzi
  3. Dettagli ordine
  4. Contenuto del carrello
    Lo schema del contenuto del carrello è fisso dall'API:
        public void addCartEntry(Product product, int quantity);
        public void modifyCartEntry(int entryNumber, int quantity);
        public void deleteCartEntry(int entryNumber);
    
    
  5. Prezzi
    Lo schema tariffario è anche fissato dall'API:
        public String getCartPreTaxPrice();
        public String getCartTax();
        public String getCartTotalPrice();
        public String getOrderShipping();
        public String getOrderTotalTax();
        public String getOrderTotalPrice();
    
    
  6. Dettagli ordine
    Tuttavia, i dettagli dell'ordine non vengono corretti dall'API:
        public void updateOrderDetails(Map<String, String> orderDetails);
        public Map<String, String> getOrderDetails();
        public void submitOrder();
    
    
Calcoli di spedizione
  • I moduli di ordine spesso devono presentare più opzioni di spedizione (e prezzi).
  • I prezzi possono essere basati su articoli e dettagli dell'ordine, come peso e/o indirizzo di consegna.
  • L' CommerceSession utente ha accesso a tutte le dipendenze, quindi può essere trattato in modo simile al prezzo del prodotto:
    • Il CommerceSession proprietario del prezzo di spedizione.
    • Può recuperare/aggiornare i dettagli di consegna utilizzando updateOrder(Map<String, Object> delta)
È possibile implementare un selettore di spedizione; ad esempio:
yourProject/commerce/components/shippingpicker :
  • Essenzialmente questa potrebbe essere una copia di foundation/components/form/radio , ma con callback al CommerceSession for:
  • Verifica della disponibilità del metodo
  • Aggiunta di informazioni sui prezzi
  • Per consentire agli acquirenti di aggiornare la pagina dell’ordine in AEM (incluso il superset di metodi di spedizione e il testo che li descrive), pur mantenendo il controllo per esporre le CommerceSession informazioni pertinenti.
Elaborazione pagamenti
  • Possiede CommerceSession anche la connessione di elaborazione del pagamento.
  • Gli implementatori devono aggiungere chiamate specifiche (al servizio di elaborazione dei pagamenti prescelto) all' CommerceSession implementazione.
Evasione ordine
  • Possiede CommerceSession anche la connessione di evasione.
  • Gli esecutori dovranno aggiungere chiamate specifiche (al servizio di elaborazione dei pagamenti prescelto) all' CommerceSession implementazione.

Ricerca definizione

In base al modello di API per i servizi standard, il progetto eCommerce fornisce un set di API relative alla ricerca che possono essere implementate dai singoli motori di commercio.
Attualmente, solo il motore ibrido implementa l'API di ricerca out-of-the-box.
Tuttavia, l'API di ricerca è generica e può essere implementata da ogni CommerceService singolarmente.
Il progetto eCommerce contiene un componente di ricerca predefinito, che si trova in:
/libs/commerce/components/search
Questo utilizza l'API di ricerca per eseguire una query sul motore di eCommerce (vedi Selezione motore di eCommerce) selezionato:

API di ricerca

Il progetto principale offre diverse classi generiche / helper:
  1. CommerceQuery
Viene utilizzato per descrivere una query di ricerca (contiene informazioni sul testo della query, la pagina corrente, la dimensione della pagina, l’ordinamento e i facet selezionati). Tutti i servizi eCommerce che implementano l'API di ricerca riceveranno le istanze di questa classe per eseguire la ricerca. È CommerceQuery possibile creare un'istanza di un oggetto di richiesta ( HttpServletRequest ).
  1. FacetParamHelper
È una classe di utilità che fornisce un metodo statico, toParams , utilizzato per generare stringhe di GET parametri da un elenco di facet e un valore attivato. Questa funzione è utile nell’interfaccia utente, dove è necessario visualizzare un collegamento ipertestuale per ciascun valore di ciascun facet, in modo che quando l’utente fa clic sul collegamento ipertestuale il relativo valore venga attivato (ovvero se è stato selezionato, viene rimosso dalla query, altrimenti aggiunto). Questo si occupa di tutte le logiche di gestione di facet multivalore/monomalore, valori prevalenti, ecc.
Il punto di ingresso per l'API di ricerca è il CommerceService#search metodo che restituisce un CommerceResult oggetto. Per ulteriori informazioni su questo argomento, consulta la Documentazione sulle API.

Integrazione utente

L'integrazione è fornita tra AEM e vari sistemi di eCommerce. Ciò richiede una strategia per la sincronizzazione degli acquirenti tra i vari sistemi, in modo che il codice specifico per AEM debba conoscere solo AEM e viceversa:
  • Autenticazione
    Si presume che AEM sia l’ unico front-end Web e pertanto esegue tutta l’autenticazione.
  • Account slave
    AEM crea un account slave in hybris per ogni acquirente. Il nome utente dell’account slave è uguale al nome utente di AEM. Una password crittografata casuale viene generata automaticamente e memorizzata (cifrata) in AEM.

Utenti preesistenti

Un front-end AEM può essere posizionato davanti a un’implementazione ibrida esistente. È inoltre possibile aggiungere un motore ibrido a un’installazione AEM esistente. A tal fine, i sistemi devono essere in grado di gestire correttamente gli utenti esistenti in entrambi i sistemi:
  • AEM -> hybris
    • Quando accedete a hybris, se l’utente AEM non esiste già:
      • creare un nuovo utente hybris con una password crittografata casuale
      • memorizzare il nome utente hybris nella directory utente dell’utente AEM
    • Vedi: com.adobe.cq.commerce.hybris.impl.HybrisSessionImpl#login()
  • hybris -> AEM
    • Quando effettuate l’accesso ad AEM, se il sistema riconosce l’utente:
      • tentativo di accedere a hybris con nome utente/pwd fornito
      • in caso di esito positivo, create il nuovo utente in AEM con la stessa password (il valore aggiunto specifico di AEM darà luogo all’hash specifico di AEM)
    • L'algoritmo di cui sopra è implementato in una Sling AuthenticationInfoPostProcessor
      • Vedi: com.adobe.cq.commerce.hybris.impl.user.LazyUserImporter.java

Personalizzazione del processo di importazione

Per sfruttare le funzionalità esistenti del gestore di importazioni personalizzato:
  • deve implementare l' ImportHandler interfaccia
  • può estendere 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;
}

Affinché il gestore personalizzato venga riconosciuto dall'importatore, deve specificare la service.ranking proprietà con un valore superiore a 0; ad esempio:
@Component
@Service
@Property(name = "service.ranking", value = 100)
public class MyImportHandler extends DefaultImportHandler {
    ...
}