Prise en charge d’une propriété de panier personnalisée dans les conditions des règles de prix panier de Magento

Le backoffice de Magento permet d’aisément créer des règles de prix via les menus Promotions > Règles de prix catalogue et Promotions > règles de prix panier. Nous allons nous intéresser aux règles de prix panier qui sont celles qui permettent d’appliquer des promotions en fonction des propriétés du panier d’un client (comme son montant, poids, mode de livraison…). Nous allons voir comment nous pouvons étendre cette fonctionnalité afin d’y ajouter le support d’une nouvelle propriété.



<p><strong>liste_proprietes_modifiees.jpg</strong></p>
<p>

Dans la plupart des cas les propriétés mises à disposition sont suffisantes mais il arrive parfois que nous travaillions sur une boutique qui a fait l’objet d’un développement spécifique. Dans l’exemple débordant d’imagination que je vais prendre ici, je suppose qu’une nouvelle propriété a été ajoutée au panier, permettant d’indiquer s’il est spécial ou non. Cette propriété prend la forme d’une colonne is_special (quelle surprise) dans la table sales_flat_quote. Sa valeur est à 1 si le panier est spécial, 0 dans les autres cas. Dans le cadre de ce tutoriel nous voudrions être capables de créer des règles de prix panier qui dépendront de la valeur de cet attribut. Pour cela nous devons étendre le fonctionnement natif de Magento.

Créer une nouvelle classe de condition

Tout d’abord il va falloir créer le module qui va contenir le code dont nous avons besoin. Si vous lisez ce tutoriel vous devriez être en mesure de le faire tout seul donc je vous laisse travailler un peu ;-). La fonctionnalité que nous allons étendre se trouve dans le module Mage_SalesRule. Je vais donc appeler le module de cet exemple My_SalesRule.

En observant un peu ce qui se trouve dans le module Mage_SalesRule, on voit qu’il existe trois grands types de conditions : Product, Address et Combine qui représentent respectivement des conditions sur les produits, l’adresse ou une combinaison de conditions. La propriété qui nous intéresse se trouve sur l’entité panier (quote). Or, aucun de ces types de conditions concerne réellement l’entité panier. Nous allons donc créer un nouveau type de condition.

Créez une classe héritant de Mage_Rule_Model_Condition_Abstract. Nous allons l’appeler My_SalesRule_Model_Rule_Condition_Quote. N’oubliez pas de gérer la réécriture de classe dans votre fichier config.xml si vous prenez un nom de module identique au module natif.

<?php
class My_SalesRule_Model_Rule_Condition_Quote
    extends Mage_Rule_Model_Condition_Abstract
{
    /**
     * Liste des attributs disponibles
     *
     * @return Mage_Rule_Model_Condition_Abstract
     */
    public function loadAttributeOptions()
    {
        $attributes = array(
            'is_special' => 'Panier spécial'
        );

        $this->setAttributeOption($attributes);

        return $this;
    }

    /**
     * Définit le type de chaque attribut
     *
     * @return string
     */
    public function getInputType()
    {
        if ($this->getAttribute() == 'is_special') {
            return 'select';
        }
        return 'string';
    }

    /**
     * Définit l'élément de formulaire de chaque attribut
     *
     * @return string
     */
    public function getValueElementType()
    {
        if ($this->getAttribute() == 'is_special') {
            return 'select';
        }
        return 'text';
    }

    /**
     * Définit les options des attributs de type "select"
     *
     * @return array|mixed
     */
    public function getValueSelectOptions()
    {
        if (!$this->hasData('value_select_options')) {
            $options = array();
            if ($this->getAttribute() == 'is_special') {
                $options = array(
                    array(
                        'label' => 'Oui',
                        'value' => 1
                    ),
                    array(
                        'label' => 'Non',
                        'value' => 0
                    )
                );
            }
            $this->setData('value_select_options', $options);
        }
        return $this->getData('value_select_options');
    }

    /**
     * Validation de la condition
     *
     * @param Varien_Object $object
     * @return bool
     */
    public function validate(Varien_Object $object)
    {
        $quote = $object;
        if (!$quote instanceof Mage_Sales_Model_Quote) {
            $quote = $object->getQuote();
        }
        return parent::validate($quote);
    }
}

En surchargeant la méthode loadAttributeOptions() on définit les attributs qui pourront être sélectionnés par la condition. Nous n’avons besoin que d’un seul attribut dans notre cas.

La méthode getInputType() permet de définir le type de valeur correspondant à chaque attribut. Cette information est utilisée lors de la validation de la condition. Nous utilisons le type select.

Pour définir le type de champ à afficher lorsqu’on sélectionne un attribut de la condition dans l’interface, nous utilisons la méthode getValueElementType(). Là encore, notre attribut sera de type select.

Pour les attributs de type select, il faut fournir la liste des valeurs possibles. getValueSelectOptions() est la méthode qui nous permet de définir cette liste.

Enfin, nous surchargeons la méthode validate() pour indiquer quel est l’objet qui sera soumis à la validation. Ce point mérite une petite explication. Vous pouvez voir que cette méthode reçoit un objet en paramètre. Cet objet peut en fait être soit une instance de Mage_Sales_Model_Quote_Item ou Mage_Sales_Model_Quote_Address. Que l’objet que nous recevons soit un item ou une adresse, nous disposons dans tous les cas de la méthode getQuote() pour récupérer le panier concerné. Nous passons finalement cet objet à la classe parent qui va effectuer les tests nécessaires pour valider la condition courante.

Déclarer notre nouvelle condition

Notre nouvelle classe de condition est prête à être utilisée mais elle n’est pas encore visible dans l’interface. Il nous faut d’abord réécrire la classe Mage_SalesRule_Model_Rule_Condition_Combine pour ajouter le support de la nouvelle classe. Nous appellerons cette nouvelle classe My_SalesRule_Model_Rule_Condition_Combine.

<?php
class My_SalesRule_Model_Rule_Condition_Combine
    extends Mage_SalesRule_Model_Rule_Condition_Combine
{
    /**
     * Liste des conditions disponibles
     *
     * @return array
     */
    public function getNewChildSelectOptions()
    {
        $addressCondition = Mage::getModel('salesrule/rule_condition_address');
        $addressAttributes = $addressCondition->loadAttributeOptions()->getAttributeOption();
        $attributes = array();
        foreach ($addressAttributes as $code => $label) {
            $attributes[] = array('value' => 'salesrule/rule_condition_address|' . $code, 'label' => $label);
        }

        $quoteCondition = Mage::getModel('salesrule/rule_condition_quote');
        $quoteAttributes = $quoteCondition->loadAttributeOptions()->getAttributeOption();
        $formattedQuoteAttributes = array();
        foreach ($quoteAttributes as $code => $label) {
            $formattedQuoteAttributes[] = array(
                'value' => 'salesrule/rule_condition_quote|' . $code,
                'label' => $label
            );
        }

        $conditions = Mage_Rule_Model_Condition_Combine::getNewChildSelectOptions();
        $conditions = array_merge_recursive($conditions, array(
            array(
                'value' => 'salesrule/rule_condition_product_found',
                'label' => Mage::helper('salesrule')->__('Product attribute combination')
            ),
            array(
                'value' => 'salesrule/rule_condition_product_subselect',
                'label' => Mage::helper('salesrule')->__('Products subselection')
            ),
            array(
                'value' => 'salesrule/rule_condition_combine',
                'label' => Mage::helper('salesrule')->__('Conditions combination')),
            array(
                'label' => Mage::helper('salesrule')->__('Cart Attribute'),
                'value' => $attributes
            ),
            array(
                'label' => 'Attribut panier personnalisé',
                'value' => $formattedQuoteAttributes)
        ));

        $additional = new Varien_Object();
        Mage::dispatchEvent('salesrule_rule_condition_combine', array('additional' => $additional));
        if ($additionalConditions = $additional->getConditions()) {
            $conditions = array_merge_recursive($conditions, $additionalConditions);
        }

        return $conditions;
    }
}

En surchargeant la méthode getNewChildSelectOptions(), nous ajoutons notre nouvelle classe à la liste des conditions disponibles. Et voilà, notre nouvelle condition apparaît dans le listing et nous permet de sélectionner un nouvel attribut personnalisé.

<p><strong>liste_proprietes_modifiees.jpg</strong></p>
<p>

<p><strong>regle.png</strong></p>
<p>

Le mot de la fin

Nous avons vu comment étendre la fonctionnalité de règle de prix panier de Magento pour gérer des attributs personnalisés. Vous pouvez aller plus loin en explorant d’autres types de valeurs. Vous en apprendrez plus en explorant la classe Mage_Rule_Model_Condition_Abstract, notamment la manière dont sont gérées les comparaisons en fonction du type de valeur rencontrée. Cela peut vous être utile si vous avez un jour besoin d’aller au-delà du fonctionnement natif des règles de prix.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.