Aller au contenu

Traitement interne

Extension payante. Une soumission reçue n’est pas une soumission traitée. Ce module ajoute à chaque demande un état, une personne responsable, une échéance, une priorité et un historique — sans toucher à ce que le cœur sait déjà d’elle.

Ce document décrit ce que le module garantit et ce qu’il refuse. Le guide utilisateur en donne la version courte, dans la section « Suivre le traitement d’une demande ».

Être désigné ne donne jamais le droit de lire

C’est la décision qui commande tout le reste.

La pente naturelle d’un module d’assignation est : « la personne assignée doit pouvoir ouvrir le dossier, donc l’assignation lui en donne l’accès ». Ce raccourci transforme une liste déroulante en outil d’attribution de droits — il suffirait d’assigner un dossier à n’importe quel compte du site pour lui ouvrir une soumission qu’il n’aurait jamais dû voir : adresse, téléphone, pièces jointes comprises.

Le sens est donc inversé. Le droit vient d’abord, l’assignation ne fait que désigner, parmi ceux qui l’ont déjà, celui dont c’est la tâche :

  • la liste proposée est calculée à partir des comptes pouvant déjà lire les soumissions de ce formulaire ;
  • le contrôle est refait à l’écriture, parce qu’une liste déroulante est du balisage et que le balisage se réécrit ;
  • un compte qui perd son droit reste inscrit sur le dossier — l’écran le signale — mais ne reçoit plus de relance et ne voit plus le dossier dans sa file.

La capacité de traitement

Elle s’appelle solis_forms_process_entries et s’emploie avec l’identifiant du formulaire : current_user_can( 'solis_forms_process_entries', $form_id ).

C’est une capacité méta, traduite par map_meta_cap en deux conditions déjà accordées par le site : voir les soumissions, et avoir la main sur ce formulaire-là. Elle n’ouvre donc aucun droit nouveau et n’est attribuée à personne.

Une capacité primitive supplémentaire aurait eu le défaut inverse : absente de tous les sites déjà installés, elle aurait privé tout le monde du traitement le jour de la mise à jour, administrateur compris, jusqu’à ce que quelqu’un comprenne qu’il faut l’attribuer.

Un site qui veut un rôle « traiteur » distinct peut rebrancher la traduction par un filtre map_meta_cap de priorité supérieure, sans toucher au code.

Sur un réseau multisite, les capacités sont par site et les tables aussi : un compte du réseau qui n’a pas le droit sur ce site n’est pas proposé, et la file d’un site ne montre jamais les dossiers d’un autre.

Les états appartiennent au formulaire

Une demande de devis ne passe pas par les mêmes étapes qu’une candidature. Les états sont donc réglés formulaire par formulaire : un intitulé, un ordre, et le fait de clore ou non. Huit au maximum.

Le réglage par défaut en propose quatre : Reçu, En cours, En attente, Résolu — le dernier clôturant.

La clé ne change jamais

Chaque état a une clé (in_progress, a_l_etude) fabriquée une fois, à la création, depuis l’intitulé. Renommer l’état ne la change pas. C’est ce qui permet de corriger une faute ou de traduire un mot sans que tous les dossiers existants se retrouvent dans un état que la configuration ne nomme plus.

Le serveur refuse une clé invalide au lieu de la réparer : réparer voudrait dire renommer, et une clé renommée ne désigne plus les mêmes dossiers.

Ce qui est refusé

Un seul refus, et c’est celui qui protège : on ne va que vers un état déclaré par ce formulaire. Une clé forgée dans une requête, un état retiré des réglages depuis, l’état d’un autre formulaire — tout cela est refusé par le serveur, que l’écran l’ait proposé ou non.

Il n’y a pas de diagramme de transitions. Une matrice « depuis tel état, on ne peut aller que vers tels autres » se configure mal, se comprend encore moins bien, et finit presque toujours ouverte en grand parce que le premier cas non prévu bloque quelqu’un un vendredi soir.

Rouvrir un dossier clos est permis. Un outil qui l’interdit se contourne par une seconde soumission, ce qui fait perdre l’historique qu’on voulait garder.

Un état retiré des réglages

Les dossiers qui s’y trouvaient le gardent : les réécrire d’office déciderait à la place de quelqu’un, et l’historique mentirait. Ils s’affichent avec leur clé, signalés comme non déclarés, et peuvent rejoindre n’importe quel état déclaré. L’issue existe toujours.

Deux personnes ne s’écrasent pas

Chaque dossier porte une révision. L’écran l’emporte dans le formulaire, et l’écriture ne s’applique qu’à cette révision-là : UPDATE … WHERE entry_id = … AND revision = ….

Deux personnes qui valident le même dossier à la même seconde ne s’écrasent donc pas. La seconde écriture ne touche aucune ligne, rien n’est enregistré, et l’écran le dit : « quelqu’un d’autre a modifié cette soumission entre-temps. Rien n’a été écrit : voici l’état actuel. »

Relire la ligne avant d’écrire aurait laissé exactement l’intervalle qu’on cherche à fermer. La condition voyage avec l’écriture.

L’état, la personne, l’échéance et la priorité partent ensemble, en une seule écriture : quatre boutons auraient produit quatre révisions, donc trois occasions supplémentaires de tomber sur un conflit à mi-parcours.

Un commentaire, lui, n’a pas de révision : ajouter à un historique n’entre en concurrence avec rien, et exiger une révision aurait fait perdre un texte rédigé pendant que quelqu’un d’autre changeait l’état.

L’historique ne se réécrit pas

Transitions, assignations, changements d’échéance et de priorité, relances et commentaires internes vivent dans une seule table, dans l’ordre où ils sont arrivés. Le dépôt n’offre ni modification ni suppression d’un événement : un historique qui se réécrit ne vaut rien, puisque son intérêt est qu’on ne puisse pas lui faire dire autre chose après coup.

Il disparaît avec ce qu’il décrit. Supprimer une soumission ou un formulaire emporte les dossiers et leur journal — un commentaire interne parle de quelqu’un, et il n’existe aucun droit à l’effacement qui épargnerait le commentaire en effaçant la réponse.

Les deux courriels

Ils sont réglés séparément. Prévenir la personne qu’on désigne est utile dès le premier jour ; relancer sur un retard suppose que les échéances soient prises au sérieux, ce qui n’arrive qu’après quelques semaines d’usage.

Ni l’un ni l’autre ne transporte le contenu d’une soumission. Ni réponse, ni nom de l’expéditeur, ni commentaire interne : le nom du formulaire, le numéro du dossier, l’échéance, un lien.

La raison n’est pas la pudeur. Le droit de lire se vérifie à l’ouverture du lien, dans l’administration, et nulle part ailleurs. Une boîte aux lettres se partage, se transfère, se synchronise sur un téléphone perdu : mettre la réponse dans le message reviendrait à livrer la donnée là où plus aucun contrôle ne s’applique, et à la livrer définitivement — on ne révoque pas un courriel parti.

La relance de retard

  • Une par dossier, et pas une de plus. La condition reminded_at IS NULL voyage avec l’écriture : deux exécutions concurrentes de la tâche n’en envoient qu’une.
  • Seulement à la personne désignée. Un dossier en retard sans personne assignée n’envoie rien : prévenir tous les administrateurs de ce qui n’est la tâche de personne produit un courriel que chacun apprend à filtrer — et le jour où le message compte, il est dans un dossier que plus personne n’ouvre. Ce retard-là se voit dans la file, ce qui est le bon endroit.
  • Rien ne part pour une soumission mise à la corbeille ou marquée indésirable, même si son traitement est resté ouvert.
  • Rien ne part à qui a perdu le droit d’ouvrir le dossier.

La tâche s’exécute toutes les heures. Une échéance se règle à l’heure, et une tâche quotidienne signalerait un retard jusqu’à vingt-trois heures après qu’il soit arrivé. Elle ne coûte rien quand aucun formulaire ne demande de relance : elle ne fait alors aucune requête.

L’échéance

Elle se règle en heures depuis la réception, et non comme une date fixe : une date fixe serait déjà passée pour toutes les soumissions du mois suivant, et la file entière s’afficherait en retard.

Zéro heure veut dire « pas d’échéance ». C’est un choix légitime : beaucoup de traitements n’ont pas de délai, et en inventer un pour que la colonne soit remplie apprend à ignorer la couleur rouge.

Le détail d’un dossier permet de déplacer son échéance. La date saisie est comprise dans le fuseau du site et conservée en heure universelle ; une date illisible est refusée plutôt que réinterprétée, car une échéance devinée s’afficherait en retard sans que personne ne l’ait fixée.

Le retard est écrit, pas seulement coloré : une couleur ne se lit pas à la voix, ne survit pas à une impression en noir et blanc, et se confond pour une partie des gens qui regardent l’écran.

Les trois écrans

Le détail d’une soumission porte le bloc de traitement : état, personne, échéance, priorité, puis l’historique et le champ de commentaire. C’est là que l’on décide.

La liste des soumissions d’un formulaire gagne une colonne — état, personne, mention du retard — et une action de ligne : Passer à : …. Elle ne propose que l’étape suivante dans l’ordre déclaré, pas la liste complète. Avec quatre états, offrir chaque état ferait trois liens de plus sur chaque ligne, à côté de « Voir », « Indésirable », « Corbeille » et « Supprimer » : plus personne ne lit une ligne d’actions aussi longue, et le lien dangereux se retrouve noyé au milieu des inoffensifs.

Le lien ne nomme pas l’état visé : il demande d’avancer, et c’est le serveur qui lit l’ordre déclaré pour savoir où.

La file de traitement (menu SolisForms → Traitement) répond à la question qu’on se pose en arrivant le matin, et qui ne se pose pas formulaire par formulaire : à traiter, qui m’est assigné, ce qui est en retard. Elle est triée par priorité décroissante puis par échéance — la priorité est ce que quelqu’un a décidé, l’échéance ce que le calendrier impose, et faire primer le calendrier rendrait le réglage de priorité décoratif.

Quelqu’un qui ne gère que ses propres formulaires n’y voit que leur file : la restriction est posée dans la requête, non appliquée à une liste déjà paginée.

Les mesures de délai

La file affiche, au-dessus du tableau et selon les filtres en cours : le nombre de dossiers ouverts, le nombre en retard, et le temps de traitement.

La médiane d’abord, la moyenne ensuite. Un dossier oublié six mois double la moyenne de tout un trimestre : on lit « délai moyen : onze jours » là où quarante-neuf dossiers sur cinquante ont été traités le jour même, et l’on conclut que l’équipe est lente. La médiane dit ce qui se passe d’habitude, la moyenne ce que coûtent les exceptions.

L’écart entre les deux est l’information. Quand la moyenne dépasse le double de la médiane, l’écran le dit en clair et donne le délai le plus long de l’échantillon, pour qu’on puisse aller voir le dossier concerné.

Seuls les dossiers clos sont mesurés. Un dossier encore ouvert n’a pas de délai : il a un âge. Les mêler rapprocherait de zéro la mesure d’une équipe qui vient d’ouvrir vingt dossiers, et l’éloignerait de zéro pour une qui n’en a aucun en cours. Les dossiers ouverts sont donc comptés, pas moyennés — et c’est le retard, non l’âge, qui dit lesquels regarder. Rouvrir un dossier le retire de la mesure.

L’échantillon porte sur les cinq cents dernières clôtures, et l’écran dit sur combien de dossiers il s’appuie. La borne répond à la question qu’on se pose : combien de temps prennent les dossiers en ce moment — une moyenne tirée sur trois ans de données répondrait à une autre.

La mesure suit les filtres de l’écran. Un délai tous formulaires confondus mélangerait une demande de devis et une candidature.

Ce que le module ne touche pas

Le statut de la soumission — active, indésirable, corbeille, brouillon — reste celui du cœur. Résoudre un dossier ne met rien à la corbeille, et mettre une soumission à la corbeille ne résout rien.

Un indésirable, une corbeille et un brouillon n’ouvrent pas de dossier : la file resterait sinon pleine de ce que personne n’a l’intention de regarder, et le compteur de retard perdrait tout sens.

Activer le traitement sur un formulaire en service laisse sans dossier les soumissions déjà reçues. L’écran de détail propose de les ouvrir une à une. Les ouvrir d’office aurait demandé de parcourir une table entière à l’enregistrement d’un réglage — et d’inventer une échéance rétroactive, donc une file intégralement en retard dès la première minute.

Pour les développeurs

Une action est diffusée après chaque changement d’état :

add_action(
	'solis_forms_pro_workflow_transitioned',
	function ( int $entry_id, string $from, string $to ): void {
		// …
	},
	10,
	3
);

Les tables sont {prefix}slf_entry_workflows (état courant, une ligne par soumission, entry_id unique) et {prefix}slf_workflow_events (journal, ajouté seulement). Le crochet de la tâche planifiée est solis_forms_workflow_reminders.

Ce que la V1 ne fait pas

  • Pas de diagramme de transitions libre.
  • Pas d’approbation à plusieurs niveaux.
  • Pas d’automatisation externe : le module n’appelle aucun service tiers.
  • Pas d’édition collaborative : la révision signale le conflit, elle ne fusionne pas deux saisies.
  • Les courriels sont internes. Rien n’est écrit à la personne qui a rempli le formulaire ; c’est le rôle des notifications du cœur.