diff --git a/NOTIFICATION_NOTES_CONTRAT.md b/NOTIFICATION_NOTES_CONTRAT.md new file mode 100644 index 0000000..cd91eb6 --- /dev/null +++ b/NOTIFICATION_NOTES_CONTRAT.md @@ -0,0 +1,114 @@ +# Notification Email - Ajout de Notes sur Contrats + +## Vue d'ensemble + +Lorsqu'un client ajoute une note depuis la page d'un contrat (CDDU mono, multi ou RG), un email de notification est automatiquement envoyé à `paie@odentas.fr`. + +## Pages concernées + +- `/contrats/[id]` - Contrats CDDU mono-mois +- `/contrats-multi/[id]` - Contrats CDDU multi-mois +- `/contrats-rg/[id]` - Contrats Régime Général + +## Fonctionnement + +### 1. Ajout d'une note + +Lorsqu'un utilisateur ajoute une note via le composant `NotesSection` : +- La note est enregistrée dans la table `notes` de Supabase +- Un email est automatiquement envoyé à l'équipe paie + +### 2. API Route + +**Route** : `POST /api/contrats/[id]/notes` + +**Processus** : +1. Validation du contenu de la note +2. Récupération des informations du contrat (org_id, numéro) +3. Insertion de la note dans la base de données +4. Récupération des informations de l'organisation (nom, code employeur) +5. Envoi de l'email de notification via le système universel v2 + +### 3. Email de notification + +**Type d'email** : `contract-note-added` + +**Destinataire** : `paie@odentas.fr` + +**Informations incluses** : +- Nom de l'organisation +- Code employeur +- Numéro du contrat +- Nom de l'utilisateur qui a ajouté la note +- Contenu de la note +- Lien direct vers le contrat dans l'interface staff + +**Template** : Utilise le système d'email universel v2 avec : +- Carte d'information (organisation, code employeur, contrat, utilisateur) +- Carte de détails (contenu de la note) +- Bouton CTA vers le contrat dans l'interface staff + +## Configuration + +### Type d'email ajouté + +Dans `lib/emailTemplateService.ts` : +```typescript +export type EmailTypeV2 = + // ... + | 'contract-note-added' // Notification interne : note ajoutée à un contrat + // ... +``` + +### Champs de données ajoutés + +Dans `EmailDataV2` : +```typescript +export interface EmailDataV2 { + // ... + noteContent?: string; + contractId?: string; + contractNumber?: string; + noteAuthor?: string; + // ... +} +``` + +### Configuration du template + +```typescript +'contract-note-added': { + subject: '[CONTRAT] Nouvelle note ajoutée - {{contractNumber}}', + title: '📝 Nouvelle note sur un contrat', + greeting: 'Équipe Paie', + mainMessage: 'Un client a ajouté une note sur un contrat.', + ctaText: 'Voir le contrat', + // ... +} +``` + +## Gestion des erreurs + +- Si l'organisation n'est pas trouvée, l'email n'est pas envoyé mais la note est quand même créée +- Si l'envoi de l'email échoue, l'erreur est loguée mais la requête ne retourne pas d'erreur (la note est bien créée) +- Cela garantit que l'ajout de note fonctionne même si le système d'email rencontre un problème + +## Logs + +Les logs suivants sont générés : +- ✅ Email de notification envoyé pour la note ajoutée au contrat: [id] +- ⚠️ Impossible de récupérer les informations de l'organisation pour l'email de notification +- ❌ Erreur lors de l'envoi de l'email de notification: [error] + +## Fichiers modifiés + +1. `lib/emailTemplateService.ts` - Ajout du type et de la configuration du template +2. `app/api/contrats/[id]/notes/route.ts` - Ajout de la logique d'envoi d'email +3. `app/api/send-email-v2/route.ts` - Ajout du type dans la liste des types valides + +## Notes techniques + +- Le système utilise le **système d'email universel v2** du projet +- L'email est envoyé de manière asynchrone et n'affecte pas la performance de l'ajout de note +- Le lien CTA pointe vers l'interface staff : `https://espace-paie.odentas.fr/staff/contrats/[id]` +- Le nom de l'utilisateur est récupéré depuis les headers HTTP (`x-user-name` ou `x-company-name`) diff --git a/app/api/contrats/[id]/notes/route.ts b/app/api/contrats/[id]/notes/route.ts index b70f488..859c043 100644 --- a/app/api/contrats/[id]/notes/route.ts +++ b/app/api/contrats/[id]/notes/route.ts @@ -1,5 +1,6 @@ import { NextResponse } from "next/server"; import { createSbServer } from "@/lib/supabaseServer"; +import { sendUniversalEmailV2 } from "@/lib/emailTemplateService"; export async function GET(req: Request, ctx: { params: { id: string } }) { const { id } = ctx.params; @@ -56,10 +57,10 @@ export async function POST(req: Request, ctx: { params: { id: string } }) { const sb = createSbServer(); - // Récupérer l'organization_id à partir du contrat (comme dans l'API payslips) + // Récupérer le contrat avec son org_id et numéro const { data: contract, error: contractError } = await sb .from("cddu_contracts") - .select("org_id") + .select("org_id, numero") .eq("id", id) .single(); @@ -73,7 +74,7 @@ export async function POST(req: Request, ctx: { params: { id: string } }) { contract_id: id, content: content.trim(), source, - organization_id: contract.org_id, // Utiliser l'org_id du contrat + organization_id: contract.org_id, }; if (author) insertPayload.author = author; @@ -82,6 +83,42 @@ export async function POST(req: Request, ctx: { params: { id: string } }) { return NextResponse.json({ error: "supabase_error", message: error.message }, { status: 502 }); } + // Envoyer un email à paie@odentas.fr pour notifier l'ajout de la note + try { + // Récupérer les informations de l'organisation + const { data: organization, error: orgError } = await sb + .from("organizations") + .select("name, api_name") + .eq("id", contract.org_id) + .single(); + + if (!orgError && organization) { + // Récupérer le nom de l'utilisateur depuis les headers + const userName = req.headers.get("x-user-name") || author || "Utilisateur inconnu"; + + await sendUniversalEmailV2({ + type: 'contract-note-added', + toEmail: 'paie@odentas.fr', + data: { + organizationName: organization.name, + employerCode: organization.api_name, + contractNumber: contract.numero || id, + userName: userName, + noteContent: content.trim(), + contractId: id, + ctaUrl: `https://espace-paie.odentas.fr/staff/contrats/${id}`, + }, + }); + + console.log('✅ Email de notification envoyé pour la note ajoutée au contrat:', id); + } else { + console.warn('⚠️ Impossible de récupérer les informations de l\'organisation pour l\'email de notification'); + } + } catch (emailError) { + console.error('❌ Erreur lors de l\'envoi de l\'email de notification:', emailError); + // On ne fait pas échouer la requête si l'email ne peut pas être envoyé + } + return NextResponse.json({ items: Array.isArray(data) ? data : [] }, { status: 201 }); } catch (e: any) { return NextResponse.json({ error: "internal_error", message: e?.message || String(e) }, { status: 500 }); diff --git a/app/api/send-email-v2/route.ts b/app/api/send-email-v2/route.ts index fb54381..70dd480 100644 --- a/app/api/send-email-v2/route.ts +++ b/app/api/send-email-v2/route.ts @@ -40,6 +40,7 @@ export async function POST(req: Request) { 'support-ticket-created', 'support-ticket-reply', 'contact-support', + 'contract-note-added', 'referral', 'account-activation', 'access-updated', diff --git a/lib/emailTemplateService.ts b/lib/emailTemplateService.ts index b163220..5c80b2a 100644 --- a/lib/emailTemplateService.ts +++ b/lib/emailTemplateService.ts @@ -53,6 +53,7 @@ export type EmailTypeV2 = | 'support-ticket-created' // Notification interne : nouveau ticket créé | 'support-ticket-reply' // Notification interne : réponse utilisateur à un ticket | 'contact-support' // Formulaire de contact public vers le support + | 'contract-note-added' // Notification interne : note ajoutée à un contrat // Parrainage | 'referral' // Email d'invitation au parrainage // Accès / habilitations @@ -113,6 +114,11 @@ export interface EmailDataV2 { // Ajout des champs pour la signature salarié (depuis Lambda DocuSeal) matricule?: string; typecontrat?: string; + // Ajout des champs pour les notes de contrat + noteContent?: string; + contractId?: string; + contractNumber?: string; + noteAuthor?: string; [key: string]: unknown; } @@ -1250,6 +1256,37 @@ const EMAIL_TEMPLATES_V2: Record = { } }, + 'contract-note-added': { + subject: '[CONTRAT] Nouvelle note ajoutée - {{contractNumber}}', + title: '📝 Nouvelle note sur un contrat', + greeting: 'Équipe Paie', + mainMessage: 'Un client a ajouté une note sur un contrat.', + ctaText: 'Voir le contrat', + footerText: 'Notification automatique du système Espace Paie Odentas.', + preheaderText: 'Nouvelle note ajoutée sur un contrat', + colors: { + headerColor: STANDARD_COLORS.HEADER, + titleColor: '#0F172A', + buttonColor: '#3B82F6', + buttonTextColor: '#FFFFFF', + cardBackgroundColor: '#FFFFFF', + cardBorder: '#E5E7EB', + cardTitleColor: '#0F172A', + }, + infoCard: [ + { label: 'Organisation', key: 'organizationName' }, + { label: 'Code employeur', key: 'employerCode' }, + { label: 'Contrat', key: 'contractNumber' }, + { label: 'Ajouté par', key: 'userName' }, + ], + detailsCard: { + title: 'Note', + rows: [ + { label: 'Contenu', key: 'noteContent' }, + ] + } + }, + 'amendment-completed-employer': { subject: 'Avenant {{#if numeroAvenant}}n°{{numeroAvenant}}{{/if}} signé - {{organizationName}}', title: 'Avenant signé',