Inventaire : Module de Facturation Actuel
Ce document liste tous les endpoints, modèles DB, et flux existants du module de facturation avant l'implémentation du plan d'amélioration.
Date de création : 2024-12-19
But : Comprendre l'état actuel avant refactoring
1. Endpoints API Existants
Controller : InvoicesController (/invoices)
GET /invoices- Liste toutes les factures de l'utilisateur (paginé)POST /invoices- Créer une nouvelle factureGET /invoices/:id- Récupérer une facture par IDPUT /invoices/:id- Mettre à jour une factureGET /invoices/:id/export?format=pdf|docx- Exporter une facture (PDF ou Word)GET /invoices/:id/pdf- Générer le PDF d'une facturePOST /invoices/:id/preview-email- Prévisualiser l'email de facturePOST /invoices/:id/send-email- Envoyer une facture par email
Controller : QuotesInvoicesController (/sessions/:sessionId/quotes-invoices)
Quotes
GET /sessions/:sessionId/quotes-invoices/quotes- Liste les devis d'une sessionGET /sessions/:sessionId/quotes-invoices/quotes/:id- Récupérer un devisPOST /sessions/:sessionId/quotes-invoices/quotes- Créer un devisPUT /sessions/:sessionId/quotes-invoices/quotes/:id- Mettre à jour un devisDELETE /sessions/:sessionId/quotes-invoices/quotes/:id- Supprimer un devisGET /sessions/:sessionId/quotes-invoices/quotes/:id/pdf- PDF du devisPOST /sessions/:sessionId/quotes-invoices/quotes/:id/preview-email- Prévisualiser email devisPOST /sessions/:sessionId/quotes-invoices/quotes/:id/send-email- Envoyer devis par email
Invoices (via session)
GET /sessions/:sessionId/quotes-invoices/invoices- Liste les factures d'une sessionPOST /sessions/:sessionId/quotes-invoices/invoices- Créer une facture pour une sessionGET /sessions/:sessionId/quotes-invoices/invoices/:id- Récupérer une facturePUT /sessions/:sessionId/quotes-invoices/invoices/:id- Mettre à jour une factureDELETE /sessions/:sessionId/quotes-invoices/invoices/:id- Supprimer une factureGET /sessions/:sessionId/quotes-invoices/invoices/:id/pdf- PDF de la facture
Controller : QuotesController (/quotes)
GET /quotes- Liste toutes les quotes de l'utilisateur (paginé)POST /quotes- Créer une quoteGET /quotes/:id- Récupérer une quotePUT /quotes/:id- Mettre à jour une quoteDELETE /quotes/:id- Supprimer une quote
2. Modèles de Base de Données
Table : invoices
Migration : 0066_create_quotes_and_invoices/up.sql
CREATE TABLE invoices (
id UUID PRIMARY KEY,
owner_id UUID NOT NULL REFERENCES users(id),
session_id UUID REFERENCES sessions(id),
quote_id UUID REFERENCES quotes(id),
contact_id UUID REFERENCES contacts(id), -- Ajouté dans 0083
title TEXT NOT NULL,
description TEXT,
amount DECIMAL(10, 2) NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'DRAFT' CHECK (status IN ('DRAFT', 'SENT', 'PAID', 'OVERDUE')),
due_date DATE,
paid_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Index :
invoices_owner_idxsurowner_idinvoices_session_idxsursession_idinvoices_quote_idxsurquote_idinvoices_status_idxsurstatus
Statuts actuels : DRAFT, SENT, PAID, OVERDUE
Table : invoice_items
Migration : 0082_create_invoice_items/up.sql
CREATE TABLE invoice_items (
id UUID PRIMARY KEY,
invoice_id UUID NOT NULL REFERENCES invoices(id) ON DELETE CASCADE,
item_type TEXT NOT NULL CHECK (item_type IN ('BLANK', 'TEXT', 'SESSION_TYPE', 'DISCOUNT')),
description TEXT,
quantity DECIMAL(10, 2) NOT NULL DEFAULT 1.0,
price_with_tax DECIMAL(10, 2) NOT NULL DEFAULT 0,
vat_percentage DECIMAL(5, 2) NOT NULL DEFAULT 0,
price_without_tax DECIMAL(10, 2) NOT NULL DEFAULT 0,
discount_percentage DECIMAL(5, 2) NOT NULL DEFAULT 0,
total DECIMAL(10, 2) NOT NULL DEFAULT 0,
display_order INTEGER NOT NULL DEFAULT 0,
user_session_type_id UUID REFERENCES user_session_types(id),
discount_amount DECIMAL(10, 2),
discount_type TEXT CHECK (discount_type IN ('PERCENTAGE_OF_TOTAL', 'FIXED_WITH_TAX', 'FIXED_WITHOUT_TAX')),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Table : stripe_payments
Migration : 0084_create_stripe_integration/up.sql
Champs clés :
invoice_id UUID REFERENCES invoices(id)stripe_payment_intent_id TEXTamount DECIMAL(10, 2)currency TEXT DEFAULT 'eur'status TEXT(succeeded, pending, failed, etc.)
Table : paypal_payments
Migration : 0093_create_paypal_integration/up.sql
Champs clés :
invoice_id UUID REFERENCES invoices(id)paypal_order_id TEXT UNIQUEamount DECIMAL(10, 2)currency TEXT DEFAULT 'EUR'status TEXT(COMPLETED, CREATED, SAVED, etc.)
Table : user_company
Migration : 0041_create_user_company_table/up.sql
Champs pertinents pour facturation :
company_name TEXT NOT NULLsiren TEXTsiret TEXTcompany_street TEXTcompany_zipcode TEXTcompany_city TEXTcompany_country TEXT
Table : audit_logs
Migration : 0101_create_audit_logs/up.sql
Structure :
action TEXT(CREATE, UPDATE, DELETE, etc.)entity_type TEXT(INVOICE, QUOTE, etc.)entity_id UUIDresource_owner_id UUIDmetadata JSONBcreated_at TIMESTAMPTZ
3. Flux Actuels
3.1. Flux de Création de Facture
-
Création (
POST /invoicesou/sessions/:id/quotes-invoices/invoices)- Validation via
createInvoiceSchema(Zod) - Vérification ownership (session/contact/quote)
- Insertion dans
invoices - Création des
invoice_itemssi fournis - Recalcul automatique du
amountdepuis les items - Audit log :
CREATEavecentityType: 'INVOICE'
- Validation via
-
Modification (
PUT /invoices/:id)- Validation via
updateInvoiceSchema - Vérification ownership
- Mise à jour de l'invoice
- Mise à jour des items (suppression/recréation)
- Recalcul du
amount - Audit log :
UPDATE
- Validation via
-
Génération PDF (
GET /invoices/:id/pdf)- Génération HTML via
getInvoicePdfHtml() - Conversion en PDF via
PdfService - Upload vers R2 (Cloudflare)
- Retour d'une signed URL
- Note : PDF généré à la demande, pas de stockage systématique
- Génération HTML via
3.2. Flux de Paiement
Via Stripe
-
Création Payment Intent (
POST /stripe/payments/invoices)- Création dans Stripe
- Enregistrement dans
stripe_payments - Retour
clientSecretpour le frontend
-
Webhook Stripe (
POST /stripe/webhooks)- Écoute événements
payment_intent.succeeded - Mise à jour
stripe_payments.status - Mise à jour
invoices.status = 'PAID' - Mise à jour
invoices.paid_at
- Écoute événements
Via PayPal
-
Création Order (
POST /paypal/payments/invoices)- Création dans PayPal
- Enregistrement dans
paypal_payments - Retour
approvalUrl
-
Webhook PayPal (
POST /paypal/webhooks)- Écoute événements
PAYMENT.CAPTURE.COMPLETED - Mise à jour
paypal_payments.status - Mise à jour
invoices.status = 'PAID' - Mise à jour
invoices.paid_at
- Écoute événements
Limitations actuelles :
- Un seul paiement par invoice (pas de paiements partiels)
- Pas de calcul de
balance_due - Statut
PAID= paiement total uniquement
3.3. Flux d'Email
-
Prévisualisation (
POST /invoices/:id/preview-email)- Génération HTML de l'email
- Remplissage des variables
- Retour HTML pour prévisualisation
-
Envoi (
POST /invoices/:id/send-email)- Validation destinataires
- Génération PDF si nécessaire
- Envoi via Gmail API
- Enregistrement dans
scheduled_emailssi planifié - Tracking dans
email_tracking - Mise à jour
invoices.status = 'SENT'si applicable
4. Services Backend
Services Principaux
QuotesInvoicesService- Service principal orchestrateurQuotesInvoicesInvoicesCrudService- CRUD invoicesQuotesInvoicesQuotesCrudService- CRUD quotesQuotesInvoicesItemsService- Gestion des itemsQuotesInvoicesPdfService- Génération PDFQuotesInvoicesEmailService- Envoi emailsStripePaymentsService- Intégration StripePaypalPaymentService- Intégration PayPal
Calculs Actuels
-
Frontend :
frontend/src/utils/document-totals.utils.ts- Fonction
calculateDocumentTotals(items) - Calcul sous-total, taxes, réductions, total
- Fonction
-
Backend :
QuotesInvoicesItemsService- Recalcul
amountdepuis items lors création/mise à jour - Pas de wrapper Decimal (utilise
Number())
- Recalcul
5. Points d'Intégration Identifiés
Webhooks Externes
- Stripe :
/stripe/webhooks→StripeWebhooksController - PayPal :
/paypal/webhooks→PaypalWebhooksController
Points d'Extension
- Audit logs :
@AuditLog()decorator existant - PDF generation :
PdfServiceavec support R2 - Email :
GmailServiceintégré - Storage :
StorageService(R2/S3)
6. Limitations et Manques Identifiés
Immutabilité
- ❌ Factures modifiables même après
SENT - ❌ Pas de snapshots figés à l'émission
- ❌ PDF régénéré à chaque demande (pas de hash)
Numérotation
- ❌ Pas de numérotation séquentielle
- ❌ Format actuel :
YYYY-{8 premiers caractères ID}(non séquentiel)
Compliance
- ❌ Pas de validation mentions obligatoires
- ❌ Pas de vérification SIREN/SIRET
- ❌ Pas de contrôle des mentions légales (pénalités, indemnité 40€)
Avoirs
- ❌ Pas de table
credit_notes - ❌ Pas de support pour avoirs
Paiements
- ❌ Pas de paiements partiels
- ❌ Pas de table
paymentsunifiée - ❌ Pas de calcul
balance_due
Export Comptable
- ❌ Pas d'export comptable
- ❌ Pas de mapping comptes
E-invoicing
- ❌ Pas de champs préparation e-invoicing
- ❌ Pas de stockage facture structurée
7. Fichiers Clés à Modifier
Services
backend/src/quotes-invoices/quotes-invoices-invoices-crud.service.tsbackend/src/quotes-invoices/quotes-invoices-items.service.tsbackend/src/quotes-invoices/invoices.controller.tsbackend/src/stripe/stripe-webhooks.service.tsbackend/src/paypal/paypal-webhooks.controller.ts
DTOs
backend/src/quotes-invoices/dto/create-invoice.dto.tsbackend/src/quotes-invoices/dto/update-invoice.dto.ts
Types
backend/src/_generated/types.gen.ts(regénéré depuis OpenAPI)backend/src/db/database.types.ts(types Kysely)
8. Migration de Données Nécessaire
Factures Existantes
DRAFT→ resteDRAFTSENT,PAID,OVERDUE→ISSUED- Générer numéros rétroactifs pour factures émises
issued_at = created_atpour factures existantes
Paiements Existants
- Copier
stripe_payments→payments - Copier
paypal_payments→payments - Recalculer
balance_duepour toutes les invoices - Mettre à jour statuts (
PARTIALLY_PAIDsi applicable)
9. Notes d'Implémentation
- Les tests existants dans
backend/src/__tests__/quotes-invoices/doivent être adaptés - L'immutabilité nécessitera des guards API et potentiellement des triggers DB
- La numérotation séquentielle nécessite une table de séquences avec locks
- Le système d'audit existant peut être enrichi avec les nouveaux événements