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/<orgId>/<uuid>.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 <noreply@anthropic.com>
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
/**
|
|
* pdf-templates — dispatcher : sélectionne le bon thème et rend en Buffer.
|
|
*
|
|
* Le code applicatif (`#services/invoice_pdf`) appelle `renderInvoiceToBuffer`
|
|
* qui :
|
|
* 1. Choisit le composant React selon `themeSlug`
|
|
* 2. Le rend en PDF via `@react-pdf/renderer.renderToBuffer`
|
|
* 3. Retourne le Buffer prêt à être uploadé sur MinIO ou streamé
|
|
*
|
|
* Les 4 thèmes consomment tous le même `InvoiceTemplateProps` (cf. common.tsx),
|
|
* ce qui permet d'ajouter ou de remplacer un thème sans toucher au dispatcher.
|
|
*/
|
|
|
|
import React from 'react'
|
|
import { renderToBuffer, type DocumentProps } from '@react-pdf/renderer'
|
|
import {
|
|
type InvoiceTemplateProps,
|
|
type InvoiceThemeSlug,
|
|
} from '#pdf-templates/common'
|
|
import { ClassiqueTemplate } from '#pdf-templates/classique'
|
|
import { ModerneTemplate } from '#pdf-templates/moderne'
|
|
import { MinimalTemplate } from '#pdf-templates/minimal'
|
|
import { ElegantTemplate } from '#pdf-templates/elegant'
|
|
|
|
/** Mapping slug → composant. Source de vérité du dispatcher. */
|
|
const THEMES: Record<
|
|
InvoiceThemeSlug,
|
|
(props: InvoiceTemplateProps) => React.ReactElement<DocumentProps>
|
|
> = {
|
|
classique: ClassiqueTemplate,
|
|
moderne: ModerneTemplate,
|
|
minimal: MinimalTemplate,
|
|
elegant: ElegantTemplate,
|
|
}
|
|
|
|
/**
|
|
* Rend la facture en PDF (Buffer).
|
|
*
|
|
* @param themeSlug Slug du thème — fallback "classique" si inconnu (defensive).
|
|
* @param props Données passées au template (cf. InvoiceTemplateProps).
|
|
*/
|
|
export async function renderInvoiceToBuffer(
|
|
themeSlug: InvoiceThemeSlug,
|
|
props: InvoiceTemplateProps
|
|
): Promise<Buffer> {
|
|
const Template = THEMES[themeSlug] ?? THEMES.classique
|
|
const element = Template(props)
|
|
return await renderToBuffer(element)
|
|
}
|
|
|
|
export type { InvoiceTemplateProps, InvoiceThemeSlug }
|