feat: Notification email lors de l'ajout de notes sur contrats
- Ajout du type 'contract-note-added' dans le système email universel v2 - Email automatique envoyé à paie@odentas.fr quand un client ajoute une note - Fonctionne pour tous les types de contrats (CDDU mono, multi, RG) - Email contient: organisation, code employeur, n° contrat, utilisateur, contenu note - Lien direct vers le contrat dans l'interface staff - Gestion des erreurs: note créée même si email échoue - Documentation complète dans NOTIFICATION_NOTES_CONTRAT.md
This commit is contained in:
parent
76821a2691
commit
206c1f2afc
4 changed files with 192 additions and 3 deletions
114
NOTIFICATION_NOTES_CONTRAT.md
Normal file
114
NOTIFICATION_NOTES_CONTRAT.md
Normal file
|
|
@ -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`)
|
||||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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<EmailTypeV2, EmailTemplateV2> = {
|
|||
}
|
||||
},
|
||||
|
||||
'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é',
|
||||
|
|
|
|||
Loading…
Reference in a new issue