feat(commercial) : catégories de type Adresse pour les blocs adresse (client + fournisseur) (#147)
Auto Tag Develop / tag (push) Successful in 12s
Auto Tag Develop / tag (push) Successful in 12s
## Objectif Introduit un `CategoryType` dédié **ADRESSE** (module Catalog) consommé par le champ « Catégorie » des blocs adresse, en remplacement de la réutilisation détournée des types CLIENT / FOURNISSEUR. ## Changements **Backend** - Migration de seed du type ADRESSE + 6 catégories : Siège, Contact issues, Facturation, Livraison, Approvisionnement, Méthaniseur (idempotente, réversible) ; fixtures alignées. - `ClientAddress` : validation blacklist (DISTRIBUTEUR/COURTIER) remplacée par une whitelist « catégories de type ADRESSE uniquement ». - `SupplierAddress` : type requis FOURNISSEUR → ADRESSE (le bloc principal fournisseur reste en FOURNISSEUR). **Frontend** - Ref dédiée `addressCategories` (`?typeCode=ADRESSE`) dans les composables référentiels client et fournisseur. - Pages new/edit client et fournisseur câblées sur les blocs adresse. **Tests** - `CategoryAdresseSeedTest` (miroir du test PRESTATAIRE). - Adaptation des tests d'adresse client/fournisseur (sémantique whitelist ADRESSE) + helper `createAddressCategory()`. ## Vérifications - Back : suites Catalog + Architecture + adresse/fournisseur vertes (le flake JWT connu du hook est sans rapport, tests verts en isolation). - Front : Vitest vert (composables référentiels + ciblés). - php-cs-fixer : 0 correction ; eslint : OK. Reviewed-on: #147 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #147.
This commit is contained in:
@@ -42,7 +42,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
* - sites : SiteInterface (module Sites) via resolve_target_entities
|
||||
* - contacts : ClientContact (meme module)
|
||||
* - categories : CategoryInterface (module Catalog) via resolve_target_entities
|
||||
* — codes DISTRIBUTEUR/COURTIER interdits (RG-1.29, validateCategoryCodes, ERP-78)
|
||||
* — type ADRESSE attendu (validateCategoryType)
|
||||
*
|
||||
* Audite (#[Auditable]) + Timestampable/Blamable.
|
||||
*
|
||||
@@ -96,11 +96,11 @@ class ClientAddress implements TimestampableInterface, BlamableInterface, Client
|
||||
use TimestampableBlamableTrait;
|
||||
|
||||
/**
|
||||
* RG-1.29 (ERP-78) : ces codes de categorie decrivent une relation entre
|
||||
* clients (distributeur / courtier) et n'ont pas de sens sur une adresse.
|
||||
* Toute autre categorie du type CLIENT est autorisee.
|
||||
* Seules les categories PORTANT ce type sont autorisees sur une adresse client.
|
||||
* S'appuie sur CategoryInterface::getCategoryTypeCodes() (multi-type — pas
|
||||
* d'import du module Catalog, regle ABSOLUE n°1).
|
||||
*/
|
||||
private const array FORBIDDEN_CATEGORY_CODES = ['DISTRIBUTEUR', 'COURTIER'];
|
||||
private const string REQUIRED_CATEGORY_TYPE_CODE = 'ADRESSE';
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
@@ -215,7 +215,7 @@ class ClientAddress implements TimestampableInterface, BlamableInterface, Client
|
||||
private Collection $contacts;
|
||||
|
||||
// Au moins une categorie est obligatoire sur une adresse (spec-front § Adresse).
|
||||
// RG-1.29 : categories de code DISTRIBUTEUR/COURTIER interdites (validateCategoryCodes).
|
||||
// Categories de type ADRESSE uniquement (validateCategoryType).
|
||||
/** @var Collection<int, CategoryInterface> */
|
||||
#[ORM\ManyToMany(targetEntity: CategoryInterface::class)]
|
||||
#[ORM\JoinTable(name: 'client_address_category')]
|
||||
@@ -335,20 +335,19 @@ class ClientAddress implements TimestampableInterface, BlamableInterface, Client
|
||||
}
|
||||
|
||||
/**
|
||||
* RG-1.29 (ERP-78) : une adresse interdit les categories de code
|
||||
* DISTRIBUTEUR / COURTIER — elles decrivent une relation entre clients
|
||||
* (RG-1.03) et n'ont pas de sens sur une adresse physique -> 422 avec
|
||||
* violation sur le champ `categories`. Toute autre categorie (type unique
|
||||
* CLIENT) est acceptee. S'appuie sur CategoryInterface::getCode() (pas
|
||||
* d'import du module Catalog — regle ABSOLUE n°1).
|
||||
* Toute categorie posee sur une adresse client doit etre de type ADRESSE ->
|
||||
* sinon 422 avec violation sur le champ `categories`. S'appuie sur
|
||||
* CategoryInterface::getCategoryTypeCodes() (multi-type — la categorie est
|
||||
* acceptee des qu'elle PORTE le type ADRESSE ; pas d'import du module Catalog,
|
||||
* regle ABSOLUE n°1).
|
||||
*/
|
||||
#[Assert\Callback]
|
||||
public function validateCategoryCodes(ExecutionContextInterface $context): void
|
||||
public function validateCategoryType(ExecutionContextInterface $context): void
|
||||
{
|
||||
foreach ($this->categories as $category) {
|
||||
if ($category instanceof CategoryInterface
|
||||
&& in_array($category->getCode(), self::FORBIDDEN_CATEGORY_CODES, true)) {
|
||||
$context->buildViolation('Type de catégorie non autorisé sur une adresse.')
|
||||
&& !in_array(self::REQUIRED_CATEGORY_TYPE_CODE, $category->getCategoryTypeCodes(), true)) {
|
||||
$context->buildViolation('Type de catégorie non autorisé (ADRESSE attendu).')
|
||||
->atPath('categories')
|
||||
->addViolation()
|
||||
;
|
||||
|
||||
@@ -40,7 +40,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
* un site obligatoire (RG-2.06, Assert\Count). Site n'a pas de `code`.
|
||||
* - contacts : SupplierContact (meme module).
|
||||
* - categories : CategoryInterface (module Catalog) via resolve_target_entities —
|
||||
* type FOURNISSEUR attendu (RG-2.10, Assert\Callback validateCategoryType).
|
||||
* type ADRESSE attendu (Assert\Callback validateCategoryType).
|
||||
*
|
||||
* Embarquee sous `supplier.addresses` au detail (groupe supplier:item:read,
|
||||
* maillon (a)).
|
||||
@@ -110,11 +110,11 @@ class SupplierAddress implements TimestampableInterface, BlamableInterface, Supp
|
||||
public const array ADDRESS_TYPES = ['PROSPECT', 'DEPART', 'RENDU'];
|
||||
|
||||
/**
|
||||
* RG-2.10 : seules les categories PORTANT ce type sont autorisees sur une
|
||||
* adresse fournisseur. S'appuie sur CategoryInterface::getCategoryTypeCodes()
|
||||
* (pas d'import du module Catalog — regle ABSOLUE n°1).
|
||||
* Seules les categories PORTANT ce type sont autorisees sur une adresse
|
||||
* fournisseur. S'appuie sur CategoryInterface::getCategoryTypeCodes() (pas
|
||||
* d'import du module Catalog — regle ABSOLUE n°1).
|
||||
*/
|
||||
private const string REQUIRED_CATEGORY_TYPE_CODE = 'FOURNISSEUR';
|
||||
private const string REQUIRED_CATEGORY_TYPE_CODE = 'ADRESSE';
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
@@ -208,8 +208,8 @@ class SupplierAddress implements TimestampableInterface, BlamableInterface, Supp
|
||||
#[Groups(['supplier:item:read', 'supplier:write:addresses'])]
|
||||
private Collection $contacts;
|
||||
|
||||
// RG-2.10 : au moins une categorie de type FOURNISSEUR par adresse (le type est
|
||||
// controle par validateCategoryType ; le minimum par Assert\Count, miroir sites).
|
||||
// Au moins une categorie de type ADRESSE par adresse (le type est controle par
|
||||
// validateCategoryType ; le minimum par Assert\Count, miroir sites).
|
||||
/** @var Collection<int, CategoryInterface> */
|
||||
#[ORM\ManyToMany(targetEntity: CategoryInterface::class)]
|
||||
#[ORM\JoinTable(name: 'supplier_address_category')]
|
||||
@@ -227,12 +227,12 @@ class SupplierAddress implements TimestampableInterface, BlamableInterface, Supp
|
||||
}
|
||||
|
||||
/**
|
||||
* RG-2.10 : toute categorie posee sur une adresse fournisseur doit etre de
|
||||
* type FOURNISSEUR -> sinon 422 avec violation sur le champ `categories`
|
||||
* (propertyPath aligne ERP-101, message FR ERP-107). S'appuie sur
|
||||
* Toute categorie posee sur une adresse fournisseur doit etre de type ADRESSE
|
||||
* -> sinon 422 avec violation sur le champ `categories` (propertyPath aligne
|
||||
* ERP-101, message FR ERP-107). S'appuie sur
|
||||
* CategoryInterface::getCategoryTypeCodes() (multi-type — la categorie est
|
||||
* acceptee des qu'elle PORTE le type FOURNISSEUR ; pas d'import du module
|
||||
* Catalog, regle ABSOLUE n°1). Joue avant la base via la validation API Platform.
|
||||
* acceptee des qu'elle PORTE le type ADRESSE ; pas d'import du module Catalog,
|
||||
* regle ABSOLUE n°1). Joue avant la base via la validation API Platform.
|
||||
*/
|
||||
#[Assert\Callback]
|
||||
public function validateCategoryType(ExecutionContextInterface $context): void
|
||||
@@ -240,7 +240,7 @@ class SupplierAddress implements TimestampableInterface, BlamableInterface, Supp
|
||||
foreach ($this->categories as $category) {
|
||||
if ($category instanceof CategoryInterface
|
||||
&& !in_array(self::REQUIRED_CATEGORY_TYPE_CODE, $category->getCategoryTypeCodes(), true)) {
|
||||
$context->buildViolation('Type de catégorie non autorisé (FOURNISSEUR attendu).')
|
||||
$context->buildViolation('Type de catégorie non autorisé (ADRESSE attendu).')
|
||||
->atPath('categories')
|
||||
->addViolation()
|
||||
;
|
||||
|
||||
Reference in New Issue
Block a user