d6790dd37d
Auto Tag Develop / tag (push) Successful in 7s
ERP-94 (etape front 7/7 du M2). **Stack sur #97** (base = `feature/ERP-97-suppliers-i18n-sidebar`, elle-meme sur #93) pour un diff isole. A recibler sur `develop` une fois #93 (MR #81) et #97 (MR #82) mergees. Page « Ajouter un fournisseur » — **replique a l'identique le fonctionnement de l'ecran Client** (workflow inline par onglets, blocs reutilisables, validation 422 inline ERP-101), avec les specificites M2. ## Architecture (miroir Client) - Workflow par onglets **inline dans `suppliers/new.vue`** (comme `clients/new.vue` — il n'existe pas de `useClientForm` monolithique). Helpers paralleles : `useSupplierReferentials`, `useSupplierFormErrors`, `supplierFormRules`, `supplierEdit` (payloads), `types/supplierForm`. - Blocs `SupplierContactBlock` / `SupplierAddressBlock` (miroir des blocs Client). - POST `/suppliers` puis PATCH partiels par onglet (mode strict, groupes de serialisation). Sous-ressources : `/suppliers/{id}/contacts|addresses|ribs`. - Validation ERP-101 : 422 `violations[].propertyPath` mappees inline par champ (`useFormErrors` / `mapViolationsToRecord`), `{ toast: false }`, bouton Valider toujours actif. ## Specificites M2 (vs M1) - Formulaire principal **sans contact inline** (ERP-106) : Entreprise + Categorie (type FOURNISSEUR, `?typeCode=FOURNISSEUR`). - Adresse : **radio exclusif** Prospect/Depart/Rendu (`addressType` enum, RG-2.09), champs **Bennes** (stepper) + **Prestation de triage**, **pas d'email de facturation**. - Information : champ **Volume previsionnel** (8e champ). - Compta (Admin+Compta) : banque si VIREMENT (RG-2.07), RIB si LCR (RG-2.08) ; RIB sous-ressource gardee par `accounting.manage`. ## Tests (mirroir strategie Client) - `make nuxt-test` : 338 passed (specs ajoutees : supplierFormRules, supplierEdit, useSupplierReferentials, SupplierContactBlock, SupplierAddressBlock). - ESLint propre ; `nuxi typecheck` (lance en container) : **0 erreur**. - Golden path navigateur valide end-to-end : POST /suppliers OK, companyName normalise UPPERCASE (RG-2.12), gating des onglets (Information actif, Contacts deverrouille). ## Note de revue ~30 `WARN Duplicated imports` au typecheck : les helpers Supplier exportent les memes noms generiques que leurs equivalents Client (`buildMainPayload`, `omitEmptyRequired`, `RefOption`...), tous deux auto-importes par Nuxt. **Sans impact runtime** : tous les consommateurs utilisent des imports explicites (qui priment). Consequence directe du miroir 1:1 ; une factorisation des generiques dans `shared/` pourrait etre un suivi. Reviewed-on: #83 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
79 lines
2.8 KiB
PHP
79 lines
2.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Module\Commercial\Application\Validator;
|
|
|
|
use ApiPlatform\Validator\Exception\ValidationException;
|
|
use App\Module\Commercial\Domain\Entity\Supplier;
|
|
use Symfony\Component\Validator\ConstraintViolation;
|
|
use Symfony\Component\Validator\ConstraintViolationList;
|
|
|
|
/**
|
|
* Validator metier (spec-front M2 § Onglet Comptabilite) : a la soumission
|
|
* complete de l'onglet Comptabilite, les six champs scalaires obligatoires
|
|
* doivent etre renseignes (SIREN, Numero de compte, Mode de TVA, N de TVA, Delai
|
|
* de reglement, Type de reglement). La banque reste conditionnelle (RG-2.07) et
|
|
* les RIB aussi (RG-2.08) : ils ne sont pas couverts ici (Assert\Callback sur
|
|
* l'entite Supplier — validatePaymentTypeConsistency).
|
|
*
|
|
* Parti pris (miroir ClientAccountingCompletenessValidator M1) : colonnes nullable
|
|
* en base + validateur contextuel, plutot qu'un Assert\NotBlank sur l'entite (qui
|
|
* casserait le POST de l'onglet principal, lequel n'envoie aucun champ comptable).
|
|
*
|
|
* Invoque par le SupplierProcessor uniquement quand le payload porte les six
|
|
* champs (= une validation d'onglet), jamais sur un PATCH ciblant un seul champ.
|
|
*
|
|
* Leve une ValidationException (HTTP 422) listant chaque champ manquant, par
|
|
* coherence avec les violations Symfony rendues par API Platform (mapping inline
|
|
* front via useFormErrors, ERP-101).
|
|
*/
|
|
final class SupplierAccountingCompletenessValidator
|
|
{
|
|
public function validate(Supplier $supplier): void
|
|
{
|
|
// Map champ -> valeur courante des champs obligatoires de l'onglet.
|
|
$fields = [
|
|
'siren' => $supplier->getSiren(),
|
|
'accountNumber' => $supplier->getAccountNumber(),
|
|
'tvaMode' => $supplier->getTvaMode(),
|
|
'nTva' => $supplier->getNTva(),
|
|
'paymentDelay' => $supplier->getPaymentDelay(),
|
|
'paymentType' => $supplier->getPaymentType(),
|
|
];
|
|
|
|
$violations = new ConstraintViolationList();
|
|
|
|
foreach ($fields as $property => $value) {
|
|
if ($this->isMissing($value)) {
|
|
$violations->add(new ConstraintViolation(
|
|
'Ce champ est obligatoire.',
|
|
null,
|
|
[],
|
|
$supplier,
|
|
$property,
|
|
$value,
|
|
));
|
|
}
|
|
}
|
|
|
|
if (count($violations) > 0) {
|
|
throw new ValidationException($violations);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Une valeur est manquante si null ou, pour une chaine, vide apres trim. Les
|
|
* references (TvaMode / PaymentDelay / PaymentType) ne sont manquantes que
|
|
* lorsqu'elles valent null.
|
|
*/
|
|
private function isMissing(mixed $value): bool
|
|
{
|
|
if (null === $value) {
|
|
return true;
|
|
}
|
|
|
|
return is_string($value) && '' === trim($value);
|
|
}
|
|
}
|