Blog

Quando le tipologie di prodotto Magento non bastano

Lettura 6 minuti

Ogni volta che vogliamo creare un nuovo prodotto nel nostro catalogo Magento, manualmente o tramite importazione, dobbiamo specificare due principali informazioni:

  • product-type
  • attribute-set

Possiamo dire che questa accoppiata di caratteristiche rappresenta il DNA del prodotto, non esiste infatti la possibilità di modificare questa combinazione una volta che il prodotto è creato a catalogo.

L’attribute-set identifica la lista di caratteristiche descrittive del prodotto e Magento, tramite una comoda interfaccia di backend, ci consente di modellare tanti attribute-set quante sono le categorie merceologiche degli articoli che dobbiamo presentare.

Il product-type invece contraddistingue il comportamento del prodotto nella presentazione a catalogo, nell’esperienza di acquisto e nella modalità di fruizione successiva alla fase di acquisto. Magento Community Edition nativamente mette a disposizione sei tipologie di prodotto, ognuna con proprie peculiarità:

  • Prodotto semplice
  • Prodotto virtuale
  • Prodotto scaricabile
  • Prodotto configurabile
  • Prodotto raggruppato
  • Prodotto bundle

Se abbiamo confidenza non solo con Magento, ma in generale con la progettazione di soluzioni e-commerce, e conosciamo bene la natura e la destinazione dei prodotti che verranno venduti sulla piattaforma che stiamo realizzando, allora non avremo dubbi nell’identificare la tipologia di prodotto più attinente per ogni articolo, tra le sei sopra citate.

A volte però abbiamo la necessità di prevedere un comportamento specifico per alcuni prodotti, aggiuntivo o parzialmente differente rispetto al comportamento predefinito delle tipologie a disposizione: in questo caso serve l’intervento dello sviluppatore dato che Magento non consente da backend di creare una nuova tipologia di prodotto proprio perché la necessità di disporre di una nuova tipologia nasce dall’esigenza di poter identificare la casistica in modo da implementare logiche specifiche.

Ovviamente potremmo aggirare l’ostacolo creando un attributo oppure un attribute-set specifico per riconoscere i prodotti con questa esigenza, ma creare un nuovo tipo prodotto ha sicuramente dei vantaggi ed è anche una soluzione più elegante.

Vantaggi

Uno dei vantaggi dell’introduzione di una nuova tipologia di prodotto è che la relativa informazione (product-type) viene di default storicizzata sia a livello di righe carrello (nella tabella sales_flat_quote_item) sia a livello di righe ordine (sales_flat_order_item).

Questo è un grosso vantaggio poiché in qualsiasi fase del processo di acquisto e anche nello storico ordini è possibile recuperare l’informazione senza necessità di accedere al catalogo che nel frattempo potrebbe essere stato aggiornato.

Inoltre nella creazione di una nuova tipologia di prodotto si può scegliere di estendere una tipologia già esistente, ereditandone il comportamento predefinito e aggiungendo solo la logica personalizzata.

Come creare un nuovo tipo prodotto?

Vediamo come creare un modulo Magento che espone una nuova tipologia di prodotto. Nel mio esempio creo un modulo chiamato “SampleProduct” sotto il namespace “Bitbull”, e lo posiziono nel codepool “local”.

Decido di registrare la nuova tipologia di prodotto “bitbull_sample” come estensione di un prodotto semplice.

Vediamo la struttura del modulo e analizziamo i files principali:

  • app/
    • code/
      • local/
        • Bitbull/
          • SampleProduct/
            • etc/
              • config.xml
            • Helper
              • Data.php
            • Model/
              • Product/
                • Price.php
                • Type.php
              • sql/
              • bitbull_sampleproduct_setup/
                • install-1.0.0.php
    • etc/
      • modules/
        • Bitbull_SampleProduct.xml

Il file config.xml definisce la struttura del modulo:

<?xml version="1.0"?>
<config>
   <modules>
      <Bitbull_SampleProduct>
         <version>1.0.0</version>
      </Bitbull_SampleProduct>
   </modules>
   <global>
      <models>
         <bitbull_sampleproduct>
            <class>Bitbull_SampleProduct_Model</class>
         </bitbull_sampleproduct>
      </models>
      <catalog>
         <product>
            <type>
               <bitbull_sample translate="label" module="bitbull_sampleproduct">
                  <label>Bitbull Sample Product</label>
                  <model>bitbull_sampleproduct/product_type</model>
                  <price_model>bitbull_sampleproduct/product_price</price_model>
                  <composite>0</composite>
                  <is_qty>1</is_qty>
                  <is_qty_decimal>0</is_qty_decimal>
               </bitbull_sample>
            </type>   
         </product>   
      </catalog>
   </global>
   <adminhtml>
      <sales>
         <order>
            <create>
               <available_product_types>
                  <bitbull_sample/>
               </available_product_types>
            </create>
         </order>
      </sales>
   </adminhtml>
</config>

Magento utilizza il nodo per definire la struttura del catalogo; all’interno definisco il nodo che identifica il tipo prodotto e contiene le caratteristiche dello stesso.

  • label: identifica l’etichetta del tipo prodotto
  • model: indica il path del model per il nuovo tipo prodotto
  • price_model: indica il path del model per configurare un’eventuale logica estesa per i prezzi del tipo prodotto
  • composite: indica se il prodotto è strutturato (ad es. i configurabili, raggruppati e bundle)
  • is_qty: indica se può essere definita una quantità per il prodotto
  • is_qty_decimal: indica se può essere definita una quantità decimale per il prodotto

Esistono anche altre configurazioni avanzate relative all’indicizzazione dei prodotti della nuova tipologia:

  • index_priority: priorità di indicizzazione
  • price_indexer, stock_indexer, index_data_retriever: relative ai modelli e risorse da usare per l’indicizzazione

L’altra configurazione importante è contenuta nel nodo in cui andiamo a indicare se il tipo prodotto esposto dal nostro modulo è disponibile nell’interfaccia di backend che consente di aggiungere prodotti in fase di creazione di un nuovo ordine.

Gli altri file importanti da creare sono i modelli definiti per il tipo prodotto e per il prezzo.

Model/Product/Type.php

In questo file creo anche una costante a cui fare riferimento nel codice dei miei model e observer per identificare il nuovo tipo prodotto.

class Bitbull_SampleProduct_Model_Product_Type 
   extends Mage_Catalog_Model_Product_Type_Simple { 
   
   const TYPE_BITBULL_SAMPLE = 'bitbull_sample';
}

Model/Product/Price.php

class Bitbull_SampleProduct_Model_Product_Price 
   extends Mage_Catalog_Model_Product_Type_Price { }

Infine ho previsto un file di setup, non obbligatorio ma utile, che in fase di installazione del modulo associa la nuova tipologia di prodotto a tutti gli attributi di catalogo relativi alla gestione delle informazioni relative al prezzo del prodotto. Senza questo file non sarebbe visibile il tab “Prezzo” per i prodotti della nuova tipologia a meno di effettuare manualmente da backend l’associazione nella gestione attributi del catalogo.

sql/bitbull_sampleproduct_setup/install-1.0.0.php

$installer = $this;
$installer->startSetup();

$attributes = array(
   'price',
   'special_price',
   'special_from_date',
   'special_to_date',
   'minimal_price',
   'tax_class_id',
   'group_price',
   'tier_price',
   'msrp',
   'msrp_enabled',
   'msrp_display_actual_price_type',
   'cost',
   'is_recurring'
);

foreach ($attributes as $attributeCode) {
   $applyTo = explode(
       ',',
       $installer->getAttribute(
           Mage_Catalog_Model_Product::ENTITY,
           $attributeCode,
           'apply_to'
       )
   );

   if (!in_array(Bitbull_SampleProduct_Model_Product_Type::TYPE_BITBULL_SAMPLE, $applyTo)) {
       $applyTo[] = Bitbull_SampleProduct_Model_Product_Type::TYPE_BITBULL_SAMPLE;
       $installer->updateAttribute(
           Mage_Catalog_Model_Product::ENTITY,
           $attributeCode,
           'apply_to',
           join(',', $applyTo)
       );
   }
}

$installer->endSetup();

Conclusioni

Con poche righe di codice è possibile estendere le tipologie di prodotto standard Magento; personalmente ho adottato questa strategia per necessità legate alla fase di checkout e post-vendita.

Nel primo caso mi serviva poter riconoscere la presenza di una particolare tipologia di prodotto nell’ordine per presentare all’utente un metodo di spedizione inizializzato con parametri differenti rispetto alla configurazione standard del carrier. La stessa logica poteva essere sfruttata per esporre campi aggiuntivi in fase di checkout oppure per nascondere un metodo di pagamento, ad esempio.

Nel secondo caso avevo necessità di generare una serie di documenti pdf per gli articoli acquistati contraddistinti dalla nuova tipologia di prodotto.

In questi casi ho scritto un metodo nell’helper del modulo descritto in questo articolo, per avere una logica accentrata che permettesse di valutare se un particolare prodotto, quote item o order item fosse della tipologia di prodotto esposta tramite il modulo stesso.

class Bitbull_SampleProduct_Helper_Data extends Mage_Core_Helper_Abstract {

   public function productIsSampleProduct(Mage_Catalog_Model_Product $product) {
       return $product->getTypeId() == Bitbull_SampleProduct_Model_Product_Type::TYPE_BITBULL_SAMPLE;
   }

   public function quoteItemIsSampleProduct(Mage_Sales_Model_Quote_Item $item) {
       return $item->getProductType() == Bitbull_SampleProduct_Model_Product_Type::TYPE_BITBULL_SAMPLE;
   }

   public function orderItemIsSampleProduct(Mage_Sales_Model_Order_Item $item) {
       return $item->getProductType() == Bitbull_SampleProduct_Model_Product_Type::TYPE_BITBULL_SAMPLE;
   }

}

Per ogni funzionalità aggiuntiva ho poi creato un apposito modulo con dipendenza dal modulo Bitbull_SampleProduct e nell’implementazione delle logiche personalizzate ho richiamato i metodi predisposti nell’helper.

Di seguito l’implementazione di un controller con esempio della action che genera i documenti delle righe ordini (modulo Bitbull_SampleProductDocuments):

class Bitbull_SampleProductDocuments_Helper_Data extends Mage_Core_Controller_Front_Action {

   public function documentsAction()
   {
       $orderId = $this->getRequest()->get('order_id');
       if ($orderId) {
           $order = Mage::getModel('sales/order')->load($orderId);
           if ($order->getId()) {
               $_items = $order->getItemsCollection();
               foreach ($_items as $_item) {
                   if (Mage::helper('bitbull_sampleproduct')->orderItemIsSampleProduct($_item))
                   {
                       //creazione del documento per la riga ordine
                       ....
                   }
               }
           }
       }
       .....
   }
}

Questa soluzione ci consente quindi di personalizzare il comportamento del catalogo prodotti come mostrato o comunque intercettando casistiche particolari tramite, ad esempio, l’implementazione di observer, l’applicazione di filtri sulle collection, la gestione di layout handle specifici, e molte altre soluzioni.

Nadia Sala