> */ private array $rows = []; /** @var list */ private array $columns = []; /** @var array */ private array $columnWidths = []; public function __construct( private readonly KernelInterface $kernel, string $documentTitle, string $periodFrom, string $periodTo, ) { parent::__construct(); $this->documentTitle = $documentTitle; $this->periodFrom = $periodFrom; $this->periodTo = $periodTo; $this->SetTitle($this->enc($documentTitle)); $this->SetAuthor($this->enc('Association E-Cosplay')); $this->SetCreator('CRM E-Cosplay'); } /** * @param list> $rows */ public function setData(array $rows): void { $this->rows = $rows; if (!empty($rows)) { $this->columns = array_keys($rows[0]); $this->columnWidths = $this->computeColumnWidths(); } } public function generate(): void { $this->AliasNbPages(); $this->AddPage('L'); $this->writeContextBlock(); $this->writeDataTable(); $this->writeSummary(); $this->writeSignatureBlock(); } // --------------------------------------------------------------- // Header / Footer // --------------------------------------------------------------- public function Header(): void { $logo = $this->kernel->getProjectDir().'/public/logo.jpg'; if (file_exists($logo)) { $this->Image($logo, 10, 8, 40); } // Titre du document $this->SetFont('Arial', 'B', 16); $this->SetXY(60, 10); $this->Cell(0, 8, $this->enc(mb_strtoupper($this->documentTitle)), 0, 1, 'L'); // Periode $this->SetFont('Arial', '', 10); $this->SetXY(60, 18); $this->Cell(0, 5, $this->enc('Periode : du '.$this->periodFrom.' au '.$this->periodTo), 0, 1, 'L'); // Date de generation $formatter = new \IntlDateFormatter( 'fr_FR', \IntlDateFormatter::FULL, \IntlDateFormatter::NONE, 'Europe/Paris', \IntlDateFormatter::GREGORIAN ); $this->SetXY(60, 23); $this->SetFont('Arial', '', 9); $this->SetTextColor(100, 100, 100); $this->Cell(0, 5, $this->enc('Genere le '.$formatter->format(new \DateTime())), 0, 1, 'L'); $this->SetTextColor(0, 0, 0); $this->Ln(5); } public function Footer(): void { $this->SetY(-20); $this->SetDrawColor(253, 140, 4); $this->Line(15, $this->GetY(), $this->GetPageWidth() - 15, $this->GetY()); $this->Ln(3); $this->SetFont('Arial', '', 7); $this->SetTextColor(0, 0, 0); $this->Cell(0, 3, $this->enc('42 rue de Saint-Quentin - 02800 BEAUTOR - Tel: 06 79 34 88 02 - contact@e-cosplay.fr - www.e-cosplay.fr'), 0, 1, 'C'); $this->Cell(0, 3, $this->enc('Association E-Cosplay - N SIRET 943 121 517 00011 - CODE APE 9329Z - RNA W022006988'), 0, 1, 'C'); $this->SetFont('Arial', 'I', 7); $this->SetTextColor(150, 150, 150); $this->Cell(0, 3, $this->enc('Page ').$this->PageNo().' / {nb}', 0, 0, 'C'); } // --------------------------------------------------------------- // Bloc legal / contextuel // --------------------------------------------------------------- private function writeContextBlock(): void { $this->SetY(35); $labelW = 55; $dataW = 120; // Ligne superieure $this->SetDrawColor(200, 200, 200); $this->Cell(0, 0.5, '', 'T', 1, 'L'); $this->Ln(2); $this->SetFont('Arial', 'B', 10); $this->Cell(0, 5, $this->enc('INFORMATIONS LEGALES ET CONTEXTUELLES'), 0, 1, 'C'); $this->Ln(1); $this->SetFont('Arial', '', 9); // Association / RNA $this->Cell($labelW, 5, $this->enc('Association :'), 0, 0, 'L'); $this->SetFont('Arial', 'B', 9); $this->Cell($dataW, 5, $this->enc('E-Cosplay Association loi 1901 - RNA N W022006988'), 0, 1, 'L'); $this->SetFont('Arial', '', 9); // Siege social $this->Cell($labelW, 5, $this->enc('Siege social :'), 0, 0, 'L'); $this->Cell($dataW, 5, $this->enc('42 rue de Saint-Quentin 02800 Beautor'), 0, 1, 'L'); // SIRET $this->Cell($labelW, 5, $this->enc('SIRET :'), 0, 0, 'L'); $this->Cell($dataW, 5, $this->enc('943 121 517 00011'), 0, 1, 'L'); // Code APE $this->Cell($labelW, 5, $this->enc('Code APE :'), 0, 0, 'L'); $this->Cell($dataW, 5, $this->enc('9329Z'), 0, 1, 'L'); // Document $this->Cell($labelW, 5, $this->enc('Document :'), 0, 0, 'L'); $this->SetFont('Arial', 'B', 9); $this->Cell($dataW, 5, $this->enc($this->documentTitle), 0, 1, 'L'); $this->SetFont('Arial', '', 9); // Periode $this->Cell($labelW, 5, $this->enc('Periode comptable :'), 0, 0, 'L'); $this->Cell($dataW, 5, $this->enc('Du '.$this->periodFrom.' au '.$this->periodTo), 0, 1, 'L'); // Ligne inferieure $this->Ln(2); $this->Cell(0, 0.5, '', 'T', 1, 'L'); $this->Ln(3); } // --------------------------------------------------------------- // Tableau de donnees // --------------------------------------------------------------- private function writeDataTable(): void { if (empty($this->rows)) { $this->SetFont('Arial', '', 11); $this->Cell(0, 10, $this->enc('Aucune donnee sur cette periode.'), 0, 1, 'C'); return; } // En-tete du tableau $this->SetFont('Arial', 'B', 7); $this->SetFillColor(35, 35, 35); $this->SetTextColor(255, 255, 255); foreach ($this->columns as $col) { $w = $this->columnWidths[$col] ?? 25; $this->Cell($w, 6, $this->enc($col), 1, 0, 'C', true); } $this->Ln(); $this->SetTextColor(0, 0, 0); // Donnees $this->SetFont('Arial', '', 7); $fill = false; foreach ($this->rows as $row) { // Verifier si on a besoin d'une nouvelle page if ($this->GetY() + 5 > $this->GetPageHeight() - 30) { $this->AddPage('L'); $this->SetY(35); // Re-dessiner l'en-tete du tableau $this->SetFont('Arial', 'B', 7); $this->SetFillColor(35, 35, 35); $this->SetTextColor(255, 255, 255); foreach ($this->columns as $col) { $w = $this->columnWidths[$col] ?? 25; $this->Cell($w, 6, $this->enc($col), 1, 0, 'C', true); } $this->Ln(); $this->SetTextColor(0, 0, 0); $this->SetFont('Arial', '', 7); $fill = false; } $this->SetFillColor(245, 245, 240); foreach ($this->columns as $col) { $w = $this->columnWidths[$col] ?? 25; $value = $row[$col] ?? ''; $align = $this->isNumericColumn($col) ? 'R' : 'L'; $this->Cell($w, 5, $this->enc($value), 'B', 0, $align, $fill); } $this->Ln(); $fill = !$fill; } $this->Ln(3); } // --------------------------------------------------------------- // Resume / totaux // --------------------------------------------------------------- private function writeSummary(): void { $this->SetFont('Arial', 'B', 9); $this->Cell(0, 6, $this->enc('Total : '.\count($this->rows).' ecriture(s)'), 0, 1, 'L'); // Si colonnes Debit/Credit, afficher les totaux $totalDebit = 0.0; $totalCredit = 0.0; $hasDebitCredit = false; foreach ($this->rows as $row) { if (isset($row['Debit'])) { $totalDebit += (float) $row['Debit']; $hasDebitCredit = true; } if (isset($row['Credit'])) { $totalCredit += (float) $row['Credit']; } // Grand livre / balance if (isset($row['MontantHT'])) { $totalDebit += (float) $row['MontantHT']; } } if ($hasDebitCredit) { $this->SetFont('Arial', '', 9); $this->Cell(60, 5, $this->enc('Total Debit : '.number_format($totalDebit, 2, ',', ' ')).' '.EURO, 0, 0, 'L'); $this->Cell(60, 5, $this->enc('Total Credit : '.number_format($totalCredit, 2, ',', ' ')).' '.EURO, 0, 1, 'L'); } $this->Ln(5); } // --------------------------------------------------------------- // Bloc signature (champ DocuSeal) // --------------------------------------------------------------- private function writeSignatureBlock(): void { // S'assurer qu'on a assez de place if ($this->GetY() + 45 > $this->GetPageHeight() - 25) { $this->AddPage('L'); $this->SetY(35); } $this->SetDrawColor(200, 200, 200); $this->Cell(0, 0.5, '', 'T', 1, 'L'); $this->Ln(3); $formatter = new \IntlDateFormatter( 'fr_FR', \IntlDateFormatter::LONG, \IntlDateFormatter::NONE, 'Europe/Paris', \IntlDateFormatter::GREGORIAN ); $this->SetFont('Arial', '', 9); $this->Cell(0, 5, $this->enc('Fait a Beautor, le '.$formatter->format(new \DateTime())), 0, 1, 'L'); $this->Ln(2); $this->SetFont('Arial', 'B', 9); $this->Cell(0, 5, $this->enc('Signature du responsable :'), 0, 1, 'L'); $this->Ln(1); // Champ signature DocuSeal (meme format que DevisPdf) $this->SetAutoPageBreak(false); $this->SetFont('Arial', '', 10); $this->SetTextColor(0, 0, 0); $this->Cell(60, 20, '{{Sign;type=signature;role=First Party}}', 0, 1, 'L'); } // --------------------------------------------------------------- // Helpers // --------------------------------------------------------------- /** * @return array */ private function computeColumnWidths(): array { if (empty($this->columns)) { return []; } $pageWidth = 277; // A4 landscape - margins $widths = []; // Colonnes connues avec taille fixe $known = [ 'JournalCode' => 15, 'JournalLib' => 28, 'EcritureNum' => 22, 'EcritureDate' => 20, 'CompteNum' => 25, 'CompteLib' => 35, 'CompAuxNum' => 22, 'CompAuxLib' => 30, 'PieceRef' => 22, 'PieceDate' => 20, 'EcritureLib' => 45, 'Debit' => 18, 'Credit' => 18, 'Lettrage' => 14, 'DateLettrage' => 20, 'ValidDate' => 20, 'MontantDevise' => 18, 'Idevise' => 12, 'EcrtureLet' => 14, 'DateLet' => 18, 'Montantdevise' => 18, 'Solde' => 18, 'CodeJournal' => 15, 'Statut' => 16, 'MethodePaiement' => 24, 'DatePaiement' => 20, 'CodeComptable' => 25, 'Client' => 40, 'NumFacture' => 25, 'DateFacture' => 20, 'MontantHT' => 20, 'MontantTVA' => 20, 'MontantTTC' => 20, 'JoursRetard' => 16, 'Tranche' => 22, 'DateReglement' => 22, 'CompteBanque' => 20, ]; $usedWidth = 0; $unknownCols = []; foreach ($this->columns as $col) { if (isset($known[$col])) { $widths[$col] = $known[$col]; $usedWidth += $known[$col]; } else { $unknownCols[] = $col; } } // Distribuer l'espace restant aux colonnes inconnues if (!empty($unknownCols)) { $remaining = max($pageWidth - $usedWidth, \count($unknownCols) * 15); $each = (int) floor($remaining / \count($unknownCols)); foreach ($unknownCols as $col) { $widths[$col] = $each; } } return $widths; } private function isNumericColumn(string $col): bool { return \in_array($col, [ 'Debit', 'Credit', 'Solde', 'MontantHT', 'MontantTVA', 'MontantTTC', 'MontantDevise', 'Montantdevise', 'JoursRetard', ], true); } private function enc(string $text): string { return mb_convert_encoding($text, 'Windows-1252', 'UTF-8'); } }