mirror of
https://github.com/JMP-MS/ASPIC.git
synced 2026-10-27 17:17:08 +00:00
374 lines
22 KiB
PHP
374 lines
22 KiB
PHP
<?php
|
|
/**
|
|
* ASPIC — moteur_consignes.php
|
|
*
|
|
* Moteur générique du chantier des consignes (6 septembre 2026, voir
|
|
* Réflexions stratégiques). Lit ASP_Consignes/ASP_Fonctions à l'exécution et
|
|
* applique ce qu'il y trouve — l'objectif explicite de Jean-Marc étant que
|
|
* l'ajout d'une ligne dans ASP_Consignes change le comportement réel de
|
|
* l'application sans qu'aucun fichier PHP/JS ne soit retouché, sauf si une
|
|
* fonction nouvelle doit être écrite dans consignes_fonctions.php (ou en cas
|
|
* de bug). Ce fichier ne doit donc plus jamais contenir la moindre référence
|
|
* à un champ ou une consigne précis — tout vient de la base.
|
|
*
|
|
* Portée de cette première version, volontairement limitée :
|
|
* - CNS_Champ NULL (consigne transverse à la fiche entière, ex. futur
|
|
* contrôle de doublon) n'est PAS encore géré ; ces lignes sont ignorées
|
|
* pour l'instant, à reprendre quand un vrai cas se présentera. En revanche
|
|
* CNS_Champ PEUT désormais contenir PLUSIEURS noms de champs séparés par
|
|
* une virgule (ex. "CNT_AdrVille,CNT_AdrCP") — extension du 7 septembre
|
|
* 2026 (soir), nécessaire pour une consigne dont la réponse dépend de
|
|
* plusieurs champs à la fois (ex. déduire le code postal à partir de la
|
|
* ville, voir consigne_completer_code_postal() dans
|
|
* consignes_fonctions.php). Une consigne à un seul champ garde exactement
|
|
* le même contrat qu'avant (fonction appelée avec une simple chaîne) ; une
|
|
* consigne à plusieurs champs appelle sa fonction avec un tableau associatif
|
|
* [nom_du_champ => valeur] et attend en retour, pour un Traitement, ce même
|
|
* type de tableau (valeurs mises à jour) — voir les deux boucles ci-dessous.
|
|
* - CNS_Moment n'est PAS distingué ici : temps réel (Saisie) abandonné pour
|
|
* cette version (décision de Jean-Marc, 6 septembre 2026 — priorité à la
|
|
* robustesse plutôt qu'au retour immédiat à l'écran). Toute consigne
|
|
* active s'applique donc au moment de l'enregistrement, qu'elle porte
|
|
* Saisie ou Validation.
|
|
* - Un seul message d'erreur retourné (le premier test en échec) — pas
|
|
* d'accumulation de plusieurs erreurs à la fois pour ce premier chantier.
|
|
*
|
|
* CNS_Portee : 'Mise à jour' est traité comme un mot-clé signifiant "les deux
|
|
* moments" (Création et Modification), à côté de valeurs plus précises
|
|
* ('Création' ou 'Modification' seules seraient possibles plus tard pour une
|
|
* règle d'immuabilité — voir Réflexions stratégiques).
|
|
*
|
|
* CNS_Agent (7 septembre 2026) : nom libre (varchar, pas de clé étrangère
|
|
* vers ASP_Agents) permettant de rattacher une consigne à un agent — utile
|
|
* en particulier pour les prochaines consignes de test qui simuleront des
|
|
* comportements par agent. Champ facultatif, remonté via le paramètre par
|
|
* référence $agentEchec plutôt qu'en changeant le type de retour de la
|
|
* fonction (qui reste un simple string|null, pour ne pas casser le contrat
|
|
* déjà en place) : seul contacts.php lit ce paramètre pour l'ajouter à sa
|
|
* réponse JSON, le front-end (afficherToast) l'affiche en italique sous le
|
|
* message quand il est présent.
|
|
*
|
|
* Journalisation des Traitements IA (7 septembre 2026, soir) : après le
|
|
* premier essai réel de consigne_completer_code_postal(), Jean-Marc a demandé
|
|
* de pouvoir tracer QUAND et POURQUOI l'IA a été sollicitée (bilan de
|
|
* consommation de tokens, entre autres). Un Traitement à PLUSIEURS champs
|
|
* (voir ci-dessus) peut donc désormais glisser, dans le tableau qu'il
|
|
* retourne, une clé réservée "_realisation" — jamais un vrai nom de champ
|
|
* ASPIC (tous commencent par un préfixe majuscule type "CNT_") donc aucun
|
|
* risque de collision. Cette clé est retirée par le moteur avant d'écrire le
|
|
* reste dans $data (voir boucle des Traitements ci-dessous), et collectée
|
|
* dans le nouveau paramètre par référence $journalisations. Volontairement
|
|
* PAS d'écriture directe dans ASP_Realisations ici : ce fichier n'a pas
|
|
* connaissance de CNT_Incr (inexistant tant que l'INSERT n'a pas eu lieu, en
|
|
* création) — c'est contacts.php qui journalise réellement, une fois
|
|
* l'identifiant du contact connu (voir ce fichier).
|
|
*
|
|
* Badge IA générique côté écran (7 septembre 2026, soir, suite) : le premier
|
|
* jet de ce badge reposait sur une condition écrite en dur dans
|
|
* liste_contacts.html (ville renseignée, code postal vide) — Jean-Marc a
|
|
* fait remarquer à juste titre que c'est exactement la même condition que la
|
|
* garde en tête de consigne_completer_code_postal(), et que dupliquer cette
|
|
* condition côté écran allait à l'encontre du chantier des consignes (une
|
|
* nouvelle consigne IA aurait demandé de retoucher le JS). Nouvelle
|
|
* convention à la place : une fonction de Traitement porteuse de
|
|
* FON_VisuelAttenteIA = 'O' (ASP_Fonctions — propriété de la FONCTION,
|
|
* remarque de Jean-Marc : c'est elle qui interroge une IA, pas la consigne
|
|
* qui l'utilise) DOIT avoir un jumeau nommé "<FON_NomPHP>_seraitDeclenchee"
|
|
* dans consignes_fonctions.php, signature (array $valeurs): bool — jamais
|
|
* d'appel réseau, juste la même garde que la vraie fonction (qui l'appelle en
|
|
* premier, voir consigne_completer_code_postal()) : la condition n'existe
|
|
* ainsi qu'à un seul endroit. Voir auMoinsUneConsigneIaSeraitDeclenchee()
|
|
* ci-dessous, utilisée par le nouveau point d'accès consignes_apercu.php —
|
|
* l'écran l'interroge une fois, juste avant l'enregistrement réel, pour
|
|
* savoir s'il doit afficher le badge pendant l'attente qui suit.
|
|
*
|
|
* Hiérarchisation Traitements de cohérence / Traitements IA (7 septembre
|
|
* 2026, nuit) : test réel de Jean-Marc (mail invalide + ville sans code
|
|
* postal) — l'ordre d'origine (TOUS les Traitements, puis TOUS les Tests)
|
|
* faisait sonner l'IA (coût réel, appel réseau) AVANT que le Test MAIL_VALIDE
|
|
* échoue et bloque l'enregistrement ; le contact n'étant jamais créé, cet
|
|
* appel IA n'était même pas journalisable (pas de CNT_Incr) — perdu, coût et
|
|
* trace. Pire : en resaisissant pour corriger le mail, un DEUXIÈME appel IA
|
|
* partait pour le même contact. Jean-Marc : "il faut qu'on hiérarchise les
|
|
* traitements : d'abord les traitements de cohérence, après les traitements
|
|
* par IA". Nouvel ordre d'exécution, réutilisant FON_VisuelAttenteIA comme
|
|
* seule frontière (déjà la bonne propriété : "cette fonction interroge un
|
|
* service externe") :
|
|
* 1. Traitements de cohérence (FON_VisuelAttenteIA != 'O') — silencieux,
|
|
* gratuits, locaux, comme avant.
|
|
* 2. Tests, sur les valeurs déjà mises en cohérence ci-dessus — premier
|
|
* échec = arrêt immédiat, AVANT tout appel IA.
|
|
* 3. Traitements IA (FON_VisuelAttenteIA = 'O') — atteints seulement si
|
|
* tous les Tests sont passés : un enregistrement voué à l'échec ne
|
|
* déclenche donc plus jamais d'appel IA.
|
|
* Limite assumée, à revoir le jour où un vrai cas se présentera : un Test qui
|
|
* porterait sur un champ produit par un Traitement IA (ex. valider le format
|
|
* d'un code postal déduit par l'IA) verrait la valeur D'AVANT cet appel IA,
|
|
* puisque les Tests s'exécutent avant l'étape 3 — aucune consigne actuelle
|
|
* n'est dans ce cas.
|
|
*
|
|
* Test à un champ avec accès base (8 septembre 2026) : première consigne de
|
|
* cette nature (unicité du mail/portable, voir consigne_mail_unique() et
|
|
* consigne_portable_unique() dans consignes_fonctions.php). Le contrat de
|
|
* base d'un Test à un champ reste (string $valeur): bool (voir en-tête de
|
|
* consignes_fonctions.php), mais le moteur appelle désormais TOUJOURS ces
|
|
* fonctions avec deux arguments supplémentaires, $pdo et $idExclusion — sans
|
|
* effet sur les fonctions existantes qui ne déclarent qu'un seul paramètre
|
|
* (PHP ignore silencieusement les arguments en trop), et exploitable par une
|
|
* nouvelle fonction qui déclare ces deux paramètres en plus. $idExclusion est
|
|
* l'identifiant (ex. CNT_Incr) de la fiche en cours de modification — null en
|
|
* Création (rien à exclure), ou en Modification si l'appelant ne le fournit
|
|
* pas — pour qu'une consigne d'unicité ne se bloque jamais elle-même en
|
|
* retrouvant la propre valeur déjà enregistrée de la fiche qu'on modifie.
|
|
* Fourni par l'appelant (voir $idExclusion du paramètre d'appliquerConsignes()
|
|
* ci-dessous) : ce fichier n'a connaissance d'aucun identifiant métier propre
|
|
* à un contexte précis, volontairement générique.
|
|
*/
|
|
|
|
/**
|
|
* Charge les consignes actives d'un contexte/portée donnés, avec leur
|
|
* fonction associée — factorisé ici (7 septembre 2026, soir) car utilisé à
|
|
* la fois par appliquerConsignes() ci-dessous et par
|
|
* auMoinsUneConsigneIaSeraitDeclenchee() : une seule requête à faire évoluer
|
|
* si la jointure ASP_Consignes/ASP_Fonctions change un jour.
|
|
*/
|
|
function chargerConsignesActives(PDO $pdo, string $contexte, string $portee): array
|
|
{
|
|
$sql = "SELECT c.CNS_Champ, c.CNS_Nature, c.CNS_MessageErreur, c.CNS_Agent,
|
|
f.FON_NomPHP, f.FON_VisuelAttenteIA
|
|
FROM ASP_Consignes c
|
|
LEFT JOIN ASP_Fonctions f
|
|
ON f.FON_Nom = c.CNS_Fonction AND f.FON_Active = 'O'
|
|
WHERE c.CNS_Contexte = ?
|
|
AND c.CNS_Active = 'O'
|
|
AND c.CNS_Champ IS NOT NULL
|
|
AND (c.CNS_Portee = 'Mise à jour' OR FIND_IN_SET(?, c.CNS_Portee))
|
|
ORDER BY c.CNS_Incr";
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute([$contexte, $portee]);
|
|
return $stmt->fetchAll();
|
|
}
|
|
|
|
/**
|
|
* Est-ce qu'au moins une consigne de Traitement porteuse de
|
|
* FON_VisuelAttenteIA = 'O' se déclencherait réellement pour ces données ?
|
|
* Jamais d'appel réseau ici (voir commentaire d'en-tête) : chaque fonction
|
|
* concernée est interrogée via son jumeau "_seraitDeclenchee", pas la
|
|
* fonction réelle. Utilisée par consignes_apercu.php pour piloter le badge
|
|
* IA générique côté écran — un simple booléen, jamais le détail de quelle
|
|
* consigne précisément (le badge reste volontairement générique, voir
|
|
* réflexions avec Jean-Marc : pas de couleur/identité par agent ici).
|
|
*/
|
|
function auMoinsUneConsigneIaSeraitDeclenchee(PDO $pdo, string $contexte, string $portee, array $data): bool
|
|
{
|
|
$consignes = chargerConsignesActives($pdo, $contexte, $portee);
|
|
foreach ($consignes as $c) {
|
|
if ($c['CNS_Nature'] !== 'Traitement') continue;
|
|
if (($c['FON_VisuelAttenteIA'] ?? 'N') !== 'O') continue;
|
|
if (!$c['FON_NomPHP']) continue;
|
|
$nomApercu = $c['FON_NomPHP'] . '_seraitDeclenchee';
|
|
if (!function_exists($nomApercu)) continue;
|
|
|
|
$champs = array_map('trim', explode(',', $c['CNS_Champ']));
|
|
$valeurs = [];
|
|
foreach ($champs as $champ) {
|
|
$valeurs[$champ] = (string)($data[$champ] ?? '');
|
|
}
|
|
if (call_user_func($nomApercu, $valeurs)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Exécute une liste de consignes de Traitement (déjà filtrée par l'appelant)
|
|
* sur $data, dans l'ordre reçu. Factorisé (7 septembre 2026, nuit) car
|
|
* désormais appelé deux fois par appliquerConsignes() — une fois pour les
|
|
* Traitements de cohérence, une fois pour les Traitements IA — avec
|
|
* exactement la même mécanique à champ unique/multiple et la même collecte
|
|
* de "_realisation" dans les deux cas.
|
|
*
|
|
* Provenance de l'agent journalisé (7 septembre 2026, nuit — suite) : Jean-
|
|
* Marc a repéré que consigne_completer_code_postal() inventait elle-même son
|
|
* agent ("Mat", en dur dans le code, sans lien avec aucune table) et a fait
|
|
* remarquer que CNS_Agent existe déjà dans ASP_Consignes — exactement ce qui
|
|
* alimente déjà $agentEchec pour un Test en échec (voir plus bas). Même
|
|
* principe appliqué ici : l'agent réellement journalisé est TOUJOURS celui
|
|
* de CNS_Agent quand la consigne en porte un (nom en clair, tronqué à 15
|
|
* caractères pour tenir dans REA_CodeUser — voir suggestion SQL associée),
|
|
* jamais celui que la fonction aurait pu proposer elle-même. Une fonction de
|
|
* Traitement n'a donc plus aucune raison d'inventer un nom d'agent dans son
|
|
* "_realisation" — au mieux une valeur de repli si jamais CNS_Agent était
|
|
* laissé vide par erreur.
|
|
*
|
|
* Clé réservée "_avertissement" (7 septembre 2026, nuit — suite) : Jean-Marc,
|
|
* testant "Paris" (ville sans code postal unique, découpée en
|
|
* arrondissements), a remarqué qu'un appel IA infructueux ne laissait AUCUNE
|
|
* trace, ni à l'écran ni dans les réalisations — "il y a un appel fait à
|
|
* l'IA et pas de trace dans les réalisations, ce qui n'est pas normal".
|
|
* "_realisation" couvre déjà l'historique (voir consigne_completer_code_postal(),
|
|
* désormais journalisée aussi en cas d'échec) ; "_avertissement" couvre
|
|
* l'AUTRE moitié du problème, le retour immédiat à l'écran — sans lui,
|
|
* l'utilisateur ne voit rien se passer alors que l'IA a bien réfléchi et a
|
|
* sciemment renoncé. Contrat : une simple chaîne (le message tel quel,
|
|
* déjà formulé pour l'utilisateur), collectée ici de la même façon que
|
|
* "_realisation", jamais écrite dans $data.
|
|
*/
|
|
function executerTraitements(array $consignesTraitement, array &$data, array &$journalisations, array &$avertissements): void
|
|
{
|
|
foreach ($consignesTraitement as $c) {
|
|
if (!$c['FON_NomPHP'] || !function_exists($c['FON_NomPHP'])) continue;
|
|
$champs = array_map('trim', explode(',', $c['CNS_Champ']));
|
|
if (count($champs) === 1) {
|
|
// Contrat historique, inchangé : une chaîne en entrée, une
|
|
// chaîne en sortie.
|
|
$valeurActuelle = (string)($data[$champs[0]] ?? '');
|
|
$data[$champs[0]] = call_user_func($c['FON_NomPHP'], $valeurActuelle);
|
|
} else {
|
|
// Consigne à plusieurs champs (7 septembre 2026, voir
|
|
// commentaire d'en-tête) : un tableau associatif dans les deux
|
|
// sens, pour que la fonction sache quel champ correspond à
|
|
// quelle valeur sans dépendre de l'ordre dans CNS_Champ.
|
|
$valeursActuelles = [];
|
|
foreach ($champs as $champ) {
|
|
$valeursActuelles[$champ] = (string)($data[$champ] ?? '');
|
|
}
|
|
$valeursMisesAJour = call_user_func($c['FON_NomPHP'], $valeursActuelles);
|
|
// Clé réservée "_realisation" (7 septembre 2026, voir commentaire
|
|
// d'en-tête) : jamais écrite dans $data, juste collectée à part.
|
|
if (isset($valeursMisesAJour['_realisation'])) {
|
|
$realisation = $valeursMisesAJour['_realisation'];
|
|
// L'agent vient de la consigne (CNS_Agent), jamais de la
|
|
// fonction — voir commentaire ci-dessus. Repli sur ce que la
|
|
// fonction avait proposé, puis sur 'IA' générique, seulement
|
|
// si CNS_Agent est vide (ne devrait plus arriver une fois la
|
|
// consigne correctement renseignée).
|
|
$agentConsigne = trim((string)($c['CNS_Agent'] ?? ''));
|
|
$realisation['agent'] = $agentConsigne !== ''
|
|
? mb_substr($agentConsigne, 0, 15, 'UTF-8')
|
|
: ($realisation['agent'] ?? 'IA');
|
|
$journalisations[] = $realisation;
|
|
unset($valeursMisesAJour['_realisation']);
|
|
}
|
|
// Clé réservée "_avertissement" (voir commentaire ci-dessus) :
|
|
// même principe que "_realisation", jamais écrite dans $data.
|
|
if (isset($valeursMisesAJour['_avertissement'])) {
|
|
$avertissements[] = (string)$valeursMisesAJour['_avertissement'];
|
|
unset($valeursMisesAJour['_avertissement']);
|
|
}
|
|
foreach ($valeursMisesAJour as $champ => $valeur) {
|
|
$data[$champ] = $valeur;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param PDO $pdo Connexion déjà ouverte (voir db.php).
|
|
* @param string $contexte Ex. 'Contacts' (ASP_Consignes.CNS_Contexte).
|
|
* @param string $portee 'Création' ou 'Modification'.
|
|
* @param array $data Données du formulaire, par référence —
|
|
* les traitements silencieux (ex.
|
|
* majuscules) modifient directement ce
|
|
* tableau.
|
|
* @param string|null $agentEchec Sortie par référence : CNS_Agent de la
|
|
* consigne dont le test a échoué (ou null
|
|
* si tout est passé, ou si la consigne en
|
|
* échec n'a pas d'agent renseigné).
|
|
* @param array|null $journalisations Sortie par référence : liste des
|
|
* entrées ['action'=>ACT_Code,
|
|
* 'agent'=>CNS_Agent de la consigne
|
|
* (nom en clair, tronqué à 15 caractères
|
|
* — voir executerTraitements() ci-dessus),
|
|
* 'commentaire'=>...] glissées par les
|
|
* Traitements à plusieurs champs qui l'ont
|
|
* demandé (voir commentaire d'en-tête) —
|
|
* tableau vide si aucun (jamais null en
|
|
* sortie, seul le type d'entrée est
|
|
* nullable — voir note ci-dessous). À
|
|
* journaliser dans ASP_Realisations par
|
|
* l'appelant.
|
|
* @param array|null $avertissements Sortie par référence : messages à
|
|
* afficher immédiatement à l'écran
|
|
* (voir "_avertissement" dans
|
|
* executerTraitements() ci-dessus) —
|
|
* tableau vide si aucun. À afficher par
|
|
* l'appelant (ex. un toast par message),
|
|
* indépendamment de $journalisations qui
|
|
* couvre l'historique, pas l'écran.
|
|
* @param int|null $idExclusion Identifiant de la fiche en cours de
|
|
* modification (ex. CNT_Incr), à exclure
|
|
* d'une éventuelle vérification
|
|
* d'unicité — null en Création, ou si
|
|
* aucune consigne du contexte n'en a
|
|
* besoin (8 septembre 2026, voir
|
|
* commentaire d'en-tête). Simplement
|
|
* retransmis tel quel aux fonctions de
|
|
* Test à un champ qui le demandent.
|
|
* @return string|null Message d'erreur du premier test en
|
|
* échec (déjà le texte à renvoyer tel
|
|
* quel au front-end), ou null si tout est
|
|
* passé.
|
|
*/
|
|
function appliquerConsignes(PDO $pdo, string $contexte, string $portee, array &$data, ?string &$agentEchec = null, ?array &$journalisations = null, ?array &$avertissements = null, ?int $idExclusion = null): ?string
|
|
{
|
|
// Type nullable en entrée (comme $agentEchec ci-dessus) : un appelant qui
|
|
// passe une variable non initialisée par référence la fait exister à
|
|
// null, ce qu'un type "array" strict refuserait (TypeError) — repéré à
|
|
// l'usage le 7 septembre 2026 en testant ce paramètre. Toujours remis à
|
|
// un tableau (vide ou rempli) avant de sortir de la fonction.
|
|
$agentEchec = null;
|
|
$journalisations = [];
|
|
$avertissements = [];
|
|
|
|
$consignes = chargerConsignesActives($pdo, $contexte, $portee);
|
|
|
|
// Étape 1 : Traitements de cohérence (silencieux, jamais de message,
|
|
// jamais d'appel réseau) — une consigne de test lue ensuite doit voir la
|
|
// valeur déjà mise en forme (ex. le nom déjà en majuscules avant de
|
|
// vérifier qu'il n'est pas vide).
|
|
$traitementsCoherence = array_filter($consignes, function (array $c): bool {
|
|
return $c['CNS_Nature'] === 'Traitement' && ($c['FON_VisuelAttenteIA'] ?? 'N') !== 'O';
|
|
});
|
|
executerTraitements($traitementsCoherence, $data, $journalisations, $avertissements);
|
|
|
|
// Étape 2 : les Tests, sur les valeurs déjà mises en cohérence ci-dessus
|
|
// (voir commentaire d'en-tête, 7 septembre 2026, nuit) : un premier échec
|
|
// arrête tout ICI, avant la moindre sollicitation d'IA — c'est tout
|
|
// l'objet de la réorganisation de ce soir.
|
|
foreach ($consignes as $c) {
|
|
if ($c['CNS_Nature'] !== 'Test') continue;
|
|
if (!$c['FON_NomPHP'] || !function_exists($c['FON_NomPHP'])) continue;
|
|
$champs = array_map('trim', explode(',', $c['CNS_Champ']));
|
|
if (count($champs) === 1) {
|
|
$valeur = (string)($data[$champs[0]] ?? '');
|
|
// $pdo et $idExclusion toujours passés (voir commentaire
|
|
// d'en-tête, 8 septembre 2026) : sans effet pour une fonction qui
|
|
// ne déclare que (string $valeur), exploités par une fonction qui
|
|
// a besoin d'interroger la base (ex. unicité mail/portable).
|
|
$ok = call_user_func($c['FON_NomPHP'], $valeur, $pdo, $idExclusion);
|
|
} else {
|
|
$valeurs = [];
|
|
foreach ($champs as $champ) {
|
|
$valeurs[$champ] = (string)($data[$champ] ?? '');
|
|
}
|
|
$ok = call_user_func($c['FON_NomPHP'], $valeurs);
|
|
}
|
|
if (!$ok) {
|
|
$agentEchec = $c['CNS_Agent'] ?: null;
|
|
return $c['CNS_MessageErreur'] ?: 'Consigne non respectée.';
|
|
}
|
|
}
|
|
|
|
// Étape 3 : Traitements IA — atteints seulement si tous les Tests sont
|
|
// passés (voir commentaire d'en-tête) : un enregistrement voué à échouer
|
|
// ne déclenche donc plus jamais d'appel IA facturé pour rien.
|
|
$traitementsIA = array_filter($consignes, function (array $c): bool {
|
|
return $c['CNS_Nature'] === 'Traitement' && ($c['FON_VisuelAttenteIA'] ?? 'N') === 'O';
|
|
});
|
|
executerTraitements($traitementsIA, $data, $journalisations, $avertissements);
|
|
|
|
return null;
|
|
}
|