Juil 20, 2018 Prestashop

Un module mandat administratif pour Prestashop


Edit au 05/12/2019

La législation a changé et désormais les factures, lorsqu’il y a commande par mandat administratif, doivent comporter le numéro de cette commande. De base Prestashop ne propose pas ça. Du coup ce module perd beaucoup de son utilité. Si quelqu’un s’est lancé dans la modification pour corriger ça je suis preneur.


J’utilise Prestashop pour gérer une boutique en ligne. Je le trouve complet et performant malgré quelques soucis agaçants qui ne font pas l’objet de cet article.

Je n’avais jamais trop plongé dans le code sauf pour quelques réglages discrets mais comme je crée une nouvelle version de ma boutique avec la version 1.7 (la migration de la version 1.6 vers la version 1.7 est une aventure que j’ai abandonnée…) je remets tout à plat et j’ai besoin d’un module pour le paiement par mandat administratif.

En fouillant un peu sur la toile j’ai trouvé ce module en vente. Il a l’air plutôt bien conçu et pas trop cher. Toutefois au niveau fonctionnalité je n’ai pas envie de générer un PDF tout prêt comme bon de commande parce que les administrations ont déjà leurs modèles et habitudes. Je préfère leur expédier un email avec tous les renseignements nécessaires.

Alors j’ai plongé dans la documentation développeurs et plus précisément dans le chapitre concernant la création d’un module. Bon évidemment tout est en anglais mais je m’y suis habitué depuis des années de codage, par contre il y a de fortes lacunes qui obligent à aller fouiller le code pour comprendre le fonctionnement de certaines fonctionnalités…

J’ai aussi trouvé intéressant mais incomplet cet article.

Dans cet article je vais décrire mes pérégrinations pour développer ce module. Il en est arrivé maintenant à un stade mature et je n’aurai plus de grosses modifications à lui apporter. je tiens à préciser que je le livre comme un exemple de réalisation sans aucune garantie pour ceux qui l’utiliseraient en production. Mon expertise en développement Prestashop n’est pas suffisant pour donner ce genre de garantie. Je suis d’ailleurs preneur de toute proposition de correction ou évolution. Le module est disponible ici en téléchargement.

Je ne vais pas tout détailler dans cet article mais me pencher sur les éléments qui ne font pas l’objet d’une description dans la documentation et que j’ai découverts au fil de mes recherches.

Il existe un outil en ligne pour créer l’architecture de base d’un module mais il ne m’a paru pas trop à jour…

d’autre par on dispose aussi d’un outil de validation mais de mon expérience il a pas mal de bugs pour la version 1.7.

Installation et utilisation

L’installation se fait par l’outil de Prestashop :

Il suffit de sélectionner l’archive et c’est parti !

On doit normalement trouver le module dans la liste :

Le module alerte par notification si la configuration n’est pas faite complètement :

Lorsque le module est activé on retrouve la possibilité de paiement pour l’acheteur :

Lorsque l’achat est validé on donne quelques informations :

Un email supplémentaire est généré avec les précisions nécessaires :

Il est probable qu’il y aura des changements dans les textes mais globalement ça restera comme ça.

Organisation du code

Il y a un dossier modules qui rassemble l’ensemble des modules de Prestashop. lorsqu’on installe le module il vient se placer dans ce dossier :

Les sous-dossiers sont :

  • controllers : pour les contrôleurs
  • transalations : pour les traductions parce que les textes de base doivent être en anglais et on doit générer les traductions pour les autres langues
  • upgrade : pour les mises à jour
  • views : pour les templates des vues de l’administration et pour le client

A la racine on trouve les fichiers de configuration (config…) qui détaillent le nom, l’objet, la version, l’auteur…

On trouve aussi le principal fichier du module mandatadministratif.php qui doit avoir le même nom que le module.

On trouve aussi le logo et un fichier de renseignements.

La configuration

Un aspect fondamental pour un module est sa configuration. Toutes les valeurs de la configuration se trouvent dans la table ps_configuration. C’est à l’installation du module qu’il faut prévoir le code pour créer les lignes nécessaires pour le module. Dans le fichier mandatadministratif.php on trouve une fonction install qui comporte en particulier ce code :

if (!Configuration::updateValue ('MANDATADMINISTRATIF_COMPANY_NAME', '')
    || !Configuration::updateValue ('MANDATADMINISTRATIF_COMPANY_ADDRESS', '')
    || !Configuration::updateValue ('MANDATADMINISTRATIF_ACCOUNT_OWNER', '')
    || !Configuration::updateValue ('MANDATADMINISTRATIF_ACCOUNT_DETAILS', '')
    || !Configuration::updateValue ('MANDATADMINISTRATIF_ACCOUNT_ADDRESS', '')
) {
    return false;
}

C’est là que les entrées sont créées dans la table (sauf celle pour l’état qu’on va ajouter qu’on verra plus loin).

Prestashop sait que le module a des valeurs de configuration si on crée une fonction getContent :

public function getContent()
{
    $output = $this->context->smarty->fetch ($this->local_path . 'views/templates/admin/infos.tpl');

    $this->html .= $output;

    if (Tools::isSubmit ('submitMandatadministratifModule')) {
        $this->postValidation ();
        if (!empty($this->postError)) {
            $this->html .= $this->displayError ($this->postError);
            $this->html .= $this->renderForm ();
        }
        $this->html .= $this->displayConfirmation ($this->trans ('Settings updated', array(), 'Admin.Global'));
    } else {
        $this->html .= '<br />';
    }

    $this->html .= $this->renderForm ();

    return $this->html;
}

Ici on trouve une ligne chargée de la génération du formulaire :

$this->html .= $this->renderForm ();

Et aussi le code pour traiter la soumission du formulaires :

if (Tools::isSubmit ('submitMandatadministratifModule')) {
    $this->postValidation ();
    if (!empty($this->postError)) {
        $this->html .= $this->displayError ($this->postError);
        $this->html .= $this->renderForm ();
    }
    $this->html .= $this->displayConfirmation ($this->trans ('Settings updated', array(), 'Admin.Global'));
} else {
    $this->html .= '<br />';
}

Je ne vais pas entrer dans le détail du code parce que ça serait un peu laborieux…

La seule validation que j’ai prévue est de rendre les champs obligatoires :

Configuration::updateValue ('MANDATADMINISTRATIF_COMPANY_NAME', Tools::getValue ('MANDATADMINISTRATIF_COMPANY_NAME'));
if (!Tools::getValue ('MANDATADMINISTRATIF_COMPANY_NAME')) {
    $this->postError = $this->l ('Company name is required.');
    return;
}

Les erreurs sont générées par ce code :

$this->html .= $this->displayError ($this->postError);

Les hooks

Dans Prestashop on peut pratiquement tout faire en utilisant des hooks. Ce sont en fait des événements disponibles. Pour mon module de paiement j’ai besoin d’enregistrer deux hooks :

public function install()
{
    ...

    // Registration hooks
    if (!$this->registerHook ('paymentReturn')
        || !$this->registerHook ('paymentOptions')) {
        return false;
    }

    ...
}

payementReturn

Ce hook permet d’intervenir après le paiement :

public function hookPaymentReturn($params)
{
    if (!$this->active) {
        return;
    }

    $this->smarty->assign ([
        'total_to_pay' => Tools::displayPrice (
            $params['order']->getOrdersTotalPaid (),
            new Currency($params['order']->id_currency),
            false
        ),
        'shop_name' => $this->context->shop->name,
        'id_order' => $params['order']->id,
        'company_name' => Configuration::get ('MANDATADMINISTRATIF_COMPANY_NAME'),
        'company_address' => Configuration::get ('MANDATADMINISTRATIF_COMPANY_ADDRESS')
    ]);
    if (isset($params['order']->reference) && !empty($params['order']->reference)) {
        $this->smarty->assign ('reference', $params['order']->reference);
    }

    return $this->fetch ('module:mandatadministratif/views/templates/hook/payment_return.tpl');
}

En gros c’est pour afficher ça après la validation:

Avec ce template (views/templates/hook/payment_return.tpl) :

<p>{l s='You have chosen to pay by administrative mandate. This type of payment is reserved for administrations.' mod='mandatadministratif'}</p>
<p>{l s='Send us your purchase order with mention "good for agreement".' mod='mandatadministratif'}</p>
<hr>
<p>{l s='Your order will be processed upon receipt...' mod='mandatadministratif'}
<hr>
<p>{l s='You must send this document to :' mod='mandatadministratif'}</p>
<p>{$company_name}</p>
<p>{$company_address}</p>

paymentOptions

Un hook très riche très bien détaillé dans cet article.

public function hookPaymentOptions($params)
{
    ...

    $newOption = new PaymentOption();
    $newOption->setModuleName ($this->name)
        ->setCallToActionText ($this->l ('Pay by administrative mandat'))
        ->setAction ($this->context->link->getModuleLink ($this->name, 'validation', array(), true))
        ->setAdditionalInformation ($this->fetch ('module:mandatadministratif/views/templates/hook/displayPayment.tpl'));

    return [$newOption];
}

Ici on peut définir le texte, l’action, le template concerné…

En gros pour afficher ça :

L’état de commande

Pour créer un état de commande la documentation est… inexistante. Il m’a donc fallu un peu chercher…

Les état dans la base de données sont dans la table ps_order_states. Il faut donc créer une entrée à l’installation du module. c’est l’objet de la fonction installOrderState :

public function installOrderState()
{
    if (!Configuration::get ('MANDATADMINISTRATIF_WAITING')
        || !Validate::isLoadedObject (new OrderState(Configuration::get ('MANDATADMINISTRATIF_WAITING')))) {
        $order_state = new OrderState();
        $order_state->name = array();
        foreach (Language::getLanguages () as $language) {
            if (Tools::strtolower ($language['iso_code']) == 'fr') {
                $order_state->name[$language['id_lang']] = 'En attente de bon de commande';
            } else {
                $order_state->name[$language['id_lang']] = 'Waiting for command form';
            }
        }
        $order_state->module_name = 'mandatadministratif';
        $order_state->send_email = true;
        $order_state->template = 'mandat';
        $order_state->color = '#4169E1';
        $order_state->hidden = false;
        $order_state->delivery = false;
        $order_state->logable = false;
        $order_state->invoice = false;
        if ($order_state->add ()) {
            $source = _PS_MODULE_DIR_ . 'mandatadministratif/views/img/os_mandat.gif';
            $destination = _PS_ROOT_DIR_ . '/img/os/' . (int)$order_state->id . '.gif';
            copy ($source, $destination);
        }
        Configuration::updateValue ('MANDATADMINISTRATIF_WAITING', (int)$order_state->id);
    }
    return true;
}

Ici on crée une nouvelle entrée de configuration (MANDATADMINISTRATIF_WAITING).

On crée le nouvel état avec tous ses paramètres, principalement :

  • le nom du module
  • si on doit envoyer un email (ici oui)
  • le nom du template pour l’email
  • la couleur de l’état

D’autre part pour l’icône on doit la copier dans le dossier /img/os avec comme nom l’id de l’état. Voilà le genre de chose que j’aurais bien aimé trouver dans la documentation !!!

Du coup on a bien l’état qui apparaît dans la liste des commandes :

Et dans la commande elle-même :

J’ai un peu galéré pour faire fonctionner le bouton de renvoi de l’email 🙂

Pour cet email lors de l’installation on copie les fichiers dans le dossier des emails de Prestashop :

$source = _PS_MODULE_DIR_ . 'mandatadministratif/mandat.html';
$destination = _PS_ROOT_DIR_ . '/mails/fr/mandat.html';
copy ($source, $destination);
$source = _PS_MODULE_DIR_ . 'mandatadministratif/mandat.txt';
$destination = _PS_ROOT_DIR_ . '/mails/fr/mandat.txt';
copy ($source, $destination);

Je n’ai prévu que la version française parce que le module est limité à ce pays.

Les valeurs pour les paramètres de cet emails sont renseignés à la construction de la classe Mandatadministratif :

$this->extra_mail_vars = [
    '{account_owner}' => $this->acount_owner,
    '{company_name}' => $this->company_name,
    '{account_details}' => str_replace ("\n", '<br />', $this->acount_details),
    '{account_address}' => str_replace ("\n", '<br />', $this->acount_address),
    '{company_address}' => str_replace ("\n", '<br />', $this->company_address)
];

Mais également dans le contrôleur (fonction postProcess).

Conclusion

Cet article est un peu rapide et ne rentre pas dans les détails mais il illustre les points fondamentaux. Vous disposez en téléchargement du module complet que vous pouvez télécharger, installer, tester, modifier. Je suis ouvert à toute suggestion, critique, correction, évolution, parce que c’est vraiment tout nouveau pour moi et j’ai certainement dû commettre quelques erreurs dans le code.

8 Comments

Laisser un commentaire