feat : étape 2/5 - endpoint POST /bovines/sync-inventory
- Appelle BovinApiInterface::getInventory() puis upsert local par nationalNumber
- Marque exitedAt sur les bovins absents de la réponse EDNOTIF
- Retourne les stats { created, updated, exited, total }
- Admin only
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
42
src/ApiResource/BovineSyncInventoryResult.php
Normal file
42
src/ApiResource/BovineSyncInventoryResult.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\ApiResource;
|
||||||
|
|
||||||
|
use ApiPlatform\Metadata\ApiProperty;
|
||||||
|
use ApiPlatform\Metadata\ApiResource;
|
||||||
|
use ApiPlatform\Metadata\Post;
|
||||||
|
use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation;
|
||||||
|
use App\State\Bovin\BovineSyncInventoryProcessor;
|
||||||
|
|
||||||
|
#[ApiResource(
|
||||||
|
operations: [
|
||||||
|
new Post(
|
||||||
|
uriTemplate: '/bovines/sync-inventory',
|
||||||
|
openapi: new OpenApiOperation(
|
||||||
|
summary: "Synchronise l'inventaire bovin local avec EDNOTIF.",
|
||||||
|
description: 'Upsert des bovins par numéro national ; marque comme sortis ceux absents de la réponse EDNOTIF.',
|
||||||
|
tags: ['Bovines'],
|
||||||
|
),
|
||||||
|
security: "is_granted('ROLE_ADMIN')",
|
||||||
|
input: false,
|
||||||
|
output: self::class,
|
||||||
|
processor: BovineSyncInventoryProcessor::class,
|
||||||
|
read: false,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)]
|
||||||
|
final class BovineSyncInventoryResult
|
||||||
|
{
|
||||||
|
#[ApiProperty(identifier: true)]
|
||||||
|
public string $id = 'current';
|
||||||
|
|
||||||
|
public int $created = 0;
|
||||||
|
|
||||||
|
public int $updated = 0;
|
||||||
|
|
||||||
|
public int $exited = 0;
|
||||||
|
|
||||||
|
public int $total = 0;
|
||||||
|
}
|
||||||
99
src/State/Bovin/BovineSyncInventoryProcessor.php
Normal file
99
src/State/Bovin/BovineSyncInventoryProcessor.php
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\State\Bovin;
|
||||||
|
|
||||||
|
use ApiPlatform\Metadata\Operation;
|
||||||
|
use ApiPlatform\State\ProcessorInterface;
|
||||||
|
use App\ApiResource\BovineSyncInventoryResult;
|
||||||
|
use App\Entity\Bovine;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Api\BovinApiInterface;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\AnimalSummaryDto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements ProcessorInterface<mixed, BovineSyncInventoryResult>
|
||||||
|
*/
|
||||||
|
final class BovineSyncInventoryProcessor implements ProcessorInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private BovinApiInterface $bovinApi,
|
||||||
|
private EntityManagerInterface $em,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function process(
|
||||||
|
mixed $data,
|
||||||
|
Operation $operation,
|
||||||
|
array $uriVariables = [],
|
||||||
|
array $context = [],
|
||||||
|
): BovineSyncInventoryResult {
|
||||||
|
$inventory = $this->bovinApi->getInventory(new DateTimeImmutable('2000-01-01'));
|
||||||
|
|
||||||
|
$result = new BovineSyncInventoryResult();
|
||||||
|
$result->total = count($inventory->animals);
|
||||||
|
|
||||||
|
$existingByNationalNumber = [];
|
||||||
|
foreach ($this->em->getRepository(Bovine::class)->findAll() as $bovine) {
|
||||||
|
$existingByNationalNumber[$bovine->getNationalNumber()] = $bovine;
|
||||||
|
}
|
||||||
|
|
||||||
|
$seen = [];
|
||||||
|
foreach ($inventory->animals as $animal) {
|
||||||
|
$nationalNumber = $animal->identification?->bovin?->nationalNumber;
|
||||||
|
if (null === $nationalNumber || '' === $nationalNumber) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$seen[$nationalNumber] = true;
|
||||||
|
|
||||||
|
if (isset($existingByNationalNumber[$nationalNumber])) {
|
||||||
|
$bovine = $existingByNationalNumber[$nationalNumber];
|
||||||
|
++$result->updated;
|
||||||
|
} else {
|
||||||
|
$bovine = new Bovine();
|
||||||
|
$bovine->setNationalNumber($nationalNumber);
|
||||||
|
$this->em->persist($bovine);
|
||||||
|
++$result->created;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->applyEdnotifData($bovine, $animal);
|
||||||
|
$bovine->setExitedAt(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
foreach ($existingByNationalNumber as $nationalNumber => $bovine) {
|
||||||
|
if (isset($seen[$nationalNumber])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (null !== $bovine->getExitedAt()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$bovine->setExitedAt($now);
|
||||||
|
++$result->exited;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyEdnotifData(Bovine $bovine, AnimalSummaryDto $animal): void
|
||||||
|
{
|
||||||
|
$identification = $animal->identification;
|
||||||
|
if (null !== $identification) {
|
||||||
|
$bovine->setSex($identification->sex);
|
||||||
|
$bovine->setBreedCode($identification->breedType);
|
||||||
|
$bovine->setWorkNumber($identification->workNumber);
|
||||||
|
$bovine->setBirthDate($identification->birthDate?->date);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($animal->presencePeriods as $period) {
|
||||||
|
if (null === $period->exit && null !== $period->entry?->date) {
|
||||||
|
$bovine->setArrivalDate($period->entry->date);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user