Quand l'utilisateur confirme « Oui, payé » via check-in (lien email ou modale in-app) ou marque une facture encaissée manuellement, on envoie automatiquement un email de remerciement chaleureux au client final. Subject + body éditables par plan (mêmes variables que les relances), avec fallback hardcodé si vide. Gardé par la transition `* → paid` pour idempotence ; envoi async via BullMQ avec retry exponentiel ; capture en mode démo. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
44 lines
1.8 KiB
TypeScript
44 lines
1.8 KiB
TypeScript
import vine from '@vinejs/vine'
|
|
|
|
const RELANCE_TONES = ['amical', 'courtois', 'ferme', 'mise_en_demeure'] as const
|
|
|
|
const planStep = vine.object({
|
|
// id optionnel : présent si on édite une étape existante, absent pour
|
|
// une création (le contrôleur le générera).
|
|
id: vine.string().optional(),
|
|
order: vine.number().min(0),
|
|
// Plage : -30 (rappel avant échéance) à 180 jours (gros retards).
|
|
offsetDays: vine.number().min(-30).max(180),
|
|
tone: vine.enum(RELANCE_TONES),
|
|
subject: vine.string().minLength(1).maxLength(200),
|
|
body: vine.string().minLength(1).maxLength(5000),
|
|
requiresManualValidation: vine.boolean(),
|
|
})
|
|
|
|
/**
|
|
* Validator pour PATCH /plans/:slug. Tous les champs optionnels — l'éditeur
|
|
* front peut envoyer juste `name` ou juste `steps` selon ce qu'il modifie.
|
|
*
|
|
* `thanksSubject` / `thanksBody` : nullable pour permettre à l'utilisateur
|
|
* d'effacer le template (retomber sur le fallback hardcodé).
|
|
*/
|
|
export const updatePlanValidator = vine.create({
|
|
name: vine.string().minLength(1).maxLength(80).optional(),
|
|
description: vine.string().maxLength(500).optional(),
|
|
steps: vine.array(planStep).minLength(1).maxLength(10).optional(),
|
|
thanksSubject: vine.string().maxLength(200).nullable().optional(),
|
|
thanksBody: vine.string().maxLength(5000).nullable().optional(),
|
|
})
|
|
|
|
/**
|
|
* Validator pour POST /plans — création d'un plan custom.
|
|
* Le slug est généré côté contrôleur depuis le name.
|
|
*/
|
|
export const createPlanValidator = vine.create({
|
|
name: vine.string().minLength(1).maxLength(80),
|
|
description: vine.string().maxLength(500).optional(),
|
|
steps: vine.array(planStep).minLength(1).maxLength(10),
|
|
thanksSubject: vine.string().maxLength(200).nullable().optional(),
|
|
thanksBody: vine.string().maxLength(5000).nullable().optional(),
|
|
})
|