feat: Migration Lambda avenant completion vers Next.js API
- Créé route /api/webhooks/docuseal-amendment-completed - Ajouté templates emails amendment-completed-employer et amendment-completed-employee - Intégration système emails universel v2 (Handlebars) - Logging dans Supabase email_logs (plus d'Airtable) - Types ajoutés à EmailTypeV2 et EmailType - Documentation complète dans LAMBDA_MIGRATION_AVENANT_COMPLETION.md - Script SQL migration dans MIGRATION_SQL_EMAIL_TYPES.md Migration complète AWS Lambda → Next.js cdg1 (RGPD compliant)
This commit is contained in:
parent
4292041f40
commit
2520a73602
5 changed files with 585 additions and 0 deletions
218
LAMBDA_MIGRATION_AVENANT_COMPLETION.md
Normal file
218
LAMBDA_MIGRATION_AVENANT_COMPLETION.md
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
# Migration Lambda → Next.js API - Avenant Completion
|
||||
|
||||
## 📋 Context
|
||||
|
||||
Migration de la Lambda AWS `postDocuSealFinalEmailsAvenant` vers une route API Next.js intégrée au système d'emails universel v2.
|
||||
|
||||
## 🎯 Objectifs
|
||||
|
||||
1. ✅ Remplacer la Lambda AWS par une route Next.js
|
||||
2. ✅ Utiliser le système d'emails universel v2 (templates Handlebars)
|
||||
3. ✅ Logger les emails dans Supabase (`email_logs`)
|
||||
4. ✅ Supprimer la dépendance à Airtable
|
||||
5. ✅ Supprimer le HTML inline hardcodé
|
||||
|
||||
## 🔧 Fichiers Créés/Modifiés
|
||||
|
||||
### ✅ Nouveau Webhook Handler
|
||||
**Fichier** : `app/api/webhooks/docuseal-amendment-completed/route.ts`
|
||||
|
||||
**Fonction** : Traite la complétion d'un avenant (toutes parties signées)
|
||||
|
||||
**Flow** :
|
||||
1. Reçoit webhook DocuSeal avec `submissionId`
|
||||
2. Recherche l'avenant par `docuseal_submission_id`
|
||||
3. Met à jour `signature_status` → `'completed'`
|
||||
4. Envoie email à l'employeur (`amendment-completed-employer`)
|
||||
5. Envoie email au salarié (`amendment-completed-employee`)
|
||||
6. Logs les emails dans `email_logs`
|
||||
|
||||
**Sécurité** :
|
||||
- Utilise `createRouteHandlerClient` (Supabase Auth)
|
||||
- Clé API DocuSeal en Authorization header
|
||||
|
||||
### ✅ Templates d'Emails Ajoutés
|
||||
**Fichier** : `lib/emailTemplateService.ts`
|
||||
|
||||
**Templates créés** :
|
||||
|
||||
#### 1. `amendment-completed-employer`
|
||||
- **Sujet** : "Avenant n°X signé - [Organisation]"
|
||||
- **CTA** : "Voir les documents"
|
||||
- **Info** : Salarié, matricule, détails avenant
|
||||
- **Message** : Confirmation signature par toutes les parties
|
||||
|
||||
#### 2. `amendment-completed-employee`
|
||||
- **Sujet** : "Votre avenant n°X est signé - [Organisation]"
|
||||
- **CTA** : "Télécharger l'avenant"
|
||||
- **Info** : Employeur, matricule, détails avenant
|
||||
- **Message** : Téléchargement de l'exemplaire signé
|
||||
|
||||
### ✅ Types Ajoutés
|
||||
**Fichiers** :
|
||||
- `lib/emailTemplateService.ts` (EmailTypeV2)
|
||||
- `lib/emailLoggingService.ts` (EmailType)
|
||||
|
||||
**Types** :
|
||||
- `amendment-completed-employer`
|
||||
- `amendment-completed-employee`
|
||||
|
||||
## 🔄 Flux Complet Avenant
|
||||
|
||||
### Étape 1 : Signature Employeur
|
||||
**Webhook** : `/api/webhooks/docuseal-amendment`
|
||||
**Action** :
|
||||
1. Employeur signe l'avenant sur DocuSeal
|
||||
2. Webhook reçu avec `submissionId`
|
||||
3. Update avenant : `signature_status` → `'pending_employee'`
|
||||
4. Envoi email au salarié (`signature-request-employee-amendment`)
|
||||
|
||||
### Étape 2 : Signature Salarié (Complétion)
|
||||
**Webhook** : `/api/webhooks/docuseal-amendment-completed`
|
||||
**Action** :
|
||||
1. Salarié signe l'avenant sur DocuSeal
|
||||
2. Webhook reçu avec `submissionId`
|
||||
3. Update avenant : `signature_status` → `'completed'`
|
||||
4. Envoi email employeur (`amendment-completed-employer`)
|
||||
5. Envoi email salarié (`amendment-completed-employee`)
|
||||
|
||||
## 📊 Comparaison Lambda vs Next.js
|
||||
|
||||
| Aspect | Lambda (Avant) | Next.js (Après) |
|
||||
|--------|----------------|-----------------|
|
||||
| **Localisation** | iad1 (US-Est) ❌ | cdg1 (Paris) ✅ |
|
||||
| **Templates** | HTML inline hardcodé | Handlebars universel v2 |
|
||||
| **Logging** | Airtable ❌ | Supabase `email_logs` ✅ |
|
||||
| **Auth** | Clé API custom | Supabase Auth |
|
||||
| **Maintenance** | Code séparé | Code intégré au projet |
|
||||
| **Réutilisabilité** | Zéro | Composants réutilisables |
|
||||
|
||||
## ⚠️ Migration SQL Requise
|
||||
|
||||
Exécuter dans **Supabase SQL Editor** :
|
||||
|
||||
```sql
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'amendment-completed-employer';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'amendment-completed-employee';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'signature-request-employee-amendment';
|
||||
```
|
||||
|
||||
Voir : `MIGRATION_SQL_EMAIL_TYPES.md` pour le script complet.
|
||||
|
||||
## 🧪 Tests à Effectuer
|
||||
|
||||
### Test 1 : Signature Employeur → Email Salarié
|
||||
1. Créer un avenant via staff/contrats
|
||||
2. Envoyer pour signature employeur
|
||||
3. Signer en tant qu'employeur
|
||||
4. ✅ Vérifier email reçu par salarié
|
||||
5. ✅ Vérifier log dans `email_logs` (type: `signature-request-employee-amendment`)
|
||||
|
||||
### Test 2 : Signature Salarié → Emails Confirmation
|
||||
1. Reprendre avenant de Test 1 (pending_employee)
|
||||
2. Signer en tant que salarié
|
||||
3. ✅ Vérifier email reçu par employeur (type: `amendment-completed-employer`)
|
||||
4. ✅ Vérifier email reçu par salarié (type: `amendment-completed-employee`)
|
||||
5. ✅ Vérifier logs dans `email_logs` (2 entrées)
|
||||
6. ✅ Vérifier `signature_status` = `'completed'` dans `avenants`
|
||||
|
||||
### Test 3 : Liens de Téléchargement
|
||||
1. Cliquer sur CTA dans email employeur
|
||||
2. ✅ Vérifier accès aux documents
|
||||
3. Cliquer sur CTA dans email salarié
|
||||
4. ✅ Vérifier téléchargement avenant signé
|
||||
|
||||
## 🗑️ Nettoyage Lambda (Après Tests)
|
||||
|
||||
Une fois les tests validés :
|
||||
|
||||
1. **AWS Lambda Console** :
|
||||
- Désactiver trigger DocuSeal
|
||||
- Supprimer fonction `postDocuSealFinalEmailsAvenant`
|
||||
- Supprimer layer Node.js si non utilisé ailleurs
|
||||
|
||||
2. **DocuSeal** :
|
||||
- Vérifier webhook configuré sur nouvelle route Next.js
|
||||
- URL : `https://espacepaieodentas.com/api/webhooks/docuseal-amendment-completed`
|
||||
|
||||
3. **Airtable** :
|
||||
- ✅ Déjà supprimé (variables d'environnement retirées)
|
||||
|
||||
4. **Documentation** :
|
||||
- Mettre à jour `DOCUSEAL_SIGNATURE_CONFIG.md`
|
||||
- Archiver code Lambda dans repo si backup souhaité
|
||||
|
||||
## 📝 Configuration DocuSeal
|
||||
|
||||
**Webhook à Configurer** :
|
||||
|
||||
- **Event** : `form.completed` (toutes parties signées)
|
||||
- **URL** : `https://espacepaieodentas.com/api/webhooks/docuseal-amendment-completed`
|
||||
- **Method** : POST
|
||||
- **Headers** :
|
||||
- `Authorization: Bearer [DOCUSEAL_API_KEY]`
|
||||
- `Content-Type: application/json`
|
||||
|
||||
**Payload Attendu** :
|
||||
```json
|
||||
{
|
||||
"event_type": "form.completed",
|
||||
"data": {
|
||||
"id": "submission_123456",
|
||||
"template": {
|
||||
"name": "AVENANT_REF_CONTRACT"
|
||||
},
|
||||
"created_at": "2025-01-XX",
|
||||
"submitters": [
|
||||
{
|
||||
"email": "employer@company.com",
|
||||
"role": "Employeur"
|
||||
},
|
||||
{
|
||||
"email": "employee@example.com",
|
||||
"role": "Salarié"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 Avantages de la Migration
|
||||
|
||||
1. **RGPD** : Région Paris (cdg1) → données EU uniquement
|
||||
2. **Maintenance** : Code centralisé dans le projet Next.js
|
||||
3. **Réutilisabilité** : Templates Handlebars pour tous les emails
|
||||
4. **Logging** : Traçabilité complète dans Supabase
|
||||
5. **Performance** : Moins de latence (cdg1 vs iad1)
|
||||
6. **Coûts** : Réduction coûts AWS Lambda
|
||||
7. **Cohérence** : Système unifié pour tous les emails
|
||||
|
||||
## 🔗 Références
|
||||
|
||||
- Webhook avenant étape 1 : `/api/webhooks/docuseal-amendment`
|
||||
- Webhook avenant étape 2 : `/api/webhooks/docuseal-amendment-completed`
|
||||
- Email templates : `lib/emailTemplateService.ts`
|
||||
- Email logging : `lib/emailLoggingService.ts`
|
||||
- Migration SQL : `MIGRATION_SQL_EMAIL_TYPES.md`
|
||||
- Lambda original : `LAMBDA_EMAIL_SIGNATURE_SALARIE_GUIDE.md` (contrats initiaux)
|
||||
|
||||
## ✅ Checklist Déploiement
|
||||
|
||||
- [x] Créer route API Next.js
|
||||
- [x] Ajouter templates emails (employer + employee)
|
||||
- [x] Ajouter types TypeScript
|
||||
- [ ] Exécuter migration SQL Supabase
|
||||
- [ ] Configurer webhook DocuSeal
|
||||
- [ ] Tester flux complet (étape 1 + étape 2)
|
||||
- [ ] Vérifier logs dans `email_logs`
|
||||
- [ ] Valider emails reçus (contenu + design)
|
||||
- [ ] Désactiver Lambda AWS
|
||||
- [ ] Mettre à jour documentation
|
||||
- [ ] Commit + push code
|
||||
|
||||
## 📅 Status
|
||||
|
||||
**Date** : 2025-01-XX
|
||||
**Status** : ✅ Code prêt, en attente SQL + tests
|
||||
**Bloquants** : Migration SQL à exécuter dans Supabase
|
||||
**Prochaine étape** : Exécuter SQL puis tester avec avenant réel
|
||||
67
MIGRATION_SQL_EMAIL_TYPES.md
Normal file
67
MIGRATION_SQL_EMAIL_TYPES.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# Migration SQL - Nouveaux Types d'Emails
|
||||
|
||||
## 📋 Context
|
||||
|
||||
Ajout de nouveaux types d'emails pour supporter les notifications d'avenants et autres fonctionnalités récentes.
|
||||
|
||||
## 🎯 Types à Ajouter
|
||||
|
||||
Les types TypeScript ont été ajoutés dans :
|
||||
- `lib/emailTemplateService.ts` (EmailTypeV2)
|
||||
- `lib/emailLoggingService.ts` (EmailType)
|
||||
|
||||
Il faut maintenant ajouter les valeurs correspondantes à l'enum PostgreSQL `email_type` dans Supabase.
|
||||
|
||||
## 🔧 Script SQL à Exécuter
|
||||
|
||||
Exécuter dans **Supabase SQL Editor** :
|
||||
|
||||
```sql
|
||||
-- Ajouter les nouveaux types d'emails à l'enum email_type
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'signature-request-employee-amendment';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'signature-request-salarie';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'contribution-notification';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'support-reply';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'support-ticket-created';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'support-ticket-reply';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'contact-support';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'amendment-completed-employer';
|
||||
ALTER TYPE email_type ADD VALUE IF NOT EXISTS 'amendment-completed-employee';
|
||||
```
|
||||
|
||||
## ✅ Vérification
|
||||
|
||||
Après exécution, vérifier que les types sont bien ajoutés :
|
||||
|
||||
```sql
|
||||
SELECT enumlabel
|
||||
FROM pg_enum
|
||||
WHERE enumtypid = 'email_type'::regtype
|
||||
ORDER BY enumlabel;
|
||||
```
|
||||
|
||||
## 📝 Détails des Nouveaux Types
|
||||
|
||||
| Type | Description | Utilisé par |
|
||||
|------|-------------|-------------|
|
||||
| `signature-request-employee-amendment` | Demande signature avenant par salarié | Webhook avenant (étape 1) |
|
||||
| `signature-request-salarie` | Demande signature salarié (legacy Lambda) | Lambda DocuSeal |
|
||||
| `contribution-notification` | Notification cotisations mensuelles | Envoi cotisations |
|
||||
| `support-reply` | Réponse du support | Système tickets |
|
||||
| `support-ticket-created` | Nouveau ticket créé | Système tickets |
|
||||
| `support-ticket-reply` | Réponse utilisateur sur ticket | Système tickets |
|
||||
| `contact-support` | Formulaire contact public | Page contact |
|
||||
| `amendment-completed-employer` | Avenant signé (notif employeur) | Webhook avenant (étape 2) |
|
||||
| `amendment-completed-employee` | Avenant signé (notif salarié) | Webhook avenant (étape 2) |
|
||||
|
||||
## ⚠️ Important
|
||||
|
||||
**L'ajout d'une valeur à un ENUM PostgreSQL est irréversible** (ne peut pas être supprimé sans recréer l'enum).
|
||||
|
||||
La commande `IF NOT EXISTS` permet d'exécuter le script plusieurs fois sans erreur.
|
||||
|
||||
## 🔗 Références
|
||||
|
||||
- Route webhook : `/api/webhooks/docuseal-amendment-completed`
|
||||
- Template service : `lib/emailTemplateService.ts`
|
||||
- Logging service : `lib/emailLoggingService.ts`
|
||||
226
app/api/webhooks/docuseal-amendment-completed/route.ts
Normal file
226
app/api/webhooks/docuseal-amendment-completed/route.ts
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { createSbServiceRole } from "@/lib/supabaseServer";
|
||||
import { sendUniversalEmailV2, EmailDataV2 } from "@/lib/emailTemplateService";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
/**
|
||||
* Webhook appelé quand TOUTES les parties ont signé l'avenant (employeur + salarié)
|
||||
* Envoie les emails de confirmation finaux aux deux parties
|
||||
*
|
||||
* Flux :
|
||||
* 1. Employeur signe → Lambda postDocuSealAvenantSalarie → /api/webhooks/docuseal-amendment
|
||||
* 2. Salarié signe → DocuSeal webhook → Cette route
|
||||
* 3. Envoi emails de confirmation à l'employeur ET au salarié
|
||||
*/
|
||||
export async function POST(request: NextRequest) {
|
||||
console.log("🎉 [WEBHOOK AVENANT COMPLETED] Début du traitement");
|
||||
|
||||
try {
|
||||
const body = await request.json();
|
||||
console.log("📦 [WEBHOOK AVENANT COMPLETED] Body reçu:", JSON.stringify(body, null, 2));
|
||||
|
||||
// Extraire les données du webhook DocuSeal
|
||||
const eventType = body.event_type;
|
||||
const submissionId = body.data?.submission?.id || body.data?.submission_id;
|
||||
const templateExternalId = body.data?.template?.external_id;
|
||||
|
||||
console.log("🔍 [WEBHOOK AVENANT COMPLETED] Event type:", eventType);
|
||||
console.log("🔍 [WEBHOOK AVENANT COMPLETED] Submission ID:", submissionId);
|
||||
console.log("🔍 [WEBHOOK AVENANT COMPLETED] Template external ID:", templateExternalId);
|
||||
|
||||
// Vérifier que c'est bien un événement de complétion
|
||||
if (eventType !== "submission.completed") {
|
||||
console.log("ℹ️ [WEBHOOK AVENANT COMPLETED] Event type non géré:", eventType);
|
||||
return NextResponse.json({ message: "Event type ignoré" }, { status: 200 });
|
||||
}
|
||||
|
||||
if (!submissionId) {
|
||||
console.error("❌ [WEBHOOK AVENANT COMPLETED] submission_id manquant");
|
||||
return NextResponse.json(
|
||||
{ error: "submission_id requis" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const supabase = createSbServiceRole();
|
||||
|
||||
// 1. Récupérer l'avenant depuis Supabase via le docuseal_submission_id
|
||||
console.log("🔍 [WEBHOOK AVENANT COMPLETED] Recherche de l'avenant...");
|
||||
const { data: avenant, error: avenantError } = await supabase
|
||||
.from("avenants")
|
||||
.select(`
|
||||
*,
|
||||
cddu_contracts (
|
||||
*,
|
||||
salaries (
|
||||
prenom,
|
||||
nom,
|
||||
adresse_mail
|
||||
),
|
||||
organizations (
|
||||
id,
|
||||
name,
|
||||
code_employeur
|
||||
)
|
||||
)
|
||||
`)
|
||||
.eq("docuseal_submission_id", submissionId)
|
||||
.maybeSingle();
|
||||
|
||||
if (avenantError || !avenant) {
|
||||
console.error("❌ [WEBHOOK AVENANT COMPLETED] Avenant non trouvé:", avenantError);
|
||||
return NextResponse.json(
|
||||
{ error: "Avenant non trouvé", details: avenantError?.message },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log("✅ [WEBHOOK AVENANT COMPLETED] Avenant trouvé:", {
|
||||
id: avenant.id,
|
||||
numero: avenant.numero_avenant,
|
||||
contract_id: avenant.contract_id,
|
||||
});
|
||||
|
||||
// 2. Mettre à jour le statut de l'avenant
|
||||
console.log("🔄 [WEBHOOK AVENANT COMPLETED] Mise à jour du statut...");
|
||||
const { error: updateError } = await supabase
|
||||
.from("avenants")
|
||||
.update({
|
||||
signature_status: "completed",
|
||||
completed_at: new Date().toISOString(),
|
||||
})
|
||||
.eq("id", avenant.id);
|
||||
|
||||
if (updateError) {
|
||||
console.error("❌ [WEBHOOK AVENANT COMPLETED] Erreur mise à jour:", updateError);
|
||||
} else {
|
||||
console.log("✅ [WEBHOOK AVENANT COMPLETED] Statut mis à jour: completed");
|
||||
}
|
||||
|
||||
// 3. Préparer les données pour les emails
|
||||
const contract = avenant.cddu_contracts;
|
||||
const salarie = contract?.salaries;
|
||||
const organization = contract?.organizations;
|
||||
|
||||
if (!contract || !salarie || !organization) {
|
||||
console.error("❌ [WEBHOOK AVENANT COMPLETED] Données manquantes:", {
|
||||
hasContract: !!contract,
|
||||
hasSalarie: !!salarie,
|
||||
hasOrganization: !!organization,
|
||||
});
|
||||
return NextResponse.json(
|
||||
{ error: "Données du contrat/salarié/organisation manquantes" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Formater la date
|
||||
const formatDate = (dateStr?: string | null) => {
|
||||
if (!dateStr) return "-";
|
||||
try {
|
||||
const parts = dateStr.split("-");
|
||||
if (parts.length === 3) {
|
||||
const [y, m, d] = parts;
|
||||
return `${d}/${m}/${y}`;
|
||||
}
|
||||
return dateStr;
|
||||
} catch {
|
||||
return dateStr;
|
||||
}
|
||||
};
|
||||
|
||||
const startDate = formatDate(contract.start_date);
|
||||
const employerEmail = organization.email || "hello@odentas.fr"; // Fallback si pas d'email
|
||||
const employeeEmail = salarie.adresse_mail;
|
||||
|
||||
// Récupérer le prénom du signataire depuis l'organisation (profiles)
|
||||
let employerFirstName = "Employeur";
|
||||
if (organization.id) {
|
||||
const { data: profiles } = await supabase
|
||||
.from("profiles")
|
||||
.select("first_name, last_name")
|
||||
.eq("organization_id", organization.id)
|
||||
.limit(1)
|
||||
.maybeSingle();
|
||||
|
||||
if (profiles?.first_name) {
|
||||
employerFirstName = profiles.first_name;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Envoyer l'email à l'EMPLOYEUR
|
||||
console.log("📧 [WEBHOOK AVENANT COMPLETED] Envoi email employeur...");
|
||||
|
||||
const employerEmailData: EmailDataV2 = {
|
||||
firstName: employerFirstName,
|
||||
organizationName: organization.name || "Votre structure",
|
||||
employerCode: organization.code_employeur || "Non spécifié",
|
||||
contractReference: contract.contract_number || "Non spécifié",
|
||||
startDate: startDate,
|
||||
profession: contract.fonction || "Non spécifié",
|
||||
productionName: contract.analytique || "Non spécifié",
|
||||
ctaUrl: "https://paie.odentas.fr/",
|
||||
ctaText: "Accès à l'Espace Paie",
|
||||
numeroAvenant: avenant.numero_avenant,
|
||||
salarieName: `${salarie.prenom} ${salarie.nom}`,
|
||||
contractType: "CDDU (contrat intermittent)",
|
||||
};
|
||||
|
||||
try {
|
||||
const employerMessageId = await sendUniversalEmailV2({
|
||||
type: "amendment-completed-employer",
|
||||
toEmail: employerEmail,
|
||||
data: employerEmailData,
|
||||
});
|
||||
console.log("✅ [WEBHOOK AVENANT COMPLETED] Email employeur envoyé:", employerMessageId);
|
||||
} catch (emailError: any) {
|
||||
console.error("❌ [WEBHOOK AVENANT COMPLETED] Erreur email employeur:", emailError);
|
||||
}
|
||||
|
||||
// 5. Envoyer l'email au SALARIÉ
|
||||
console.log("📧 [WEBHOOK AVENANT COMPLETED] Envoi email salarié...");
|
||||
|
||||
const employeeEmailData: EmailDataV2 = {
|
||||
firstName: salarie.prenom || "Salarié",
|
||||
organizationName: organization.name || "Votre employeur",
|
||||
matricule: contract.matricule || "Non spécifié",
|
||||
contractReference: contract.contract_number || "Non spécifié",
|
||||
startDate: startDate,
|
||||
profession: contract.fonction || "Non spécifié",
|
||||
productionName: contract.analytique || "Non spécifié",
|
||||
ctaUrl: `https://paie.odentas.fr/dl-avenant?avenant_id=${avenant.id}`,
|
||||
ctaText: "Télécharger l'avenant",
|
||||
numeroAvenant: avenant.numero_avenant,
|
||||
contractType: "CDDU (contrat intermittent)",
|
||||
};
|
||||
|
||||
try {
|
||||
const employeeMessageId = await sendUniversalEmailV2({
|
||||
type: "amendment-completed-employee",
|
||||
toEmail: employeeEmail,
|
||||
data: employeeEmailData,
|
||||
});
|
||||
console.log("✅ [WEBHOOK AVENANT COMPLETED] Email salarié envoyé:", employeeMessageId);
|
||||
} catch (emailError: any) {
|
||||
console.error("❌ [WEBHOOK AVENANT COMPLETED] Erreur email salarié:", emailError);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "Emails de confirmation envoyés",
|
||||
avenantId: avenant.id,
|
||||
numeroAvenant: avenant.numero_avenant,
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("❌ [WEBHOOK AVENANT COMPLETED] Erreur:", error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Erreur lors du traitement",
|
||||
details: error.message,
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ export type EmailType =
|
|||
| 'support-ticket-created' // Nouveau ticket
|
||||
| 'support-ticket-reply' // Réponse utilisateur
|
||||
| 'contact-support' // Formulaire contact public
|
||||
| 'amendment-completed-employer' // Avenant signé (notification employeur)
|
||||
| 'amendment-completed-employee' // Avenant signé (notification salarié)
|
||||
| 'account-activation'
|
||||
| 'access-updated'
|
||||
| 'access-revoked'
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ export type EmailTypeV2 =
|
|||
| 'signature-request-employee'
|
||||
| 'signature-request-employee-amendment' // Nouveau type pour signature avenant salarié
|
||||
| 'signature-request-salarie' // Nouveau type pour demande signature salarié (depuis Lambda DocuSeal)
|
||||
| 'amendment-completed-employer' // Confirmation signature complète avenant pour employeur
|
||||
| 'amendment-completed-employee' // Confirmation signature complète avenant pour salarié
|
||||
| 'bulk-signature-notification' // Nouveau type pour notification de signatures en masse
|
||||
| 'salary-transfer-notification' // Nouveau type pour notification d'appel à virement
|
||||
| 'contribution-notification' // Nouveau type pour notification de cotisations
|
||||
|
|
@ -1031,6 +1033,76 @@ const EMAIL_TEMPLATES_V2: Record<EmailTypeV2, EmailTemplateV2> = {
|
|||
{ label: 'Contenu', key: 'message' },
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
'amendment-completed-employer': {
|
||||
subject: 'Avenant {{#if numeroAvenant}}n°{{numeroAvenant}}{{/if}} signé - {{organizationName}}',
|
||||
title: 'Avenant signé',
|
||||
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
|
||||
mainMessage: 'L\'avenant au contrat de travail a été signé par toutes les parties.<br><br>Les deux exemplaires signés sont disponibles sur la plateforme Odentas.',
|
||||
ctaText: 'Voir les documents',
|
||||
closingMessage: 'Pour toute question, contactez-nous à <a href="mailto:paie@odentas.fr" style="color:#0B5FFF; text-decoration:none;">paie@odentas.fr</a>.',
|
||||
footerText: 'Notification de signature · Espace Paie Odentas',
|
||||
preheaderText: 'Avenant signé · {{#if numeroAvenant}}n°{{numeroAvenant}}{{/if}} · {{organizationName}}',
|
||||
colors: {
|
||||
headerColor: STANDARD_COLORS.HEADER,
|
||||
titleColor: '#0F172A',
|
||||
buttonColor: STANDARD_COLORS.BUTTON,
|
||||
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
|
||||
cardBackgroundColor: '#FFFFFF',
|
||||
cardBorder: '#E5E7EB',
|
||||
cardTitleColor: '#0F172A',
|
||||
alertIndicatorColor: '#22C55E',
|
||||
},
|
||||
infoCard: [
|
||||
{ label: 'Salarié', key: 'employeeName' },
|
||||
{ label: 'Matricule', key: 'matricule' },
|
||||
],
|
||||
detailsCard: {
|
||||
title: 'Détails de l\'avenant',
|
||||
rows: [
|
||||
{ label: 'Référence contrat', key: 'contractReference' },
|
||||
{ label: 'Type de contrat', key: 'contractType' },
|
||||
{ label: 'Profession', key: 'profession' },
|
||||
{ label: 'Date de début', key: 'startDate' },
|
||||
{ label: 'Production', key: 'productionName' },
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
'amendment-completed-employee': {
|
||||
subject: 'Votre avenant {{#if numeroAvenant}}n°{{numeroAvenant}}{{/if}} est signé - {{organizationName}}',
|
||||
title: 'Avenant signé',
|
||||
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
|
||||
mainMessage: 'Votre avenant au contrat de travail a été signé par toutes les parties.<br><br>Vous pouvez dès maintenant télécharger votre exemplaire signé depuis le lien ci-dessous.',
|
||||
ctaText: 'Télécharger l\'avenant',
|
||||
closingMessage: 'Pour toute question, contactez-nous à <a href="mailto:paie@odentas.fr" style="color:#0B5FFF; text-decoration:none;">paie@odentas.fr</a>.',
|
||||
footerText: 'Vous recevez cet e-mail car votre employeur ({{organizationName}}) est client d\'Odentas Media SAS, pour vous notifier d\'une action sur votre contrat de travail avec cet employeur.',
|
||||
preheaderText: 'Avenant signé · {{#if numeroAvenant}}n°{{numeroAvenant}}{{/if}} · {{organizationName}}',
|
||||
colors: {
|
||||
headerColor: STANDARD_COLORS.HEADER,
|
||||
titleColor: '#0F172A',
|
||||
buttonColor: STANDARD_COLORS.BUTTON,
|
||||
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
|
||||
cardBackgroundColor: '#FFFFFF',
|
||||
cardBorder: '#E5E7EB',
|
||||
cardTitleColor: '#0F172A',
|
||||
alertIndicatorColor: '#22C55E',
|
||||
},
|
||||
infoCard: [
|
||||
{ label: 'Votre employeur', key: 'organizationName' },
|
||||
{ label: 'Votre matricule', key: 'matricule' },
|
||||
],
|
||||
detailsCard: {
|
||||
title: 'Détails de l\'avenant',
|
||||
rows: [
|
||||
{ label: 'Référence contrat', key: 'contractReference' },
|
||||
{ label: 'Type de contrat', key: 'contractType' },
|
||||
{ label: 'Profession', key: 'profession' },
|
||||
{ label: 'Date de début', key: 'startDate' },
|
||||
{ label: 'Production', key: 'productionName' },
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue