From 93aa22594d1a8a1d67e747a144eac1fdb0051c95 Mon Sep 17 00:00:00 2001 From: tristan Date: Tue, 2 Jun 2026 16:10:00 +0200 Subject: [PATCH] fix(commercial) : retours de review ERP-62 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Export : message d'erreur dédié (toast.exportError) distinct du titre. - formatLastActivity : garde-fou date invalide (Number.isNaN) → cellule vide. - normalizeIntList/normalizeStringList : normalisation défensive (foreach + is_numeric/cast), plus de TypeError strict pour un appelant direct. - phone.ts : docblock reformulé (helper transverse assumé, usage à venir partout). --- frontend/i18n/locales/fr.json | 3 +- .../commercial/pages/clients/index.vue | 10 ++++-- frontend/shared/utils/phone.ts | 10 +++--- .../Doctrine/DoctrineClientRepository.php | 33 ++++++++++++++----- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/frontend/i18n/locales/fr.json b/frontend/i18n/locales/fr.json index 682d621..b3c0490 100644 --- a/frontend/i18n/locales/fr.json +++ b/frontend/i18n/locales/fr.json @@ -86,7 +86,8 @@ "updateSuccess": "Client mis à jour avec succès", "archiveSuccess": "Client archivé avec succès", "restoreSuccess": "Client restauré avec succès", - "error": "Une erreur est survenue. Réessayez." + "error": "Une erreur est survenue. Réessayez.", + "exportError": "L'export du répertoire clients a échoué. Réessayez." }, "validation": { "informationRequiredForCommercial": "Les informations de l'entreprise sont obligatoires pour le rôle Commerciale.", diff --git a/frontend/modules/commercial/pages/clients/index.vue b/frontend/modules/commercial/pages/clients/index.vue index 4d92ed4..df25fda 100644 --- a/frontend/modules/commercial/pages/clients/index.vue +++ b/frontend/modules/commercial/pages/clients/index.vue @@ -228,7 +228,13 @@ function formatLastActivity(item: Record): string { return '' } - return new Date(value).toLocaleDateString('fr-FR') + // Garde-fou date invalide : un updatedAt mal forme donnerait « Invalid Date ». + const date = new Date(value) + if (Number.isNaN(date.getTime())) { + return '' + } + + return date.toLocaleDateString('fr-FR') } /** Clic sur une ligne → ecran Consultation (route a plat /clients/{id}). */ @@ -383,7 +389,7 @@ async function exportXlsx(): Promise { catch { toast.error({ title: t('commercial.clients.toast.error'), - message: t('commercial.clients.toast.error'), + message: t('commercial.clients.toast.exportError'), }) } finally { diff --git a/frontend/shared/utils/phone.ts b/frontend/shared/utils/phone.ts index e02a98e..d00f7a0 100644 --- a/frontend/shared/utils/phone.ts +++ b/frontend/shared/utils/phone.ts @@ -2,11 +2,11 @@ * Formatage d'un numero de telephone francais en groupes de 2 chiffres * (`XX XX XX XX XX`). * - * Signature cible partagee avec le ticket 1.13 / ERP-66 : si ce dernier livre - * une version plus riche (validation, indicatif international), elle remplacera - * cette implementation minimale. En attendant, on couvre le besoin du Repertoire - * clients (ERP-62) : afficher un telephone lisible a partir de la valeur stockee - * en base (deja normalisee en 10 chiffres par le ClientProcessor, RG-1.20). + * Helper PARTAGE volontaire : les telephones sont presents un peu partout dans + * l'app (fiches clients, contacts, fournisseurs, prestataires...). Introduit ici + * comme util transverse stable plutot que duplique a chaque ecran. La signature + * `formatPhoneFR(value): string` est coordonnee avec ERP-66, qui pourra enrichir + * l'implementation (validation, indicatif international) sans casser les appelants. * * - Ne garde que les chiffres puis groupe par 2 (tolere une saisie deja espacee * ou pointee, ex: `06.12.34.56.78` ou `0612345678`). diff --git a/src/Module/Commercial/Infrastructure/Doctrine/DoctrineClientRepository.php b/src/Module/Commercial/Infrastructure/Doctrine/DoctrineClientRepository.php index 5b7eefe..da60851 100644 --- a/src/Module/Commercial/Infrastructure/Doctrine/DoctrineClientRepository.php +++ b/src/Module/Commercial/Infrastructure/Doctrine/DoctrineClientRepository.php @@ -144,30 +144,47 @@ class DoctrineClientRepository extends ServiceEntityRepository implements Client /** * Nettoie une liste de chaines : trim, retrait des vides, reindexation. + * Defensive : tolere des elements scalaires non-string (cast) et ignore le + * reste sans lever de TypeError, le contrat etant justement de normaliser une + * entree potentiellement brute (query params). * - * @param list $values + * @param array $values * * @return list */ private function normalizeStringList(array $values): array { - $cleaned = array_filter( - array_map(static fn (string $v): string => trim($v), $values), - static fn (string $v): bool => '' !== $v, - ); + $out = []; + foreach ($values as $value) { + if (is_string($value) || is_int($value) || is_float($value)) { + $trimmed = trim((string) $value); + if ('' !== $trimmed) { + $out[] = $trimmed; + } + } + } - return array_values($cleaned); + return $out; } /** * Nettoie une liste d'identifiants : cast int, retrait des <= 0, reindexation. + * Defensive (cf. normalizeStringList) : accepte des entiers ou des chaines + * numeriques ('1', '2') sans TypeError, ignore le reste. * - * @param list $values + * @param array $values * * @return list */ private function normalizeIntList(array $values): array { - return array_values(array_filter($values, static fn (int $v): bool => $v > 0)); + $out = []; + foreach ($values as $value) { + if (is_numeric($value) && (int) $value > 0) { + $out[] = (int) $value; + } + } + + return $out; } }