Compare commits
8 Commits
develop
...
b390dd51de
| Author | SHA1 | Date | |
|---|---|---|---|
| b390dd51de | |||
| 754898da39 | |||
| 5b24d642bb | |||
| b932798a87 | |||
| ee766311e3 | |||
| 2f8aa1dd32 | |||
| de76a77120 | |||
| 642ee43c53 |
@@ -1,2 +1,2 @@
|
|||||||
parameters:
|
parameters:
|
||||||
app.version: '0.0.101'
|
app.version: '0.0.99'
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ interface BovineMovementData {
|
|||||||
enteredAt: string
|
enteredAt: string
|
||||||
leftAt: string | null
|
leftAt: string | null
|
||||||
buildingCase: BuildingCaseRef | null
|
buildingCase: BuildingCaseRef | null
|
||||||
|
building: BuildingRef | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BovinePassportData {
|
interface BovinePassportData {
|
||||||
@@ -300,7 +301,7 @@ const movementRows = computed(() => {
|
|||||||
const list = bovine.value?.movements ?? []
|
const list = bovine.value?.movements ?? []
|
||||||
return list.map(m => ({
|
return list.map(m => ({
|
||||||
id: m.id,
|
id: m.id,
|
||||||
building: m.buildingCase?.building?.label ?? '—',
|
building: m.buildingCase?.building?.label ?? m.building?.label ?? '—',
|
||||||
case: m.buildingCase?.caseNumber != null ? `Case ${m.buildingCase.caseNumber}` : '—',
|
case: m.buildingCase?.caseNumber != null ? `Case ${m.buildingCase.caseNumber}` : '—',
|
||||||
enteredAt: formatDate(m.enteredAt),
|
enteredAt: formatDate(m.enteredAt),
|
||||||
leftAt: m.leftAt ? formatDate(m.leftAt) : null,
|
leftAt: m.leftAt ? formatDate(m.leftAt) : null,
|
||||||
|
|||||||
@@ -125,7 +125,7 @@
|
|||||||
{{ formatDate(item.arrivalDate) }}
|
{{ formatDate(item.arrivalDate) }}
|
||||||
</template>
|
</template>
|
||||||
<template #cell-buildingCase.building.label="{ item }">
|
<template #cell-buildingCase.building.label="{ item }">
|
||||||
{{ item.buildingCase?.building?.label ?? '—' }}
|
{{ item.effectiveBuilding?.label ?? '—' }}
|
||||||
</template>
|
</template>
|
||||||
<template #cell-buildingCase.caseNumber="{ item }">
|
<template #cell-buildingCase.caseNumber="{ item }">
|
||||||
{{ item.buildingCase?.caseNumber ?? '—' }}
|
{{ item.buildingCase?.caseNumber ?? '—' }}
|
||||||
|
|||||||
@@ -9,3 +9,34 @@ export async function createBovine(payload: BovinePayload) {
|
|||||||
toastSuccessKey: 'success.bovine.create'
|
toastSuccessKey: 'success.bovine.create'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createBovines(nationalNumbers: string[]): Promise<{ created: BovineData[]; errors: string[] }> {
|
||||||
|
const created: BovineData[] = []
|
||||||
|
const errors: string[] = []
|
||||||
|
|
||||||
|
for (const nationalNumber of nationalNumbers) {
|
||||||
|
try {
|
||||||
|
const bovine = await createBovine({ nationalNumber })
|
||||||
|
if (bovine) {
|
||||||
|
created.push(bovine)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
errors.push(nationalNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { created, errors }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getBovine(id: number) {
|
||||||
|
const api = useApi()
|
||||||
|
return api.get<BovineData>(`bovines/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateBovine(id: number, payload: BovinePayload) {
|
||||||
|
const api = useApi()
|
||||||
|
return api.patch<BovineData>(`bovines/${id}`, payload, {
|
||||||
|
toastErrorKey: 'errors.bovine.update',
|
||||||
|
toastSuccessKey: 'success.bovine.update'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ export interface BovineData {
|
|||||||
arrivalDate: string | null
|
arrivalDate: string | null
|
||||||
exitDate: string | null
|
exitDate: string | null
|
||||||
buildingCase: BovineBuildingCaseRef | null
|
buildingCase: BovineBuildingCaseRef | null
|
||||||
|
building: BovineBuildingRef | null
|
||||||
|
effectiveBuilding: BovineBuildingRef | null
|
||||||
supplier: string | null
|
supplier: string | null
|
||||||
workNumber: string | null
|
workNumber: string | null
|
||||||
birthDate: string | null
|
birthDate: string | null
|
||||||
@@ -27,5 +29,9 @@ export interface BovineData {
|
|||||||
|
|
||||||
export type BovinePayload = {
|
export type BovinePayload = {
|
||||||
nationalNumber?: string
|
nationalNumber?: string
|
||||||
|
receivedWeight?: number | null
|
||||||
|
pricePerKg?: number | null
|
||||||
|
arrivalDate?: string | null
|
||||||
buildingCase?: string | null
|
buildingCase?: string | null
|
||||||
|
supplier?: string | null
|
||||||
}
|
}
|
||||||
|
|||||||
93
src/Command/BackfillBovineMovementsCommand.php
Normal file
93
src/Command/BackfillBovineMovementsCommand.php
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Entity\Bovine;
|
||||||
|
use App\Entity\BovineMovement;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
use function count;
|
||||||
|
|
||||||
|
#[AsCommand(
|
||||||
|
name: 'app:backfill-bovine-movements',
|
||||||
|
description: 'Crée un mouvement initial pour chaque bovin ayant une case ou un bâtiment mais aucun mouvement enregistré.'
|
||||||
|
)]
|
||||||
|
class BackfillBovineMovementsCommand extends Command
|
||||||
|
{
|
||||||
|
private const FLUSH_EVERY = 100;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly EntityManagerInterface $entityManager,
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
|
||||||
|
$bovines = $this->entityManager->createQueryBuilder()
|
||||||
|
->select('b')
|
||||||
|
->from(Bovine::class, 'b')
|
||||||
|
->where('b.buildingCase IS NOT NULL OR b.building IS NOT NULL')
|
||||||
|
->andWhere('NOT EXISTS (SELECT 1 FROM '.BovineMovement::class.' m WHERE m.bovine = b)')
|
||||||
|
->getQuery()
|
||||||
|
->getResult()
|
||||||
|
;
|
||||||
|
|
||||||
|
$total = count($bovines);
|
||||||
|
if (0 === $total) {
|
||||||
|
$io->success('Aucun bovin à backfiller.');
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->info(sprintf('%d bovin(s) à backfiller.', $total));
|
||||||
|
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
$created = 0;
|
||||||
|
$fallback = 0;
|
||||||
|
|
||||||
|
foreach ($bovines as $i => $bovine) {
|
||||||
|
$movement = new BovineMovement();
|
||||||
|
$movement->setBovine($bovine);
|
||||||
|
|
||||||
|
if (null !== $bovine->getBuildingCase()) {
|
||||||
|
$movement->setBuildingCase($bovine->getBuildingCase());
|
||||||
|
} else {
|
||||||
|
$movement->setBuilding($bovine->getBuilding());
|
||||||
|
}
|
||||||
|
|
||||||
|
$enteredAt = $bovine->getArrivalDate();
|
||||||
|
if (null === $enteredAt) {
|
||||||
|
$enteredAt = $now;
|
||||||
|
++$fallback;
|
||||||
|
}
|
||||||
|
$movement->setEnteredAt($enteredAt);
|
||||||
|
|
||||||
|
$this->entityManager->persist($movement);
|
||||||
|
++$created;
|
||||||
|
|
||||||
|
if (0 === ($i + 1) % self::FLUSH_EVERY) {
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$io->success(sprintf('%d mouvement(s) créé(s).', $created));
|
||||||
|
if ($fallback > 0) {
|
||||||
|
$io->warning(sprintf("%d bovin(s) sans date d'arrivée → enteredAt = maintenant.", $fallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
215
src/Command/FeedBovinePricesCommand.php
Normal file
215
src/Command/FeedBovinePricesCommand.php
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Entity\Bovine;
|
||||||
|
use App\Entity\Building;
|
||||||
|
use App\Entity\Supplier;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
#[AsCommand(
|
||||||
|
name: 'app:feed-bovine-prices',
|
||||||
|
description: 'Met à jour le poids, le prix au kilo et le fournisseur des bovins existants depuis un fichier XLSX.'
|
||||||
|
)]
|
||||||
|
final class FeedBovinePricesCommand extends Command
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private EntityManagerInterface $em,
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->addArgument('file', InputArgument::REQUIRED, 'Chemin absolu vers le fichier XLSX')
|
||||||
|
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Simule sans persister en BDD')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
$file = (string) $input->getArgument('file');
|
||||||
|
$dryRun = (bool) $input->getOption('dry-run');
|
||||||
|
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
$io->error(sprintf('Fichier introuvable : %s', $file));
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->title('Feed bovins depuis '.basename($file));
|
||||||
|
if ($dryRun) {
|
||||||
|
$io->warning('Dry-run activé : aucune écriture en BDD.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$spreadsheet = IOFactory::load($file);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$io->error('Impossible de lire le fichier : '.$e->getMessage());
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
$highestRow = $sheet->getHighestRow();
|
||||||
|
|
||||||
|
// Pré-chargement des fournisseurs pour des lookups rapides (insensible casse).
|
||||||
|
$supplierByName = [];
|
||||||
|
foreach ($this->em->getRepository(Supplier::class)->findAll() as $supplier) {
|
||||||
|
$supplierByName[mb_strtoupper($supplier->getName())] = $supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pré-chargement des bâtiments par code (insensible casse).
|
||||||
|
$buildingByCode = [];
|
||||||
|
foreach ($this->em->getRepository(Building::class)->findAll() as $building) {
|
||||||
|
$buildingByCode[mb_strtoupper($building->getCode())] = $building;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bovineRepo = $this->em->getRepository(Bovine::class);
|
||||||
|
|
||||||
|
$stats = [
|
||||||
|
'total' => 0,
|
||||||
|
'updated' => 0,
|
||||||
|
'notFound' => 0,
|
||||||
|
'invalid' => 0,
|
||||||
|
'supplierMissing' => 0,
|
||||||
|
'buildingMissing' => 0,
|
||||||
|
];
|
||||||
|
$missingNationalNumbers = [];
|
||||||
|
$missingSuppliers = [];
|
||||||
|
$missingBuildings = [];
|
||||||
|
|
||||||
|
$io->progressStart($highestRow);
|
||||||
|
for ($row = 1; $row <= $highestRow; ++$row) {
|
||||||
|
++$stats['total'];
|
||||||
|
|
||||||
|
$rawNationalNumber = (string) ($sheet->getCell([1, $row])->getValue() ?? '');
|
||||||
|
$rawSupplier = (string) ($sheet->getCell([2, $row])->getValue() ?? '');
|
||||||
|
$rawWeight = $sheet->getCell([3, $row])->getValue();
|
||||||
|
$rawPrice = $sheet->getCell([4, $row])->getValue();
|
||||||
|
$rawBuilding = (string) ($sheet->getCell([5, $row])->getValue() ?? '');
|
||||||
|
|
||||||
|
$rawNationalNumber = trim($rawNationalNumber);
|
||||||
|
if ('' === $rawNationalNumber) {
|
||||||
|
++$stats['invalid'];
|
||||||
|
$io->progressAdvance();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Garde : strip "FR" + espace optionnel uniquement s'il est présent.
|
||||||
|
$nationalNumber = preg_replace('/^FR\s*/i', '', $rawNationalNumber);
|
||||||
|
|
||||||
|
$bovine = $bovineRepo->findOneBy(['nationalNumber' => $nationalNumber]);
|
||||||
|
if (null === $bovine) {
|
||||||
|
++$stats['notFound'];
|
||||||
|
$missingNationalNumbers[] = $nationalNumber;
|
||||||
|
$io->progressAdvance();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup supplier (peut être null si introuvable ou colonne vide).
|
||||||
|
$supplier = null;
|
||||||
|
$supplierName = mb_strtoupper(trim($rawSupplier));
|
||||||
|
if ('' !== $supplierName) {
|
||||||
|
$supplier = $supplierByName[$supplierName] ?? null;
|
||||||
|
if (null === $supplier) {
|
||||||
|
++$stats['supplierMissing'];
|
||||||
|
$missingSuppliers[$supplierName] = ($missingSuppliers[$supplierName] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$weight = is_numeric($rawWeight) ? (int) $rawWeight : null;
|
||||||
|
$price = is_numeric($rawPrice) ? (float) $rawPrice : null;
|
||||||
|
|
||||||
|
if (null !== $weight) {
|
||||||
|
$bovine->setReceivedWeight($weight);
|
||||||
|
}
|
||||||
|
if (null !== $price) {
|
||||||
|
$bovine->setPricePerKg($price);
|
||||||
|
}
|
||||||
|
$bovine->setSupplier($supplier);
|
||||||
|
|
||||||
|
// Bâtiment direct : on n'écrase pas une affectation à une case existante.
|
||||||
|
$buildingCode = mb_strtoupper(trim($rawBuilding));
|
||||||
|
if ('' !== $buildingCode && null === $bovine->getBuildingCase()) {
|
||||||
|
$building = $buildingByCode[$buildingCode] ?? null;
|
||||||
|
if (null !== $building) {
|
||||||
|
$bovine->setBuilding($building);
|
||||||
|
} else {
|
||||||
|
++$stats['buildingMissing'];
|
||||||
|
$missingBuildings[$buildingCode] = ($missingBuildings[$buildingCode] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++$stats['updated'];
|
||||||
|
$io->progressAdvance();
|
||||||
|
}
|
||||||
|
$io->progressFinish();
|
||||||
|
|
||||||
|
if (!$dryRun) {
|
||||||
|
$this->em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->section('Résultats');
|
||||||
|
$io->table(
|
||||||
|
['Métrique', 'Valeur'],
|
||||||
|
[
|
||||||
|
['Lignes totales', $stats['total']],
|
||||||
|
['Bovins mis à jour', $stats['updated']],
|
||||||
|
['Bovins introuvables', $stats['notFound']],
|
||||||
|
['Lignes invalides', $stats['invalid']],
|
||||||
|
['Fournisseurs introuvables (supplier=null)', $stats['supplierMissing']],
|
||||||
|
['Bâtiments introuvables (building non set)', $stats['buildingMissing']],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ([] !== $missingNationalNumbers) {
|
||||||
|
$preview = array_slice($missingNationalNumbers, 0, 10);
|
||||||
|
$io->warning(sprintf(
|
||||||
|
'%d bovin(s) introuvable(s). Aperçu : %s%s',
|
||||||
|
count($missingNationalNumbers),
|
||||||
|
implode(', ', $preview),
|
||||||
|
count($missingNationalNumbers) > 10 ? '…' : '',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([] !== $missingSuppliers) {
|
||||||
|
$list = [];
|
||||||
|
foreach ($missingSuppliers as $name => $count) {
|
||||||
|
$list[] = sprintf('%s (%d)', $name, $count);
|
||||||
|
}
|
||||||
|
$io->warning('Fournisseurs introuvables (bovins rattachés en null) : '.implode(', ', $list));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([] !== $missingBuildings) {
|
||||||
|
$list = [];
|
||||||
|
foreach ($missingBuildings as $code => $count) {
|
||||||
|
$list[] = sprintf('%s (%d)', $code, $count);
|
||||||
|
}
|
||||||
|
$io->warning('Bâtiments introuvables (champ non renseigné) : '.implode(', ', $list));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dryRun) {
|
||||||
|
$io->success('Dry-run terminé. Relance sans --dry-run pour persister.');
|
||||||
|
} else {
|
||||||
|
$io->success('Feed terminé avec succès.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -96,6 +96,11 @@ class Bovine
|
|||||||
#[ApiProperty(readableLink: true)]
|
#[ApiProperty(readableLink: true)]
|
||||||
private ?BuildingCase $buildingCase = null;
|
private ?BuildingCase $buildingCase = null;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne]
|
||||||
|
#[Groups(['bovine:read'])]
|
||||||
|
#[ApiProperty(readableLink: true)]
|
||||||
|
private ?Building $building = null;
|
||||||
|
|
||||||
#[ORM\ManyToOne]
|
#[ORM\ManyToOne]
|
||||||
#[Groups(['bovine:read', 'bovine:write', 'building_case:read'])]
|
#[Groups(['bovine:read', 'bovine:write', 'building_case:read'])]
|
||||||
private ?Supplier $supplier = null;
|
private ?Supplier $supplier = null;
|
||||||
@@ -239,6 +244,28 @@ class Bovine
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBuilding(): ?Building
|
||||||
|
{
|
||||||
|
return $this->building;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBuilding(?Building $building): static
|
||||||
|
{
|
||||||
|
$this->building = $building;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bâtiment effectif d'un bovin : la case affectée si elle existe (logique
|
||||||
|
* historique), sinon le bâtiment direct (fed depuis l'XLSX initial).
|
||||||
|
*/
|
||||||
|
#[Groups(['bovine:read', 'building_case:read'])]
|
||||||
|
public function getEffectiveBuilding(): ?Building
|
||||||
|
{
|
||||||
|
return $this->buildingCase?->getIdBuilding() ?? $this->building;
|
||||||
|
}
|
||||||
|
|
||||||
public function getSupplier(): ?Supplier
|
public function getSupplier(): ?Supplier
|
||||||
{
|
{
|
||||||
return $this->supplier;
|
return $this->supplier;
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ class BovineMovement
|
|||||||
#[ApiProperty(readableLink: true)]
|
#[ApiProperty(readableLink: true)]
|
||||||
private ?BuildingCase $buildingCase = null;
|
private ?BuildingCase $buildingCase = null;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne]
|
||||||
|
#[Groups(['bovine:read'])]
|
||||||
|
#[ApiProperty(readableLink: true)]
|
||||||
|
private ?Building $building = null;
|
||||||
|
|
||||||
#[ORM\Column(type: 'datetime_immutable')]
|
#[ORM\Column(type: 'datetime_immutable')]
|
||||||
#[Groups(['bovine:read', 'bovine_movement:write'])]
|
#[Groups(['bovine:read', 'bovine_movement:write'])]
|
||||||
private DateTimeImmutable $enteredAt;
|
private DateTimeImmutable $enteredAt;
|
||||||
@@ -81,6 +86,18 @@ class BovineMovement
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBuilding(): ?Building
|
||||||
|
{
|
||||||
|
return $this->building;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBuilding(?Building $building): static
|
||||||
|
{
|
||||||
|
$this->building = $building;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function getEnteredAt(): DateTimeImmutable
|
public function getEnteredAt(): DateTimeImmutable
|
||||||
{
|
{
|
||||||
return $this->enteredAt;
|
return $this->enteredAt;
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ final class BovineInventoryExportProvider implements ProviderInterface
|
|||||||
$type = $bovine->getBovineType();
|
$type = $bovine->getBovineType();
|
||||||
$isLim = self::BREED_CODE_LIMOUSINE === $type?->getCode();
|
$isLim = self::BREED_CODE_LIMOUSINE === $type?->getCode();
|
||||||
$isCharo = self::BREED_CODE_CHAROLAISE === $type?->getCode();
|
$isCharo = self::BREED_CODE_CHAROLAISE === $type?->getCode();
|
||||||
$building = $bovine->getBuildingCase()?->getIdBuilding();
|
$building = $bovine->getBuildingCase()?->getIdBuilding() ?? $bovine->getBuilding();
|
||||||
$code = $building?->getCode();
|
$code = $building?->getCode();
|
||||||
|
|
||||||
$sheet->setCellValue('A'.$row, $isLim ? 'X' : '');
|
$sheet->setCellValue('A'.$row, $isLim ? 'X' : '');
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ final class BovineMovementProcessor implements ProcessorInterface
|
|||||||
$enteredAt = $data->hasEnteredAt() ? $data->getEnteredAt() : new DateTimeImmutable();
|
$enteredAt = $data->hasEnteredAt() ? $data->getEnteredAt() : new DateTimeImmutable();
|
||||||
$data->setEnteredAt($enteredAt);
|
$data->setEnteredAt($enteredAt);
|
||||||
$data->setLeftAt(null);
|
$data->setLeftAt(null);
|
||||||
|
$data->setBuilding(null);
|
||||||
|
|
||||||
$bovine = $data->getBovine();
|
$bovine = $data->getBovine();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user