d3d00425f7
Branche l'API REST du repertoire clients (M1) sur l'entite Client preparee en ERP-54. Operations GetCollection / Get / Post / Patch (pas de Delete au M1 : l'archivage passe par PATCH isArchived). ClientProvider : - liste paginee (Paginator ORM, aligne sur la convention ERP-72) + echappatoire ?pagination=false - exclut archives + soft-deletes par defaut (RG-1.24), ?includeArchived=true reintegre les archives (RG-1.25) - tri companyName ASC (RG-1.26), filtres ?search (fuzzy companyName/lastName/ email) et ?categoryType=<code> - detail : 404 sur soft-delete, embarque contacts/adresses/ribs ClientProcessor : - normalisation serveur via ClientFieldNormalizer (RG-1.18 a 1.21) - 409 sur doublon de nom de societe (RG-1.16) ; 409 dedie sur conflit de restauration (RG-1.23) - gating par onglet : champ comptable -> accounting.manage, isArchived -> archive, mode strict 403 sur tout le payload (RG-1.28) ; archivage exclusif (RG-1.22) + pose/retrait archivedAt - regles metier RG-1.01 (prenom/nom), RG-1.03 (distributor/broker exclusifs + controle du type de categorie), RG-1.12 (Virement -> banque), RG-1.13 (LCR -> >= 1 RIB), RG-1.04 (completude Information pour le role Commerciale) Lecture comptable conditionnelle : ClientReadGroupContextBuilder ajoute le groupe client:read:accounting selon commercial.clients.accounting.view. Resolution des references categorie : CategoryReferenceDenormalizer resout les IRI vers Category quand la propriete est type-hintee par le contrat CategoryInterface (denormalisation impossible sur une interface sinon). Contrats Shared : - CategoryInterface::getCategoryTypeCode() (implemente par Category) pour la verification de type sans import inter-modules - BusinessRoleAwareInterface (implemente par User) + BusinessRoles::COMMERCIALE pour detecter le role metier ; le code de role sera seede par ERP-74 et reutilise par ERP-59/60. RG-1.04 reste dormante tant qu'aucun user ne porte ce role. Coordination stack : - chaines de permission commercial.clients.* referencees ici, declarees en ERP-59 (tests RBAC complets en ERP-60) - config globale de pagination (itemsPerPage client, max 50) portee par ERP-72 - referentiels comptables (PaymentType/Bank/...) exposes en ERP-56 Tests : 31 tests Commercial (integration admin sur les regles metier + unitaires sur le gating, RG-1.04/1.12/1.13 et le context builder). Suite complete verte (339 tests).
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;
|
|
}
|
|
}
|