Aller au contenu

Module Commandes fournisseurs

Objectif

Le module Commandes fournisseurs permet a une entreprise de preparer, envoyer et suivre une commande destinee a un fournisseur. Il couvre plusieurs sources de produits, plusieurs types de destinataires, des pieces jointes, des croquis de ligne, une conversation, un suivi de statut et une file de notifications email.

Le point important pour la reprise : ce module n'est pas seulement un formulaire. Il relie catalogue, bibliotheques fournisseurs, devis, fournisseurs internes, portail fournisseur, messagerie, tracking email et feature plan.

Perimetre documente

Cette page documente les fichiers listes dans les points d'entree ci-dessous. Avant une correction, ouvrir ces fichiers dans la branche de travail concernee et verifier l'historique git du module si le comportement observe ne correspond pas a la documentation.

Architecture fonctionnelle

flowchart LR
  Router[Router.php] --> Controller[SupplierOrderController]
  Controller --> Model[SupplierOrderModel]
  Model --> DB[(MySQL)]
  Model --> Messaging[MessagingModel]
  Model --> Devis[DevisModel]
  Model --> Notify[SupplierOrderNotificationService]
  Notify --> Mailer[MailerService]
  Notify --> Tracking[DocumentEmailViewModel]
  Cron[supplier_order_notifications_cron.php] --> Notify
  Controller --> View[supplier-orders.php]

Points d'entree

Backend

  • app/controllers/SupplierOrderController.php : routes HTTP, payloads JSON/form-data, chargement de page entreprise et fournisseur.
  • app/models/SupplierOrderModel.php : regles metier, droits, sauvegarde, statuts, pieces jointes, conversations, catalogue, devis.
  • app/services/SupplierOrderNotificationService.php : file de notifications, rendu email, tracking, retry.
  • app/cron/supplier_order_notifications_cron.php : traitement CLI des notifications en attente.

Front et stockage

  • app/views/supplier-orders.php : interface principale, modales, wizard, timeline, conversation.
  • public/uploads/supplier_orders/.gitkeep : racine de stockage des fichiers du module.

SQL

  • app/bd/supplier-orders.sql
  • app/bd/supplier-orders-pme-feature.sql

La page squelette historique mentionnait app/bd/supplier-orders-tpe-feature.sql, mais ce fichier n'est pas present dans le checkout actuel. Si un environnement attend ce script, retrouver son origine avant migration.

Routes

Routes principales dans app/core/Router.php :

  • commandes-fournisseurs : page entreprise, protegee par FEATURE_COMMANDE_FOURNISSEUR.
  • commandes : page fournisseur, reservee aux comptes fournisseur.
  • commande-fournisseur/get : detail commande.
  • commande-fournisseur/conversation : conversation liee.
  • commande-fournisseur/pdf : export PDF.
  • commande-fournisseur/save : creation ou mise a jour.
  • commande-fournisseur/change-status : changement de statut, utilisable par entreprise ou fournisseur selon le contexte.
  • commande-fournisseur/libraries : bibliotheques accessibles.
  • commande-fournisseur/recipients : fournisseurs enregistres.
  • commande-fournisseur/quotes : devis disponibles.
  • commande-fournisseur/quote-draft : brouillon de commande depuis devis.
  • commande-fournisseur/products : produits disponibles selon source.
  • commande-fournisseur/product-config : configurateur produit.

Permissions, feature et contextes utilisateur

La feature fonctionnelle est FEATURE_COMMANDE_FOURNISSEUR.

Le modele distingue trois contextes :

  • admin : traite comme contexte membre pour la societe active ;
  • membre : entreprise qui cree et suit la commande ;
  • fournisseur : destinataire qui consulte et met a jour certains statuts.

checkMemberFeatureAccess ne bloque pas les fournisseurs. Les fournisseurs doivent pouvoir acceder a leurs commandes sans posseder la feature entreprise.

Sources et destinataires

Modes source (source_mode) :

  • partner_library : commande depuis bibliotheque fournisseur partenaire.
  • direct_catalog : commande depuis catalogue direct.
  • quote : commande pre-remplie depuis un devis.

Types de destinataire (recipient_type) :

  • library : bibliotheque fournisseur, avec portail fournisseur si recipient_membre_id existe.
  • supplier : fournisseur enregistre localement dans fournisseurs.
  • email : destinataire libre par email.

Types de bibliotheque :

  • cpt : menuiserie sur mesure.
  • std : classique.

Types de produit en ligne :

  • catalogue
  • cpt
  • std

SupplierOrderModel normalise les anciennes valeurs standard vers std et carpentry vers cpt. Ne pas changer ces valeurs sans migration des donnees existantes.

Donnees et schema

supplier_orders

Table principale.

Colonnes structurantes :

  • societe_id : societe emettrice.
  • source_mode, source_quote_id : origine de la commande.
  • recipient_type, recipient_library_type, recipient_library_id, recipient_supplier_id, recipient_name, recipient_email, recipient_membre_id : destinataire.
  • created_by_membre_id : membre createur.
  • conversation_id : conversation liee.
  • reference : reference commande.
  • customer_name, customer_email, customer_phone, customer_address, site_address : client et lieu.
  • requested_delivery_date, delivery_week, delivery_week_status : livraison demandee ou annoncee.
  • factory_departure_date, shipping_date, received_at : jalons de production/livraison.
  • status, submitted_at, last_status_changed_at, archived_at, deleted_at : workflow.

Statuts SQL :

  • draft
  • en attente
  • incomplet
  • validé
  • en fabrication
  • expédiée
  • réceptionnée
  • archivée

La migration convertit l'ancien statut terminée vers réceptionnée.

supplier_order_lines

Lignes de commande.

Colonnes importantes :

  • product_type, product_id, source_library_id, source_library_name_snapshot.
  • product_name_snapshot, product_reference_snapshot : snapshots pour garder la commande stable si le catalogue evolue.
  • quantity, line_reference, width, height.
  • measure_basis : ajoute runtime si absent ; valeurs metier pour les produits cpt.
  • configuration_json, configuration_summary_json.
  • croquis_file_path, croquis_original_name, croquis_mime_type, croquis_file_size.
  • sort_order.

replaceOrderLines supprime toutes les lignes d'une commande puis les reinsere. Toute modification de ce flux doit donc prendre en compte la perte potentielle d'identifiants de ligne.

supplier_order_attachments

Pieces jointes globales de la commande :

  • file_path
  • original_name
  • mime_type
  • file_size

syncAttachments supprime les pieces non conservees via existing_attachment_ids, puis ajoute les nouveaux fichiers attachments.

supplier_order_status_history

Historique des statuts :

  • old_status
  • new_status
  • changed_by_membre_id
  • changed_by_type : supplier, member, admin, etc.
  • note
  • created_at

La timeline combine cet historique, l'evenement de creation, l'envoi au fournisseur et les consultations email.

supplier_order_notifications

File des emails :

  • source_type : order_created ou status_updated.
  • payload_json : payload rendu par le service.
  • status : pending, processing, sent, failed.
  • retry_count, next_retry_at, last_error, sent_at.

La table est creee par migration SQL et aussi assuree dans SupplierOrderNotificationService::ensureStorageSchema. Garder les deux en coherence.

document_email_views

Table de tracking partagee avec d'autres documents. Ici elle suit les ouvertures de liens email pour document_type = supplier_order.

Creation et sauvegarde

SupplierOrderController::save envoie au modele :

  • order_id
  • source_mode
  • source_quote_id
  • recipient_type
  • recipient_library_type
  • recipient_library_id
  • recipient_supplier_id
  • recipient_name
  • recipient_email
  • reference
  • customer_name
  • customer_address
  • site_address
  • observations
  • save_mode
  • lines_json
  • existing_attachment_ids
  • $_FILES

Regles importantes :

  • seuls les contextes entreprise peuvent creer ou editer ;
  • un fournisseur ne peut jamais editer une commande ;
  • une commande n'est editable par l'entreprise que si elle appartient a la societe active ;
  • seuls les statuts draft et incomplet sont editables ;
  • save_mode = draft garde un brouillon ;
  • une soumission passe en en attente.

Apres sauvegarde, le modele remplace les lignes, synchronise les pieces jointes, cree ou synchronise la conversation et planifie la notification de creation si la commande est envoyee.

Devis vers commande

getQuoteDraft charge un devis via DevisModel, puis transforme certaines lignes en lignes de commande.

Points de vigilance :

  • toutes les lignes de devis ne sont pas forcement compatibles ;
  • le modele retourne aussi des lignes exclues ;
  • source_mode = quote conserve le lien vers source_quote_id ;
  • le destinataire choisi influence la compatibilite des lignes.

Avant de modifier le mapping devis, tester un devis avec lignes catalogue, cpt, std, lignes sans produit et lignes avec dimensions.

Produits et configurateur

Le module interroge trois univers :

  • catalogue interne (catalogue) ;
  • bibliotheques cpt ;
  • bibliotheques std.

getProductSourceConfig centralise les noms de tables et colonnes par source. Pour cpt, la reference fournisseur vient de reference_fournisseur. Pour std, elle vient de reference. Pour le catalogue, il n'y a pas de colonne de reference produit dediee dans cette configuration.

Le configurateur lit les options, valeurs et compatibilites propres a chaque source. Ne pas dupliquer ces requetes dans le controleur.

Uploads et fichiers

Constantes :

  • module upload : supplier_orders;
  • dossier pieces jointes : attachments;
  • dossier croquis : croquis;
  • taille maximum : 5 Mio.

Pieces jointes :

  • champ attachments;
  • plusieurs fichiers ;
  • suppression des anciens fichiers non conserves en base.

Croquis de ligne :

  • champ attendu : line_croquis_<client_key>;
  • utilise seulement pour les produits cpt;
  • si aucun nouveau fichier n'est envoye, le modele conserve existing_croquis_*.

Risques :

  • une ligne sans client_key correct ne pourra pas rattacher son croquis ;
  • supprimer/reinserer toutes les lignes impose de bien transporter les anciens chemins de croquis ;
  • les suppressions base ne garantissent pas, a elles seules, la suppression physique des fichiers.

Statuts et transitions

Statuts metier :

  • draft : brouillon entreprise.
  • en attente : commande envoyee au fournisseur.
  • incomplet : fournisseur ou entreprise signale un complement necessaire.
  • validé : fournisseur valide.
  • en fabrication : fournisseur indique la fabrication.
  • expédiée : fournisseur indique l'expedition.
  • réceptionnée : entreprise confirme la reception.
  • archivée : archive logique.

Transitions fournisseur :

  • interdit si la commande ne supporte pas le portail fournisseur ;
  • interdit si recipient_membre_id ne correspond pas au fournisseur connecte ;
  • interdit depuis réceptionnée ;
  • peut choisir en attente, incomplet, validé, en fabrication, expédiée.

Transitions entreprise :

  • pour flux fournisseur externe (supplier ou email sans portail), l'entreprise peut appliquer en attente, incomplet, validé, en fabrication, expédiée, réceptionnée.
  • pour flux portail fournisseur, l'entreprise ne peut confirmer que réceptionnée, et seulement depuis expédiée.
  • aucun changement de statut depuis draft ou archivée via changeStatus.

Dates obligatoires :

  • en fabrication exige factory_departure_date.
  • expédiée exige shipping_date.
  • réceptionnée remplit received_at avec maintenant si la date est absente.

Chaque changement ecrit supplier_order_status_history. Les notifications de statut ne sont planifiees que si le statut change vraiment ; une modification de date seule ajoute l'historique mais ne declenche pas la notification de statut.

Notifications

SupplierOrderNotificationService gere deux sources :

  • order_created
  • status_updated

Cycle d'envoi :

  1. insertion dans supplier_order_notifications avec status = pending ;
  2. envoi immediat possible via sendNotificationById ;
  3. claim atomique : passage pending vers processing ;
  4. en cas de succes : sent, sent_at, last_error = NULL ;
  5. en cas d'echec : retry ou echec definitif.

Parametres :

  • MAX_RETRIES = 3 ;
  • RETRY_DELAY_SECONDS = 300 ;
  • processPendingNotifications traite 1 a 100 notifications, 50 par defaut.

Le cron app/cron/supplier_order_notifications_cron.php appelle processPendingNotifications. Il retourne un JSON avec processed, sent, failed.

Tracking email et lien document

Les emails peuvent construire une URL de document suivie via DocumentEmailViewModel. La timeline commande lit ensuite les ouvertures pour ajouter des evenements "Commande consultee".

Points de reprise :

  • ne pas supprimer document_email_views en pensant qu'il s'agit d'un detail email ;
  • une commande peut etre consultee via lien email sans connexion au portail fournisseur ;
  • le tracking contribue a la timeline fonctionnelle visible dans l'interface.

Conversations

Le lien de conversation utilise :

  • type : supplier_order ;
  • cle : supplier_order:<id>.

ensureConversation retrouve une conversation existante via MessagingModel::findConversationIdByLink, sinon elle en cree une et synchronise le destinataire fournisseur. Les commandes vers fournisseur externe ou email peuvent ne pas avoir le meme comportement qu'une commande vers bibliotheque avec recipient_membre_id.

Schema runtime vs migrations

Le modele contient des verifications runtime :

  • ensureSupplierOrderLinesSchema ajoute ou corrige product_type et measure_basis.
  • ensureSupplierOrdersStatusSchema corrige l'enum de statut, ajoute factory_departure_date et shipping_date.
  • SupplierOrderNotificationService::ensureStorageSchema cree la table de notifications si absente.

Ces garde-fous ne remplacent pas les migrations SQL. Pour une installation neuve ou une base staging, appliquer d'abord app/bd/supplier-orders.sql, puis verifier que les ensure runtime ne masquent pas une migration oubliee.

Integrations internes

  • Bibliotheques fournisseurs : cpt_libraries, std_libraries, acces publics ou demandes acceptees.
  • Produits : cpt_products, std_products, catalogue.
  • Devis : DevisModel, source_quote_id, generation de brouillon.
  • Fournisseurs locaux : table fournisseurs.
  • Messagerie : conversation liee a la commande.
  • Emails : MailerService, table supplier_order_notifications.
  • Tracking : DocumentEmailViewModel, document_email_views.
  • Feature plans : feature id 44, nom Commande fournisseurs.

Risques et points d'attention

  • Ne pas autoriser l'edition apres envoi sauf retour en incomplet.
  • Ne pas laisser un fournisseur confirmer réceptionnée : cette action revient a l'entreprise.
  • Ne pas envoyer une commande sans destinataire email valide pour les flux supplier ou email.
  • Ne pas confondre pieces jointes de commande et croquis de ligne.
  • Ne pas casser les snapshots de lignes : ils garantissent la lisibilite historique si le produit source change.
  • Ne pas oublier les statuts accentues dans les comparaisons (validé, expédiée, réceptionnée, archivée).
  • Ne pas supposer que toutes les commandes ont un portail fournisseur.
  • Ne pas rendre les notifications bloquantes pour la sauvegarde si le code les traite comme secondaires.

Bugs connus ou signales

Aucun bug confirme n'est documente dans le code pour ce module. Zones a surveiller en reprise :

  • divergence entre fichiers en base et fichiers physiques apres edition ;
  • croquis perdu si client_key change cote front ;
  • statut bloque si recipient_membre_id n'est pas synchronise pour une bibliotheque ;
  • notifications restees en processing si un envoi est interrompu apres claim.

Tests recommandes

  • Creation brouillon sans envoi.
  • Soumission vers bibliotheque cpt avec portail fournisseur.
  • Soumission vers bibliotheque std.
  • Soumission vers fournisseur local.
  • Soumission vers email libre.
  • Creation depuis devis avec lignes compatibles et incompatibles.
  • Upload pieces jointes multiples.
  • Upload croquis sur ligne cpt.
  • Edition d'une commande incomplet.
  • Refus d'edition sur commande en attente.
  • Transition fournisseur vers validé, en fabrication, expédiée.
  • Obligation de factory_departure_date pour en fabrication.
  • Obligation de shipping_date pour expédiée.
  • Confirmation entreprise réceptionnée apres expédiée.
  • File de notifications : succes, retry, echec apres 3 tentatives.
  • Tracking d'ouverture email dans la timeline.

Commandes utiles

php app/cron/supplier_order_notifications_cron.php

Il n'y a pas de test automatise dedie au module dans le checkout actuel. Ajouter en priorite des tests de modele sur transitions, sauvegarde, uploads et notifications.

Checklist de reprise

  • Lire SupplierOrderController.php, puis SupplierOrderModel.php.
  • Appliquer/verifier app/bd/supplier-orders.sql.
  • Verifier que FEATURE_COMMANDE_FOURNISSEUR et la feature id 44 sont coherentes en base.
  • Tester un compte entreprise et un compte fournisseur.
  • Tester un destinataire avec portail et un destinataire externe.
  • Verifier les permissions d'edition par statut.
  • Verifier les fichiers dans public/uploads/supplier_orders/attachments et public/uploads/supplier_orders/croquis.
  • Verifier la table supplier_order_notifications avant d'accuser le SMTP.
  • Verifier document_email_views si la timeline ne montre pas les consultations.

Questions ouvertes

  • Faut-il recreer un script supplier-orders-tpe-feature.sql ou supprimer definitivement cette reference des traces historiques ?
  • Les notifications en processing doivent-elles etre recyclees automatiquement apres un timeout ?
  • La suppression des lignes devrait-elle conserver les ids pour faciliter l'audit des croquis ?
  • Une commande externe sans portail fournisseur doit-elle creer une conversation ou seulement utiliser l'email ?