From 351801d4ac88f74f4506265dfe3c811a6aa6486e Mon Sep 17 00:00:00 2001 From: Tolotsoa Date: Fri, 22 Aug 2025 01:33:56 +0300 Subject: [PATCH] feat change template facture not vat --- gestion/composer.json | 3 +- gestion/composer.lock | 298 +++++++++++++++- gestion/lib/Exception/TemplateException.php | 7 + gestion/lib/Service/HtmlToPdfService.php | 126 +++++++ gestion/lib/Service/InvoicePdfService.php | 354 ++++++++++++++++++- gestion/templates/pdf/facture_dv_thanato.php | 194 ++++++++++ gestion/vendor/composer/installed.json | 303 ++++++++++++++++ 7 files changed, 1266 insertions(+), 19 deletions(-) create mode 100644 gestion/lib/Exception/TemplateException.php create mode 100644 gestion/lib/Service/HtmlToPdfService.php create mode 100644 gestion/templates/pdf/facture_dv_thanato.php diff --git a/gestion/composer.json b/gestion/composer.json index a4d7aba..3623570 100644 --- a/gestion/composer.json +++ b/gestion/composer.json @@ -15,6 +15,7 @@ "symfony/framework-bundle": "^5.4" }, "require": { - "setasign/fpdf": "^1.8" + "setasign/fpdf": "^1.8", + "dompdf/dompdf": "^3.1" } } diff --git a/gestion/composer.lock b/gestion/composer.lock index 8e93dfa..6ad9006 100644 --- a/gestion/composer.lock +++ b/gestion/composer.lock @@ -4,8 +4,296 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "79912f1c84e373fcd7778fb095176063", + "content-hash": "2cbec79cf4e2f6e464d23e0fd4df0b09", "packages": [ + { + "name": "dompdf/dompdf", + "version": "v3.1.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/dompdf.git", + "reference": "a51bd7a063a65499446919286fb18b518177155a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a", + "reference": "a51bd7a063a65499446919286fb18b518177155a", + "shasum": "" + }, + "require": { + "dompdf/php-font-lib": "^1.0.0", + "dompdf/php-svg-lib": "^1.0.0", + "ext-dom": "*", + "ext-mbstring": "*", + "masterminds/html5": "^2.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "ext-gd": "*", + "ext-json": "*", + "ext-zip": "*", + "mockery/mockery": "^1.3", + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" + }, + "suggest": { + "ext-gd": "Needed to process images", + "ext-gmagick": "Improves image processing performance", + "ext-imagick": "Improves image processing performance", + "ext-zlib": "Needed for pdf stream compression" + }, + "type": "library", + "autoload": { + "psr-4": { + "Dompdf\\": "src/" + }, + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "The Dompdf Community", + "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" + } + ], + "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", + "homepage": "https://github.com/dompdf/dompdf", + "support": { + "issues": "https://github.com/dompdf/dompdf/issues", + "source": "https://github.com/dompdf/dompdf/tree/v3.1.0" + }, + "time": "2025-01-15T14:09:04+00:00" + }, + { + "name": "dompdf/php-font-lib", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "FontLib\\": "src/FontLib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "The FontLib Community", + "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/dompdf/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.1" + }, + "time": "2024-12-02T14:37:59+00:00" + }, + { + "name": "dompdf/php-svg-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "The SvgLib Community", + "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/dompdf/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0" + }, + "time": "2024-04-29T13:26:35+00:00" + }, + { + "name": "masterminds/html5", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "fcf91eb64359852f00d921887b219479b4f21251" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" + }, + "time": "2025-07-25T09:04:22+00:00" + }, + { + "name": "sabberworm/php-css-parser", + "version": "v8.9.0", + "source": { + "type": "git", + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9", + "reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41", + "rawr/cross-data-providers": "^2.0.0" + }, + "suggest": { + "ext-mbstring": "for parsing UTF-8 CSS" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Sabberworm\\CSS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" + } + ], + "description": "Parser for CSS Files written in PHP", + "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", + "keywords": [ + "css", + "parser", + "stylesheet" + ], + "support": { + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0" + }, + "time": "2025-07-11T13:20:48+00:00" + }, { "name": "setasign/fpdf", "version": "1.8.5", @@ -4777,10 +5065,10 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, - "platform": [], - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/gestion/lib/Exception/TemplateException.php b/gestion/lib/Exception/TemplateException.php new file mode 100644 index 0000000..92ead45 --- /dev/null +++ b/gestion/lib/Exception/TemplateException.php @@ -0,0 +1,7 @@ +templatesPath = __DIR__ . '/../../templates/pdf/'; + $this->assetsPath = '/var/www/html/data/admin/files/.gestion/'; + } + + public function generatePdf($templateName, $data, $options = []) + { + try { + $htmlContent = $this->renderPhpTemplate($templateName, $data); + return $this->convertToPdf($htmlContent, $options); + } catch (\Exception $e) { + error_log('HtmlToPdfService Error: ' . $e->getMessage()); + throw new TemplateException('Erreur génération PDF: ' . $e->getMessage()); + } + } + + /** + * Rend un template PHP avec les données + */ + private function renderPhpTemplate($templateName, $data) + { + $templateFile = $this->templatesPath . $templateName . '.php'; + + if (!file_exists($templateFile)) { + throw new TemplateException("Template introuvable: " . $templateFile); + } + + try { + $templateData = array_merge($data, [ + 'logo_base64' => $this->getLogoBase64() + ]); + + extract($templateData); + + ob_start(); + include $templateFile; + return ob_get_clean(); + + } catch (Throwable $e) { + ob_end_clean(); + throw new TemplateException("Erreur lors du rendu du template: " . $e->getMessage(), 0, $e); + } + } + + /** + * Récupère le logo en base64 + */ + private function getLogoBase64() + { + $logoPath = $this->assetsPath . 'logo.png'; + + if (file_exists($logoPath)) { + return base64_encode(file_get_contents($logoPath)); + } + + // Retour d'un pixel transparent si pas de logo + return 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; + } + + /** + * Convertit HTML en PDF + */ + private function convertToPdf($htmlContent, $options = []) + { + $dompdfOptions = new Options(); + $dompdfOptions->set('defaultFont', 'DejaVu Sans'); + $dompdfOptions->set('isRemoteEnabled', true); + $dompdfOptions->set('isHtml5ParserEnabled', true); + $dompdfOptions->set('enable_css_float', true); + $dompdfOptions->set('enable_font_subsetting', true); + + $paper = $options['paper'] ?? 'A4'; + $orientation = $options['orientation'] ?? 'portrait'; + + $dompdf = new Dompdf($dompdfOptions); + $dompdf->loadHtml($htmlContent); + $dompdf->setPaper($paper, $orientation); + $dompdf->render(); + + return $dompdf->output(); + } + + public function generateInvoiceFilename($factureData, $prefix = 'FACTURE') + { + $numero = str_pad($factureData['num'] ?? '', 6, '0', STR_PAD_LEFT); + $month = str_pad($factureData['month'] ?? date('m'), 2, '0', STR_PAD_LEFT); + $year = $factureData['year'] ?? date('Y'); + + return "{$prefix}_{$numero}_{$month}_{$year}.pdf"; + } + + /** + * Debug template PHP + */ + public function debugTemplate($templateName, $data) + { + echo "=== DONNÉES REÇUES ===\n"; + var_dump($data); + + echo "\n=== TEMPLATE PHP UTILISÉ ===\n"; + $templateFile = $this->templatesPath . $templateName . '.php'; + echo "Fichier: $templateFile\n"; + echo "Existe: " . (file_exists($templateFile) ? "OUI" : "NON") . "\n"; + + echo "\n=== HTML GÉNÉRÉ ===\n"; + $html = $this->renderPhpTemplate($templateName, $data); + echo substr($html, 0, 2000) . "...\n"; + + return $html; + } +} diff --git a/gestion/lib/Service/InvoicePdfService.php b/gestion/lib/Service/InvoicePdfService.php index 284898a..62cd532 100644 --- a/gestion/lib/Service/InvoicePdfService.php +++ b/gestion/lib/Service/InvoicePdfService.php @@ -27,19 +27,21 @@ declare(strict_types=1); namespace OCA\Gestion\Service; use DateTime; -use OCA\Gestion\Constants\BddConstant; -use OCA\Gestion\Constants\ClientTemplateTypeConstant; -use OCA\Gestion\Constants\DevisMentionConstant; -use OCA\Gestion\Constants\FactureTypeConstant; -use OCA\Gestion\Constants\MultipleFactureTypeConstant; +use Exception; use OCA\Gestion\Db\Bdd; -use OCA\Gestion\Helpers\DateHelpers; -use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceFunecapPdfHandler; -use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceGroupPdfHandler; -use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceOgfPdfHandler; -use OCA\Gestion\Service\InvoiceRecap\InvoiceRecapService; -use OCP\DB\Exception; use OCP\Files\IRootFolder; +use OCA\Gestion\Helpers\DateHelpers; +use OCA\Gestion\Constants\BddConstant; +use OCA\Gestion\Service\HtmlToPdfService; +use OCA\Gestion\Exception\TemplateException; +use OCA\Gestion\Constants\FactureTypeConstant; +use OCA\Gestion\Constants\DevisMentionConstant; +use OCA\Gestion\Constants\ClientTemplateTypeConstant; +use OCA\Gestion\Constants\MultipleFactureTypeConstant; +use OCA\Gestion\Service\InvoiceRecap\InvoiceRecapService; +use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceOgfPdfHandler; +use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceGroupPdfHandler; +use OCA\Gestion\Service\InvoiceGroupPdfHandler\InvoiceFunecapPdfHandler; class InvoicePdfService { @@ -52,6 +54,8 @@ class InvoicePdfService /** @var InvoiceRecapService */ private $invoiceRecapService; + private $htmlToPdfService; + private const DEFAULT_NEXTCLOUD_ADMIN = "admin"; public function __construct( Bdd $gestionBdd, @@ -61,6 +65,7 @@ class InvoicePdfService $this->gestionBdd = $gestionBdd; $this->rootFolder = $rootFolder; $this->invoiceRecapService = $invoiceRecapService; + $this->htmlToPdfService = new HtmlToPdfService(); } private function getLogo() @@ -174,6 +179,12 @@ class InvoicePdfService if($invoicePdfData == null) { return ""; } + + // NOUVELLE LOGIQUE : Vérifier si TVA exonérée + if ($this->isTvaExempt($invoicePdfData)) { + return $this->generateWithHtmlTemplate($invoicePdfData, $storage); + } + $templateType = $invoicePdfData['template_type_key']; $clean_folder = html_entity_decode(string: $currentConfig->path).'/'; $factureFolders = $this->getGroupFactureFolder($invoicePdfData, $clean_folder); @@ -200,17 +211,20 @@ class InvoicePdfService $pdfContent = $pdf->Output('', 'S'); $pdfFilename = $pdf->GetInvoiceFilename(); $filenames = []; + foreach($factureFolders as $folder) { try { $storage->newFolder($folder); - } catch(\OCP\Files\NotPermittedException $e) { + } catch(TemplateException $e) { + // Ignore si le dossier existe déjà } - $ff_pdf = $folder.$pdfFilename.'.pdf'; + $ff_pdf = $folder.$pdfFilename; $storage->newFile($ff_pdf); $file_pdf = $storage->get($ff_pdf); $file_pdf->putContent($pdfContent); $filenames[] = $ff_pdf; } + $this->gestionBdd->setFactureGeneratedDate($factureId); return [ "content" => $pdfContent, @@ -218,6 +232,19 @@ class InvoicePdfService ]; } + public function sanitizePathDev(string $path): string + { + $path = ltrim($path, '/'); + // Remplacer accents UTF-8 par ASCII + $path = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $path); + // Supprimer caractères interdits par Nextcloud/Docker + $path = preg_replace('#[<>:"/\\|?*]#', '_', $path); + // Supprimer doublons d'espaces + $path = preg_replace('#\s+#', ' ', $path); + return trim($path); + } + + public function generateFacturePdfByFactureIds(array $factureIds, $idNextCloud) { foreach($factureIds as $factureId) { @@ -338,4 +365,305 @@ class InvoicePdfService } } + + /** + * NOUVELLE MÉTHODE : Génération avec template HTML + */ + private function generateWithHtmlTemplate($invoicePdfData, $storage) + { + try { + // Préparer les données pour le template HTML + $templateData = $this->prepareHtmlTemplateData($invoicePdfData); + + // Générer le PDF avec le nouveau système + $pdfContent = $this->htmlToPdfService->generatePdf('facture_dv_thanato', $templateData); + + // Nom du fichier + $pdfFilename = $this->htmlToPdfService->generateInvoiceFilename($invoicePdfData); + + // Sauvegarder dans Nextcloud + $clean_folder = html_entity_decode(string: $invoicePdfData['configuration']->path).'/'; + $factureFolders = $this->getGroupFactureFolder($invoicePdfData, $clean_folder); + $filenames = []; + + foreach ($factureFolders as $folder) { + + // --- GESTION DU CHEMIN --- + if (($_ENV['APP_ENV'] ?? 'prod') === 'dev') { + // En dev : remplacer les accents et caractères spéciaux pour Docker + $relativeFolder = $this->sanitizePathDev($folder); + $pdfFileNameSafe = $this->sanitizePathDev($pdfFilename); + } else { + // En prod : garder UTF-8, juste retirer slash initial + $relativeFolder = ltrim($folder, '/'); + $pdfFileNameSafe = $pdfFilename; + } + + // --- CREATION DU DOSSIER --- + try { + if (!$storage->nodeExists($relativeFolder)) { + $storage->newFolder($relativeFolder); + } + } catch (\Exception $e) { + echo "ERROR creating folder '$relativeFolder': " . $e->getMessage(); + exit; + } + + // --- CHEMIN COMPLET DU FICHIER --- + $ff_pdf = rtrim($relativeFolder, '/') . '/' . $pdfFileNameSafe . '.pdf'; + + // --- CREATION OU MISE A JOUR DU FICHIER --- + try { + if ($storage->nodeExists($ff_pdf)) { + $file_pdf = $storage->get($ff_pdf); + } else { + $file_pdf = $storage->newFile($ff_pdf); + } + $file_pdf->putContent($pdfContent); + $filenames[] = $ff_pdf; + } catch (\Throwable $e) { + echo "ERROR on file '$ff_pdf': " . $e->getMessage(); + exit; + } + } + + $this->gestionBdd->setFactureGeneratedDate($invoicePdfData['id']); + + return [ + "content" => $pdfContent, + "filenames" => $filenames + ]; + + } catch (TemplateException $e) { + error_log('HTML Template PDF Error: ' . $e->getMessage()); + throw $e; + } + } + + /** + * NOUVELLE MÉTHODE : Détecte si TVA exonérée + */ + private function isTvaExempt($invoicePdfData) + { + // Vérifier si c'est un client unique avec TVA = 0 + if (isset($invoicePdfData['fk_client_id']) && $invoicePdfData['fk_client_id'] != null && $invoicePdfData['fk_client_id'] != 0) { + $client = $this->gestionBdd->getClientById($invoicePdfData['fk_client_id']); + if (isset($client['tva']) && $client['tva'] == 0) { + return true; + } + } + + // Vérification alternative dans les totaux si la première méthode ne fonctionne pas + if (isset($invoicePdfData['totalPrices'])) { + foreach ($invoicePdfData['totalPrices'] as $label => $amount) { + if (strpos($label, 'TVA') !== false && (strpos($label, 'exonéré') !== false || $amount == 0)) { + return true; + } + } + } + + return false; + } + + /** + * Prépare les données pour le template HTML - Version refactorisée + */ + private function prepareHtmlTemplateData($invoicePdfData) + { + return [ + 'company' => $this->prepareCompanyData($invoicePdfData), + 'client' => $this->prepareClientData($invoicePdfData), + 'facture' => $this->prepareInvoiceData($invoicePdfData), + 'groupedArticles' => $this->prepareGroupedArticles($invoicePdfData), + 'totals' => $this->prepareTotals($invoicePdfData), + 'bank' => $this->prepareBankData($invoicePdfData), + 'legal_text' => $this->getLegalText() + ]; + } + + /** + * Prépare les données de l'entreprise + */ + private function prepareCompanyData($invoicePdfData) + { + $config = $invoicePdfData['configuration']; + + return [ + 'name' => $config->entreprise ?? 'DV Thanato', + 'address' => $invoicePdfData['configuration_adresse'] ?? '47 rue Boldoduc', + 'city' => $invoicePdfData['configuration_adresse_city'] ?? '59800 Lille', + 'phone' => $config->telephone ?? '06.13.57.29.84', + 'email' => $config->mail ?? 'soins@dvthanato.fr', + 'logo' => 'logo_dv_thanato.png' + ]; + } + + /** + * Prépare les données du client + */ + private function prepareClientData($invoicePdfData) + { + return [ + 'name' => $invoicePdfData['group_name'] ?? '', + 'address' => $invoicePdfData['client_real_adress'] ?? '', + 'city' => $invoicePdfData['client_adress_city'] ?? '', + 'siret' => $invoicePdfData['siret'] ?? '' + ]; + } + + /** + * Prépare les données de la facture + */ + private function prepareInvoiceData($invoicePdfData) + { + $numero = $invoicePdfData['num'] ?? ''; + + return [ + 'date' => date('d-m-Y'), + 'number' => 'FAC' . str_pad((string)$numero, 6, '0', STR_PAD_LEFT), + 'echeance' => date('d-m-Y', strtotime('+30 days')), + 'period_start' => date('d/m/Y', strtotime($invoicePdfData['date'] ?? 'now')), + 'period_end' => date('d/m/Y', strtotime($invoicePdfData['date_paiement'] ?? 'now')) + ]; + } + + /** + * Prépare les articles groupés par date et défunt + */ + private function prepareGroupedArticles($invoicePdfData) + { + if (!isset($invoicePdfData['devis']) || !is_array($invoicePdfData['devis'])) { + return []; + } + + $groupedByDate = []; + + foreach ($invoicePdfData['devis'] as $devis) { + $this->processDevis($devis, $groupedByDate); + } + + return $this->convertToIndexedArray($groupedByDate); + } + + /** + * Traite un devis et l'ajoute aux données groupées + */ + private function processDevis($devis, &$groupedByDate) + { + $dateDevis = date('d/m/Y', strtotime($devis['devis_date'] ?? 'now')); + $defuntNom = $devis['defunt_nom'] ?? 'Non défini'; + + $this->initializeDateGroup($groupedByDate, $dateDevis); + $this->initializeDefuntGroup($groupedByDate, $dateDevis, $defuntNom); + $this->addServicesToDefunt($groupedByDate, $dateDevis, $defuntNom, $devis['products'] ?? []); + } + + /** + * Initialise un groupe de date + */ + private function initializeDateGroup(&$groupedByDate, $dateDevis) + { + if (!isset($groupedByDate[$dateDevis])) { + $groupedByDate[$dateDevis] = [ + 'date' => $dateDevis, + 'defunts' => [] + ]; + } + } + + /** + * Initialise un groupe de défunt + */ + private function initializeDefuntGroup(&$groupedByDate, $dateDevis, $defuntNom) + { + if (!isset($groupedByDate[$dateDevis]['defunts'][$defuntNom])) { + $groupedByDate[$dateDevis]['defunts'][$defuntNom] = [ + 'nom' => $defuntNom, + 'services' => [] + ]; + } + } + + /** + * Ajoute les services à un défunt + */ + private function addServicesToDefunt(&$groupedByDate, $dateDevis, $defuntNom, $products) + { + foreach ($products as $product) { + $service = $this->createServiceFromProduct($product); + $groupedByDate[$dateDevis]['defunts'][$defuntNom]['services'][] = $service; + } + } + + /** + * Crée un service à partir d'un produit + */ + private function createServiceFromProduct($product) + { + $prixHt = ($product['produit_price'] ?? 0) * ($product['quantite'] ?? 1); + + return [ + 'reference' => $product['produit_reference'] ?? '', + 'description' => $product['produit_description'] ?? 'Produit inconnu', + 'prix_ht' => number_format($prixHt, 2, ',', ' '), + 'quantite' => number_format($product['quantite'] ?? 1, 2, ',', ' '), + 'prix_ttc' => number_format($prixHt, 2, ',', ' ') + ]; + } + + /** + * Convertit les données groupées en array indexé + */ + private function convertToIndexedArray($groupedByDate) + { + $groupedArticles = []; + + foreach ($groupedByDate as $dateGroup) { + $defuntsArray = array_values($dateGroup['defunts']); + $dateGroup['defunts'] = $defuntsArray; + $groupedArticles[] = $dateGroup; + } + + return $groupedArticles; + } + + /** + * Prépare les totaux + */ + private function prepareTotals($invoicePdfData) + { + $totalPrices = $invoicePdfData['totalPrices'] ?? []; + + return [ + 'total_ht' => number_format($totalPrices['TOTAL HT'] ?? 0, 2, ',', ' '), + 'total_tva' => '0,00', + 'total_ttc' => number_format($totalPrices['TOTAL TTC'] ?? 0, 2, ',', ' '), + 'tva_label' => 'TVA (exonéré)' + ]; + } + + /** + * Prépare les données bancaires + */ + private function prepareBankData($invoicePdfData) + { + $config = $invoicePdfData['configuration']; + + return [ + 'iban' => 'FR76 1670 6052 4453 9757 9734 871', + 'swift' => 'AGRI FR PP867', + 'rcs' => $config->legal_one ?? '901 115 931 R.C.S Lille Métropole' + ]; + } + + /** + * Texte légal + */ + private function getLegalText() + { + return "Tout retard de paiement entraînera de plein droit une pénalité de retard de 3 fois le taux légal " . + "(Loi 2008-776 du 4 août 2008) et une indemnité forfaitaire de 40 EUR pour frais de recouvrement sera appliquée.\n" . + "Si les frais de recouvrement sont supérieurs à ce montant forfaitaire, une indemnisation complémentaire " . + "sera due sur présentation de justificatifs (articles L 441-3 et L 441-6 du code de commerce)."; + } } diff --git a/gestion/templates/pdf/facture_dv_thanato.php b/gestion/templates/pdf/facture_dv_thanato.php new file mode 100644 index 0000000..6a4b1d7 --- /dev/null +++ b/gestion/templates/pdf/facture_dv_thanato.php @@ -0,0 +1,194 @@ + + + + + Facture DV Thanato + + + +
+ +
+ +
+ + + + + + + +
+
+
+ Date : +
+
+ Échéance : +
+
+ Mode de paiement :Virement +
+
+
+
+ +
+
+ + SIRET: + +
+
+ + +
+

Facture

+
Période : du au
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RéférenceLibelléP.U HTQuantitéMontant HT
+ + +
+ + + + + + + + + + + + + +
Total HT
Montant total
+
+ +
+ + + +
+ + \ No newline at end of file diff --git a/gestion/vendor/composer/installed.json b/gestion/vendor/composer/installed.json index ef7af36..36e4e3e 100644 --- a/gestion/vendor/composer/installed.json +++ b/gestion/vendor/composer/installed.json @@ -125,6 +125,240 @@ ], "install-path": "../doctrine/instantiator" }, + { + "name": "dompdf/dompdf", + "version": "v3.1.0", + "version_normalized": "3.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/dompdf.git", + "reference": "a51bd7a063a65499446919286fb18b518177155a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a", + "reference": "a51bd7a063a65499446919286fb18b518177155a", + "shasum": "" + }, + "require": { + "dompdf/php-font-lib": "^1.0.0", + "dompdf/php-svg-lib": "^1.0.0", + "ext-dom": "*", + "ext-mbstring": "*", + "masterminds/html5": "^2.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "ext-gd": "*", + "ext-json": "*", + "ext-zip": "*", + "mockery/mockery": "^1.3", + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" + }, + "suggest": { + "ext-gd": "Needed to process images", + "ext-gmagick": "Improves image processing performance", + "ext-imagick": "Improves image processing performance", + "ext-zlib": "Needed for pdf stream compression" + }, + "time": "2025-01-15T14:09:04+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Dompdf\\": "src/" + }, + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "The Dompdf Community", + "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" + } + ], + "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", + "homepage": "https://github.com/dompdf/dompdf", + "support": { + "issues": "https://github.com/dompdf/dompdf/issues", + "source": "https://github.com/dompdf/dompdf/tree/v3.1.0" + }, + "install-path": "../dompdf/dompdf" + }, + { + "name": "dompdf/php-font-lib", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" + }, + "time": "2024-12-02T14:37:59+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "FontLib\\": "src/FontLib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "The FontLib Community", + "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/dompdf/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.1" + }, + "install-path": "../dompdf/php-font-lib" + }, + { + "name": "dompdf/php-svg-lib", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" + }, + "time": "2024-04-29T13:26:35+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "The SvgLib Community", + "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/dompdf/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0" + }, + "install-path": "../dompdf/php-svg-lib" + }, + { + "name": "masterminds/html5", + "version": "2.10.0", + "version_normalized": "2.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "fcf91eb64359852f00d921887b219479b4f21251" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "time": "2025-07-25T09:04:22+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" + }, + "install-path": "../masterminds/html5" + }, { "name": "myclabs/deep-copy", "version": "1.11.0", @@ -1318,6 +1552,75 @@ }, "install-path": "../psr/log" }, + { + "name": "sabberworm/php-css-parser", + "version": "v8.9.0", + "version_normalized": "8.9.0.0", + "source": { + "type": "git", + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9", + "reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41", + "rawr/cross-data-providers": "^2.0.0" + }, + "suggest": { + "ext-mbstring": "for parsing UTF-8 CSS" + }, + "time": "2025-07-11T13:20:48+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Sabberworm\\CSS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" + } + ], + "description": "Parser for CSS Files written in PHP", + "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", + "keywords": [ + "css", + "parser", + "stylesheet" + ], + "support": { + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0" + }, + "install-path": "../sabberworm/php-css-parser" + }, { "name": "sebastian/cli-parser", "version": "1.0.1",