feat(commercial) : enforce RG-1.29 by category code on address
ClientAddress::validateCategoryCodes interdit desormais les Category de code DISTRIBUTEUR/COURTIER sur une adresse (denylist), toute autre categorie etant autorisee. Fixtures clients alignees (tiers distributeur/courtier via Category de code dedie).
This commit is contained in:
@@ -39,7 +39,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
|||||||
* - sites : SiteInterface (module Sites) via resolve_target_entities
|
* - sites : SiteInterface (module Sites) via resolve_target_entities
|
||||||
* - contacts : ClientContact (meme module)
|
* - contacts : ClientContact (meme module)
|
||||||
* - categories : CategoryInterface (module Catalog) via resolve_target_entities
|
* - categories : CategoryInterface (module Catalog) via resolve_target_entities
|
||||||
* — limitees aux types SECTEUR/AUTRE (RG-1.29, validateCategoryTypes, ERP-76)
|
* — codes DISTRIBUTEUR/COURTIER interdits (RG-1.29, validateCategoryCodes, ERP-78)
|
||||||
*
|
*
|
||||||
* Audite (#[Auditable]) + Timestampable/Blamable.
|
* Audite (#[Auditable]) + Timestampable/Blamable.
|
||||||
*
|
*
|
||||||
@@ -87,8 +87,12 @@ class ClientAddress implements TimestampableInterface, BlamableInterface
|
|||||||
{
|
{
|
||||||
use TimestampableBlamableTrait;
|
use TimestampableBlamableTrait;
|
||||||
|
|
||||||
/** RG-1.29 : seuls ces types de categorie qualifient une adresse physique. */
|
/**
|
||||||
private const array ALLOWED_CATEGORY_TYPES = ['SECTEUR', 'AUTRE'];
|
* 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.
|
||||||
|
*/
|
||||||
|
private const array FORBIDDEN_CATEGORY_CODES = ['DISTRIBUTEUR', 'COURTIER'];
|
||||||
|
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
#[ORM\GeneratedValue]
|
#[ORM\GeneratedValue]
|
||||||
@@ -165,7 +169,7 @@ class ClientAddress implements TimestampableInterface, BlamableInterface
|
|||||||
#[Groups(['client_address:read', 'client_address:write'])]
|
#[Groups(['client_address:read', 'client_address:write'])]
|
||||||
private Collection $contacts;
|
private Collection $contacts;
|
||||||
|
|
||||||
// RG-1.29 : categories de type SECTEUR/AUTRE uniquement (validateCategoryTypes).
|
// RG-1.29 : categories de code DISTRIBUTEUR/COURTIER interdites (validateCategoryCodes).
|
||||||
/** @var Collection<int, CategoryInterface> */
|
/** @var Collection<int, CategoryInterface> */
|
||||||
#[ORM\ManyToMany(targetEntity: CategoryInterface::class)]
|
#[ORM\ManyToMany(targetEntity: CategoryInterface::class)]
|
||||||
#[ORM\JoinTable(name: 'client_address_category')]
|
#[ORM\JoinTable(name: 'client_address_category')]
|
||||||
@@ -232,18 +236,19 @@ class ClientAddress implements TimestampableInterface, BlamableInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RG-1.29 : seules les categories de type SECTEUR / AUTRE qualifient une
|
* RG-1.29 (ERP-78) : une adresse interdit les categories de code
|
||||||
* adresse physique. Les types DISTRIBUTEUR / COURTIER decrivent une relation
|
* DISTRIBUTEUR / COURTIER — elles decrivent une relation entre clients
|
||||||
* entre clients (RG-1.03) et n'ont pas de sens sur une adresse -> 422 avec
|
* (RG-1.03) et n'ont pas de sens sur une adresse physique -> 422 avec
|
||||||
* violation sur le champ `categories`. S'appuie sur
|
* violation sur le champ `categories`. Toute autre categorie (type unique
|
||||||
* CategoryInterface::getCategoryTypeCode() (pas d'import du module Catalog).
|
* CLIENT) est acceptee. S'appuie sur CategoryInterface::getCode() (pas
|
||||||
|
* d'import du module Catalog — regle ABSOLUE n°1).
|
||||||
*/
|
*/
|
||||||
#[Assert\Callback]
|
#[Assert\Callback]
|
||||||
public function validateCategoryTypes(ExecutionContextInterface $context): void
|
public function validateCategoryCodes(ExecutionContextInterface $context): void
|
||||||
{
|
{
|
||||||
foreach ($this->categories as $category) {
|
foreach ($this->categories as $category) {
|
||||||
if ($category instanceof CategoryInterface
|
if ($category instanceof CategoryInterface
|
||||||
&& !in_array($category->getCategoryTypeCode(), self::ALLOWED_CATEGORY_TYPES, true)) {
|
&& in_array($category->getCode(), self::FORBIDDEN_CATEGORY_CODES, true)) {
|
||||||
$context->buildViolation('Type de catégorie non autorisé sur une adresse.')
|
$context->buildViolation('Type de catégorie non autorisé sur une adresse.')
|
||||||
->atPath('categories')
|
->atPath('categories')
|
||||||
->addViolation()
|
->addViolation()
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
|||||||
*
|
*
|
||||||
* Audit / Blamable : persist hors contexte HTTP -> created_by / updated_by
|
* Audit / Blamable : persist hors contexte HTTP -> created_by / updated_by
|
||||||
* restent null (« Systeme » cote front), c'est attendu. Les donnees respectent
|
* restent null (« Systeme » cote front), c'est attendu. Les donnees respectent
|
||||||
* les CHECK BDD ET les validators applicatifs ERP-76 (exclusivite Prospect,
|
* les CHECK BDD ET les validators applicatifs (exclusivite Prospect, billingEmail
|
||||||
* billingEmail ssi facturation, aucune categorie DISTRIBUTEUR/COURTIER sur une
|
* ssi facturation, aucune categorie de code DISTRIBUTEUR/COURTIER sur une adresse
|
||||||
* adresse).
|
* — RG-1.29, ERP-78).
|
||||||
*
|
*
|
||||||
* Depend de CategoryFixtures (categories), SitesFixtures (sites) et
|
* Depend de CategoryFixtures (categories), SitesFixtures (sites) et
|
||||||
* CommercialReferentialFixtures (referentiels comptables Bank / PaymentType).
|
* CommercialReferentialFixtures (referentiels comptables Bank / PaymentType).
|
||||||
@@ -116,7 +116,7 @@ class ClientFixtures extends Fixture implements DependentFixtureInterface
|
|||||||
lastName: 'Garnier',
|
lastName: 'Garnier',
|
||||||
phonePrimary: '05 56 10 20 30',
|
phonePrimary: '05 56 10 20 30',
|
||||||
email: 'contact@distrib-gso.fr',
|
email: 'contact@distrib-gso.fr',
|
||||||
categoryNames: ['Distributeur Grand Sud-Ouest'],
|
categoryNames: ['Distributeur'],
|
||||||
);
|
);
|
||||||
if ($gsoIsNew) {
|
if ($gsoIsNew) {
|
||||||
$this->addContact($gso, 'Paul', 'Garnier', 'Directeur commercial', '05 56 10 20 30', null, 'paul.garnier@distrib-gso.fr');
|
$this->addContact($gso, 'Paul', 'Garnier', 'Directeur commercial', '05 56 10 20 30', null, 'paul.garnier@distrib-gso.fr');
|
||||||
@@ -131,7 +131,7 @@ class ClientFixtures extends Fixture implements DependentFixtureInterface
|
|||||||
lastName: 'Léonard',
|
lastName: 'Léonard',
|
||||||
phonePrimary: '05 49 11 22 33',
|
phonePrimary: '05 49 11 22 33',
|
||||||
email: 'contact@cabinet-leonard.fr',
|
email: 'contact@cabinet-leonard.fr',
|
||||||
categoryNames: ['Cabinet de courtage Léonard'],
|
categoryNames: ['Courtier'],
|
||||||
);
|
);
|
||||||
if ($leonardIsNew) {
|
if ($leonardIsNew) {
|
||||||
$this->addContact($leonard, 'Sophie', 'Léonard', 'Gérante', '05 49 11 22 33', null, 'sophie.leonard@cabinet-leonard.fr');
|
$this->addContact($leonard, 'Sophie', 'Léonard', 'Gérante', '05 49 11 22 33', null, 'sophie.leonard@cabinet-leonard.fr');
|
||||||
@@ -422,11 +422,11 @@ class ClientFixtures extends Fixture implements DependentFixtureInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Ajoute une adresse au client (cascade persist via Client.addresses). Les
|
* Ajoute une adresse au client (cascade persist via Client.addresses). Les
|
||||||
* donnees respectent les validators ERP-76 : exclusivite Prospect,
|
* donnees respectent les validators : exclusivite Prospect, billingEmail ssi
|
||||||
* billingEmail ssi facturation, categories limitees a SECTEUR/AUTRE.
|
* facturation, aucune categorie de code DISTRIBUTEUR/COURTIER (RG-1.29).
|
||||||
*
|
*
|
||||||
* @param list<string> $siteNames au moins un site (RG-1.10)
|
* @param list<string> $siteNames au moins un site (RG-1.10)
|
||||||
* @param list<string> $categoryNames categories SECTEUR/AUTRE uniquement (RG-1.29)
|
* @param list<string> $categoryNames categories hors DISTRIBUTEUR/COURTIER (RG-1.29)
|
||||||
*/
|
*/
|
||||||
private function addAddress(
|
private function addAddress(
|
||||||
Client $client,
|
Client $client,
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ use App\Module\Sites\Domain\Entity\Site;
|
|||||||
* - RG-1.06 / RG-1.07 / RG-1.08 : exclusivite is_prospect vs
|
* - RG-1.06 / RG-1.07 / RG-1.08 : exclusivite is_prospect vs
|
||||||
* is_delivery / is_billing ;
|
* is_delivery / is_billing ;
|
||||||
* - RG-1.11 : billing_email obligatoire ssi is_billing ;
|
* - RG-1.11 : billing_email obligatoire ssi is_billing ;
|
||||||
* - RG-1.29 : seules les categories de type SECTEUR / AUTRE sont autorisees sur
|
* - RG-1.29 (ERP-78) : les categories de code DISTRIBUTEUR / COURTIER sont
|
||||||
* une adresse (DISTRIBUTEUR / COURTIER -> 422).
|
* interdites sur une adresse (-> 422) ; toute autre categorie est acceptee.
|
||||||
*
|
*
|
||||||
* Depuis ERP-76, ces regles sont portees par des Assert\Callback sur l'entite
|
* Depuis ERP-76, ces regles sont portees par des Assert\Callback sur l'entite
|
||||||
* ClientAddress (mirror applicatif des CHECK Postgres) : la combinaison invalide
|
* ClientAddress (mirror applicatif des CHECK Postgres) : la combinaison invalide
|
||||||
|
|||||||
Reference in New Issue
Block a user