Commandes

Le plugin « commandes » permet de gérer des commandes.

Attention Le plugin ne s’occupe pas de la gestion des paniers, ni des paiements, ni des factures. Pour l’aspect « boutique », voir le post-scriptum.

Ce plugin a été élaboré grâce aux contributions de Matthieu Marcillaud, Rastapopoulos, Yffic, Touti, Cyril, et du rédacteur de cet article.

Principe

Le plugin agit sur 2 fronts :
→ d’une part il permet aux utilisateurs de gérer les commandes depuis l’espace privé.
→ d’autre part, il fournit les outils permettants et aux développeurs et aux autres plugins de créer et manipuler des commandes.

Installation et dépendances

Le plugin est repertorié dans le dépôt proposé par défaut : « SPIP-Zone - Plugins ». Aussi, il est installable depuis la page Gestion des plugins, onglet Ajouter des plugins si vous avez activé ce dépôt.

2 dépendances seront installées automatiquement :

  • Saisies
  • API prix : permet de calculer les prix HT et TTC des commandes et de leurs détails.

D’autres plugins sont plus ou moins optionnels, là c’est à vous de voir :

  • Notifications avancées : à installer si on veut bénéficier de l’envoi de notifications par email.
  • Facteur : sans lui, les notifications seront au format texte au lieu d’un joli HTML.
  • Coordonnées : fortement recommandé afin de pouvoir gérer les adresses liées aux commandes (livraison et facturation).
  • Contacts et organisations : peut vous servir à gérer les auteurs/clients des commandes.

Fonctionnement

A l’installation, 2 tables sont créées :

  • La table principale spip_commandes sert à enregistrer les données de base des commandes : l’auteur/client, le numéro de référence, le statut et les dates.
  • La table auxiliaire spip_commandes_details sert à enregistrer les « détails » correspondants aux commandes, c’est à dire tous les éléments à partir desquels on va pouvoir calculer le prix total d’une commande : objets et services commandés, frais annexes, ristournes etc.

En théorie, à chaque commande enregistrée dans la table spip_commandes doit correspondre une ou plusieurs lignes de détails dans la table spip_commandes_details.

La table spip_commandes :
Une commande est un objet éditorial, au même titre que les articles, brèves et cie. Elles ont un auteur (le client), différents statuts et 3 types de dates : date de création, date de paiement & date d’envoi.
La date de création correspond au champ « date », elle est définie à la création de la commande, et n’est pas censée être altérée par la suite.
Le changement d’un statut peut déclencher l’envoi de notifications par email, et la mise à jour de la date s’y rapportant :
→ passer le statut à "payée" met à jour la date de paiement.
→ passer le statut à "envoyée" met à jour la date d’envoi.

composition de la table spip_commandes
id_commande Identifiant unique de la commande
reference Numéro de référence (il ne s’agit pas d’une clé unique).
id_auteur Identifiant de l’auteur/client
statut encours, attente, partiel, paye, envoye, retour_partiel, retour, erreur
date Date de création
date_paiement Date de paiement
date_envoi Date d’envoi
maj Date de la dernière mise à jour

La table spip_commandes_details :
Pour le contenu des commandes, on parle de « détails » : chaque commande est constituée d’une ou plusieurs lignes de détails.
Un détail est tout élément qui participe au prix d’une commande.
On peut distinguer 2 types de détails :

  • Les détails correspondants directement aux objets ou aux services commandés.
  • Les détails « annexes » : il peut s’agir des frais de port, des frais de dossier, des ristournes etc.

Une ligne de détail comprend à minima les champs descriptif et prix_unitaire_ht, le cas échéant complétés par les champs taxe et quantite.
Dans le cas où l’objet commandé est un objet éditorial SPIP, des champs objet et id_objet permettent de l’identifier.

composition de la table spip_commandes_details
id_commandes_detail Identifiant unique du détail (attention au « s » à commandes)
id_commande Identifiant de la commande concernée
descriptif Texte décrivant le détail. S’il s’agit d’un objet éditorial, il peut s’agir de son titre, descriptif ou autre.
quantite Quantité
prix_unitaire_ht Prix Hors Taxe
taxe Taxe (TVA)
statut Statut
objet Type d’objet s’il s’agit d’un objet éditorial
id_objet Identifiant de l’objet s’il s’agit d’un objet éditorial
maj Date de la dernière mise à jour

Exemple des enregistrements en base pour une commande et ses détails

Prenons une commande de 2 objets avec TVA à 20%, comportant des frais de port et une ristourne. Dans la base de donnée, ça nous donne ceci :

1 ligne dans la table spip_commandes

id_commande reference id_auteur statut date date_paiement date_envoi maj
1 xxxxxx 1 encours 2014-05-14 09:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 2014-05-14 09:00:00

4 lignes dans la table spip_commandes_details

id_commandes

_detail

id_commande descriptif quantite prix

_unitaire_ht

taxe statut objet id_objet maj
1 1 Gibolin 2000 2 8 0.2 produit 1 2014-05-14 09:00:00
2 1 Ripolin 5000 1 12 0.2 produit 2 2014-05-14 09:00:00
3 1 Frais de port 0 4 0 2014-05-14 09:00:00
4 1 Ristourne 0 -2 0 2014-05-14 09:00:00

Boucles et balises

Balises #PRIX et #PRIX_HT

Grâce au plugin API prix, les balises #PRIX et #PRIX_HT permettent d’obtenir automagiquement les prix TTC et HT d’une commande ou d’un de ses détails.

Dans une boucle COMMANDES :

  • #PRIX = somme des prix TTC des détails.
  • #PRIX_HT = somme des prix HT des détails.

Dans une boucle COMMANDES_DETAILS :

  • #PRIX = #QUANTITE * (#PRIX_UNITAIRE_HT + (#TAXE * #PRIX_UNITAIRE_HT))
  • #PRIX_HT = #QUANTITE * #PRIX_UNITAIRE_HT.

Boucles

Exemple minimal de boucle affichant pour chaque commande un résumé de ses détails et son prix total TTC :

<BOUCLE_commandes(COMMANDES)>
<h4>Commande N°#ID_COMMANDE</h4>
<ul><BOUCLE_details(COMMANDES_DETAILS){id_commande}>
<li>[(#QUANTITE) *]#DESCRIPTIF = #PRIX</li>
</BOUCLE_details></ul>
Prix total TTC : #PRIX
</BOUCLE_commandes>

Gestion dans l’espace privé

Configuration
La page de configuration est accessible depuis le menu Configuration > Commandes
On peut y gérer les 3 points suivants :

  • La durée d’expiration des commandes ayant le statut « en cours ». On considère que les commandes restant « en cours » pendant plus d’un certain temps sont des commandes abandonnées : il est inutile de les conserver dans la base.
  • l’activation et le fonctionnement des notifications (cf. plus bas).
  • L’affichage en page d’accueil de la liste des commandes « actives » (cf. plus bas).

Liste des commandes
Une page Commandes est accessible depuis le menu Edition.
L’encart à gauche sert à filtrer les commandes en fonction de leurs états, de leurs dates de création, et des auteurs/clients.
Au niveau de la liste, les commandes ayant le statut « envoyé » sont surlignées en vert, afin de repérer facilement les commandes terminées.
Page de gestion des commandes

Fiche d’une commande
La fiche d’une commande est composé de 3 parties :

  • Le contenu de la commande : il s’agit d’un tableau listant les détails de la commande.
  • Les adresses : si le plugin Coordonnées est installé, sont affichées les adresses associées à la commande, ou à défaut celles associées à l’auteur de la commande.
  • L’auteur/client de la commande : si le plugin Contacts et Organisations est installé, on affiche les infos du contact, sinon des infos sur le client.

A noter : Pour les adresses, il n’est pas nécessaire d’activer l’ajout de coordonnées aux commandes dans les options du plugin Coordonnées.
Fiche d'une commande

Commandes « actives »
Il est possible d’afficher en page d’accueil la liste des commandes « actives ». il s’agit des commandes nécessitant une prise en charge. Pour se faire, il faut activer l’option dans la configuration du plugin, et choisir les statuts correspondants.

Commandes « actives » en page d’accueil

Notifications

Mise en place
On peut activer ’envoi d’emails de notification au vendeur et au client lorsque les commandes acquièrent certains statuts.
Le plugin « Notifications avancées » doît être installé. Le plugin Facteur est également fortement recommandé afin d’envoyer les messages au format HTML.
Rendez vous ensuite sur le formulaire de configuration du plugin pour activer et configurer les notifications.

Personnalisation des emails
Par défaut, les messages envoyés sont spartiates :

Email par défaut envoyé au client

Leurs squelettes sont présents dans le répertoire /notifications du plugin.
Pour chaque type de notification (vendeur & client), il y a 3 variantes :

  • commande_xxx_html.html au format HTML.
  • commande_xxx.html au format texte brut.
  • commande_xxx_court.html au format court, type microblog ou SMS.

Par commodité, ces 6 squelettes incluent tous le même squelette mutualisé, avec différents paramètres pour moduler l’affichage : contenu_commande_mail.html.
Il suffit de surcharger ce squelette pour le personnaliser selon vos besoins.

Si vous avez besoin de 2 squelettes vraiment différents pour les emails vendeur et client, vous pouvez au choix :

  • Faire ça au niveau du squelette contenu_commande_mail.html en jouant sur le paramètre #ENV{qui} :
    [(#ENV{qui}|=={client}|oui)<INCLURE{fond=mon_squelette_mail_client, env}>][(#ENV{qui}|=={vendeur}|oui)<INCLURE{fond=mon_squelette_mail_vendeur, env}>]
  • Ou bien surcharger directement les 6 squelettes clients et vendeurs.

Fonctions utiles

Voici une liste non exhaustive de certaines fonctions, celles qui pourront vous être utiles lors de l’intégration du plugin dans votre projet. Pour les détails (paramètres etc.) et la liste complète, voir le site https://plugins.code.magraine.net/commandes/.

commandes_fonctions.php
commandes_lister_statuts
Cette fonction retourne les différents statuts des commandes. On peut s’en servir comme filtre dans les squelettes pour obtenir la chaîne de langue d’un statut : [(#STATUT|commandes_lister_statut)]
inc/commandes.php
creer_commande_encours
Crée une commande avec le statut « en cours » pour le visiteur actuel. La commande créée est « vide » : la fonction ne se charge pas de créer les détails. C’est le rôle des plugins tiers (Commandes de paniers par ex.).

A noter : on considère qu’il ne peut y avoir qu’une commande « en cours » par session et par auteur. Si une telle commande est déjà présente dans la session, elle va être supprimée de la base et de la session avant la création de la nouvelle.

Exemple :

$creer_commande = charger_fonction('creer_commande_encours', 'inc/');
$id_commande = $creer_commande;
commandes_supprimer
Permet de supprimer « proprement » une ou plusieurs commandes, en s’occupant également des données associées. Pour chaque commande à supprimer, la fonction effectue les actions suivantes :
-  suppression de la commande
-  suppression de ses détails
-  dissociation de ses adresses liées, et éventuellement suppression si elles se retrouvent orphelines.

Exemple :
$ids_commandes = array(1,2,3);
$supprimer_commandes = charger_fonction('commandes_supprimer', 'inc/');
$supprimer_commandes($ids_commandes);
traiter_notifications_commande
Envoie les notifications par email d’une commande, si les conditions sont réunies. Cette fonction est appelée lors de la création d’une commande, puis à chaque changement de statut.
inc/commandes_reference.php
inc_commandes_reference_dist
Cette fonction retourne une référence unique utilisée pour remplir le champ éponyme lors de la création d’une commande. Il s’agit du temps écoulé depuis le 1er janvier 1970, en secondes.
Elle est destinée à être surchargée pour l’adapter à vos besoins.
action/xxx.php
supprimer_commande
Supprime « proprement » une commande. Fait appel à la fonction commandes_effacer, avec les mêmes effets donc.

Exemple :
#URL_ACTION_AUTEUR{supprimer_commande,#ID_COMMANDE,#SELF}
instituer_commande
Change le statut d’une commandes

Exemple :
#URL_ACTION_AUTEUR{instituer_commande,#ID_COMMANDE-envoye,#SELF}

Pour aller plus loin : « Commandes » au sein du framework e-commerce

Ce plugin fait partie d’un framework dédié au e-commerce, il s’interface notamment avec les plugins suivants :

Il n’y a pas encore de documentation qui traite du framework dans son ensemble, on notera cependant les 2 plugins suivants :

  • Tuto commerce » : tutoriel des briques minimales à mettre en place pour une boutique en ligne.
  • Zcommerce : charger les plugins nécessaires à la création d’une boutique en ligne

Pour un aperçu général de tous les outils destinés au e-commerce, voir l’article Inventaire des outils SPIP pour du e-commerce

Dernière modification de cette page le 17 mars 2019

Discussion

29 discussions

  • Renée Picard

    Depuis peu le site mangersaison.com ne gère plus les commandes et je ne comprends pas pourquoi ?
    plugin commande 1.4.9
    sur planet hoster

    J’ai beau faire des tests je reçois des courriels (clients et vendeurs) à 0
    Copier-coller d’un courriel client


    Bonjour Renée Picard

    Nous avons bien enregistré votre commande et nous vous remercions de votre confiance.

    Récapitulatif de commande :

    Commande 1431626474

    Date : 2015-05-14 14:01:14

    Cette commande est : En cours

    Détails de commande :

    Désignation Montant
    Total 0
    http://www.mangersaison.com


    C’est la même chose coté courriel-vendeur et sur le site en privé dans activités/commandes le message est une commande vide.
    Pourtant sur le site, à la page http://www.mangersaison.com/spip.php?page=commande_terminee&lang=fr
    j’ai bien les items commandés.

    Je suis allé voir la BD et je vois que commande prend en compte un seul item. Si je retourne sur le site et en ajoute un autre, je retourne dans la bd et il y a seulement le dernier ajout
    Toujours sur la bd, spip_commandes_details est vide

    Répondre à ce message

  • Renée Picard

    Avec le plugin 1.4.9 les courriels-notifications (client et vendeur) n’ont pas de description des produits achetés ni de prix.
    Je n’ai pas touché aux fichiers de notification du plugin et j’ai facteur 3.0.20 et notifications avancés 0.2.1
    Voir mangersaison.com il y a un produit pour le test
    http://www.mangersaison.com/Pour-tester-le-processus-d-achat

    Répondre à ce message

  • 3

    Bonjour et merci pour cette doc,
    j’envisage de mettre en place une boutique de vente de tirages photo. Une unique photo sera proposée en plusieurs formats. Et chaque format aura un prix différent.
    Ma question est de savoir comment structurer l’arborescence de départ ? J’ai dans l’idée qu’il faut une rubrique pour chaque image et un article pour chaque format/prix ? C’est un peu lourd, mais c’est ce que j’ai compris en lisant la doc ici et sur la page du carnet wiki.
    Donc, en résumé, une rubrique/image et un article/format/prix (et x articles pour décliner format/prix) ? Pouvez-vous me confirmer que c’est la méthode qui s’applique dans mon cas ?
    Merci d’avance,
    Rémy

    P.S. Dans un second temps, j’aimerais proposer en plus non pas des tirages mais l’achat direct de fichiers numériques. Est-ce-que ce plugin pourra répondre à ce besoin ?

    • Bonjour,
      Techniquement, l’arborescence n’a pas d’impact direct sur la gestion des commandes, utilisez celle qui vous semble la plus intuitive et la plus simple. Une rubrique par photo et un article par format, ça me semble ok.

      La seule chose qui importe, c’est que techniquement, la commande soit objet éditorial SPIP : ça peut être un article, mais aussi une rubrique, voir une brève, etc.
      Après, dans l’idéal, je pense qu’il vaut mieux utiliser autre chose que les articles pour faire de la vente.

      Il y a bien le plugin « produits » qui ajoute justement un objet « produit » avec tous les champs qu’il faut : prix, taxe etc. Mais la version pour SPIP 3 n’est pas encore fonctionnelle, et il ne prend pas en compte la notion de « déclinaison », or c’est ce dont vous auriez besoin pour gérer les différents formats.

      En ce qui concerne l’achat de fichiers numériques, oui c’est possible, mais il faut mettre en place un système de téléchargement des fichiers, les protéger et tout ça.
      Mais là on sort du domaine du plugin Commandes : la mise en place d’une boutique fera l’objet d’un article à part, il s’agit d’une question assez vaste.
      Pour rappel, le plugin Commandes est juste une des briques nécessaires pour faire de la vente en ligne.

    • Merci pour votre réponse rapide et claire.
      En effet la vente de fichiers numériques nécessite de sécuriser l’accès aux fichiers, etc. Dans un premier temps, si j’arrive à mettre en place la vente de tirages ce sera déjà très bien.
      Bonne journée,
      Rémy

    • Le top du top, ce serait de pouvoir lier le plugin declinaison produit avec le plugin commande.

      Je sais, c’est beaucoup demander...
      Mais je suis sûr qu’un jour, ce sera possible !

    Répondre à ce message

  • 1
    Renée Picard

    Ce plugin va-t-il être compatible SPIP 3.1

    • Il l’est peut-être déjà, il n’y a pas vraiment de différence majeure. Il faut le tester en changeant la borne supérieure dans le XML, en utilisant ses fonctionnalités, et si c’est bon, le dire soit ici soit sur la liste spip-zone (ou demander un compte pour le SVN et modifier directement :D).

    Répondre à ce message

  • 1

    Bonjour,
    J’utilise ce plugin, et j’arrive sur la page « commande_terminee » avec tous les produits choisis dans le panier et leur prix respectif.....ma question est la suivant si je veux le règlement se face par paypal qu’est ce qu’il faut faire ? j’ai déja installé les plugins paypal et « commande payées avec payppal »
    Mais je ne sais pas qu’est ce qu’il faut intégré et ou ? pour pouvoir régler par paypal avec le recap du panier et les prix. Merci de votre aide

    Répondre à ce message

  • 3

    Bonjour,

    Je cherche à utiliser le plugin « Abonnements 2 » qui semble très prometteur mais très peu documenté, je n’ai pas trouvé le moyen de le coupler à un système de paiement sécurisé, faut-il passer par un plugin de gestion de commandes comme celui ci ?

    Si quelqu’un a un peu de doc pour moi pour Abonnements, je suis preneur !

    Merci :)

    Freed

    Répondre à ce message

  • 2
    Renée Picard

    Lorsque je fais la mise à jour du plugin de 1.2.6 à 1.4.8 j’obtiens une page blanche sur http://www.mangersaison.com/mang/ecrire

    J’ai jeté les plugins commandes_panier et quantimandes et j’ai quand même une page blanche sur /ecrire

    Je suis donc revenu à la 1.2.6 avec commandes_panier 0.15 et le plugin spécial quantimandes et le tout fonctionne.

    Je pensais que le « bug » était dû à quantimandes qui nécessite dans paquet.xml
    <necessite nom="commandes" compatibilite="[1.2.0;]" ></necessite> mais ce n’est pas la bonne piste puisque même si le plugin quantimandes est jeté l’activation de commandes 1.4.8 génère toujours une page blanche dans écrire ???? QUE faire pour tenir le tout à jour ???

    • Quand il y a une page blanche, c’est qu’il y a des erreurs PHP. Par défaut ça ne s’affiche pas, il faut ajouter des directives (dans config/mes_options.php par exemple) pour que ça s’affiche. Une fois les erreurs affichées, on sait déjà mieux de quoi il retourne.

      Pour info cette semaine le plugin Commandes a eu une mise à jour notoire qui transforme les détails de commandes en vrai objet SPIP, et qui permet de les modifier manuellement (ainsi que d’en ajouter à la main).

      Mais du coup le plugin « Commandes de Paniers » (panier2commande) n’était plus raccord. Tcharlss a corrigé ça hier !

    • Renée Picard

      Merci
      J’ai installé le plugin 1.4.9 et maintenant tout fonctionne à merveille !

    Répondre à ce message

  • 4

    Bonjour,

    Je suis en train de monter un site e-commerce en SPIP, pour mon plus grand plaisir...

    Après la confirmation de la commande, je souhaiterai décrémenter un champ Quantité que j’ai défini avec « Champs Extra ».

    Cela est-il possible ?

    Merci !

    • Bonjour,

      Oui c’est possible, la façon de procéder dépend de plusieurs choses :
      -  déjà, qu’est-ce que vous entendez par « confirmer » la commande : est-ce au moment où le panier est validé ? Ou quand le visiteur choisit des adresses pour la commande ? Ou quand la commande aquiert un statut précis ?
      -  ensuite, comment avez-vous mis en place la partie e-commerce de votre site ? Quels autres plugins sont installés ? Y a-t-il des formulaires persos ?

      Il va très certainement falloir utiliser un pipeline pour compléter les traitements d’un formulaire, mais sans plus de détail, impossible de vous dire lequel et comment.

    • Bonjour,

      Merci pour ce retour.
      Je souhaite décrémenter la quantité lorsque la commande a été payée.

      Le champ Quantité a été ajouté dans Articles avec « Champs Extras ».

      Ensuite, j’utilise les plug-ins Paniers, Commande de paniers et les plug-ins paypal.

    • Une possibilité est se se brancher sur le pipeline « traitement_paypal » du plugin Commandes payées avec Paypal.
      Ce pipeline est utilisé au moment où la notification de paiement (IPN) de Paypal est réceptionnée, donc c’est le plus indiqué.

      L’idéal serait de faire ça dans un petit plugin perso, sinon dans mes_options.php.
      Voilà un exemple de base, à adapter à vos besoins. Attention, j’ai pas testé, il y a peut-être des coquilles qui trainent.

      $GLOBALS['spip_pipeline']['traitement_paypal'] .= "|maj_quantites_commandes";
       
      function maj_quantites_commandes($flux){
       
      // Si on est dans le cas d'un paiement de commande, que la commande est valide, et que le paiement a été fait
      // Dans le formulaire paypal, il faut avoir utilisé les bonnes valeurs pour les 2 paramètres «custom» et «identifiant», sinon ça ne marchera pas, cf. http://contrib.spip.net/Paypal-4519, section «syntaxe avancée»
      // #ARRAY{custom,payer_commande, identifiant,#REFERENCE}
      if (
      	$flux['args']['paypal']['custom'] == 'payer_commande'
      	AND $reference = $flux['args']['paypal']['invoice']
      	AND $id_commande = sql_getfetsel('id_commande', 'spip_commandes', 'reference = '.sql_quote($reference))
      	AND $flux['args']['paypal']['payment_status'] == 'Completed'
      ){
       
      	// retrouver les objets correspondants à la commande dans spip_commandes_details
      	if ($objets = sql_allfetsel('objet,id_objet,quantite', 'spip_commandes_details', 'id_commande='.intval($id_commande))){
       
      		// mettre à jour la quantité de chaque objet
      		include_spip('action/editer_objet');
      		foreach($objets as $v) {
       
      			$objet = $v['objet']; // 'article'
      			$id_table_objet = id_table_objet($objet); // 'id_article'
      			$table_objet = table_objet_sql($objet); // 'spip_articles'
      			$id_objet = intval($v['id_objet']);
      			$quantite = intval($v['quantite']);
       
      			// calculer la nouvelle quantité
      			$quantite_ancienne = intval(sql_getfetsel('quantite', $table_objet, $id_table_objet.'='.$id_objet));
      			$quantite_nouvelle = $quantite_ancienne - 1;
       
      			// mettre à jour la quantité
      			objet_modifier($objet, $id_objet, array('quantite'=>$quantite_nouvelle));
      		}
       
      	}
      }
    • Merci beaucoup !

      Je vais tester çà !

    Répondre à ce message

  • 3
    Renée Picard

    J’ai ajouté avec le plugin champ extra un champ quantite.
    J’ai créé dans plugin un dossier intitulé : editer_commande
    J’y ai mis un fichier nommé plugin.xml

    <plugin>
     <nom>editer_commande</nom>
     <version>0.1</version>
     <prefix>ed_com</prefix>
     <etat>experimental</etat>
     <auteur>R Picard [contact->mailto:rpicardinfo@gmail.com]
    </auteur>
     <description>Gestion des produits </description>
     <pipeline>
                    <nom>editer_commande</nom>
                    <inclure>editer_commande.php</inclure>
            </pipeline>
    
    
    </plugin>

    puis j’ai ajouté un fichier nommé editer_commande.php

    <?php
    /**
     * API d'édition du plugin Commandes
     *
     * @plugin     Commandes
     * @copyright  2014
     * @author     Ateliers CYM, Matthieu Marcillaud, Les Développements Durables
     * @licence    GPL 3
     * @package    SPIP\Commandes\Editer
     */
    
    // Sécurité
    if (!defined("_ECRIRE_INC_VERSION")) return;
    
    /**
     * Point d'entrée d'édition d'une commande
     *
     * On ne peut entrer que par un appel en fournissant `$id_commande`
     * mais pas pas une url
     *
     * @uses commande_inserer()
     * @uses commande_modifier()
     *
     * @param int $id_commande
     *     Identifiant de la commande
     * @return array
     *     Identifiant de la commande et message d'erreur eventuel
     */
    function action_editer_commande_dist($id_commande=null) {
    
            // appel direct depuis une url interdit
            if (is_null($id_commande)){
                    //$securiser_action = charger_fonction('securiser_action', 'inc');
                    //$id_commande = $securiser_action();
                    include_spip('inc/minipres');
                    echo minipres(_T('info_acces_interdit'));
                    die();
            }
    
            // si id_commande n'est pas un nombre, c'est une creation
            if (!$id_commande = intval($id_commande)) {
                    $id_commande = commande_inserer(null,array('id_auteur'=>_request('id_auteur')));
            }
    
            if (!($id_commande = intval($id_commande))>0)
                    return array($id_commande,_L('echec enregistrement en base'));
    
            // Enregistre l'envoi dans la BD
            $err = commande_modifier($id_commande);
    
            return array($id_commande,$err);
    }
    
    
    /**
     * Crée une nouvelle commande et retourne son identifiant
     *
     * Les notifications par email sont traitées après l'insertion en base et l'appel des pipelines
     *
     * @uses traiter_notifications_commande()
     *
     * @pipeline_appel pre_insertion
     * @pipeline_appel post_insertion
     * @param null $id_parent
     *     Paramètre inutilisé, présent pour compatibilité avec api modifier objet
     * @param array $champs
     *     Couples des champs/valeurs par défaut
     * @return int|bool
     *     - Identifiant de la commande si succès
     *     - False en cas d'erreur
     */
     
    function commande_inserer($id_parent=null, $champs=array()) {
            $id_commande = false;
    
            // On insère seulement s'il y a un auteur correct
            if (isset($champs['id_auteur']) and $champs['id_auteur'] = intval($champs['id_auteur'])){
                    // Si id_auteur vaut 0 ou n'est pas defini, ne pas creer de commande et envoyer message impossible
                    if (!$id_auteur = intval($champs['id_auteur'])) {
                            return false; // ? minipress(); ?
                    } 
    
                    // La date de tout de suite
                    $champs['date'] = date('Y-m-d H:i:s');
    
                    // Le statut en cours
                    $champs['statut'] = 'encours';
    
                    // Envoyer aux plugins avant insertion
                    $champs = pipeline('pre_insertion',
                            array(
                                    'args' => array(
                                            'table' => 'spip_commandes',
                                    ),
                                    'data' => $champs
                            )
                    );
    
                    // Insérer l'objet
                    $id_commande = sql_insertq("spip_commandes", $champs);
    
                    // Envoyer aux plugins après insertion
                    pipeline('post_insertion',
                            array(
                                    'args' => array(
                                            'table' => 'spip_commandes',
                                            'id_objet' => $id_commande
                                    ),
                                    'data' => $champs
                            )
                    );
    
                    // Envoi des notifications par email
                    spip_log("inserer_commande : appel des notifications pour la commande $id_commande",'commandes.'._LOG_INFO);
                    include_spip('inc/commandes');
                    traiter_notifications_commande($id_commande);
    
            }
    
            return $id_commande;
    }
    
    /**
     * Appelle les fonctions de modification d'une commande
     *
     * @uses objet_modifier_champs()
     * @uses commande_instituer()
     *
     * @param int $id_commande
     *     Identifiant de la commande
     * @param array|null $set
     *     Couples des champs/valeurs à modifier
     * @return mixed|string $err
     *     Message d'erreur éventuel
     */
    function commande_modifier($id_commande, $set=null) {
            $err = '';
    
            include_spip('inc/saisies');
            $saisies = saisies_chercher_formulaire('editer_commande', array($id_commande));
            $champs = saisies_lister_champs($saisies, false);
    
            include_spip('inc/modifier');
            $c = collecter_requests(
                    // whitelist
                    $champs,
                    // blacklist
                    array('date','statut'),
                    // donnees eventuellement fournies
                    $set
            );
    
            // Si l'objet est publie, invalider les caches et demander sa reindexation
            if (objet_test_si_publie('commande',$id_commande)){
                    $invalideur = "id='id_commande/$id_commande'";
                    $indexation = true;
            }
            else {
                    $invalideur = "";
                    $indexation = false;
            }
    
            if ($err = objet_modifier_champs('commande', $id_commande,
                    array(
                            'nonvide' => array('statut' => _T('info_sans_statut')),
                            'invalideur' => $invalideur,
                            'indexation' => $indexation,
                    ),
                    $c))
                    return $err;
    
            // Modification de statut
            $c = array();
            foreach (array('id_auteur', 'date', 'statut',) as $champ)
                    $c[$champ] = _request($champ, $set);
            $err = commande_instituer($id_commande, $c);
    
            return $err;
    }
    
    /**
     * Instituer une commande
     *
     * Modifie des éléments à part que sont l'auteur, la date, le statut
     *
     * @uses editer_commande_details()
     * @uses traiter_notifications_commande()
     *
     * @pipeline_appel pre_edition
     * @pipeline_appel post_edition
     * @param int $id_commande
     *     Identifiant de la commande
     * @param array $c
     *     Couples champ/valeur à modifier
     * @param bool $calcul_details
     *     (?) Inutilisé
     * @return mixed|string
     */
    function commande_instituer($id_commande, $c, $calcul_details=true){
            include_spip('inc/autoriser');
            include_spip('inc/modifier');
    
            $row = sql_fetsel("statut, date, id_auteur", "spip_commandes", "id_commande=$id_commande");
            $id_auteur = $row['id_auteur'];
            $statut_ancien = $statut = $row['statut'];
            $date_ancienne = $date = $row['date'];
            $champs = array();
    
            $d = isset($c['date']) ? $c['date'] : null;
            $s = isset($c['statut']) ? $c['statut'] : $statut;
    
            // On ne modifie le statut que si c'est autorisé
            if ($s != $statut or ($d AND $d != $date)) {
                    //todo = donner l'autorisation a commandes_paypal_traitement_paypal
                    //if (autoriser('modifier', 'commande', $id_commande))
                            $statut = $champs['statut'] = $s;
                    //else
                    //        spip_log("editer_commande $id_commande refus " . join(' ', $c),'commandes');
    
                    // Si on doit changer la date explicitement
                    if ($d){
                            $champs['date'] = $date = $d;
                    }
            }
    
            $champs['id_auteur'] = $id_auteur;
    
            // Mettre à jour les dates de paiement ou d'envoi pour les statuts correspondants
            if ($statut != $statut_ancien)
                    foreach (array('partiel'=>'paiement', 'paye'=>'paiement', 'envoye'=>'envoi') as $k=>$v)
                            if ($statut == $k)
                                    $champs["date_$v"] = date('Y-m-d H:i:s');
    
            // Envoyer aux plugins avant édition
            $champs = pipeline(
                    'pre_edition',
                    array(
                            'args' => array(
                                    'table' => 'spip_commandes',
                                    'id_objet' => $id_commande,
                                    'action' => 'instituer',
                                    'statut_ancien' => $statut_ancien,
                            ),
                            'data' => $champs
                    )
            );
    
            if (!count($champs)) return;
    
            // Envoyer les modifications et calculer les héritages
            editer_commande_details($id_commande, $champs, $calcul_details);
    
            // Invalider les caches
            include_spip('inc/invalideur');
            suivre_invalideur("id='id_commande/$id_commande'");
    
            if ($date) {
                    $t = strtotime($date);
                    $p = @$GLOBALS['meta']['date_prochain_postdate'];
                    if ($t > time() AND (!$p OR ($t < $p))) {
                            ecrire_meta('date_prochain_postdate', $t);
                    }
            }
    
            spip_log("instituer_commande : flux post_edition pour la commande $id_commande",'commandes.'._LOG_INFO);
    
            // Envoyer aux plugins après édition
            pipeline(
                    'post_edition',
                    array(
                            'args' => array(
                                    'table' => 'spip_commandes',
                                    'id_objet' => $id_commande,
                                    'action' => 'instituer',
                                    'statut_ancien' => $statut_ancien,
                            ),
                            'data' => $champs
                    )
            );
    
            // Envoi des notifications par email
            spip_log("instituer_commande : appel des notifications pour la commande $id_commande",'commandes.'._LOG_INFO);
            include_spip('inc/commandes');
            traiter_notifications_commande($id_commande);
    
            return ''; // pas d'erreur
    }
    
    /**
     * Fabrique la requête d'institution de la commande
     *
     * Modifie la commande en calculant les dépendances des détails
     * 
     * @param int $id_commande
     *     Identifiant de la commande
     * @param array $champs
     *     Couples des champs/valeurs à modifier
     * @param bool $cond
     *     (?) inutilisé
     * @return void
     */
    function editer_commande_details($id_commande, $champs, $cond=true) {
    
            if (!$champs) return;
    
            sql_updateq(table_objet_sql('commande'), $champs, "id_commande=$id_commande");
    
            // Changer le statut des elements concernes ? (voir details)
    
            /*
            if ($cond) {
                    include_spip('inc/rubriques');
                    $postdate = ($GLOBALS['meta']["post_dates"] == "non" and isset($champs['date']) and (strtotime($champs['date']) < time())) ? $champs['date'] : false;
                    calculer_rubriques_if($id_rubrique, $champs, $statut, $postdate);
            }
            */
    }
    
    // Ci dessous, fonctions dépréciées gardées pour rétro-compatibilité
    
    /**
     * Enregistre une modification d'une commande
     *
     * @deprecated Alias de 'commande_modifier' pour rétro-compatibilité
     * @uses commande_modifier()
     *
     * @param int $id_commande
     *     Identifiant de la commande
     * @param array $c
     *     Couples des champs/valeurs modifiées
     * @return mixed|string
     */
    function revision_commande($id_commande, $c=false) {
            return commande_modifier($id_commande, $c);
    }
    
    /**
     * Crée une nouvelle commande
     *
     * @deprecated Alias de 'commande_inserer' pour rétro-compatibilité
     * @uses commande_inserer()
     *
     * @param array $champs
     *     Couples des champs/valeurs par défaut
     * @return
     */
    function commande_insert($champs=array()){
            return commande_inserer(null,$champs);
    }
    
    /**
     * Appelle les fonctions de modification d'une commande
     *
     * @deprecated Alias de 'commande_modifier' pour rétro-compatibilité
     * @uses commande_modifier()
     * 
     * @param int $id_commande
     *     Identifiant de la commande
     * @param array|null $set
     *     Couples des champs/valeurs à modifier
     * @return
     */
    function commande_set($id_commande, $set=null){
            return commande_modifier($id_commande, $set);
    }
    
    /**
     * Modifie des éléments à part que sont l'auteur, la date, le statut
     * 
     * @deprecated Alias de 'commande_instituer' pour rétro-compatibilité
     * @uses commande_instituer()
     * 
     * @param int $id_commande
     *     Identifiant de la commande
     * @param array $c
     *     Couples des champs/valeurs à modifier
     * @param bool $calcul_details
     *     (?) Inutilisé
     * @return
     */
    function instituer_commande($id_commande, $c, $calcul_details=true){
            return commande_instituer($id_commande, $c, $calcul_details);
    }
    // mettre à jour la quantité de chaque objet
                    include_spip('action/editer_objet');
                    foreach($objets as $v) {
     
                            $objet = $v['objet']; // 'article'
                            $id_table_objet = id_table_objet($objet); // 'id_article'
                            $table_objet = table_objet_sql($objet); // 'spip_articles'
                            $id_objet = intval($v['id_objet']);
                            $quantite = intval($v['quantite']);
     
                            // calculer la nouvelle quantité
                            $quantite_ancienne = intval(sql_getfetsel('quantite', $table_objet, $id_table_objet.'='.$id_objet));
                            $quantite_nouvelle = $quantite_ancienne - 1;
     
                            // mettre à jour la quantité
                            objet_modifier($objet, $id_objet, array('quantite'=>$quantite_nouvelle));
                    }
     
            
    }
    
    ?>

    J’ai été coché acheté dans l’interface de commandes en espace privé.

    Cela ne fonctionne pas. Les quantités ne bougent pas.
    Je ne sais pas comment faire pour gérer les quantités une fois que le produit a été coché acheté

    • Bonjour,

      Pour les gens qui aimeraient suivre, le message fait suite à une discussion sur la liste spip users. La question était la suivante :

      Maintenant comment mettre une quantité EX : 50 pots de beurre de pommes et une fois que j’en ai vendu 50 le site dit épuisé ?
      NOTE : Le paiement d’une commande se fera en espèce ou par chèque.

      Je vais vous faire à peu près la même réponse que la pour question précédente : la gestion des quantités n’est pas gérée par le plugin, les options dans l’interface n’auront aucun effet sur ce point. Le mieux, c’est de gérer ça dans un plugin perso adapté à vos besoins, comme vous le faîtes.

      Par contre, c’est très déconseillé de surcharger le fichier editer_commande.php (et puis quelles modifs y apportez vous ? on ne saura pas... ), il vaut mieux passer par un pipeline.

      L’idée de base serait de décrémenter le champ « quantite » des articles d’une commande quand elle acquiert le statut « paye », via le pipeline « post_edition ».

      Donc dans ed_com_pipelines.php (et en déclarant le pipeline dans paquet.xml) :

      // Changer les quantités des objets d'une commande quand elle passe du statut "attente" à "paye"
      function ed_com_post_edition($flux){
       
      	if (
      			$flux['args']['action'] == 'instituer'
      			AND $flux['args']['table'] == 'spip_commandes'
      			AND ($id_commande = intval($flux['args']['id_objet'])) > 0
      			AND ($statut_nouveau = $flux['data']['statut']) == 'paye'
      			AND ($statut_ancien = $flux['args']['statut_ancien']) == 'attente'
      	){
       
      		// retrouver les objets correspondants à la commande dans spip_commandes_details
      		if (
      			$objets = sql_allfetsel('objet,id_objet,quantite', 'spip_commandes_details', 'id_commande='.intval($id_commande))
      			AND is_array($objets)
      			AND count($objets)
      		){
       
      			// mettre à  jour la quantité de chaque objet de la commande
      			include_spip('action/editer_objet');
      			foreach($objets as $v) {
       
      				// récupérer les infos
      				$objet = $v['objet'];                     // 'article'
      				$id_table_objet = id_table_objet($objet); // 'id_article'
      				$table_objet = table_objet_sql($objet);   // 'spip_articles'
      				$id_objet = intval($v['id_objet']);
      				$quantite = intval($v['quantite']);
       
      				// calculer la nouvelle quantité
      				$quantite_ancienne = intval(sql_getfetsel('quantite', $table_objet, $id_table_objet.'='.$id_objet));
      				$quantite_nouvelle = $quantite_ancienne - $quantite;
       
      				// mettre à jour la quantité
      				if ($quantite_nouvelle) > 0 {
      					objet_modifier($objet, $id_objet, array('quantite'=>$quantite_nouvelle));
      				}
      			}
       
      		}
      	}
      }

      Bon, c’est juste un exemple de base, avec un calcul des quantités tout simple.
      C’est à compléter et à adapter à votre situation.

    • Renée Picard

      C’est dommage que ce plugin ne gère pas les stocks car pour le reste il est parfait et ma boutique en développement avec SPIP fonctionne à merveille.

      Je n’ai jamais fait de plugin, je ne connais pas les pipelines. J’ai lu http://programmer.spip.net/Utiliser-les-pipelines puis j’ai découvert que post_edition est déjà dans SPIP http://code.spip.net/autodoc/pipelines/post_edition.html puis j’ai rédigé un paquet http://plugins.spip.net/redaction-du-paquet-xml.html je l’ai validé http://plugins.spip.net/validation/
      J’ai copié le code fourni ci_haut dans un fichier ed_com_pipelines.php que j’ai placé dans le nouveau plugin au même niveau que le paquet. Sur l’article qui affiche le produit j’ai ajouté un champ #QUANTITE en espérant que celui-ci diminuerait après avoir fait des achats.
      Voici le paquet

      <paquet
      prefix="ed_com_post_edition"
       categorie="divers"
       version="1.0.0"
       etat="dev"
       compatibilite="[3.0.0-alpha2;3.0.*]"
       logo="prive/themes/spip/images/compagnon-32.png"
       schema="1.0.0"
       meta="ed_com_post_edition">
      <nom>ed_com_post_edition</nom>
      <auteur> R Picard </auteur>
      <pipeline nom="post_edition"></pipeline>
      <pipeline nom="post_edition" inclure="post_edition/ed_com_pipelines.php" ></pipeline>
      </paquet>

      Il y a sûrement une ou des erreurs car cela ne fonctionne pas.
      Merci de m’aider.

    • C’est normal que ce plugin ne gère pas les quantités, car ça n’a aucun rapport avec « une commande ». Ce plugin ne fait qu’une seule chose, comme tous les plugins de la suite de commerce (Produits ne fait que des listes de produits, Paniers ne gère que les paniers, etc).

      Dans le code au-dessus, je vois au moins à changer « >= 0 » pour le test de mise à jour de la quantité. Car elle peut bien évidemment être à 0. Par ailleurs les parenthèses ne sont pas du tout au bon endroit.

      Il faut au moins remplacer :

      1. if ($quantite_nouvelle) > 0 {

      Par :

      1. if ($quantite_nouvelle >= 0) {

      Mais il y a peut-être d’autres choses, je n’ai lu que rapidement…

    Répondre à ce message

Ajouter un commentaire

Qui êtes-vous ?
  • [Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom