fix(logistique) : corrections review ticket de pesée (ERP-208)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m59s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m32s

- Édition : listes contrepartie filtrées sur le site DU TICKET (immuable), chargées après hydrate, sans purge de la contrepartie persistée (injection de l'option si absente) → corrige la perte silencieuse / race.
- Entité : constantes COUNTERPARTY_* (Assert\Choice + validation + getCounterpartyName) ; libellé FR du type déplacé du Domain vers le template.
- PDF : cartouche conditionné sur le type (nom à l'intérieur), layout Dompdf-safe (largeurs de cellules, cartouche en bloc, nom long renvoyé à la ligne).
This commit is contained in:
2026-06-25 14:55:35 +02:00
parent 527e47d822
commit 2b03c4ae15
5 changed files with 65 additions and 63 deletions
@@ -175,6 +175,15 @@ class WeighingTicket implements TimestampableInterface, BlamableInterface
/** Valide : contrepartie + immatriculation + 2 pesees OK, numero attribue (« Terminée »). */
public const string STATUS_VALIDATED = 'VALIDATED';
/** Contrepartie « Client » (M1) — RG-5.03. */
public const string COUNTERPARTY_CLIENT = 'CLIENT';
/** Contrepartie « Fournisseur » (M2) — RG-5.03. */
public const string COUNTERPARTY_FOURNISSEUR = 'FOURNISSEUR';
/** Contrepartie « Autre » (libelle libre) — RG-5.03. */
public const string COUNTERPARTY_AUTRE = 'AUTRE';
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
@@ -195,7 +204,7 @@ class WeighingTicket implements TimestampableInterface, BlamableInterface
/** CLIENT | FOURNISSEUR | AUTRE (RG-5.03) — null tant que brouillon, requis a la validation. Pilote le champ associe obligatoire. */
#[ORM\Column(name: 'counterparty_type', length: 12, nullable: true)]
#[Assert\NotBlank(message: 'La contrepartie (Client / Fournisseur / Autre) est obligatoire.', groups: ['finalize'])]
#[Assert\Choice(choices: ['CLIENT', 'FOURNISSEUR', 'AUTRE'], message: 'Type de contrepartie invalide.')]
#[Assert\Choice(choices: [self::COUNTERPARTY_CLIENT, self::COUNTERPARTY_FOURNISSEUR, self::COUNTERPARTY_AUTRE], message: 'Type de contrepartie invalide.')]
#[Groups(['weighing_ticket:read', 'weighing_ticket:write'])]
private ?string $counterpartyType = null;
@@ -313,7 +322,7 @@ class WeighingTicket implements TimestampableInterface, BlamableInterface
public function validateCounterpartyConsistency(ExecutionContextInterface $context): void
{
switch ($this->counterpartyType) {
case 'CLIENT':
case self::COUNTERPARTY_CLIENT:
if (null === $this->client) {
$context->buildViolation('Le client est obligatoire pour une contrepartie « Client ».')
->atPath('client')
@@ -323,7 +332,7 @@ class WeighingTicket implements TimestampableInterface, BlamableInterface
break;
case 'FOURNISSEUR':
case self::COUNTERPARTY_FOURNISSEUR:
if (null === $this->supplier) {
$context->buildViolation('Le fournisseur est obligatoire pour une contrepartie « Fournisseur ».')
->atPath('supplier')
@@ -333,7 +342,7 @@ class WeighingTicket implements TimestampableInterface, BlamableInterface
break;
case 'AUTRE':
case self::COUNTERPARTY_AUTRE:
if (null === $this->otherLabel || '' === trim($this->otherLabel)) {
$context->buildViolation('Le libellé est obligatoire pour une contrepartie « Autre ».')
->atPath('otherLabel')
@@ -466,24 +475,10 @@ class WeighingTicket implements TimestampableInterface, BlamableInterface
public function getCounterpartyName(): ?string
{
return match ($this->counterpartyType) {
'CLIENT' => $this->client?->getCompanyName(),
'FOURNISSEUR' => $this->supplier?->getCompanyName(),
'AUTRE' => $this->otherLabel,
default => null,
};
}
/**
* Libellé FR du type de contrepartie (cartouche du bon de pesée PDF, ERP-208),
* affiché au-dessus du nom. Null si aucun type défini (brouillon).
*/
public function getCounterpartyTypeLabel(): ?string
{
return match ($this->counterpartyType) {
'CLIENT' => 'Client',
'FOURNISSEUR' => 'Fournisseur',
'AUTRE' => 'Autre',
default => null,
self::COUNTERPARTY_CLIENT => $this->client?->getCompanyName(),
self::COUNTERPARTY_FOURNISSEUR => $this->supplier?->getCompanyName(),
self::COUNTERPARTY_AUTRE => $this->otherLabel,
default => null,
};
}