From ab07cd4a3bcd8f673ae1ac1e9f93274d2836f188 Mon Sep 17 00:00:00 2001 From: ordinarthur <@arthurbarre.js@gmail.com> Date: Thu, 14 May 2026 02:16:45 +0200 Subject: [PATCH] =?UTF-8?q?feat(invoices):=20g=C3=A9n=C3=A9ration=20PDF=20?= =?UTF-8?q?native=20via=20@react-pdf/renderer=20(Phase=202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implémente les 4 thèmes de factures (Classique, Moderne, Minimal, Élégant) en composants React PDF et remplace les stubs Phase 1 par la vraie génération + upload MinIO. Templates (app/pdf-templates/) - common.tsx : props partagées, formatters fr-FR (cents → euros, dates longues, taux TVA), palette neutre. - classique : sobre, header texte centré, filets fins. Pour les cabinets et professions réglementées. - moderne : bandeau coloré pleine largeur, logo dans le bandeau. Pour les agences et studios. - minimal : noir et blanc, aéré, accent uniquement sur le numéro. Pour les indépendants et les designers. - elegant : Times Roman, filets fins, titre centré encadré, italique sur le pied légal. Pour les boutiques premium. - index.tsx : dispatcher slug → composant + renderInvoiceToBuffer. Génération - media_storage : nouveau scope `invoice-pdf` (`invoices//.pdf`) et fonction `uploadBuffer(buffer, scope, subPath?)` pour stocker les buffers générés en mémoire (vs. uploads multipart existants). - invoice_pdf : `generateInvoicePdf` rend + upload, `previewInvoicePdf` rend en Buffer pour stream HTTP direct. - InvoicesController.pdf : lazy regenerate si pdf_storage_key est null sur une facture native (cas où la génération initiale a échoué). - InvoicesController.previewPdf : synthétise un clientSnapshot depuis les données live, passe dans le pipeline standard. - InvoicesController.storeNative : appelle la vraie génération en post-commit, log + continue si échec. Conformité Factur-X (V1.5) : la structure de génération est un point d'extension Buffer → Buffer ; l'injection d'un XML CII en pièce jointe PDF sera ajoutée sans toucher aux templates. Co-Authored-By: Claude Opus 4.7 --- .../app/controllers/invoices_controller.ts | 97 ++++-- apps/api/app/pdf-templates/classique.tsx | 289 ++++++++++++++++++ apps/api/app/pdf-templates/common.tsx | 148 +++++++++ apps/api/app/pdf-templates/elegant.tsx | 286 +++++++++++++++++ apps/api/app/pdf-templates/index.tsx | 51 ++++ apps/api/app/pdf-templates/minimal.tsx | 230 ++++++++++++++ apps/api/app/pdf-templates/moderne.tsx | 269 ++++++++++++++++ apps/api/app/services/invoice_pdf.ts | 114 +++++-- apps/api/app/services/media_storage.ts | 58 +++- apps/api/package.json | 1 + 10 files changed, 1488 insertions(+), 55 deletions(-) create mode 100644 apps/api/app/pdf-templates/classique.tsx create mode 100644 apps/api/app/pdf-templates/common.tsx create mode 100644 apps/api/app/pdf-templates/elegant.tsx create mode 100644 apps/api/app/pdf-templates/index.tsx create mode 100644 apps/api/app/pdf-templates/minimal.tsx create mode 100644 apps/api/app/pdf-templates/moderne.tsx diff --git a/apps/api/app/controllers/invoices_controller.ts b/apps/api/app/controllers/invoices_controller.ts index 8a4165b..4ec7506 100644 --- a/apps/api/app/controllers/invoices_controller.ts +++ b/apps/api/app/controllers/invoices_controller.ts @@ -353,12 +353,17 @@ export default class InvoicesController { } /** - * GET /invoices/:id/pdf — stream le PDF/image originel de la facture. + * GET /invoices/:id/pdf — stream le PDF (généré ou uploadé) de la facture. * - * Source : `pdfStorageKey` propagé depuis le draft d'import lors de la - * validation. 404 si la facture n'a pas de fichier (saisie manuelle). - * Auth : Bearer (vérifié sur l'org). Le SPA fetch via api.fetchBlob - * puis affiche dans un