/** * Seed des données pour l'utilisateur démo. * * On factorise le seed dans son propre fichier pour ne pas alourdir db.ts * avec 200 lignes de données. Calibré sur les wireframes pour donner un * dashboard / liste réalistes au premier login. */ import type { Client, Invoice, Plan } from "@rubis/shared"; const NOW = new Date("2026-05-06T08:30:00.000Z"); function isoFromOffset(daysOffset: number, hour = 9): string { const d = new Date(NOW); d.setDate(d.getDate() + daysOffset); d.setHours(hour, 0, 0, 0); return d.toISOString(); } const ORG = "org_demo"; export const SEED_CLIENTS: Client[] = [ { id: "cli_martin", organizationId: ORG, name: "Boulangerie Martin SARL", email: "compta@boulangerie-martin.fr", phone: "+33 1 23 45 67 89", address: "12 rue du Pain, 75011 Paris", siret: "82345678900012", notes: null, createdAt: isoFromOffset(-90), updatedAt: isoFromOffset(-2), }, { id: "cli_durand", organizationId: ORG, name: "Atelier Durand", email: "contact@atelier-durand.fr", phone: null, address: null, siret: null, notes: "Le client a confirmé la réception le 14/04 par téléphone — relance ferme inutile.", createdAt: isoFromOffset(-120), updatedAt: isoFromOffset(-3), }, { id: "cli_rousseau", organizationId: ORG, name: "Cabinet Rousseau", email: "facturation@cabinet-rousseau.fr", phone: "+33 4 56 78 90 12", address: "8 place de la République, 69002 Lyon", siret: "53412987600028", notes: null, createdAt: isoFromOffset(-200), updatedAt: isoFromOffset(-1), }, { id: "cli_lemoine", organizationId: ORG, name: "Garage Lemoine", email: "admin@garage-lemoine.fr", phone: null, address: null, siret: null, notes: null, createdAt: isoFromOffset(-60), updatedAt: isoFromOffset(-5), }, { id: "cli_lefevre", organizationId: ORG, name: "Studio Lefèvre", email: "hello@studio-lefevre.com", phone: null, address: null, siret: null, notes: null, createdAt: isoFromOffset(-30), updatedAt: isoFromOffset(-1), }, ]; export const SEED_PLANS: Plan[] = [ { id: "plan_standard", organizationId: ORG, slug: "standard-30j", name: "Standard B2B", description: "Cadence sobre, ton qui monte progressivement. Pour la majorité des clients sérieux.", isDefault: true, steps: [ { id: "step_std_1", order: 0, offsetDays: 3, tone: "amical", subject: "Petit rappel — facture {{numero}}", body: "Bonjour {{client.name}},\n\nNous espérons que tout va bien. Un petit rappel concernant la facture {{numero}} d'un montant de {{amount}}, échue le {{dueDate}}.\n\nMerci d'avance,\n{{signature}}", requiresManualValidation: false, }, { id: "step_std_2", order: 1, offsetDays: 10, tone: "courtois", subject: "Relance — facture {{numero}} en retard", body: "Bonjour {{client.name}},\n\nSauf erreur de notre part, la facture {{numero}} d'un montant de {{amount}} reste impayée.\n\nMerci de procéder au règlement dans les meilleurs délais.\n\n{{signature}}", requiresManualValidation: false, }, { id: "step_std_3", order: 2, offsetDays: 25, tone: "ferme", subject: "Mise en demeure — facture {{numero}}", body: "Bonjour {{client.name}},\n\nMalgré nos relances, la facture {{numero}} d'un montant de {{amount}} reste impayée. Nous vous mettons en demeure de régler sous 8 jours.\n\n{{signature}}", requiresManualValidation: true, }, ], createdAt: isoFromOffset(-365), updatedAt: isoFromOffset(-30), }, { id: "plan_rapide", organizationId: ORG, slug: "rapide-15j", name: "Rapide", description: "Cadence resserrée pour les factures récurrentes ou les délais courts.", isDefault: true, steps: [ { id: "step_rap_1", order: 0, offsetDays: 1, tone: "amical", subject: "Facture {{numero}} échue", body: "Bonjour, petit rappel pour la facture {{numero}}.\n\n{{signature}}", requiresManualValidation: false, }, { id: "step_rap_2", order: 1, offsetDays: 7, tone: "courtois", subject: "Relance facture {{numero}}", body: "La facture {{numero}} reste impayée à ce jour. Merci de régulariser.\n\n{{signature}}", requiresManualValidation: false, }, { id: "step_rap_3", order: 2, offsetDays: 15, tone: "ferme", subject: "Mise en demeure {{numero}}", body: "Mise en demeure formelle de payer sous 8 jours.\n\n{{signature}}", requiresManualValidation: true, }, ], createdAt: isoFromOffset(-365), updatedAt: isoFromOffset(-365), }, { id: "plan_patient", organizationId: ORG, slug: "patient-60j", name: "Patient", description: "Pour les clients de longue date. On laisse respirer avant de relancer.", isDefault: true, steps: [ { id: "step_pat_1", order: 0, offsetDays: 15, tone: "amical", subject: "Facture {{numero}}", body: "Bonjour, simple rappel.\n\n{{signature}}", requiresManualValidation: false, }, { id: "step_pat_2", order: 1, offsetDays: 30, tone: "courtois", subject: "Relance facture {{numero}}", body: "Merci de régulariser dans les meilleurs délais.\n\n{{signature}}", requiresManualValidation: false, }, ], createdAt: isoFromOffset(-365), updatedAt: isoFromOffset(-365), }, { id: "plan_ferme", organizationId: ORG, slug: "ferme-7j", name: "Ferme", description: "Cadence stricte pour les clients à risque ou les retards récurrents.", isDefault: true, steps: [ { id: "step_fer_1", order: 0, offsetDays: 1, tone: "courtois", subject: "Facture {{numero}}", body: "Premier rappel.\n\n{{signature}}", requiresManualValidation: false, }, { id: "step_fer_2", order: 1, offsetDays: 5, tone: "ferme", subject: "Relance ferme {{numero}}", body: "Le règlement est attendu sous 48h.\n\n{{signature}}", requiresManualValidation: false, }, { id: "step_fer_3", order: 2, offsetDays: 10, tone: "mise_en_demeure", subject: "Mise en demeure {{numero}}", body: "Mise en demeure formelle.\n\n{{signature}}", requiresManualValidation: true, }, ], createdAt: isoFromOffset(-365), updatedAt: isoFromOffset(-365), }, ]; type SeedInvoice = Invoice & { clientName: string; planName: string | null; statusLabel?: string }; export const SEED_INVOICES: SeedInvoice[] = [ // À relancer (échéance future) { id: "inv_001", organizationId: ORG, clientId: "cli_martin", clientName: "Boulangerie Martin SARL", numero: "F-2026-0042", amountTtcCents: 124_000, issueDate: isoFromOffset(-15), dueDate: isoFromOffset(10), status: "pending", planId: "plan_standard", planName: "Standard B2B", pdfStorageKey: null, notes: null, rubisEarned: 0, createdAt: isoFromOffset(-15), updatedAt: isoFromOffset(-15), }, { id: "inv_002", organizationId: ORG, clientId: "cli_lefevre", clientName: "Studio Lefèvre", numero: "F-2026-0044", amountTtcCents: 245_000, issueDate: isoFromOffset(-10), dueDate: isoFromOffset(20), status: "pending", planId: "plan_standard", planName: "Standard B2B", pdfStorageKey: null, notes: null, rubisEarned: 0, createdAt: isoFromOffset(-10), updatedAt: isoFromOffset(-10), }, { id: "inv_003", organizationId: ORG, clientId: "cli_lemoine", clientName: "Garage Lemoine", numero: "F-2026-0045", amountTtcCents: 89_000, issueDate: isoFromOffset(-5), dueDate: isoFromOffset(25), status: "pending", planId: "plan_patient", planName: "Patient", pdfStorageKey: null, notes: null, rubisEarned: 0, createdAt: isoFromOffset(-5), updatedAt: isoFromOffset(-5), }, // En relance (échéance passée, étape envoyée) { id: "inv_004", organizationId: ORG, clientId: "cli_durand", clientName: "Atelier Durand", numero: "F-2026-0039", amountTtcCents: 360_000, issueDate: isoFromOffset(-34), dueDate: isoFromOffset(-4), status: "in_relance", planId: "plan_standard", planName: "Standard B2B", pdfStorageKey: null, notes: "Client a confirmé la réception le 14/04 par téléphone.", rubisEarned: 1, statusLabel: "Relance J+3 envoyée", createdAt: isoFromOffset(-34), updatedAt: isoFromOffset(-1), }, { id: "inv_005", organizationId: ORG, clientId: "cli_durand", clientName: "Atelier Durand", numero: "F-2026-0036", amountTtcCents: 180_000, issueDate: isoFromOffset(-50), dueDate: isoFromOffset(-20), status: "in_relance", planId: "plan_standard", planName: "Standard B2B", pdfStorageKey: null, notes: null, rubisEarned: 2, statusLabel: "Relance J+10 envoyée", createdAt: isoFromOffset(-50), updatedAt: isoFromOffset(-10), }, { id: "inv_006", organizationId: ORG, clientId: "cli_martin", clientName: "Boulangerie Martin SARL", numero: "F-2026-0033", amountTtcCents: 95_500, issueDate: isoFromOffset(-40), dueDate: isoFromOffset(-10), status: "in_relance", planId: "plan_standard", planName: "Standard B2B", pdfStorageKey: null, notes: null, rubisEarned: 1, statusLabel: "Relance J+10 demain", createdAt: isoFromOffset(-40), updatedAt: isoFromOffset(-3), }, // À valider (mise en demeure) { id: "inv_007", organizationId: ORG, clientId: "cli_rousseau", clientName: "Cabinet Rousseau", numero: "F-2026-0028", amountTtcCents: 85_000, issueDate: isoFromOffset(-65), dueDate: isoFromOffset(-35), status: "awaiting_user_confirmation", planId: "plan_standard", planName: "Standard B2B", pdfStorageKey: null, notes: null, rubisEarned: 2, statusLabel: "Mise en demeure prête", createdAt: isoFromOffset(-65), updatedAt: isoFromOffset(0), }, // Encaissées { id: "inv_008", organizationId: ORG, clientId: "cli_lemoine", clientName: "Garage Lemoine", numero: "F-2026-0035", amountTtcCents: 420_000, issueDate: isoFromOffset(-45), dueDate: isoFromOffset(-15), status: "paid", planId: "plan_standard", planName: "Standard B2B", pdfStorageKey: null, notes: null, rubisEarned: 2, createdAt: isoFromOffset(-45), updatedAt: isoFromOffset(0), }, { id: "inv_009", organizationId: ORG, clientId: "cli_lefevre", clientName: "Studio Lefèvre", numero: "F-2026-0030", amountTtcCents: 156_000, issueDate: isoFromOffset(-60), dueDate: isoFromOffset(-30), status: "paid", planId: "plan_standard", planName: "Standard B2B", pdfStorageKey: null, notes: null, rubisEarned: 1, createdAt: isoFromOffset(-60), updatedAt: isoFromOffset(-25), }, // Litige { id: "inv_010", organizationId: ORG, clientId: "cli_rousseau", clientName: "Cabinet Rousseau", numero: "F-2026-0019", amountTtcCents: 1_200_000, issueDate: isoFromOffset(-100), dueDate: isoFromOffset(-70), status: "litigation", planId: null, planName: null, pdfStorageKey: null, notes: "Litige en cours — passé en contentieux.", rubisEarned: 3, createdAt: isoFromOffset(-100), updatedAt: isoFromOffset(-15), }, ];