e265a008bc
Auto Tag Develop / tag (push) Successful in 7s
Étape 4/7 du M2 fournisseurs — stackée sur #67 (ERP-88). ## Périmètre (RG-2.03 / 2.07 / 2.08 / 2.10) Décision figée ERP-89 : les RG inter-champs passent par `Assert\Callback` + `->atPath()` sur l'entité Supplier (et non dans le Processor), pour que chaque 422 porte un `propertyPath` consommable par `extractApiViolations` (mapping inline, pas un toast — ERP-101). - **RG-2.10** — `Supplier::validateCategoryType()` → `atPath('categories')` : catégories de type FOURNISSEUR uniquement sur `supplier.categories` (miroir d'ERP-88 côté adresse). - **RG-2.07** — `Supplier::validatePaymentTypeConsistency()` → `atPath('bank')` : VIREMENT impose une banque. - **RG-2.08** — même Callback → `atPath('ribs')` : LCR impose ≥ 1 RIB (le 409 sur DELETE du dernier RIB en LCR reste porté par ERP-88). - **RG-2.03** — `SupplierInformationCompletenessValidator` (8 champs Information dont `volumeForecast`), invoqué par le `SupplierProcessor` après détection back du rôle Commerciale via `BusinessRoleAwareInterface`. Le Processor ne porte que rôle / mode strict / gating. ## Tests (16, verts) - `SupplierValidationTest` — Callbacks RG-2.07/2.08/2.10, assertion par propertyPath. - `SupplierInformationCompletenessValidatorTest` — complétude / champs manquants / zéros valides. - `SupplierProcessorTest` — détection rôle RG-2.03 (POST + PATCH main-only + non-Commerciale). `make test` : 499 tests OK. `php-cs-fixer` : clean. --------- Co-authored-by: admin malio <malio@yuno.malio.fr> Co-authored-by: Matthieu <contact@malio.fr> Reviewed-on: #68 Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
80 lines
2.9 KiB
PHP
80 lines
2.9 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 RG-2.03 (jumeau du ClientInformationCompletenessValidator M1) :
|
|
* pour un utilisateur portant le role metier Commerciale, TOUS les champs de
|
|
* l'onglet Information sont obligatoires sur POST comme sur tout PATCH,
|
|
* independamment des champs reellement envoyes.
|
|
*
|
|
* Invoque par le SupplierProcessor des que l'utilisateur courant porte le role
|
|
* Commerciale (detection du role cote back). Pour les autres roles, ces champs
|
|
* restent optionnels — le validator n'est pas appele.
|
|
*
|
|
* NEW vs Client : ajoute le champ `volumeForecast` (volume previsionnel),
|
|
* specifique fournisseur.
|
|
*
|
|
* Leve une ValidationException (HTTP 422) listant chaque champ manquant, chaque
|
|
* violation portant son propertyPath (consommable par extractApiViolations,
|
|
* ERP-101), par coherence avec les violations Symfony rendues par API Platform.
|
|
*/
|
|
final class SupplierInformationCompletenessValidator
|
|
{
|
|
public function validate(Supplier $supplier): void
|
|
{
|
|
// Map champ -> valeur courante de l'onglet Information.
|
|
$fields = [
|
|
'description' => $supplier->getDescription(),
|
|
'competitors' => $supplier->getCompetitors(),
|
|
'foundedAt' => $supplier->getFoundedAt(),
|
|
'employeesCount' => $supplier->getEmployeesCount(),
|
|
'revenueAmount' => $supplier->getRevenueAmount(),
|
|
'directorName' => $supplier->getDirectorName(),
|
|
'profitAmount' => $supplier->getProfitAmount(),
|
|
'volumeForecast' => $supplier->getVolumeForecast(),
|
|
];
|
|
|
|
$violations = new ConstraintViolationList();
|
|
|
|
foreach ($fields as $property => $value) {
|
|
if ($this->isMissing($value)) {
|
|
$violations->add(new ConstraintViolation(
|
|
sprintf('Ce champ est obligatoire pour le rôle Commerciale (champ "%s").', $property),
|
|
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
|
|
* zeros numeriques (employeesCount = 0, profitAmount = "0.00",
|
|
* volumeForecast = 0) sont des valeurs valides : on ne les considere pas
|
|
* manquants.
|
|
*/
|
|
private function isMissing(mixed $value): bool
|
|
{
|
|
if (null === $value) {
|
|
return true;
|
|
}
|
|
|
|
return is_string($value) && '' === trim($value);
|
|
}
|
|
}
|