espace-paie-odentas/lib/emailTemplateService.ts
odentas 206c1f2afc 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
2025-12-16 20:39:36 +01:00

1656 lines
No EOL
71 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// lib/emailTemplateService.ts - Version modernisée
import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses";
import { readFileSync } from "fs";
import { join } from "path";
// Importer la build ESM/UMD de Handlebars pour éviter l'avertissement webpack sur require.extensions
import Handlebars from 'handlebars/dist/handlebars.js';
import { emailLogger, type EmailType, extractSesDataFromResponse } from './emailLoggingService';
// Couleurs standardisées pour tous les emails
const STANDARD_COLORS = {
HEADER: '#171424',
BUTTON: '#efc543',
BUTTON_HOVER: '#d4a834',
BUTTON_TEXT: '#000000',
ALERT_RED: '#EF4444',
} as const;
export interface EmailConfigV2 {
type: EmailTypeV2;
toEmail: string;
ccEmail?: string;
subject?: string; // Rendu optionnel, car peut être défini dans le template
data: EmailDataV2;
}
export type EmailTypeV2 =
| 'contract-created'
| 'contract-updated'
| 'contract-cancelled'
| 'employee-created' // Ajout du nouveau type
| 'invitation'
| 'auto-declaration-invitation' // Nouveau type pour l'invitation auto-déclaration
| 'invoice'
| 'signature-request'
| 'signature-request-employer'
| '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
| 'salary-transfer-payment-confirmation' // Nouveau type pour notification de paiement effectué
| 'contribution-notification' // Nouveau type pour notification de cotisations
| 'production-declared' // Nouveau type pour notification de déclaration de production
| 'sepa-mandate-request' // Nouveau type pour demande de signature de mandat SEPA
| 'virements-gestion-to-odentas' // Nouveau type pour changement gestion Client → Odentas
| 'virements-gestion-to-client' // Nouveau type pour changement gestion Odentas → Client
| 'virements-gestion-internal' // Nouveau type pour notification interne de changement de gestion
| 'notification'
// Support
| 'support-reply' // Réponse du staff à un ticket support
| '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
| 'account-activation'
| 'access-updated'
| 'access-revoked'
| 'staff-account-created'
// Sécurité compte
| 'password-created'
| 'password-changed'
| 'twofa-enabled'
| 'twofa-disabled';
export interface EmailDataV2 {
firstName?: string;
organizationName?: string;
employeeName?: string;
contractReference?: string;
startDate?: string;
endDate?: string;
profession?: string;
amount?: string;
ctaUrl?: string;
customMessage?: string;
// Ajout des champs pour la carte d'info
companyName?: string;
employerCode?: string;
userName?: string;
productionName?: string;
supportUrl?: string;
// Ajout des champs pour les factures et virements
invoiceNumber?: string;
invoiceDate?: string;
sepaDate?: string;
paymentMethod?: string;
invoiceType?: string;
siteName?: string; // Nom du site web pour factures studio
// Ajout des champs pour les notifications de signatures en masse
contractCount?: number;
handlerName?: string;
status?: string;
// Ajout des champs pour les appels à virement
totalAmount?: string;
periodLabel?: string;
deadline?: string;
transferReference?: string;
// Ajout des champs pour les tickets support
ticketId?: string;
ticketSubject?: string;
staffName?: string;
staffMessage?: string;
// Ajout des champs pour les notifications internes de tickets
ticketCategory?: string;
ticketMessage?: string;
ticketStatus?: string;
userEmail?: string;
userMessage?: string;
// 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;
}
interface EmailTemplateV2 {
subject: string;
title: string;
mainMessage: string;
greeting?: string;
closingMessage?: string;
ctaText?: string;
ctaSubtext?: string; // Texte sous le bouton CTA
ctaUrl?: string; // URL du bouton CTA
footerText: string;
preheaderText: string;
// Configuration des cartes
infoCard?: Array<{ label: string; key: string; }>;
detailsCard?: {
title: string;
rows: Array<{ label: string; key: string; }>;
disclaimer?: string;
};
bankCard?: {
title: string;
subtitle?: string;
conditionKey: string; // Clé pour vérifier la condition
conditionValue: string; // Valeur attendue
additionalConditionKey?: string;
additionalConditionValue?: string;
rows: Array<{ label: string; value: string; }>;
disclaimer?: string;
};
// Couleurs et indicateurs
colors: {
headerColor: string;
titleColor: string;
buttonColor: string;
buttonTextColor: string;
cardBorder: string;
cardBackgroundColor: string;
cardTitleColor: string;
alertIndicatorColor?: string;
};
}
const EMAIL_TEMPLATES_V2: Record<EmailTypeV2, EmailTemplateV2> = {
'password-created': {
subject: 'Mot de passe créé sur votre compte',
title: 'Mot de passe créé',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Vous venez de créer un mot de passe pour votre compte Odentas Paie.',
closingMessage: 'Si vous nêtes pas à lorigine de cette action, <a href="{{supportUrl}}" style="color:#0B5FFF; text-decoration:none;">contactez le support</a> immédiatement.',
ctaText: 'Gérer ma sécurité',
footerText: 'Vous recevez cet e-mail suite à une modification de la sécurité de votre compte.',
preheaderText: 'Mot de passe créé · Sécurisez votre compte',
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: 'Utilisateur', key: 'userEmail' },
{ label: 'Statut', key: 'status' },
],
detailsCard: {
title: 'Détails',
rows: [
{ label: 'Date', key: 'eventDate' },
{ label: 'Plateforme', key: 'platform' },
]
}
},
'password-changed': {
subject: 'Votre mot de passe a été modifié',
title: 'Mot de passe modifié',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Votre mot de passe a été modifié avec succès.',
closingMessage: 'Si vous nêtes pas à lorigine de cette modification, <a href="{{supportUrl}}" style="color:#0B5FFF; text-decoration:none;">contactez le support</a> immédiatement.',
ctaText: 'Accès à l\'Espace Paie',
footerText: 'Vous recevez cet e-mail pour confirmer une modification de mot de passe.',
preheaderText: 'Mot de passe modifié · Vérifiez la sécurité de votre compte',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#F59E0B',
},
infoCard: [
{ label: 'Utilisateur', key: 'userEmail' },
{ label: 'Statut', key: 'status' },
],
detailsCard: {
title: 'Détails',
rows: [
{ label: 'Date', key: 'eventDate' },
{ label: 'Plateforme', key: 'platform' },
]
}
},
'twofa-enabled': {
subject: '2FA activée sur votre compte',
title: 'Double authentification activée',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'La double authentification (2FA) est maintenant activée sur votre compte.',
ctaText: 'Gérer ma sécurité',
footerText: 'Vous recevez cet e-mail pour confirmer lactivation de la 2FA.',
preheaderText: '2FA activée · Sécurité renforcée',
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: 'Utilisateur', key: 'userEmail' },
{ label: 'Statut', key: 'status' },
],
detailsCard: {
title: 'Détails',
rows: [
{ label: 'Date', key: 'eventDate' },
{ label: 'Plateforme', key: 'platform' },
]
}
},
'twofa-disabled': {
subject: '2FA désactivée sur votre compte',
title: 'Double authentification désactivée',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'La double authentification (2FA) a été désactivée sur votre compte.',
closingMessage: 'Nous recommandons de la réactiver pour une sécurité optimale. <a href="{{supportUrl}}" style="color:#0B5FFF; text-decoration:none;">Contactez le support</a> si ce nétait pas vous.',
ctaText: 'Gérer ma sécurité',
footerText: 'Vous recevez cet e-mail pour confirmer la désactivation de la 2FA.',
preheaderText: '2FA désactivée · Votre sécurité est réduite',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: STANDARD_COLORS.ALERT_RED,
},
infoCard: [
{ label: 'Utilisateur', key: 'userEmail' },
{ label: 'Statut', key: 'status' },
],
detailsCard: {
title: 'Détails',
rows: [
{ label: 'Date', key: 'eventDate' },
{ label: 'Plateforme', key: 'platform' },
]
}
},
'virements-gestion-to-odentas': {
subject: 'Modification de la gestion des virements de salaire {{organizationName}}',
title: 'Modification de la gestion des virements de salaire',
greeting: 'Bonjour {{firstName}},',
mainMessage: 'Nous confirmons qu\'<strong>Odentas gère désormais vos virements de salaires</strong>.',
closingMessage: 'Chaque mois, nous vous envoyons un appel à virement avec le total des salaires nets. Vous effectuez un virement unique vers notre compte bancaire, et nous redistribuons les salaires à vos salariés.<br><br>L\'équipe Odentas vous remercie pour votre confiance.',
ctaText: 'Accès à l\'Espace Paie',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Modification de la gestion des virements · Votre compte',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#22C55E',
},
ctaUrl: 'https://paie.odentas.fr',
infoCard: [
{ label: 'Votre structure', key: 'companyName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Comment ça fonctionne',
rows: [
{ label: 'Étape 1', key: 'step1' },
{ label: 'Étape 2', key: 'step2' },
{ label: 'Étape 3', key: 'step3' },
]
}
},
'virements-gestion-to-client': {
subject: 'Modification de la gestion des virements de salaire {{organizationName}}',
title: 'Modification de la gestion des virements de salaire',
greeting: 'Bonjour {{firstName}},',
mainMessage: 'Nous confirmons que <strong>vous gérez désormais vous-même vos virements de salaires</strong>.',
closingMessage: 'L\'équipe Odentas vous remercie pour votre confiance.',
ctaText: 'Accès à l\'Espace Paie',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Modification de la gestion des virements · Votre compte',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#3B82F6',
},
ctaUrl: 'https://paie.odentas.fr',
infoCard: [
{ label: 'Votre structure', key: 'companyName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
},
'virements-gestion-internal': {
subject: '[Virements] Changement de gestion - {{organizationName}}',
title: 'Changement de gestion des virements',
greeting: 'Notification interne',
mainMessage: 'Un client a modifié son mode de gestion des virements salaires.',
closingMessage: 'Cette notification est automatique.',
footerText: 'Odentas - Notification interne',
preheaderText: 'Notification interne · Changement de gestion',
colors: {
headerColor: '#64748B',
titleColor: '#0F172A',
buttonColor: '#64748B',
buttonTextColor: '#FFFFFF',
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#F59E0B',
},
infoCard: [
{ label: 'Organisation', key: 'organizationName' },
{ label: 'Mode précédent', key: 'previousMode' },
{ label: 'Nouveau mode', key: 'newMode' },
{ label: 'Date', key: 'changeDate' },
],
},
'referral': {
subject: '{{referrer_first_name}} de {{organization_name}} vous recommande Odentas',
title: 'Vous avez été recommandé',
greeting: 'Bonjour {{referee_first_name}},',
mainMessage: '<strong>{{referrer_first_name}}</strong> de <strong>{{organization_name}}</strong> vous invite à découvrir les services de Odentas pour votre gestion de la paie du spectacle.<br><br>[Placeholder : Présentation des avantages Odentas]<br><br>[Placeholder : Offre de réduction 20 € HT]{{#if personal_message}}<br><br><div style="background-color:#F8FAFC; padding:16px; border-left:3px solid #A78BFA; border-radius:4px;"><strong style="color:#0F172A;">Message de {{referrer_first_name}} :</strong><br><br><em style="color:#475569;">{{personal_message}}</em></div>{{/if}}',
ctaText: 'Découvrir Odentas',
closingMessage: 'Nous espérons avoir le plaisir de vous accompagner dans la gestion de vos contrats intermittents.<br><br>À très bientôt,<br>L\'équipe Odentas',
footerText: 'Vous recevez cet email car {{referrer_first_name}} de {{organization_name}} vous a recommandé nos services.',
preheaderText: '{{referrer_first_name}} de {{organization_name}} vous invite à découvrir Odentas',
colors: {
headerColor: '#A78BFA',
titleColor: '#0F172A',
buttonColor: '#A78BFA',
buttonTextColor: '#FFFFFF',
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
},
ctaUrl: 'https://espace-paie.odentas.fr/auth/signup',
infoCard: [
{ label: 'Recommandé par', key: 'referrer_first_name' },
{ label: 'Organisation', key: 'organization_name' },
],
},
'account-activation': {
subject: 'Votre accès a été créé',
title: 'Votre compte est prêt',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Bienvenue ! Votre accès à {{organizationName}} sur l\'Espace Paie Odentas est prêt. Vous pouvez vous connecter dès maintenant.<br><br>Depuis la page de connexion, vous pouvez vous authentifier par code e-mail puis créer un mot de passe dans la section Sécurité de votre compte.',
closingMessage: 'Toute l\'équipe Odentas reste à votre disposition si vous avez des questions. <a href="mailto:paie@odentas.fr" style="color:#0B5FFF; text-decoration:none;">Contactez-nous</a> ou répondez à cet e-mail.<br><br><span style="color: #64748B; font-size: 13px;">Par mesure de sécurité, nous vous invitons à ne pas transférer cet e-mail.</span>',
ctaText: 'Se connecter',
footerText: 'Vous recevez cet e-mail car un accès vous a été créé sur l\'Espace Paie Odentas, par un administrateur de l\'organisation {{organizationName}}, qui est cliente de Odentas. Si vous estimez avoir reçu cet e-mail par erreur, contactez-nous en répondant à cet e-mail.',
preheaderText: 'Accès créé · {{organizationName}} · Connectez-vous dès maintenant',
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: 'Invité par', key: 'inviterNameWithStatus' },
{ label: 'Organisation', key: 'organizationName' },
{ label: 'Niveau d\'accès', key: 'role' },
],
},
'access-updated': {
subject: 'Vos habilitations ont été modifiées {{organizationName}}',
title: 'Habilitation mise à jour',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Votre rôle au sein de {{organizationName}} a été modifié.',
ctaText: 'Voir vos accès',
footerText: 'Vous recevez cet e-mail suite à une modification de vos droits daccès.',
preheaderText: 'Habilitation mise à jour · Nouveau rôle: {{newRole}}',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#F59E0B',
},
infoCard: [
{ label: 'Organisation', key: 'organizationName' },
{ label: 'Utilisateur', key: 'userEmail' },
],
detailsCard: {
title: 'Détails de la modification',
rows: [
{ label: 'Ancien rôle', key: 'oldRole' },
{ label: 'Nouveau rôle', key: 'newRole' },
{ label: 'Modifié par', key: 'updatedBy' },
{ label: 'Date', key: 'updateDate' },
]
}
},
'access-revoked': {
subject: 'Votre accès a été révoqué {{organizationName}}',
title: 'Accès révoqué',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Votre accès à {{organizationName}} a été révoqué.',
closingMessage: 'Si vous pensez quil sagit dune erreur, <a href="{{supportUrl}}" style="color:#0B5FFF; text-decoration:none;">contactez le support</a>.',
ctaText: 'Contacter le support',
footerText: 'Vous recevez cet e-mail pour vous informer de la révocation de votre accès.',
preheaderText: 'Accès révoqué · Contactez le support en cas derreur',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: STANDARD_COLORS.ALERT_RED,
},
infoCard: [
{ label: 'Organisation', key: 'organizationName' },
{ label: 'Utilisateur', key: 'userEmail' },
{ label: 'Statut', key: 'status' },
],
detailsCard: {
title: 'Détails de la révocation',
rows: [
{ label: 'Date de révocation', key: 'revocationDate' },
{ label: 'Révoqué par', key: 'revokedBy' },
{ label: 'Raison', key: 'reason' },
]
}
},
'contract-created': {
subject: 'Nouveau CDDU créé - {{employeeName}}',
title: 'Nouveau contrat CDDU',
greeting: 'Bonjour {{userName}},',
mainMessage: 'Un nouveau contrat CDDU a été créé sur votre Espace Paie Odentas.',
ctaText: 'Voir le contrat',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Nouveau contrat créé · Consultez et téléchargez votre contrat',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#22C55E', // Vert pour création
},
infoCard: [
{ label: 'Votre structure', key: 'companyName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails du contrat',
rows: [
{ label: 'Salarié', key: 'employeeName' },
{ label: 'Poste', key: 'profession' },
{ label: 'Date de début', key: 'startDate' },
{ label: 'Référence', key: 'contractReference' }
]
}
},
'employee-created': {
subject: 'Nouveau salarié créé - {{employeeName}}',
title: 'Nouveau salarié créé',
greeting: 'Bonjour {{userName}},',
mainMessage: 'Un nouveau salarié a été créé avec succès dans votre Espace Paie Odentas.',
ctaText: 'Voir la fiche du salarié',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Nouveau salarié créé · Consultez la fiche du salarié',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#10B981', // Vert émeraude pour nouveau salarié
},
infoCard: [
{ label: 'Votre structure', key: 'companyName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails du salarié',
rows: [
{ label: 'Salarié', key: 'employeeName' },
{ label: 'Email', key: 'email' },
{ label: 'Matricule', key: 'matricule' },
]
}
},
'contract-updated': {
subject: 'CDDU modifié - {{employeeName}}',
title: 'Contrat CDDU modifié',
greeting: 'Bonjour {{userName}},',
mainMessage: 'Votre contrat CDDU a été modifié sur votre Espace Paie Odentas.',
ctaText: 'Voir les modifications',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Contrat modifié · Consultez les changements',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#F59E0B', // Orange pour modification
},
infoCard: [
{ label: 'Votre structure', key: 'companyName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails du contrat',
rows: [
{ label: 'Salarié', key: 'employeeName' },
{ label: 'Poste', key: 'profession' },
{ label: 'Date de début', key: 'startDate' },
{ label: 'Référence', key: 'contractReference' }
]
}
},
'contract-cancelled': {
subject: 'CDDU annulé - {{employeeName}}',
title: 'CDDU annulé',
greeting: 'Bonjour {{userName}},',
mainMessage: 'Votre contrat CDDU a été annulé.',
closingMessage: 'Pour votre sécurité, ne partagez jamais ce message. <br>Si vous n\'êtes pas à l\'origine de cette annulation, <a href="{{supportUrl}}" style="color:#0B5FFF; text-decoration:none;">contactez le support</a>.<br><br>L\'équipe Odentas vous remercie pour votre confiance.',
ctaText: 'Accès à l\'Espace Paie',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'CDDU annulé pour {{employeeName}} · Réf {{contractReference}} · Plus d\'informations disponibles',
colors: {
headerColor: '#efc543',
titleColor: '#0F172A',
buttonColor: '#efc543',
buttonTextColor: '#000000',
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: STANDARD_COLORS.ALERT_RED,
},
infoCard: [
{ label: 'Votre structure', key: 'companyName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' }, // Note: 'handlerName' is new
],
detailsCard: {
title: 'Détails du contrat',
rows: [
{ label: 'Référence', key: 'contractReference' },
{ label: 'Salarié', key: 'employeeName' },
{ label: 'Poste', key: 'profession' },
{ label: 'Date de début', key: 'startDate' },
{ label: 'Production', key: 'productionName' },
]
}
},
'invitation': {
subject: 'Invitation à rejoindre {{organizationName}}',
title: 'Vous êtes invité',
mainMessage: 'Vous avez été invité à rejoindre l\'organisation {{organizationName}} sur Odentas.',
ctaText: 'Accepter l\'invitation',
footerText: 'Vous recevez cet e-mail car vous avez été invité sur Odentas.',
preheaderText: 'Invitation reçue · Rejoignez votre équipe',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#F0F9FF',
cardBorder: '#BAE6FD',
cardTitleColor: '#0369A1'
}
},
'auto-declaration-invitation': {
subject: 'Complétez votre dossier d\'embauche - Documents requis',
title: 'Complétez votre dossier d\'embauche',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Dans le cadre de votre projet d\'embauche géré par les services d\'Odentas pour le compte de {{organizationName}}, nous vous invitons à compléter votre dossier.\n\nPour finaliser votre embauche, nous avons besoin que vous nous transmettiez certaines informations personnelles et justificatifs.',
closingMessage: 'Important : Ce lien d\'accès expire dans 7 jours. Pensez à compléter votre dossier avant cette date.<br><br>Besoin d\'aide ? N\'hésitez pas à nous contacter à <a href="mailto:paie@odentas.fr" style="color:#0B5FFF;">paie@odentas.fr</a> pour toute question.',
ctaText: 'Compléter mon dossier',
footerText: 'Ce lien est personnel et sécurisé. Ne le partagez avec personne d\'autre.<br><br>Vous recevez cet e-mail car votre employeur ou futur employeur est client de Odentas, pour vous notifier d\'une action sur votre contrat de travail ou votre projet d\'embauche avec cet employeur. Ce mail ne constitue pas une promesse d\'embauche.',
preheaderText: 'Dossier d\'embauche · Complétez vos informations',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: '#059669',
buttonTextColor: '#FFFFFF',
cardBackgroundColor: '#F0F9FF',
cardBorder: '#E0F2FE',
cardTitleColor: '#0C4A6E'
},
infoCard: [
{ label: 'Votre employeur', key: 'organizationName' },
{ label: 'Votre matricule', key: 'matricule' }
]
},
'invoice': {
subject: 'Nouvelle facture - {{amount}}',
title: 'Nouvelle facture',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: '{{{customMessage}}}',
closingMessage: 'Si vous avez des questions concernant cette facture, <a href="mailto:paie@odentas.fr" style="color:#0B5FFF; text-decoration:none;">contactez-nous à paie@odentas.fr</a>.<br><br>L\'équipe Odentas vous remercie pour votre confiance.',
ctaText: 'Télécharger la facture', // Sera "Voir la facture" pour paie via le template
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Nouvelle facture · Accédez à votre espace',
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 structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' }
],
detailsCard: {
title: 'Détails de la facture',
rows: [
{ label: 'Numéro', key: 'invoiceNumber' },
{ label: 'Montant', key: 'amount' },
{ label: 'Date de facture', key: 'invoiceDate' },
{ label: 'Prélèvement SEPA', key: 'sepaDate' },
{ label: 'Site web concerné', key: 'siteName' } // Pour factures studio
]
},
bankCard: {
title: 'Coordonnées bancaires pour le virement',
conditionKey: 'paymentMethod',
conditionValue: 'virement',
rows: [
{ label: 'Bénéficiaire', value: 'Odentas Media SAS' },
{ label: 'IBAN', value: 'FR7616958000014277434166014' },
{ label: 'BIC', value: 'QNTOFRP1XXX' },
{ label: 'Libellé', value: '{{invoiceNumber}}' }
]
}
},
'signature-request': {
subject: 'Signature requise - {{employeeName}}',
title: 'Signature électronique requise',
mainMessage: 'Votre signature est requise pour finaliser le contrat.',
ctaText: 'Signer maintenant',
footerText: 'Vous recevez cet e-mail car votre signature est requise.',
preheaderText: 'Signature requise · Finalisez votre contrat',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#22C55E'
},
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
infoCard: [
{ label: 'Votre structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails de la signature',
rows: [
{ label: 'Document', key: 'documentType' },
{ label: 'Salarié', key: 'employeeName' },
{ label: 'Référence', key: 'contractReference' },
{ label: 'Statut', key: 'status' },
]
}
},
'signature-request-employer': {
subject: 'Signature requise {{employeeName}}',
title: 'Signature électronique requise',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Un document nécessite votre signature électronique en tant quemployeur.',
ctaText: 'Signer le document',
footerText: 'Vous recevez ce document car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Signature électronique requise · Signez en tant quemployeur',
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 structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'code_employeur' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails du document',
rows: [
{ label: 'Document', key: 'documentType' },
{ label: 'Salarié', key: 'employeeName' },
{ label: 'Référence contrat', key: 'contractReference' },
]
}
},
'signature-request-employee': {
subject: 'Signature requise {{documentType}}',
title: 'Signature électronique requise',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Ce rappel vous est envoyé par votre employeur, votre contrat de travail est en attente de signature.',
ctaText: 'Signer le document',
closingMessage: 'Nous restons à votre disposition à paie@odentas.fr si vous avez besoin d\'assistance.',
footerText: 'Vous recevez cet e-mail car votre employeur est client de Odentas, pour vous notifier d\'une action sur votre contrat de travail avec cet employeur.',
preheaderText: 'Signature électronique requise · Signez votre document',
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 du document',
rows: [
{ label: 'Référence', key: 'contractReference' },
{ label: 'Profession', key: 'profession' },
{ label: 'Date de début', key: 'startDate' },
{ label: 'Production', key: 'productionName' },
]
}
},
'signature-request-employee-amendment': {
subject: 'Signez votre avenant {{#if numeroAvenant}}n°{{numeroAvenant}}{{/if}} - {{organizationName}}',
title: 'Demande de signature électronique',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Nous vous invitons à signer votre avenant au contrat de travail ci-dessous.<br><br>Cliquez sur « Signer l\'avenant » pour accéder à Odentas Sign. Vous pourrez télécharger votre avenant dès validation de votre signature.',
ctaText: 'Signer 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: 'Signature électronique · Avenant {{#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 avenant', key: 'contractReference' },
{ label: 'Type de contrat', key: 'contractType' },
{ label: 'Profession', key: 'profession' },
{ label: 'Date de début', key: 'startDate' },
{ label: 'Production', key: 'productionName' },
]
}
},
'signature-request-salarie': {
subject: 'Signez votre contrat {{organizationName}}',
title: 'Demande de signature électronique',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Nous vous invitons à signer votre contrat de travail ci-dessous.<br><br>Cliquez sur « Signer le contrat » pour accéder à Odentas Sign. Vous pourrez télécharger votre contrat dès validation de votre signature.',
ctaText: 'Signer le contrat',
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 ou futur employeur ({{organizationName}}) est client d\'Odentas Media SAS, pour vous notifier d\'une action sur votre contrat de travail avec cet employeur. Si vous pensez avoir reçu cet e-mail par erreur, merci de contacter notre équipe à l\'adresse paie@odentas.fr.',
preheaderText: 'Signature électronique · {{organizationName}} · Signez votre contrat',
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 du contrat',
rows: [
{ label: 'Référence', key: 'contractReference' },
{ label: 'Type de contrat', key: 'typecontrat' },
{ label: 'Employeur', key: 'organizationName' },
{ label: 'Début contrat', key: 'startDate' },
{ label: 'Poste', key: 'profession' },
{ label: 'Production', key: 'productionName' },
]
}
},
'bulk-signature-notification': {
subject: 'Contrats à signer {{contractCount}} signature{{#if (gt contractCount 1)}}s{{/if}} en attente',
title: 'Contrats en attente de signature',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Vous avez {{contractCount}} contrat{{#if (gt contractCount 1)}}s{{/if}} en attente de signature électronique.<br><br>Pour consulter et signer vos contrats, cliquez sur le bouton ci-dessous :',
closingMessage: 'Si vous avez des questions, n\'hésitez pas à nous contacter à <a href="mailto:paie@odentas.fr" style="color:#0B5FFF; text-decoration:none;">paie@odentas.fr</a>.',
ctaText: 'Accéder aux signatures',
ctaUrl: 'https://paie.odentas.fr/signatures-electroniques',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Contrats à signer · {{contractCount}} signature{{#if (gt contractCount 1)}}s{{/if}} requise{{#if (gt contractCount 1)}}s{{/if}}',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#6366F1',
},
infoCard: [
{ label: 'Votre structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Signatures en attente',
rows: [
{ label: 'Nombre de contrats', key: 'contractCount' },
{ label: 'Statut', key: 'status' },
]
}
},
'salary-transfer-notification': {
subject: 'Nouvel appel à virement - {{periodLabel}}',
title: 'Nouvel appel à virement',
greeting: '{{#if firstName}}👋 Bonjour {{firstName}},{{/if}}',
mainMessage: 'Vous trouverez ci-dessous les détails du virement à nous transférer pour le paiement des rémunérations de vos salariés.<br><br>L\'appel à virement est disponible sur votre Espace Paie, en cliquant sur le bouton ci-dessous.',
closingMessage: 'Le montant correspond au cumul des salaires nets de la période concernée, après prélèvement à la source.<br><br>Dès réception du virement, nous procéderons sous 24 heures ouvrées aux versements individuels des salaires. Vos salariés et vous-même recevrez une notification.<br><br>Les cotisations (ainsi que le prélèvement à la source) sont prélevées directement sur votre compte bancaire par les organismes concernés.<br><br>N\'hésitez pas à répondre à cet e-mail si vous avez besoin d\'assistance.<br><br>Merci pour votre confiance,<br>L\'équipe Odentas.',
ctaText: 'Télécharger l\'Appel à Virement',
ctaUrl: 'https://paie.odentas.fr/virements-salaires/',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Appel à virement · {{periodLabel}}',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#F0F0F5',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#22C55E',
},
infoCard: [
{ label: 'Votre structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails du virement',
rows: [
{ label: 'Montant à virer', key: 'totalAmount' },
{ label: 'Période concernée', key: 'periodLabel' },
]
},
bankCard: {
title: 'Nos coordonnées bancaires',
subtitle: 'Attention, le compte bancaire ci-dessous est uniquement destiné à la gestion des salaires.',
conditionKey: 'showBankInfo',
conditionValue: 'true',
rows: [
{ label: 'Bénéficiaire', value: 'ODENTAS MEDIA SAS' },
{ label: 'IBAN', value: 'FR76 1695 8000 0141 0850 9729 813' },
{ label: 'BIC', value: 'QNTOFRP1XXX' },
{ label: 'Référence', value: '{{transferReference}}' },
],
disclaimer: 'Ce compte bancaire est réservé à la réception des virements de salaires.'
}
},
'salary-transfer-payment-confirmation': {
subject: 'Paiement des salaires effectué - {{periodLabel}}',
title: 'Paiement des salaires effectué',
greeting: '{{#if firstName}}👋 Bonjour {{firstName}},{{/if}}',
mainMessage: 'Nous vous confirmons avoir bien reçu votre virement pour le paiement des rémunérations de vos salariés.<br><br>Nous avons procédé aux versements individuels des salaires auprès de vos salariés*.<br><br>Les fiches de paie, AEM et bordereaux Congés Spectacles ont été mis à disposition sur les espaces Transat de vos salariés et sur votre Espace Paie Odentas.',
closingMessage: 'Vous pouvez retrouver l\'ensemble des détails de ce virement dans votre Espace Paie.<br><br>N\'hésitez pas à répondre à cet e-mail si vous avez besoin d\'assistance.<br><br>Merci pour votre confiance,<br>L\'équipe Odentas.',
ctaText: 'Accéder à mon Espace Paie',
ctaUrl: 'https://paie.odentas.fr/virements-salaires/',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Confirmation de paiement · {{periodLabel}}',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#F0F0F5',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#22C55E',
},
infoCard: [
{ label: 'Votre structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails du paiement',
rows: [
{ label: 'Montant versé', key: 'totalAmount' },
{ label: 'Période concernée', key: 'periodLabel' },
{ label: 'Date de réception', key: 'paymentDate' },
],
disclaimer: '* Pour les contrats signés et terminés. Pour les autres contrats, nous procéderons au paiement du salaire à la réception de la signature de votre salarié et/ou le jour ouvré suivant la fin du contrat, sauf demande expresse contraire de votre part.'
}
},
'contribution-notification': {
subject: 'Échéance de cotisations - {{periodLabel}}',
title: 'Échéance de cotisations',
greeting: '{{#if firstName}}👋 Bonjour {{firstName}},{{/if}}',
mainMessage: '{{#if hasZeroContributions}}Nous vous informons qu\'en l\'absence de paie pour la période {{periodLabel}}, aucune cotisation ne vous sera prélevée par les caisses et organismes.{{else}}Nous vous rappelons que les prélèvements des cotisations sociales pour la période {{periodLabel}} auront lieu prochainement.{{/if}}',
closingMessage: 'Si vous avez des questions concernant ces cotisations, n\'hésitez pas à nous contacter en répondant à cet e-mail.<br><br>Cordialement,<br>L\'équipe Odentas.',
ctaText: 'Voir mes cotisations',
ctaUrl: 'https://paie.odentas.fr/cotisations',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Rappel de prélèvement · {{periodLabel}}',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#F0F0F5',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#F59E0B',
},
infoCard: [
{ label: 'Votre structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Informations sur la période',
rows: [
{ label: 'Période concernée', key: 'periodLabel' },
{ label: 'Date de prélèvement théorique', key: 'collectionPeriod' },
]
}
},
'production-declared': {
subject: 'Nouvelle production déclarée : {{productionName}}',
title: 'Nouvelle production déclarée',
greeting: '{{#if firstName}}👋 Bonjour {{firstName}},{{/if}}',
mainMessage: 'Nous vous confirmons avoir procédé à la déclaration de votre nouvelle production auprès de France Travail Spectacle.<br><br>Le numéro d\'objet attribué apparaîtra sur les contrats de travail, fiches de paie et AEM de vos salariés, conformément à la législation en vigueur.',
closingMessage: 'N\'hésitez pas à répondre à cet e-mail si vous avez besoin d\'assistance.<br><br>Merci pour votre confiance,<br>L\'équipe Odentas.',
ctaText: 'Accès à l\'Espace Paie',
ctaUrl: 'https://paie.odentas.fr/',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Nouvelle production déclarée · {{productionName}}',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#F0F0F5',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
alertIndicatorColor: '#22C55E',
},
infoCard: [
{ label: 'Votre structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails de la production',
rows: [
{ label: 'Nom de la production', key: 'productionName' },
{ label: 'Date de déclaration', key: 'declarationDate' },
{ label: 'Numéro d\'objet', key: 'productionReference' },
]
}
},
'sepa-mandate-request': {
subject: 'Signez votre mandat de prélèvement SEPA',
title: 'Signature du mandat de prélèvement SEPA',
greeting: '{{#if firstName}}Bonjour {{firstName}} !{{/if}}',
mainMessage: 'Toute l\'équipe Odentas vous souhaite la bienvenue et vous remercie pour votre confiance.<br><br>Nous vous invitons dès à présent à signer votre mandat de prélèvement SEPA en cliquant sur le bouton ci-dessous.<br><br>Vos factures sont directement prélevées sur le compte bancaire de votre structure, au même titre que les cotisations des caisses et organismes.<br><br>Vous êtes prévenus quelques jours avant le prélèvement par une notification par e-mail. Comme pour tout mandat SEPA, vous pouvez révoquer l\'autorisation de prélèvement à tout moment auprès de nos services ou de votre banque.',
closingMessage: 'N\'hésitez pas à répondre à cet e-mail si vous avez des questions.<br><br>L\'équipe Odentas vous remercie pour votre confiance.',
ctaText: 'Signer le mandat de prélèvement',
ctaSubtext: 'Vous serez redirigé vers notre partenaire Gocardless.',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Signature de votre mandat SEPA · Finalisez votre inscription',
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 structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
]
},
'notification': {
subject: 'Notification - {{title}}',
title: 'Notification',
mainMessage: 'Vous avez une nouvelle notification.',
footerText: 'Vous recevez cet e-mail car vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
preheaderText: 'Nouvelle notification',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#F9FAFB',
cardBorder: '#E5E7EB',
cardTitleColor: '#374151'
}
},
'support-reply': {
subject: 'Nouvelle réponse à votre ticket support',
title: 'Réponse à votre ticket',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Vous avez reçu une réponse à votre ticket support.',
ctaText: 'Voir le ticket',
footerText: 'Vous recevez cet e-mail suite à une réponse de notre équipe support.',
preheaderText: 'Notre équipe support a répondu à votre ticket',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
},
infoCard: [
{ label: 'Votre structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Message',
rows: [
{ label: 'Répondu par', key: 'staffName' },
{ label: 'Sujet', key: 'ticketSubject' },
{ label: 'Réponse', key: 'staffMessage' },
]
}
},
'support-ticket-created': {
subject: '[SUPPORT] Nouveau ticket : {{ticketSubject}}',
title: '🎫 Nouveau ticket support',
greeting: 'Notification interne',
mainMessage: 'Un utilisateur a créé un nouveau ticket support.',
ctaText: 'Voir le ticket',
footerText: 'Notification automatique du système de support Odentas.',
preheaderText: 'Nouveau ticket support créé',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: '#3B82F6', // Bleu pour les notifications internes
buttonTextColor: '#FFFFFF',
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
},
infoCard: [
{ label: 'Organisation', key: 'organizationName' },
{ label: 'Code employeur', key: 'employerCode' },
{ label: 'Créé par', key: 'userName' },
{ label: 'Email', key: 'userEmail' },
],
detailsCard: {
title: 'Détails du ticket',
rows: [
{ label: 'ID', key: 'ticketId' },
{ label: 'Sujet', key: 'ticketSubject' },
{ label: 'Catégorie', key: 'ticketCategory' },
{ label: 'Message', key: 'ticketMessage' },
]
}
},
'support-ticket-reply': {
subject: '[SUPPORT] Réponse au ticket : {{ticketSubject}}',
title: '💬 Réponse sur un ticket',
greeting: 'Notification interne',
mainMessage: 'Un utilisateur a répondu à un ticket support.',
ctaText: 'Voir le ticket',
footerText: 'Notification automatique du système de support Odentas.',
preheaderText: 'Nouvelle réponse sur un ticket support',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: '#3B82F6', // Bleu pour les notifications internes
buttonTextColor: '#FFFFFF',
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
},
infoCard: [
{ label: 'Organisation', key: 'organizationName' },
{ label: 'Code employeur', key: 'employerCode' },
{ label: 'Répondu par', key: 'userName' },
{ label: 'Email', key: 'userEmail' },
],
detailsCard: {
title: 'Détails de la réponse',
rows: [
{ label: 'ID', key: 'ticketId' },
{ label: 'Sujet', key: 'ticketSubject' },
{ label: 'Statut', key: 'ticketStatus' },
{ label: 'Réponse', key: 'userMessage' },
]
}
},
'contact-support': {
subject: '[CONTACT] Nouveau message de {{name}}',
title: '📧 Nouveau message de contact',
greeting: 'Équipe Support',
mainMessage: 'Vous avez reçu un nouveau message via le formulaire de contact.',
ctaText: 'Répondre par email',
footerText: 'Message envoyé depuis le formulaire de contact Odentas.',
preheaderText: 'Nouveau message de contact',
colors: {
headerColor: STANDARD_COLORS.HEADER,
titleColor: '#0F172A',
buttonColor: STANDARD_COLORS.BUTTON,
buttonTextColor: STANDARD_COLORS.BUTTON_TEXT,
cardBackgroundColor: '#FFFFFF',
cardBorder: '#E5E7EB',
cardTitleColor: '#0F172A',
},
infoCard: [
{ label: 'Nom', key: 'name' },
{ label: 'Email', key: 'email' },
{ label: 'Envoyé le', key: 'submittedAt' },
],
detailsCard: {
title: 'Message',
rows: [
{ label: 'Contenu', key: 'message' },
]
}
},
'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é',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'L\'avenant au contrat de travail a été signé par toutes les parties.<br><br>Le document est disponible dans la fiche contrat sur l\'Espace Paie Odentas.',
ctaText: 'Accès à l\'Espace Paie',
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 vous êtes client de Odentas, pour vous notifier d\'une action sur votre compte.',
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 structure', key: 'organizationName' },
{ label: 'Votre code employeur', key: 'employerCode' },
{ label: 'Votre gestionnaire', key: 'handlerName' },
],
detailsCard: {
title: 'Détails de l\'avenant',
rows: [
{ label: 'Salarié', key: 'employeeName' },
{ label: 'Matricule', key: 'matricule' },
{ 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' },
]
}
},
'staff-account-created': {
subject: 'Votre compte staff Odentas Paie a été créé',
title: 'Bienvenue sur Odentas Paie',
greeting: '{{#if firstName}}Bonjour {{firstName}},{{/if}}',
mainMessage: 'Votre compte administrateur Odentas Paie a été créé avec succès.<br><br>Vous pouvez dès maintenant vous connecter en utilisant le lien d\'activation ci-dessous. Ce lien est valable pendant 7 jours.',
ctaText: 'Activer mon compte',
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 un compte administrateur Odentas a été créé avec votre adresse email.',
preheaderText: 'Votre compte staff Odentas Paie a été créé',
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: 'Email', key: 'userEmail' },
{ label: 'Type de compte', key: 'accountType' },
{ label: 'Créé par', key: 'createdBy' },
],
detailsCard: {
title: 'Informations importantes',
rows: [
{ label: 'Date de création', key: 'createdAt' },
{ label: 'Validité du lien', key: 'linkValidity' },
],
disclaimer: 'Pour des raisons de sécurité, le lien d\'activation expire au bout de 7 jours. Vous devrez ensuite contacter l\'équipe technique pour obtenir un nouveau lien.'
}
}
};
// Register Handlebars helpers
Handlebars.registerHelper('gt', function(a: any, b: any) {
return a > b;
});
function replaceVariables(template: string, data: EmailDataV2): string {
const compiled = Handlebars.compile(template);
return compiled(data);
}
// Fonction pour traiter les retours à la ligne dans mainMessage
function processMainMessage(template: string, data: EmailDataV2): string {
const processed = replaceVariables(template, data);
// Convertir les \n en <br> pour l'affichage HTML
return processed.replace(/\n/g, '<br>');
}
export async function renderUniversalEmailV2(config: EmailConfigV2): Promise<{ subject: string; html: string; text: string; }> {
const templateConfig = EMAIL_TEMPLATES_V2[config.type];
if (!templateConfig) {
throw new Error(`Template not found for type: ${config.type}`);
}
// Enrichir les données avec des valeurs par défaut ou statiques
const data: EmailDataV2 = {
handlerName: 'Renaud BREVIERE-ABRAHAM',
supportUrl: 'mailto:paie@odentas.fr',
...config.data,
};
// Debug log pour les factures
if (config.type === 'invoice') {
console.log('[emailTemplateService] Invoice email data:', {
customMessage: data.customMessage,
firstName: data.firstName,
amount: data.amount,
invoiceNumber: data.invoiceNumber,
ctaUrl: data.ctaUrl,
invoiceType: data.invoiceType
});
}
const templateData = {
subject: replaceVariables(config.subject || templateConfig.subject, data),
title: replaceVariables(templateConfig.title, data),
greeting: templateConfig.greeting ? replaceVariables(templateConfig.greeting, data) : undefined,
mainMessage: processMainMessage(templateConfig.mainMessage, data),
closingMessage: templateConfig.closingMessage ? replaceVariables(templateConfig.closingMessage, data) : undefined,
// Pour les factures studio, adapter le texte du bouton
ctaText: (config.type === 'invoice' && (data.invoiceType === 'studio_renouvellement' || data.invoiceType === 'studio_site_web'))
? 'Télécharger la facture'
: (config.type === 'invoice'
? 'Voir la facture'
: (templateConfig.ctaText ? replaceVariables(templateConfig.ctaText, data) : undefined)),
ctaSubtext: templateConfig.ctaSubtext ? replaceVariables(templateConfig.ctaSubtext, data) : undefined,
footerText: replaceVariables(templateConfig.footerText, data),
preheaderText: replaceVariables(templateConfig.preheaderText, data),
textFallback: `${replaceVariables(templateConfig.title, data)} - ${replaceVariables(templateConfig.mainMessage, data)}`,
// ctaUrl vient des data pour les factures (défini dans launch/route.ts)
ctaUrl: templateConfig.ctaUrl || data.ctaUrl,
logoUrl: 'https://newstaging.odentas.fr/wp-content/uploads/2025/08/Odentas-Logo-Bleu-Fond-Transparent-4-1.png',
showInfoCard: !!templateConfig.infoCard,
// Pour les factures studio, filtrer le code employeur de l'infoCard
infoCardRows: templateConfig.infoCard?.map(field => ({
label: field.label,
value: data[field.key] ?? '—'
})).filter(row => {
// Exclure le code employeur pour les factures studio
if (config.type === 'invoice' && (data.invoiceType === 'studio_renouvellement' || data.invoiceType === 'studio_site_web')) {
return row.label !== 'Votre code employeur';
}
return true;
}),
showDetailsCard: !!templateConfig.detailsCard,
detailsCardTitle: templateConfig.detailsCard?.title,
detailsCardRows: templateConfig.detailsCard?.rows.map(field => ({
label: field.label,
value: data[field.key] ?? '—'
})).filter(row => {
// Pour les factures, filtrer les lignes selon le type
if (config.type === 'invoice') {
const isStudioInvoice = data.invoiceType === 'studio_renouvellement' || data.invoiceType === 'studio_site_web';
// Pour factures studio : enlever "Prélèvement SEPA", garder "Site web concerné"
if (isStudioInvoice) {
if (row.label === 'Prélèvement SEPA') return false;
// Afficher "Site web concerné" seulement s'il y a une valeur
if (row.label === 'Site web concerné') return !!data.siteName && data.siteName !== '—';
}
// Pour factures paie : enlever "Site web concerné", garder "Prélèvement SEPA"
else {
if (row.label === 'Site web concerné') return false;
}
}
return true;
}),
detailsCardDisclaimer: templateConfig.detailsCard?.disclaimer,
// Logique pour la carte bancaire conditionnelle
showBankCard: templateConfig.bankCard ?
(data[templateConfig.bankCard.conditionKey] === templateConfig.bankCard.conditionValue &&
(!templateConfig.bankCard.additionalConditionKey ||
data[templateConfig.bankCard.additionalConditionKey] === templateConfig.bankCard.additionalConditionValue)) : false,
bankCardTitle: templateConfig.bankCard?.title,
bankCardRows: templateConfig.bankCard?.rows.map(field => ({
label: field.label,
value: replaceVariables(field.value, data)
})),
bankCardDisclaimer: templateConfig.bankCard?.disclaimer,
...templateConfig.colors,
};
// Debug log pour vérifier le ctaUrl final
if (config.type === 'invoice') {
console.log('[emailTemplateService] Final templateData ctaUrl:', {
templateConfigCtaUrl: templateConfig.ctaUrl,
dataCtaUrl: data.ctaUrl,
finalCtaUrl: templateData.ctaUrl,
invoiceType: data.invoiceType
});
}
const templatePath = join(process.cwd(), 'templates-mails', 'universal-template.html');
const htmlTemplateSource = readFileSync(templatePath, 'utf-8');
const handlebarsTemplate = Handlebars.compile(htmlTemplateSource);
const renderedHtml = handlebarsTemplate(templateData);
return { subject: templateData.subject, html: renderedHtml, text: templateData.textFallback };
}
export async function sendUniversalEmailV2(config: EmailConfigV2): Promise<string> {
console.log('🔍 [SES DEBUG] sendUniversalEmailV2 called with:', {
type: config.type,
toEmail: config.toEmail,
ccEmail: config.ccEmail,
toEmailType: typeof config.toEmail,
ccEmailType: typeof config.ccEmail,
subject: config.subject
});
// Validation des emails
const isValidEmail = (email: string) => {
return email && typeof email === 'string' && email.includes('@') && email.includes('.') && email.trim().length > 0;
};
// Valider l'email principal
if (!isValidEmail(config.toEmail)) {
console.error('🚨 [SES DEBUG] Invalid toEmail detected:', {
toEmail: config.toEmail,
type: typeof config.toEmail,
length: config.toEmail?.length,
isEmpty: config.toEmail === '',
isNull: config.toEmail === null,
isUndefined: config.toEmail === undefined
});
throw new Error(`Invalid email address: "${config.toEmail}"`);
}
// Valider l'email CC s'il existe
if (config.ccEmail && !isValidEmail(config.ccEmail)) {
console.warn(`Invalid CC email address, ignoring: "${config.ccEmail}"`);
config.ccEmail = undefined; // Supprimer l'email CC invalide
}
console.log('🔍 [SES DEBUG] Emails validated, proceeding with send:', {
toEmail: config.toEmail,
ccEmail: config.ccEmail
});
// Rendre l'email pour obtenir HTML/TXT et sujet
const rendered = await renderUniversalEmailV2(config);
// Créer le log d'email AVANT l'envoi
const logId = await emailLogger.logEmail({
senderEmail: process.env.AWS_SES_FROM || 'paie@odentas.fr',
recipientEmail: config.toEmail,
ccEmails: config.ccEmail ? [config.ccEmail] : undefined,
subject: rendered.subject,
htmlContent: rendered.html,
textContent: rendered.text,
emailType: config.type as EmailType,
templateName: 'universal-v2',
templateData: config.data,
emailStatus: 'sending',
organizationId: typeof config.data.organizationId === 'string' ? config.data.organizationId : undefined,
contractId: typeof config.data.contractId === 'string' ? config.data.contractId : undefined,
tags: {
template_version: 'v2',
email_system: 'universal'
},
context: {
subject_preview: rendered.subject.substring(0, 100),
has_cta: !!config.data.ctaUrl,
data_keys: Object.keys(config.data)
}
});
// Configuration SES
const sesClient = new SESClient({ region: process.env.AWS_REGION || 'eu-west-3' });
// Nettoyer l'adresse source pour AWS SES
const rawSource = process.env.AWS_SES_FROM || 'paie@odentas.fr';
const cleanSource = rawSource.replace(/^["']|["']$/g, ''); // Supprimer les guillemets externes
const params = {
Source: cleanSource,
Destination: {
ToAddresses: [config.toEmail] as string[],
...(config.ccEmail ? { CcAddresses: [config.ccEmail] as string[] } : {})
},
Message: {
Subject: { Data: rendered.subject, Charset: "UTF-8" },
Body: {
Html: { Data: rendered.html, Charset: "UTF-8" },
Text: { Data: rendered.text, Charset: "UTF-8" }
}
}
};
console.log('🔍 [SES DEBUG] Full SES params before send:', {
SourceRaw: process.env.AWS_SES_FROM,
SourceCleaned: params.Source,
ToAddresses: params.Destination.ToAddresses,
CcAddresses: params.Destination.CcAddresses || 'none',
Subject: params.Message.Subject.Data,
awsRegion: process.env.AWS_REGION || 'eu-west-3',
paramsDestination: JSON.stringify(params.Destination),
allAddresses: [...params.Destination.ToAddresses, ...(params.Destination.CcAddresses || [])]
});
try {
const command = new SendEmailCommand(params);
const response = await sesClient.send(command);
const messageId = (response as any)?.MessageId || '';
console.log(`Email sent successfully to ${config.toEmail} - Type: ${config.type} - MessageId: ${messageId}`);
// Mettre à jour le log avec le succès et l'ID SES
if (logId) {
await emailLogger.updateEmailLog(logId, {
emailStatus: 'sent',
sesMessageId: messageId,
sentAt: new Date()
});
}
return messageId;
} catch (error) {
console.error("Error sending email via SES:", error);
// Mettre à jour le log avec l'erreur
if (logId) {
await emailLogger.updateEmailLog(logId, {
emailStatus: 'failed',
failureReason: error instanceof Error ? error.message : 'Unknown error'
});
}
throw error;
}
}