0c9b563cae
Auto Tag Develop / tag (push) Successful in 9s
**MR stackée sur ERP-54** — cible = `feature/ERP-54-creer-entites-client-m1` (PAS `develop`). Tristan validera le stack en fin de chaîne. Branche l'API REST du répertoire clients (M1) sur l'entité `Client` d'ERP-54. ## Périmètre - **ClientProvider** : liste paginée (Paginator ORM aligné ERP-72, `?pagination=false`), exclusion archives+soft-delete par défaut (RG-1.24), `?includeArchived=true` (RG-1.25), tri `companyName ASC` (RG-1.26), filtres `?search` (fuzzy) + `?categoryType`, détail 404 si soft-deleted + embarque contacts/adresses/ribs. - **ClientProcessor** : normalisation (RG-1.18→1.21), 409 doublon nom (RG-1.16) + 409 restauration (RG-1.23), gating par onglet `accounting.manage`/`archive` + mode strict 403 (RG-1.28), archivage exclusif + `archivedAt` (RG-1.22), RG-1.01 / RG-1.03 (mutex + type catégorie) / RG-1.12 / RG-1.13 / RG-1.04. - **ClientReadGroupContextBuilder** : ajout conditionnel du groupe `client:read:accounting` selon `commercial.clients.accounting.view`. - **CategoryReferenceDenormalizer** : résout les IRI catégorie vers `Category` (dénormalisation impossible sur l'interface sinon). - **Contrats Shared** : `CategoryInterface::getCategoryTypeCode()`, `BusinessRoleAwareInterface` + `BusinessRoles::COMMERCIALE`. ## Coordination stack - Permissions `commercial.clients.*` **référencées** ici, déclarées en **ERP-59** (tests RBAC en **ERP-60**). - Rôle métier `commerciale` seedé par **ERP-74** (RG-1.04 dormante d'ici là). - Config globale pagination (itemsPerPage client / max 50) portée par **ERP-72**. - Référentiels comptables (PaymentType/Bank/...) exposés en **ERP-56** → RG-1.12/1.13 testées en unitaire ici (pas d'IRI référentiel disponible avant ERP-56). ## Tests 31 tests Commercial (intégration admin sur les RG métier + unitaires sur le gating / RG-1.04 / RG-1.12 / RG-1.13 / context builder). Suite complète verte (343 tests). Règle n°1 respectée (aucun import inter-modules dans Commercial). --------- Co-authored-by: tristan <tristan@yuno.malio.fr> Co-authored-by: Matthieu <contact@malio.fr> Co-authored-by: Matthieu <mtholot19@gmail.com> Reviewed-on: #31 Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
81 lines
2.4 KiB
PHP
81 lines
2.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Module\Commercial\Application\Service;
|
|
|
|
/**
|
|
* Normalisation serveur des champs texte d'un Client / ClientContact, appliquee
|
|
* par le ClientProcessor (et plus tard le ClientContactProcessor) AVANT
|
|
* persistance. Cf. spec-back M1 § 2.9 + RG-1.18 a RG-1.21.
|
|
*
|
|
* - companyName : UPPERCASE integral (RG-1.18)
|
|
* - firstName / lastName (personnes) : Title Case (RG-1.19)
|
|
* - phone* : chiffres uniquement, ex "06.12.34.56.78" -> "0612345678" (RG-1.20).
|
|
* Le formatage d'affichage "XX XX XX XX XX" est de la responsabilite du front.
|
|
* - email : lowercase integral (RG-1.21)
|
|
*
|
|
* Toutes les methodes sont null-safe et trim-ent l'entree ; une chaine vide
|
|
* apres trim devient null (evite de persister "" dans des colonnes nullable).
|
|
*/
|
|
final class ClientFieldNormalizer
|
|
{
|
|
/**
|
|
* Nom de societe en majuscules (RG-1.18). Conserve null tel quel ; une
|
|
* chaine non vide est trim + upper. Une chaine vide reste "" (champ
|
|
* obligatoire : c'est l'Assert\NotBlank qui rejette, pas le normalizer).
|
|
*/
|
|
public function normalizeCompanyName(?string $value): ?string
|
|
{
|
|
if (null === $value) {
|
|
return null;
|
|
}
|
|
|
|
return mb_strtoupper(trim($value), 'UTF-8');
|
|
}
|
|
|
|
/**
|
|
* Nom/prenom de personne en Title Case (RG-1.19) : "JEAN dupont" ->
|
|
* "Jean Dupont". Une chaine vide apres trim devient null.
|
|
*/
|
|
public function normalizePersonName(?string $value): ?string
|
|
{
|
|
if (null === $value) {
|
|
return null;
|
|
}
|
|
|
|
$value = trim($value);
|
|
|
|
return '' === $value ? null : mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
|
|
}
|
|
|
|
/**
|
|
* Email en minuscules (RG-1.21). Une chaine vide apres trim devient null.
|
|
*/
|
|
public function normalizeEmail(?string $value): ?string
|
|
{
|
|
if (null === $value) {
|
|
return null;
|
|
}
|
|
|
|
$value = trim($value);
|
|
|
|
return '' === $value ? null : mb_strtolower($value, 'UTF-8');
|
|
}
|
|
|
|
/**
|
|
* Telephone reduit aux chiffres (RG-1.20) : "06.12.34.56.78" ->
|
|
* "0612345678". Une valeur sans aucun chiffre devient null.
|
|
*/
|
|
public function normalizePhone(?string $value): ?string
|
|
{
|
|
if (null === $value) {
|
|
return null;
|
|
}
|
|
|
|
$digits = preg_replace('/\D+/', '', $value) ?? '';
|
|
|
|
return '' === $digits ? null : $digits;
|
|
}
|
|
}
|