diff --git a/gestion/lib/Service/Devis/DevisDataProcessor.php b/gestion/lib/Service/Devis/DevisDataProcessor.php index fcb84b7..a440c38 100644 --- a/gestion/lib/Service/Devis/DevisDataProcessor.php +++ b/gestion/lib/Service/Devis/DevisDataProcessor.php @@ -63,11 +63,24 @@ class DevisDataProcessor { $produits = json_decode($this->gestionBdd->getListProduit($devis['devis_id'], $idNextCloud)); + // Variables pour gérer les articles comme dans les factures + $produitsReferenceArray = []; + foreach ($produits as $produit) { $htPrice = $this->getProductPrice($produit, $devis, $filter); $devis_temp['montant_htc'] += $htPrice * $produit->quantite; + + // Collecter les références comme dans les factures + if (isset($produit->reference) && !empty($produit->reference)) { + $produitsReferenceArray[] = $produit->reference; + } } + // Traitement identique aux factures + $produitsReferenceArray = array_unique($produitsReferenceArray); + $produitsReferenceAsString = implode("-", $produitsReferenceArray); + $devis_temp['article'] = !empty($produitsReferenceAsString) ? $produitsReferenceAsString : 'SOINS'; + $devis_temp['montant_tva'] = ($devis_temp['montant_htc'] * $devis_temp['tva']) / 100; $devis_temp['montant_ttc'] = $devis_temp['montant_tva'] + $devis_temp['montant_htc']; diff --git a/gestion/lib/Service/Devis/DevisPdfGenerator.php b/gestion/lib/Service/Devis/DevisPdfGenerator.php index 11036c6..d3979fb 100644 --- a/gestion/lib/Service/Devis/DevisPdfGenerator.php +++ b/gestion/lib/Service/Devis/DevisPdfGenerator.php @@ -82,8 +82,8 @@ class DevisPdfGenerator private function calculatePagination($totalItems) { return [ - 'nb_pages' => ceil($totalItems / 26), - 'items_per_page' => 26, + 'nb_pages' => ceil($totalItems / 12), // RÉDUIRE à 12 par page + 'items_per_page' => 12, 'current_index' => 0 ]; } diff --git a/gestion/lib/Service/Devis/DevisPdfLayoutManager.php b/gestion/lib/Service/Devis/DevisPdfLayoutManager.php index c58db49..a80a2a6 100644 --- a/gestion/lib/Service/Devis/DevisPdfLayoutManager.php +++ b/gestion/lib/Service/Devis/DevisPdfLayoutManager.php @@ -21,7 +21,7 @@ class DevisPdfLayoutManager public function addPageHeader($pdf, $config, $address, $city) { if ($this->doesLogoExist()) { - $pdf->Image($this->defaultImagePath."logo.png", 10, 10, 75, 25); + $pdf->Image($this->defaultImagePath."logo.png", 10, 10, 25, 0); } $this->addCompanyInfo($pdf, $config, $address, $city); } diff --git a/gestion/lib/Service/Devis/DevisPdfTableRenderer.php b/gestion/lib/Service/Devis/DevisPdfTableRenderer.php index 5475d87..b2b36ae 100644 --- a/gestion/lib/Service/Devis/DevisPdfTableRenderer.php +++ b/gestion/lib/Service/Devis/DevisPdfTableRenderer.php @@ -6,19 +6,23 @@ class DevisPdfTableRenderer { public function createDevisTable($pdf, $dataDevis, $config) { - // Extraction des paramètres du tableau de configuration $pagination = $config['pagination']; $itemsToProcess = $config['itemsToProcess']; $numPage = $config['numPage']; $nbPage = $config['nbPage']; - $totals = &$config['totals']; // Référence pour modification - $sansMontant = $config['sansMontant'] ?? false; // false par défaut = afficher les montants + $totals = &$config['totals']; + $sansMontant = $config['sansMontant'] ?? false; + + // Système de pagination comme les factures + $maxItemsPerPage = 22; // Nombre maximum d'éléments par page + $startIndex = $pagination['current_index']; + $itemsThisPage = min($itemsToProcess, count($dataDevis) - $startIndex); $this->drawTableStructure($pdf, $numPage, $nbPage, $sansMontant); $this->addTableHeaders($pdf, $sansMontant); - $this->populateTableData($pdf, $dataDevis, $pagination['current_index'], $itemsToProcess, $totals, $sansMontant); + $this->populateTableData($pdf, $dataDevis, $startIndex, $itemsThisPage, $totals, $sansMontant); - // Afficher les totaux seulement sur la dernière page ET si les montants sont affichés + // Totaux seulement sur la dernière page if ($numPage == $nbPage && !$sansMontant) { $this->addTableTotals($pdf, $totals); } @@ -30,15 +34,14 @@ class DevisPdfTableRenderer $pdf->Rect(5, 105, 200, 130, "D"); $pdf->Line(5, 115, 205, 115); - // Si c'est la dernière page ET qu'on affiche les montants, ligne de total à 225 $endY = ($numPage == $nbPage && !$sansMontant) ? 225 : 235; if (!$sansMontant) { // AVEC montants : toutes les colonnes - $verticalLines = [25, 45, 70, 90, 125, 155, 175, 190]; + $verticalLines = [25, 45, 65, 80, 100, 125, 145, 165, 185]; } else { - // SANS montants : seulement jusqu'à Défunt - $verticalLines = [35, 70, 105, 125, 155]; + // SANS montants : SUPPRIMER la colonne vide à droite + $verticalLines = [35, 70, 105, 120, 135, 160]; // Seulement 6 lignes au lieu de 7 } foreach ($verticalLines as $x) { @@ -48,36 +51,37 @@ class DevisPdfTableRenderer private function addTableHeaders($pdf, $sansMontant) { - $pdf->SetFont('Arial', 'B', 8); + $pdf->SetFont('Arial', 'B', 7); if (!$sansMontant) { - // AVEC montants $headers = [ - [5, 20, mb_convert_encoding(html_entity_decode("N° Devis"), 'ISO-8859-1', 'UTF-8')], - [25, 20, mb_convert_encoding(html_entity_decode("N° Dossier"), 'ISO-8859-1', 'UTF-8')], - [45, 25, mb_convert_encoding(html_entity_decode("N° Commande"), 'ISO-8859-1', 'UTF-8')], - [70, 20, "Date"], - [90, 35, "Lieu du soin"], - [125, 30, \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport("Défunt")], - [155, 20, "H.T."], - [175, 15, "TVA 20%"], - [190, 15, "T.T.C"] + [5, 20, "N° Devis"], + [25, 20, "N° Dossier"], + [45, 20, "N° Commande"], + [65, 15, "Date"], + [80, 20, "Article"], + [100, 25, "Lieu du soin"], + [125, 20, "Défunt"], + [145, 20, "H.T."], + [165, 20, "TVA"], + [185, 20, "T.T.C"] ]; } else { - // SANS montants - colonnes plus larges + // SANS montants : SUPPRIMER la colonne vide, agrandir la dernière colonne $headers = [ - [5, 30, mb_convert_encoding(html_entity_decode("N° Devis"), 'ISO-8859-1', 'UTF-8')], - [35, 35, mb_convert_encoding(html_entity_decode("N° Dossier"), 'ISO-8859-1', 'UTF-8')], - [70, 35, mb_convert_encoding(html_entity_decode("N° Commande"), 'ISO-8859-1', 'UTF-8')], - [105, 20, "Date"], - [125, 30, "Lieu du soin"], - [155, 50, \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport("Défunt")] + [5, 30, "N° Devis"], + [35, 35, "N° Dossier"], + [70, 35, "N° Commande"], + [105, 15, "Date"], + [120, 15, "Article"], + [135, 25, "Lieu du soin"], + [160, 45, "Défunt"] // Dernière colonne plus large ]; } foreach ($headers as $header) { - $pdf->SetXY($header[0], 106); - $pdf->Cell($header[1], 8, $header[2], 0, 0, 'C'); + $pdf->SetXY($header[0] + 1, 106); + $pdf->Cell($header[1] - 2, 8, mb_convert_encoding($header[2], 'ISO-8859-1', 'UTF-8'), 0, 0, 'C'); } } @@ -101,7 +105,7 @@ class DevisPdfTableRenderer $totals['ttc'] += $devis['montant_ttc']; } - $yDevis += 5; + $yDevis += 10; } } @@ -109,64 +113,101 @@ class DevisPdfTableRenderer { $pdf->SetFont('Arial', '', 7); - if (!$sansMontant) { - // AVEC montants - $rowData = [ - [6, 18, $devis['devis_full_number']], - [26, 18, $devis['calendar_uuid']], - [46, 23, $devis['num_commande']], - [71, 18, mb_convert_encoding($formatterDate->format($dateSoin), 'ISO-8859-1', 'UTF-8')], - [91, 33, \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['lieu_nom'] ?? '')], // ← CORRECTION - [126, 28, \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['defunt_nom'] ?? '')], // ← CORRECTION - [156, 18, number_format($devis['montant_htc'], 2, '.', '') . chr(128), 'C'], - [176, 13, number_format($devis['montant_tva'], 2, '.', '') . chr(128), 'C'], - [191, 13, number_format($devis['montant_ttc'], 2, '.', '') . chr(128), 'C'] - ]; - } else { - // SANS montants - colonnes plus larges - $rowData = [ - [6, 28, $devis['devis_full_number']], - [36, 33, $devis['calendar_uuid']], - [71, 33, $devis['num_commande']], - [106, 18, mb_convert_encoding($formatterDate->format($dateSoin), 'ISO-8859-1', 'UTF-8')], - [126, 28, \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['lieu_nom'] ?? '')], // ← CORRECTION - [156, 48, \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['defunt_nom'] ?? '')] // ← CORRECTION - ]; - } + // Fonction généraliste pour gérer automatiquement le débordement + $addSmartCell = function ($pdf, $x, $y, $width, $text, $align = 'L') use ($yDevis) { + $textWidth = $pdf->GetStringWidth($text); + $maxWidth = $width - 2; // Marge de sécurité - foreach ($rowData as $data) { - $pdf->SetXY($data[0], $yDevis); - $align = isset($data[3]) ? $data[3] : ''; - $pdf->Cell($data[1], 5, $data[2], 0, 0, $align); + if ($textWidth > $maxWidth && strlen($text) > 10) { + // DÉBORDEMENT : utiliser MultiCell pour affichage complet + $pdf->SetXY($x, $y); + $pdf->MultiCell($width, 2.5, $text, 0, $align); + } else { + // PAS DE DÉBORDEMENT : utiliser Cell normal + $pdf->SetXY($x, $y); + $pdf->Cell($width, 5, $text, 0, 0, $align); + } + }; + + if (!$sansMontant) { + // N° Devis + $addSmartCell($pdf, 6, $yDevis, 18, $devis['devis_full_number']); + + // N° Dossier - GESTION AUTOMATIQUE + $addSmartCell($pdf, 26, $yDevis, 18, $devis['calendar_uuid']); + + // N° Commande - GESTION AUTOMATIQUE + $addSmartCell($pdf, 46, $yDevis, 18, $devis['num_commande']); + + // Date + $addSmartCell($pdf, 66, $yDevis, 13, mb_convert_encoding($formatterDate->format($dateSoin), 'ISO-8859-1', 'UTF-8')); + + // Article - GESTION AUTOMATIQUE + $articleText = \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['article'] ?? 'SOINS'); + $addSmartCell($pdf, 81, $yDevis, 18, $articleText); + + // Lieu du soin - GESTION AUTOMATIQUE + $lieuText = \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['lieu_nom'] ?? ''); + $addSmartCell($pdf, 101, $yDevis, 23, $lieuText); + + // Défunt - GESTION AUTOMATIQUE + $defuntText = \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['defunt_nom'] ?? ''); + $addSmartCell($pdf, 126, $yDevis, 18, $defuntText); + + // Montants - Toujours centrés + $addSmartCell($pdf, 146, $yDevis, 18, number_format($devis['montant_htc'], 2, '.', '') . chr(128), 'C'); + $addSmartCell($pdf, 166, $yDevis, 18, number_format($devis['montant_tva'], 2, '.', '') . chr(128), 'C'); + $addSmartCell($pdf, 186, $yDevis, 18, number_format($devis['montant_ttc'], 2, '.', '') . chr(128), 'C'); + } else { + // Mode sans montants - POSITIONS AJUSTÉES + $addSmartCell($pdf, 6, $yDevis, 28, $devis['devis_full_number']); + + $addSmartCell($pdf, 36, $yDevis, 33, $devis['calendar_uuid']); + + $addSmartCell($pdf, 71, $yDevis, 33, $devis['num_commande']); + + $addSmartCell($pdf, 106, $yDevis, 13, mb_convert_encoding($formatterDate->format($dateSoin), 'ISO-8859-1', 'UTF-8')); + + $articleText = \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['article'] ?? 'SOINS'); + $addSmartCell($pdf, 121, $yDevis, 13, $articleText); + + $lieuText = \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['lieu_nom'] ?? ''); + $addSmartCell($pdf, 136, $yDevis, 23, $lieuText); + + // Défunt - DERNIÈRE COLONNE plus large (45 au lieu de 23) + $defuntText = \OCA\Gestion\Helpers\FileExportHelpers::FormatTextForExport($devis['defunt_nom'] ?? ''); + $addSmartCell($pdf, 161, $yDevis, 44, $defuntText); // Plus large pour remplir l'espace } } private function addTableTotals($pdf, $totals) { - // Cette méthode n'est appelée que si on affiche les montants (!$sansMontant) $pdf->Line(5, 225, 205, 225); $pdf->SetFont('Arial', 'B', 8); $pdf->SetXY(5, 225); - $pdf->Cell(150, 8, 'TOTAL', 0, 0, 'C'); - $pdf->SetXY(156, 225); - $pdf->Cell(18, 8, number_format($totals['ht'], 2, '.', '') . chr(128), 0, 0, 'C'); - $pdf->SetXY(176, 225); - $pdf->Cell(13, 8, number_format($totals['tva'], 2, '.', '') . chr(128), 0, 0, 'C'); - $pdf->SetXY(191, 225); - $pdf->Cell(13, 8, number_format($totals['ttc'], 2, '.', '') . chr(128), 0, 0, 'C'); + $pdf->Cell(130, 8, 'TOTAL', 0, 0, 'C'); - $pdf->SetXY(170, 240); + // POSITIONS CORRIGÉES + $pdf->SetXY(136, 225); + $pdf->Cell(18, 8, number_format($totals['ht'], 2, '.', '') . chr(128), 0, 0, 'C'); + $pdf->SetXY(156, 225); + $pdf->Cell(18, 8, number_format($totals['tva'], 2, '.', '') . chr(128), 0, 0, 'C'); + $pdf->SetXY(176, 225); + $pdf->Cell(14, 8, number_format($totals['ttc'], 2, '.', '') . chr(128), 0, 0, 'C'); + + // TOTAL TTC + $pdf->SetXY(155, 240); $pdf->Cell(20, 8, 'TOTAL TTC', 0, 0, 'C'); - $pdf->SetXY(190, 240); - $pdf->Cell(15, 8, number_format($totals['ttc'], 2, '.', '') . chr(128), 0, 0, 'C'); + $pdf->SetXY(176, 240); + $pdf->Cell(14, 8, number_format($totals['ttc'], 2, '.', '') . chr(128), 0, 0, 'C'); $lines = [ - [170, 240, 170, 248], + [155, 240, 155, 248], + [176, 240, 176, 248], [190, 240, 190, 248], - [205, 240, 205, 248], - [170, 240, 205, 240], - [170, 248, 205, 248] + [155, 240, 190, 240], + [155, 248, 190, 248] ]; foreach ($lines as $line) { diff --git a/gestion/lib/Service/Devis/DevisRecapService.php b/gestion/lib/Service/Devis/DevisRecapService.php index 5f23efa..5f5befc 100644 --- a/gestion/lib/Service/Devis/DevisRecapService.php +++ b/gestion/lib/Service/Devis/DevisRecapService.php @@ -42,6 +42,7 @@ class DevisRecapService $currentConfig = $configs[0]; $devisData = $this->getDevisData($filter, $month, $year, $currentConfig, $filterType); + if (empty($devisData)) { return null; }