fix: Récupérer le nom du client depuis Supabase pour email signature-request-salarie
This commit is contained in:
parent
265ed6ce67
commit
5502926271
6 changed files with 445 additions and 90 deletions
|
|
@ -97,9 +97,9 @@ Le système d'export SEPA permet aux clients gérant eux-mêmes leurs virements
|
|||
## ⚠️ Limitations Connues
|
||||
|
||||
### 1. Support contrats
|
||||
- ❌ **Seulement CDDU** : La requête SQL ne récupère que `cddu_contracts`
|
||||
- ⚠️ **Pas de RG** : Les contrats régime général ne sont pas inclus
|
||||
- **Impact** : Export incomplet pour organisations mixtes CDDU+RG
|
||||
- ✅ **Tous types de contrats supportés** : CDDU et RG
|
||||
- ℹ️ **Note technique** : La table `cddu_contracts` contient en réalité tous les types de contrats (nom historique)
|
||||
- ✅ **Payslips** : Toutes les fiches de paie non payées sont incluses
|
||||
|
||||
### 2. Tests bancaires
|
||||
- ✅ **Qonto** : Testé et validé
|
||||
|
|
@ -139,18 +139,18 @@ Le système d'export SEPA permet aux clients gérant eux-mêmes leurs virements
|
|||
- Montants corrects
|
||||
- Bénéficiaires corrects
|
||||
|
||||
### Phase 2 : Support Contrats RG
|
||||
**Objectif** : Inclure les contrats régime général
|
||||
### Phase 2 : Tests Élargis Supplémentaires (OPTIONNEL)
|
||||
**Objectif** : Valider avec d'autres banques
|
||||
|
||||
**Modifications nécessaires** :
|
||||
1. Modifier la requête SQL pour inclure `rg_contracts`
|
||||
2. Unifier la structure de données (CDDU + RG)
|
||||
3. Tester avec organisations mixtes
|
||||
4. Mettre à jour la documentation
|
||||
**Banques à tester** :
|
||||
- [ ] BNP Paribas
|
||||
- [ ] Crédit Agricole
|
||||
- [ ] LCL
|
||||
- [ ] Banque Postale
|
||||
|
||||
**Estimation** : 2-4 heures de développement
|
||||
**Note** : Test Qonto réussi suffit pour activation prudente. Tests supplémentaires recommandés mais non bloquants.
|
||||
|
||||
### Phase 3 : Validation XSD (Optionnel)
|
||||
### Phase 3 : Validation XSD (OPTIONNEL)
|
||||
**Objectif** : Valider le XML contre le schéma officiel
|
||||
|
||||
**Avantages** :
|
||||
|
|
@ -165,10 +165,10 @@ Le système d'export SEPA permet aux clients gérant eux-mêmes leurs virements
|
|||
|
||||
### Phase 4 : Activation Production
|
||||
**Pré-requis** :
|
||||
- ✅ Tests réussis sur 3+ banques
|
||||
- ✅ Support CDDU + RG
|
||||
- ✅ Documentation utilisateur complète
|
||||
- ✅ Support client prêt
|
||||
- ✅ Tests réussis sur Qonto
|
||||
- ✅ Support CDDU + RG (déjà fonctionnel)
|
||||
- ⏳ Documentation utilisateur complète
|
||||
- ⏳ Support client prêt
|
||||
|
||||
**Actions** :
|
||||
1. Réactiver le bouton d'export
|
||||
|
|
@ -176,6 +176,8 @@ Le système d'export SEPA permet aux clients gérant eux-mêmes leurs virements
|
|||
3. Communiquer la nouveauté aux clients
|
||||
4. Monitorer les premiers exports
|
||||
|
||||
**Estimation activation** : Peut être fait rapidement, en attente de décision stratégique
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Problèmes Connus
|
||||
|
|
@ -190,29 +192,34 @@ Les fonctionnalités testées fonctionnent correctement. Les limitations sont do
|
|||
|
||||
### Avant activation en production
|
||||
|
||||
1. **Tester avec plus de banques** (priorité haute)
|
||||
- Demander à 2-3 clients volontaires de tester
|
||||
- Vérifier compatibilité BNP, CA, SG
|
||||
- Documenter les retours
|
||||
|
||||
2. **Ajouter support RG** (priorité haute)
|
||||
- Nécessaire pour organisations mixtes
|
||||
- Évite confusion clients
|
||||
|
||||
3. **Améliorer les messages d'erreur** (priorité moyenne)
|
||||
- Erreurs plus explicites côté client
|
||||
- Guide de résolution des problèmes
|
||||
|
||||
4. **Documentation utilisateur** (priorité haute)
|
||||
1. **Documentation utilisateur** (priorité haute)
|
||||
- Guide pas-à-pas
|
||||
- FAQ
|
||||
- Captures d'écran
|
||||
|
||||
5. **Monitoring** (priorité basse)
|
||||
2. **Tester avec plus de banques** (priorité moyenne)
|
||||
- Demander à 1-2 clients volontaires de tester
|
||||
- Vérifier compatibilité BNP, CA, SG
|
||||
- Documenter les retours
|
||||
|
||||
3. **Améliorer les messages d'erreur** (priorité basse)
|
||||
- Erreurs plus explicites côté client
|
||||
- Guide de résolution des problèmes
|
||||
|
||||
4. **Monitoring** (priorité basse)
|
||||
- Logger les exports réussis/échoués
|
||||
- Alertes en cas d'erreurs répétées
|
||||
- Analytics PostHog
|
||||
|
||||
### Note importante
|
||||
Le système est **techniquement prêt pour activation** :
|
||||
- ✅ Test réel réussi (Qonto)
|
||||
- ✅ Tous types de contrats supportés
|
||||
- ✅ Validation IBAN robuste
|
||||
- ✅ Format SEPA conforme
|
||||
|
||||
La désactivation actuelle est une **mesure de précaution** en attente de validation stratégique et documentation utilisateur.
|
||||
|
||||
### Après activation
|
||||
|
||||
1. **Collecte de feedback**
|
||||
|
|
@ -264,11 +271,13 @@ Les fonctionnalités testées fonctionnent correctement. Les limitations sont do
|
|||
### Version 1.0 (3 novembre 2025)
|
||||
- Implémentation initiale
|
||||
- Test réussi avec Qonto
|
||||
- Support CDDU uniquement
|
||||
- Support de tous les types de contrats (CDDU + RG via table cddu_contracts)
|
||||
- Validation IBAN avec checksum modulo 97
|
||||
- Interface de sélection multiple
|
||||
- Marquage groupé des paies
|
||||
- **Statut** : Désactivé en production (en attente tests élargis)
|
||||
- **Statut** : Désactivé en production par précaution
|
||||
- **Raison désactivation** : En attente documentation utilisateur et validation stratégique
|
||||
- **Prêt techniquement** : Oui ✓
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -389,6 +389,8 @@ export default function VirementsPage() {
|
|||
const [isExporting, setIsExporting] = useState(false);
|
||||
const [isMarkingPaid, setIsMarkingPaid] = useState(false);
|
||||
const [showBulkMarkPaidModal, setShowBulkMarkPaidModal] = useState(false);
|
||||
const [showChangeGestionModal, setShowChangeGestionModal] = useState(false);
|
||||
const [isChangingGestion, setIsChangingGestion] = useState(false);
|
||||
|
||||
const { data: userInfo, isLoading: isLoadingUser } = useUserInfo();
|
||||
const { data: organizations, isLoading: isLoadingOrgs, error: orgsError } = useOrganizations();
|
||||
|
|
@ -704,6 +706,42 @@ export default function VirementsPage() {
|
|||
}
|
||||
}
|
||||
|
||||
// Changement de gestion des virements
|
||||
async function handleChangeGestion() {
|
||||
if (!org || !selectedOrgId) return;
|
||||
setShowChangeGestionModal(false);
|
||||
setIsChangingGestion(true);
|
||||
|
||||
try {
|
||||
const currentMode = isOdentas ? 'odentas' : 'client';
|
||||
const newMode = isOdentas ? 'client' : 'odentas';
|
||||
|
||||
const response = await fetch('/api/virements-salaires/change-gestion', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
organizationId: selectedOrgId,
|
||||
newMode
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message || 'Erreur lors du changement de gestion');
|
||||
}
|
||||
|
||||
// Recharger les données
|
||||
await queryClient.invalidateQueries({ queryKey: ["virements-salaires"] });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Erreur changement gestion:', error);
|
||||
alert(error instanceof Error ? error.message : 'Erreur lors du changement de gestion');
|
||||
} finally {
|
||||
setIsChangingGestion(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Filtrage local pour la recherche ET la période
|
||||
const filteredItems = useMemo((): VirementItem[] => {
|
||||
let result: VirementItem[] = items;
|
||||
|
|
@ -873,23 +911,14 @@ export default function VirementsPage() {
|
|||
<div className="text-xs text-slate-600">Les virements de salaires sont effectués par</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative group inline-block">
|
||||
<button
|
||||
type="button"
|
||||
disabled
|
||||
aria-disabled="true"
|
||||
className="text-xs px-2 py-1 rounded-md border opacity-60 cursor-not-allowed"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
<div
|
||||
role="tooltip"
|
||||
className="pointer-events-none absolute right-0 mt-2 w-64 px-3 py-2 rounded-lg bg-slate-900 text-white text-xs shadow-lg opacity-0 group-hover:opacity-100 translate-y-1 group-hover:translate-y-0 transition"
|
||||
>
|
||||
Bientôt disponible, veuillez nous contacter.
|
||||
<div className="absolute -top-1 right-6 w-2 h-2 rotate-45 bg-slate-900" />
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowChangeGestionModal(true)}
|
||||
disabled={loadingOrg || isChangingGestion}
|
||||
className="text-xs px-2 py-1 rounded-md border hover:bg-slate-50 transition-colors disabled:opacity-60 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isChangingGestion ? 'Modification...' : 'Modifier'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 flex items-center justify-between gap-2">
|
||||
|
|
@ -1352,6 +1381,76 @@ export default function VirementsPage() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* Modal de changement de gestion des virements */}
|
||||
{showChangeGestionModal && (
|
||||
<div className="fixed inset-0 z-[1000]">
|
||||
<div
|
||||
className="absolute inset-0 bg-black/40"
|
||||
onClick={() => setShowChangeGestionModal(false)}
|
||||
/>
|
||||
<div className="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div role="dialog" aria-modal="true" className="w-full max-w-md rounded-2xl border bg-white shadow-xl">
|
||||
<div className="p-5 border-b bg-blue-50">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="rounded-lg bg-blue-100 p-2">
|
||||
<Info className="h-5 w-5 text-blue-700" />
|
||||
</div>
|
||||
<h2 className="text-base font-semibold text-blue-900">
|
||||
Changement de gestion des virements
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-5 space-y-4 text-sm">
|
||||
{isOdentas ? (
|
||||
<>
|
||||
<p className="text-slate-700">
|
||||
Souhaitez-vous reprendre la <strong>gestion de vos virements de salaires</strong> ?
|
||||
</p>
|
||||
<p className="text-slate-600">
|
||||
Vous pourrez effectuer vous-même les virements via votre banque.
|
||||
</p>
|
||||
<div className="rounded-lg bg-green-50 border border-green-200 p-3">
|
||||
<p className="text-sm text-green-900">
|
||||
<strong>Aucune modification tarifaire</strong> - Ce changement n'impacte pas votre facturation.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="text-slate-700">
|
||||
Souhaitez-vous <strong>confier la gestion de vos virements de salaires à Odentas</strong> ?
|
||||
</p>
|
||||
<p className="text-slate-600">
|
||||
Odentas s'occupera de redistribuer les salaires à vos salariés après réception de votre virement mensuel.
|
||||
</p>
|
||||
<div className="rounded-lg bg-green-50 border border-green-200 p-3">
|
||||
<p className="text-sm text-green-900">
|
||||
<strong>Service sans surcoût</strong> - Ce changement n'impacte pas votre facturation.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-4 border-t flex justify-end gap-2">
|
||||
<button
|
||||
onClick={() => setShowChangeGestionModal(false)}
|
||||
className="px-4 py-2 rounded-lg border hover:bg-slate-50 text-sm transition-colors"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
<button
|
||||
onClick={handleChangeGestion}
|
||||
disabled={isChangingGestion}
|
||||
className="px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 text-sm transition-colors disabled:opacity-50"
|
||||
>
|
||||
{isChangingGestion ? 'Modification en cours...' : 'Confirmer'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Modal PDF */}
|
||||
{pdfModalOpen && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
|
||||
|
|
|
|||
|
|
@ -74,48 +74,44 @@ export async function POST(request: NextRequest) {
|
|||
);
|
||||
}
|
||||
|
||||
// 3. Récupération du vrai nom de l'organisation depuis Supabase
|
||||
let organizationName = providedOrgName || 'Employeur';
|
||||
// 3. Récupération du nom du client depuis Supabase
|
||||
let organizationName = 'Employeur'; // Fallback par défaut
|
||||
|
||||
if (organizationId || contractId) {
|
||||
console.log('🔍 Récupération du nom de l\'organisation depuis la base de données...');
|
||||
try {
|
||||
const supabase = createSbServiceRole();
|
||||
|
||||
let actualOrgId = organizationId;
|
||||
|
||||
// Si on n'a que le contractId, récupérer l'org_id depuis le contrat
|
||||
if (!actualOrgId && contractId) {
|
||||
const { data: contractData } = await supabase
|
||||
.from('cddu_contracts')
|
||||
.select('org_id')
|
||||
.eq('id', contractId)
|
||||
.single();
|
||||
|
||||
if (contractData?.org_id) {
|
||||
actualOrgId = contractData.org_id;
|
||||
console.log('✅ org_id récupéré depuis le contrat:', actualOrgId);
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer le nom de l'organisation
|
||||
if (actualOrgId) {
|
||||
const { data: orgData, error: orgError } = await supabase
|
||||
.from('organizations')
|
||||
.select('name')
|
||||
.eq('id', actualOrgId)
|
||||
.single();
|
||||
|
||||
if (!orgError && orgData?.name) {
|
||||
organizationName = orgData.name;
|
||||
console.log('✅ Nom de l\'organisation trouvé:', organizationName);
|
||||
} else {
|
||||
console.warn('⚠️ Nom de l\'organisation non trouvé, utilisation du fallback');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('⚠️ Erreur lors de la récupération du nom de l\'organisation:', err);
|
||||
if (!organizationId) {
|
||||
console.error('❌ organization_id manquant');
|
||||
return NextResponse.json(
|
||||
{ error: 'organization_id est requis' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log('🔍 Récupération du nom du client depuis organizations...');
|
||||
try {
|
||||
const supabase = createSbServiceRole();
|
||||
|
||||
const { data: orgData, error: orgError } = await supabase
|
||||
.from('organizations')
|
||||
.select('name')
|
||||
.eq('id', organizationId)
|
||||
.single();
|
||||
|
||||
if (orgError) {
|
||||
console.error('❌ Erreur lors de la récupération de l\'organisation:', orgError);
|
||||
throw orgError;
|
||||
}
|
||||
|
||||
if (orgData?.name) {
|
||||
organizationName = orgData.name;
|
||||
console.log('✅ Nom du client trouvé:', organizationName);
|
||||
} else {
|
||||
console.error('❌ Nom du client non trouvé pour org_id:', organizationId);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('❌ Erreur lors de la récupération du nom du client:', err);
|
||||
return NextResponse.json(
|
||||
{ error: 'Impossible de récupérer le nom du client' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// 4. Récupération du prénom depuis Supabase si non fourni
|
||||
|
|
|
|||
157
app/api/virements-salaires/change-gestion/route.ts
Normal file
157
app/api/virements-salaires/change-gestion/route.ts
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export const revalidate = 0;
|
||||
export const runtime = 'nodejs';
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
const supabase = createRouteHandlerClient({ cookies });
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
const { organizationId, newMode } = body;
|
||||
|
||||
if (!organizationId || !newMode) {
|
||||
return NextResponse.json({ error: 'missing_parameters' }, { status: 400 });
|
||||
}
|
||||
|
||||
if (!['odentas', 'client'].includes(newMode.toLowerCase())) {
|
||||
return NextResponse.json({ error: 'invalid_mode' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Récupérer les informations de l'organisation
|
||||
const { data: orgData, error: orgError } = await supabase
|
||||
.from('organizations')
|
||||
.select(`
|
||||
id,
|
||||
name,
|
||||
structure_api,
|
||||
organization_details(
|
||||
org_id,
|
||||
virements_salaires,
|
||||
email_notifs,
|
||||
email_notifs_cc,
|
||||
code_employeur,
|
||||
prenom_contact
|
||||
)
|
||||
`)
|
||||
.eq('id', organizationId)
|
||||
.single();
|
||||
|
||||
if (orgError || !orgData) {
|
||||
return NextResponse.json({ error: 'organization_not_found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const orgDetails = Array.isArray(orgData.organization_details)
|
||||
? orgData.organization_details[0]
|
||||
: orgData.organization_details;
|
||||
|
||||
const currentMode = orgDetails?.virements_salaires?.toLowerCase() || 'client';
|
||||
const targetMode = newMode.toLowerCase() === 'odentas' ? 'Odentas' : 'Client';
|
||||
|
||||
// Vérifier que le mode change réellement
|
||||
if (currentMode === targetMode.toLowerCase()) {
|
||||
return NextResponse.json({
|
||||
error: 'no_change_needed',
|
||||
message: 'Le mode de gestion est déjà celui demandé'
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
// Mettre à jour le mode de gestion
|
||||
const { error: updateError } = await supabase
|
||||
.from('organization_details')
|
||||
.update({ virements_salaires: targetMode })
|
||||
.eq('org_id', organizationId);
|
||||
|
||||
if (updateError) {
|
||||
console.error('Erreur mise à jour virements_salaires:', updateError);
|
||||
return NextResponse.json({ error: 'update_failed' }, { status: 500 });
|
||||
}
|
||||
|
||||
// Préparer les emails
|
||||
const orgName = orgData.structure_api || orgData.name;
|
||||
const emailClient = orgDetails?.email_notifs;
|
||||
const emailClientCC = orgDetails?.email_notifs_cc;
|
||||
|
||||
// Importer le service d'email
|
||||
const { sendUniversalEmailV2 } = await import('@/lib/emailTemplateService');
|
||||
|
||||
// Email au client
|
||||
if (emailClient) {
|
||||
const emailType = targetMode === 'Odentas'
|
||||
? 'virements-gestion-to-odentas'
|
||||
: 'virements-gestion-to-client';
|
||||
|
||||
const emailData = {
|
||||
organizationName: orgName,
|
||||
companyName: orgName,
|
||||
employerCode: orgDetails?.code_employeur || '—',
|
||||
handlerName: 'Renaud BREVIERE-ABRAHAM',
|
||||
gestionMode: targetMode === 'Odentas' ? 'Géré par Odentas' : 'Géré en autonomie',
|
||||
changeDate: new Date().toLocaleString('fr-FR', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
}),
|
||||
firstName: orgDetails?.prenom_contact || '',
|
||||
supportUrl: 'https://espace-paie.odentas.fr/support',
|
||||
step1: 'Réception de l\'appel à virement mensuel',
|
||||
step2: 'Virement unique vers Odentas',
|
||||
step3: 'Redistribution automatique aux salariés',
|
||||
};
|
||||
|
||||
try {
|
||||
await sendUniversalEmailV2({
|
||||
type: emailType as any,
|
||||
toEmail: emailClient,
|
||||
ccEmail: emailClientCC || undefined,
|
||||
data: emailData
|
||||
});
|
||||
} catch (emailError) {
|
||||
console.error('Erreur envoi email client:', emailError);
|
||||
// Continue même si l'email échoue
|
||||
}
|
||||
}
|
||||
|
||||
// Email interne à l'équipe Odentas
|
||||
const internalData = {
|
||||
organizationName: orgName,
|
||||
previousMode: currentMode,
|
||||
newMode: targetMode,
|
||||
changeDate: new Date().toLocaleString('fr-FR'),
|
||||
};
|
||||
|
||||
try {
|
||||
await sendUniversalEmailV2({
|
||||
type: 'virements-gestion-internal',
|
||||
toEmail: 'paie@odentas.fr',
|
||||
data: internalData
|
||||
});
|
||||
} catch (emailError) {
|
||||
console.error('Erreur envoi email interne:', emailError);
|
||||
// Continue même si l'email échoue
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
previousMode: currentMode,
|
||||
newMode: targetMode
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error changing gestion mode:', error);
|
||||
return NextResponse.json({
|
||||
error: 'internal_server_error',
|
||||
message: error instanceof Error ? error.message : 'Unknown error'
|
||||
}, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
|
@ -302,6 +302,9 @@ export async function POST(req: Request) {
|
|||
xml += ' <SvcLvl>\n';
|
||||
xml += ' <Cd>SEPA</Cd>\n';
|
||||
xml += ' </SvcLvl>\n';
|
||||
xml += ' <CtgyPurp>\n';
|
||||
xml += ' <Cd>SALA</Cd>\n';
|
||||
xml += ' </CtgyPurp>\n';
|
||||
xml += ' </PmtTpInf>\n';
|
||||
xml += ` <ReqdExctnDt>${requestedExecutionDate}</ReqdExctnDt>\n`;
|
||||
xml += ' <Dbtr>\n';
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ export type EmailTypeV2 =
|
|||
| '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
|
||||
|
|
@ -282,6 +285,94 @@ const EMAIL_TEMPLATES_V2: Record<EmailTypeV2, EmailTemplateV2> = {
|
|||
}
|
||||
},
|
||||
|
||||
'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é',
|
||||
|
|
|
|||
Loading…
Reference in a new issue