feat : Reception.validatedAt + statut entrées + mode consultation

- Backend : champ Reception.validatedAt (timestamp) avec PreUpdate + helpers
  isFullyConfirmed/tryValidate ; sync EDNOTIF déclenche tryValidate sur
  les receptions impactées ; expose Supplier.name dans le groupe bovine:read.
- Migration : ajout colonne validated_at sans backfill (les receptions
  remontent en attente jusqu'au prochain sync).
- Front /entry-exit : remplace Historique par 'Entrées validées' (filtre
  exists[validatedAt]=true), ajoute filtres et colonne Statut sur les
  deux tableaux, retire Fournisseur, layout 2x2 (entrées + sorties).
- Front /entry-exit/entry/{id} : mode consultation quand entryCompleted=true
  (formulaire + actions masqués, colonne EDNOTIF par bovin) ; ajoute
  colonnes Vendeur et Cause dans le récap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-30 16:31:16 +02:00
parent 476502c91c
commit 8f88abab46
9 changed files with 400 additions and 240 deletions

View File

@@ -6,6 +6,7 @@ namespace App\Entity;
use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\ExistsFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiProperty;
@@ -32,6 +33,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
#[ORM\HasLifecycleCallbacks]
#[ORM\Table(name: 'reception')]
#[ApiFilter(BooleanFilter::class, properties: ['isValid', 'entryCompleted'])]
#[ApiFilter(ExistsFilter::class, properties: ['validatedAt'])]
#[ApiFilter(SearchFilter::class, properties: [
'identificationNumber' => 'ipartial',
'supplier.name' => 'ipartial',
@@ -115,6 +117,10 @@ class Reception
#[Groups(['reception:read', 'reception:write', 'reception-bovine:read'])]
private bool $entryCompleted = false;
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
#[Groups(['reception:read', 'reception-bovine:read'])]
private ?DateTimeImmutable $validatedAt = null;
#[ORM\Column(name: 'date_reception', type: 'datetime_immutable')]
#[Groups(['reception:read', 'reception:write', 'reception-bovine:read'])]
#[Context(
@@ -295,6 +301,45 @@ class Reception
return $this;
}
public function getValidatedAt(): ?DateTimeImmutable
{
return $this->validatedAt;
}
public function setValidatedAt(?DateTimeImmutable $validatedAt): self
{
$this->validatedAt = $validatedAt;
return $this;
}
public function isFullyConfirmed(): bool
{
if ($this->bovines->isEmpty()) {
return false;
}
foreach ($this->bovines as $bovine) {
if (null === $bovine->getEdnotifConfirmedAt()) {
return false;
}
}
return true;
}
public function tryValidate(): void
{
if ($this->entryCompleted && null === $this->validatedAt && $this->isFullyConfirmed()) {
$this->validatedAt = new DateTimeImmutable();
}
}
#[ORM\PreUpdate]
public function onPreUpdate(): void
{
$this->tryValidate();
}
#[Groups(['reception:read'])]
public function getRegisteredBovineCount(): int
{