'Janvier', 2 => 'Février', 3 => 'Mars', 4 => 'Avril', 5 => 'Mai', 6 => 'Juin', 7 => 'Juillet', 8 => 'Août', 9 => 'Septembre', 10 => 'Octobre', 11 => 'Novembre', 12 => 'Décembre', ]; public function __construct( private Environment $twig, private EntityManagerInterface $entityManager, private BovinApiInterface $bovinApi, ) {} /** * @throws RuntimeError * @throws SyntaxError * @throws LoaderError */ public function provide(Operation $operation, array $uriVariables = [], array $context = []): Response { $id = $uriVariables['id'] ?? null; if (null === $id) { throw new NotFoundHttpException('Case not found.'); } $buildingCase = $this->entityManager->getRepository(BuildingCase::class)->find($id); if (!$buildingCase instanceof BuildingCase) { throw new NotFoundHttpException('Case not found.'); } $rows = []; $firstArrivalDate = null; $headerBreedCode = null; foreach ($buildingCase->getBovines() as $bovine) { if (!$bovine instanceof Bovine) { continue; } $workNumber = null; $birthDate = null; $breedCode = null; try { $animalFileDto = $this->bovinApi->getAnimalFile( nationalNumber: $bovine->getNationalNumber(), countryCode: 'FR', ); $workNumber = $animalFileDto->identification?->workNumber; $birthDate = $animalFileDto->identification?->birthDate?->date?->format('d/m/y'); $breedCode = $this->normalizeBreedCode($animalFileDto->identification?->breedType); if (null === $headerBreedCode && null !== $breedCode) { $headerBreedCode = $breedCode; } } catch (Throwable) { // Keep row data even if external identification service is unavailable. } $arrivalDate = $bovine->getArrivalDate(); if ($arrivalDate instanceof DateTimeImmutable && null === $firstArrivalDate) { $firstArrivalDate = $arrivalDate; } $projectedWeights = $this->buildProjectedWeights( $bovine->getReceivedWeight(), $arrivalDate, $breedCode, ); $rows[] = [ 'nationalNumber' => $bovine->getNationalNumber(), 'workNumber' => $workNumber, 'birthDate' => $birthDate, 'receivedWeight' => $bovine->getReceivedWeight(), 'arrivalDate' => $bovine->getArrivalDate()?->format('d/m/Y'), 'projectedWeights' => $projectedWeights, ]; } $monthHeaders = $this->buildMonthHeaders($firstArrivalDate, $headerBreedCode); $dompdf = new Dompdf(); $html = $this->twig->render('case_weights_report.html.twig', [ 'buildingCase' => $buildingCase, 'rows' => $rows, 'monthHeaders' => $monthHeaders, 'printedAt' => new DateTimeImmutable(), ]); $dompdf->loadHtml($html); $dompdf->setPaper('A4', 'landscape'); $dompdf->render(); $filename = sprintf('tableau-poids-case-%d.pdf', $buildingCase->getId()); return new Response($dompdf->output(), Response::HTTP_OK, [ 'Content-Type' => 'application/pdf', 'Content-Disposition' => 'inline; filename="'.$filename.'"', ]); } private function normalizeBreedCode(mixed $breedType): ?string { if (null === $breedType) { return null; } if (is_numeric($breedType)) { return (string) $breedType; } if (is_string($breedType) && preg_match('/\d+/', $breedType, $matches)) { return $matches[0]; } return null; } private function resolveDailyGainKg(?string $breedCode): float { return 1.3; } /** * @return array */ private function buildProjectedWeights(?int $receivedWeight, ?DateTimeImmutable $arrivalDate, ?string $breedCode): array { $result = array_fill(0, 12, null); if (null === $receivedWeight || !$arrivalDate instanceof DateTimeImmutable) { return $result; } $currentWeight = (float) $receivedWeight; $dailyGainKg = $this->resolveDailyGainKg($breedCode); for ($i = 0; $i < 12; ++$i) { $monthDate = $arrivalDate->modify('first day of this month')->modify(sprintf('+%d month', $i)); $daysInMonth = (int) $monthDate->format('t'); $daysToApply = 0 === $i ? max($daysInMonth - (int) $arrivalDate->format('j'), 0) : $daysInMonth; $currentWeight += $daysToApply * $dailyGainKg; $result[$i] = $currentWeight; } return $result; } /** * @return array */ private function buildMonthHeaders(?DateTimeImmutable $arrivalDate, ?string $breedCode): array { $referenceDate = $arrivalDate ?? new DateTimeImmutable('first day of january this year'); $dailyGainKg = $this->resolveDailyGainKg($breedCode); $headers = []; for ($i = 0; $i < 12; ++$i) { $monthDate = $referenceDate->modify('first day of this month')->modify(sprintf('+%d month', $i)); $monthIndex = (int) $monthDate->format('n'); $daysInMonth = (int) $monthDate->format('t'); $daysToApply = 0 === $i ? max($daysInMonth - (int) $referenceDate->format('j'), 0) : $daysInMonth; $headers[] = [ 'name' => self::FRENCH_MONTHS[$monthIndex], 'days' => sprintf('%d jours', $daysToApply), 'baseValue' => $daysToApply * $dailyGainKg, ]; } return $headers; } }