From 1633fb9bf0047a1afd1a14a1d3f68abe18c29703 Mon Sep 17 00:00:00 2001 From: ordinarthur <@arthurbarre.js@gmail.com> Date: Thu, 7 May 2026 11:34:00 +0200 Subject: [PATCH] add factories --- .claude/settings.local.json | 5 +- .../api/app/controllers/checkin_controller.ts | 2 +- .../app/controllers/invoices_controller.ts | 59 ++- apps/api/commands/demo_schedule_relance.ts | 134 ++++++ apps/api/database/factories.ts | 446 +++++++++++++++++- apps/api/start/routes.ts | 4 + apps/web/src/components/charts/theme.ts | 2 +- .../src/components/demo/DemoEmailSlide.tsx | 425 ++++++++++++++--- .../src/components/factures/PdfPreview.tsx | 42 +- apps/web/src/components/ui/Pagination.tsx | 95 ++++ apps/web/src/lib/api.ts | 37 +- apps/web/src/routes/_app/factures.tsx | 28 +- apps/web/src/routes/_app/factures_.$id.tsx | 49 +- 13 files changed, 1192 insertions(+), 136 deletions(-) create mode 100644 apps/api/commands/demo_schedule_relance.ts create mode 100644 apps/web/src/components/ui/Pagination.tsx diff --git a/.claude/settings.local.json b/.claude/settings.local.json index a3da492..ef71591 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -2,7 +2,10 @@ "permissions": { "allow": [ "Bash(pnpm -F api typecheck)", - "Bash(pnpm -F @rubis/web typecheck)" + "Bash(pnpm -F @rubis/web typecheck)", + "Bash(rtk grep *)", + "Bash(rtk node *)", + "Bash(rtk pnpm *)" ] } } diff --git a/apps/api/app/controllers/checkin_controller.ts b/apps/api/app/controllers/checkin_controller.ts index 141c5f4..5da66ab 100644 --- a/apps/api/app/controllers/checkin_controller.ts +++ b/apps/api/app/controllers/checkin_controller.ts @@ -100,7 +100,7 @@ export default class CheckinController { await recordActivity({ organizationId: invoice.organizationId, kind: 'invoice_paid', - label: `Facture ${invoice.numero} marquée encaissée via check-in`, + label: `Facture ${invoice.numero} marquée encaissée via confirmation`, meta: { invoiceId: invoice.id, clientId: invoice.clientId }, trx, }) diff --git a/apps/api/app/controllers/invoices_controller.ts b/apps/api/app/controllers/invoices_controller.ts index ceec1b4..61f23e5 100644 --- a/apps/api/app/controllers/invoices_controller.ts +++ b/apps/api/app/controllers/invoices_controller.ts @@ -13,6 +13,7 @@ import { cancelFutureRelances } from '#services/relance_scheduler' import { scheduleCheckinForInvoice, cancelCheckinForInvoice } from '#services/checkin_scheduler' import logger from '@adonisjs/core/services/logger' import * as clock from '#services/clock' +import drive from '@adonisjs/drive/services/main' const PAGE_SIZE = 50 @@ -95,13 +96,16 @@ function buildTimeline( } else state = 'future' const subject = step.subject.replace('{{numero}}', invoice.numero) + // Wording uniforme et rassurant : aucune relance ne part sans que l'user + // confirme l'impayé. On évite "programmé" tout court qui sonne comme + // "ça va partir tout seul". const what = task ? task.status === 'sent' - ? `Email envoyé · "${subject}"` - : `Email programmé · "${subject}"` - : invoice.status === 'pending' - ? `À programmer après check-in · "${subject}"` - : `Relance non programmée · "${subject}"` + ? `Envoyée après votre confirmation · "${subject}"` + : task.status === 'cancelled' + ? `Annulée — facture encaissée · "${subject}"` + : `Confirmation avant envoi · "${subject}"` + : `Confirmation avant envoi · "${subject}"` events.push({ id: `${invoice.id}__step_${step.order}`, @@ -325,6 +329,51 @@ export default class InvoicesController { return response.status(201).json({ data: serializeInvoice(invoice) }) } + /** + * GET /invoices/:id/pdf — stream le PDF/image originel 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