feat(commercial) : 2e email de facturation optionnel sur l'adresse client (ERP-119)
Pendant du telephone secondaire (max 2). Bump @malio/layer-ui 1.7.8 (prop addable du MalioInputEmail). - back : colonne billing_email_secondary (migration + COMMENT + catalogue), propriete ClientAddress (Email + Length), Callback etendu (2e email interdit hors facturation, optionnel sinon), normalisation lowercase au Processor. - front : draft + flag UI hasSecondaryBillingEmail, mappers, payloads, champ MalioInputEmail :addable -> revele un 2e champ ; layout : 2e email qui coule dans la grille et Adresse complementaire sur une colonne. - tests back (2 emails / 2e email hors facturation) et front (payload).
This commit is contained in:
@@ -178,6 +178,15 @@ class ClientAddress implements TimestampableInterface, BlamableInterface
|
||||
#[Groups(['client_address:read', 'client_address:write'])]
|
||||
private ?string $billingEmail = null;
|
||||
|
||||
// 2e email de facturation, optionnel (max 2 — pendant du telephone secondaire).
|
||||
// Comme le principal : interdit hors facturation (validateBillingEmailPresence),
|
||||
// mais jamais obligatoire. Normalise en lowercase par le ClientAddressProcessor.
|
||||
#[ORM\Column(length: 180, nullable: true)]
|
||||
#[Assert\Email(message: 'L\'email de facturation secondaire n\'est pas valide.')]
|
||||
#[Assert\Length(max: 180, maxMessage: 'L\'email de facturation secondaire ne peut dépasser {{ limit }} caractères.', normalizer: 'trim')]
|
||||
#[Groups(['client_address:read', 'client_address:write'])]
|
||||
private ?string $billingEmailSecondary = null;
|
||||
|
||||
#[ORM\Column(options: ['default' => 0])]
|
||||
#[Groups(['client_address:read', 'client_address:write'])]
|
||||
private int $position = 0;
|
||||
@@ -308,6 +317,16 @@ class ClientAddress implements TimestampableInterface, BlamableInterface
|
||||
->addViolation()
|
||||
;
|
||||
}
|
||||
|
||||
// Le 2e email est OPTIONNEL (jamais requis), mais comme le principal il
|
||||
// n'a de sens que sur une adresse de facturation.
|
||||
$hasSecondaryEmail = null !== $this->billingEmailSecondary && '' !== trim($this->billingEmailSecondary);
|
||||
if (!$this->isBilling && $hasSecondaryEmail) {
|
||||
$context->buildViolation('L\'email de facturation n\'est autorisé que sur une adresse de facturation.')
|
||||
->atPath('billingEmailSecondary')
|
||||
->addViolation()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -497,6 +516,18 @@ class ClientAddress implements TimestampableInterface, BlamableInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBillingEmailSecondary(): ?string
|
||||
{
|
||||
return $this->billingEmailSecondary;
|
||||
}
|
||||
|
||||
public function setBillingEmailSecondary(?string $billingEmailSecondary): static
|
||||
{
|
||||
$this->billingEmailSecondary = $billingEmailSecondary;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPosition(): int
|
||||
{
|
||||
return $this->position;
|
||||
|
||||
+1
@@ -94,5 +94,6 @@ final class ClientAddressProcessor implements ProcessorInterface
|
||||
private function normalize(ClientAddress $address): void
|
||||
{
|
||||
$address->setBillingEmail($this->normalizer->normalizeEmail($address->getBillingEmail()));
|
||||
$address->setBillingEmailSecondary($this->normalizer->normalizeEmail($address->getBillingEmailSecondary()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,21 +219,22 @@ final class ColumnCommentsCatalog
|
||||
] + self::timestampableBlamableComments(),
|
||||
|
||||
'client_address' => [
|
||||
'_table' => 'Adresses d un client (1:n) — prospect exclusif de livraison/facturation (RG-1.06/07/08), >= 1 site rattache (RG-1.10).',
|
||||
'id' => 'Identifiant interne auto-incremente.',
|
||||
'client_id' => 'FK -> client.id, ON DELETE CASCADE — client proprietaire de l adresse.',
|
||||
'is_prospect' => 'Adresse de prospection — exclusive de is_delivery/is_billing (RG-1.06/07/08, chk_client_address_prospect_exclusive). Faux par defaut.',
|
||||
'is_delivery' => 'Adresse de livraison. Exclusive de is_prospect. Faux par defaut.',
|
||||
'is_billing' => 'Adresse de facturation. Exclusive de is_prospect. Impose billing_email (RG-1.11). Faux par defaut.',
|
||||
'is_broker' => 'Adresse Courtier — type autonome exclusif de tout autre usage (chk_client_address_broker_exclusive). Faux par defaut.',
|
||||
'is_distributor' => 'Adresse Distributeur — type autonome exclusif de tout autre usage (chk_client_address_distributor_exclusive). Faux par defaut.',
|
||||
'country' => 'Pays de l adresse — defaut France.',
|
||||
'postal_code' => 'Code postal (4-5 chiffres attendus, RG-1.09).',
|
||||
'city' => 'Ville — preremplie depuis le code postal via API BAN cote front (RG-1.09).',
|
||||
'street' => 'Numero et voie de l adresse.',
|
||||
'street_complement' => 'Complement d adresse (etage, batiment...) — optionnel.',
|
||||
'billing_email' => 'Email de facturation — obligatoire si is_billing, null sinon (RG-1.11, chk_client_address_billing_email).',
|
||||
'position' => 'Ordre d affichage de l adresse dans la liste du client (croissant).',
|
||||
'_table' => 'Adresses d un client (1:n) — prospect exclusif de livraison/facturation (RG-1.06/07/08), >= 1 site rattache (RG-1.10).',
|
||||
'id' => 'Identifiant interne auto-incremente.',
|
||||
'client_id' => 'FK -> client.id, ON DELETE CASCADE — client proprietaire de l adresse.',
|
||||
'is_prospect' => 'Adresse de prospection — exclusive de is_delivery/is_billing (RG-1.06/07/08, chk_client_address_prospect_exclusive). Faux par defaut.',
|
||||
'is_delivery' => 'Adresse de livraison. Exclusive de is_prospect. Faux par defaut.',
|
||||
'is_billing' => 'Adresse de facturation. Exclusive de is_prospect. Impose billing_email (RG-1.11). Faux par defaut.',
|
||||
'is_broker' => 'Adresse Courtier — type autonome exclusif de tout autre usage (chk_client_address_broker_exclusive). Faux par defaut.',
|
||||
'is_distributor' => 'Adresse Distributeur — type autonome exclusif de tout autre usage (chk_client_address_distributor_exclusive). Faux par defaut.',
|
||||
'country' => 'Pays de l adresse — defaut France.',
|
||||
'postal_code' => 'Code postal (4-5 chiffres attendus, RG-1.09).',
|
||||
'city' => 'Ville — preremplie depuis le code postal via API BAN cote front (RG-1.09).',
|
||||
'street' => 'Numero et voie de l adresse.',
|
||||
'street_complement' => 'Complement d adresse (etage, batiment...) — optionnel.',
|
||||
'billing_email' => 'Email de facturation — obligatoire si is_billing, null sinon (RG-1.11, chk_client_address_billing_email).',
|
||||
'billing_email_secondary' => '2e email de facturation, optionnel (max 2). Interdit hors facturation, normalise en minuscules (RG-1.21).',
|
||||
'position' => 'Ordre d affichage de l adresse dans la liste du client (croissant).',
|
||||
] + self::timestampableBlamableComments(),
|
||||
|
||||
'client_address_site' => [
|
||||
|
||||
Reference in New Issue
Block a user