- Ajout sous-header total net à payer sur page virements-salaires - Migration transfer_done_at pour tracking précis des virements - Nouvelle page saisie tableau pour création factures en masse - APIs bulk pour mise à jour dates signature et jours technicien - API demande mandat SEPA avec email template - Webhook DocuSeal pour signature contrats (mode TEST) - Composants modaux détails et vérification PDF fiches de paie - Upload/suppression/remplacement PDFs dans PayslipsGrid - Amélioration affichage colonnes et filtres grilles contrats/paies - Template email mandat SEPA avec sous-texte CTA - APIs bulk facturation (création, update statut/date paiement) - API clients sans facture pour période donnée - Corrections calculs dates et montants avec auto-remplissage
211 lines
7.2 KiB
TypeScript
211 lines
7.2 KiB
TypeScript
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
|
|
import { cookies } from 'next/headers';
|
|
import { NextResponse } from 'next/server';
|
|
|
|
const DOCUSEAL_TOKEN = process.env.DOCUSEAL_TOKEN;
|
|
const DOCUSEAL_API_BASE_URL = process.env.DOCUSEAL_API_BASE || 'https://api.docuseal.eu';
|
|
|
|
/**
|
|
* Webhook DocuSeal pour la signature des contrats (CDDU et RG)
|
|
* Mode TEST : Lecture seule, pas d'impact sur la production
|
|
*
|
|
* Cette route remplace les Lambda Functions AWS :
|
|
* - lambdaRouterDocuseal
|
|
* - postDocuSealSalarie
|
|
* - postDocuSealFinalEmails
|
|
*/
|
|
export async function POST(request: Request) {
|
|
const TEST_MODE = true; // ⚠️ Mode TEST activé - Pas de modifications en BDD ni d'envoi d'emails
|
|
|
|
console.log('🔔 [DOCUSEAL WEBHOOK TEST] Réception webhook contrat');
|
|
|
|
try {
|
|
// 1. Parse le payload
|
|
const payload = await request.json();
|
|
console.log('📦 [TEST] Payload reçu:', JSON.stringify(payload, null, 2));
|
|
|
|
// 2. Vérifications de base
|
|
const eventType = payload.event_type || payload.event;
|
|
console.log('📋 [TEST] Event type:', eventType);
|
|
|
|
if (eventType !== 'form.completed') {
|
|
console.log('⏭️ [TEST] Event ignoré (pas form.completed)');
|
|
return NextResponse.json({
|
|
received: true,
|
|
ignored: true,
|
|
reason: 'Event type non géré',
|
|
test_mode: true
|
|
});
|
|
}
|
|
|
|
// 3. Extraire les données importantes
|
|
const data = payload.data;
|
|
const documents = data?.documents || [];
|
|
const role = data?.role;
|
|
const submissionId = data?.id; // ID de la submission DocuSeal
|
|
|
|
console.log('🔍 [TEST] Données extraites:', {
|
|
role,
|
|
submissionId,
|
|
documentsCount: documents.length,
|
|
documentNames: documents.map((d: any) => d.name)
|
|
});
|
|
|
|
// 4. Filtrer : ne traiter que les documents "contrat*"
|
|
const contratDocs = documents.filter((doc: any) =>
|
|
doc.name && doc.name.toLowerCase().startsWith('contrat')
|
|
);
|
|
|
|
if (contratDocs.length === 0) {
|
|
console.log('⏭️ [TEST] Aucun document "contrat" trouvé (probablement un avenant)');
|
|
return NextResponse.json({
|
|
received: true,
|
|
ignored: true,
|
|
reason: 'Pas de document contrat',
|
|
test_mode: true
|
|
});
|
|
}
|
|
|
|
console.log('✅ [TEST] Document contrat trouvé:', contratDocs[0].name);
|
|
|
|
// 5. Chercher le contrat dans la BDD via docuseal_submission_id
|
|
const supabase = createRouteHandlerClient({ cookies });
|
|
|
|
console.log('🔍 [TEST] Recherche du contrat avec submission_id:', submissionId);
|
|
|
|
const { data: contract, error: contractError } = await supabase
|
|
.from('cddu_contracts')
|
|
.select('*')
|
|
.eq('docuseal_submission_id', submissionId)
|
|
.single();
|
|
|
|
if (contractError || !contract) {
|
|
console.error('❌ [TEST] Contrat non trouvé:', contractError);
|
|
return NextResponse.json({
|
|
received: true,
|
|
error: 'Contract not found',
|
|
submissionId,
|
|
test_mode: true
|
|
}, { status: 404 });
|
|
}
|
|
|
|
console.log('✅ [TEST] Contrat trouvé:', {
|
|
id: contract.id,
|
|
contract_number: contract.contract_number,
|
|
employee_id: contract.employee_id,
|
|
signature_status: contract.signature_status,
|
|
contrat_signe_par_employeur: contract.contrat_signe_par_employeur,
|
|
contrat_signe: contract.contrat_signe,
|
|
contract_pdf_s3_key: contract.contract_pdf_s3_key
|
|
});
|
|
|
|
// 6. Router selon le rôle (Employeur ou Salarié)
|
|
if (role === 'Employeur') {
|
|
console.log('👔 [TEST] === SIGNATURE EMPLOYEUR ===');
|
|
|
|
// Récupérer le slug du salarié depuis DocuSeal API
|
|
console.log('🔍 [TEST] Récupération du employee_docuseal_slug depuis DocuSeal API');
|
|
|
|
const docusealResponse = await fetch(
|
|
`${DOCUSEAL_API_BASE_URL}/submissions/${submissionId}`,
|
|
{
|
|
headers: {
|
|
'X-Auth-Token': DOCUSEAL_TOKEN || '',
|
|
'Content-Type': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
|
|
if (!docusealResponse.ok) {
|
|
console.error('❌ [TEST] Erreur DocuSeal API:', docusealResponse.status);
|
|
return NextResponse.json({
|
|
error: 'DocuSeal API error',
|
|
test_mode: true
|
|
}, { status: 500 });
|
|
}
|
|
|
|
const submissionData = await docusealResponse.json();
|
|
console.log('📦 [TEST] Données submission DocuSeal:', JSON.stringify(submissionData, null, 2));
|
|
|
|
// Trouver le submitter avec le rôle "Salarié"
|
|
const employeeSubmitter = submissionData.submitters?.find(
|
|
(s: any) => s.role === 'Salarié'
|
|
);
|
|
|
|
const employeeSlug = employeeSubmitter?.slug;
|
|
console.log('🔗 [TEST] Employee slug trouvé:', employeeSlug);
|
|
|
|
if (TEST_MODE) {
|
|
console.log('⚠️ [TEST MODE] On NE met PAS à jour la BDD');
|
|
console.log('📝 [TEST] Données qui seraient mises à jour:', {
|
|
signature_status: 'pending_employee',
|
|
contrat_signe_par_employeur: 'Oui',
|
|
employee_docuseal_slug: employeeSlug,
|
|
last_employer_notification_at: new Date().toISOString()
|
|
});
|
|
console.log('📧 [TEST] Email qui serait envoyé au salarié (NON ENVOYÉ EN MODE TEST)');
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
test_mode: true,
|
|
role: 'Employeur',
|
|
contract_id: contract.id,
|
|
contract_number: contract.contract_number,
|
|
employee_slug: employeeSlug,
|
|
message: 'TEST MODE : Aucune modification effectuée'
|
|
});
|
|
|
|
} else if (role === 'Salarié') {
|
|
console.log('👤 [TEST] === SIGNATURE SALARIE ===');
|
|
|
|
// URL du PDF signé
|
|
const pdfUrl = contratDocs[0].url;
|
|
console.log('📄 [TEST] URL du PDF signé:', pdfUrl);
|
|
|
|
if (TEST_MODE) {
|
|
console.log('⚠️ [TEST MODE] On NE télécharge PAS le PDF');
|
|
console.log('⚠️ [TEST MODE] On N\'upload PAS sur S3');
|
|
console.log('⚠️ [TEST MODE] On NE met PAS à jour la BDD');
|
|
console.log('📝 [TEST] Données qui seraient mises à jour:', {
|
|
signature_status: 'signed',
|
|
contrat_signe: 'Oui',
|
|
date_signature: new Date().toISOString()
|
|
});
|
|
console.log('📧 [TEST] Emails de confirmation qui seraient envoyés (NON ENVOYÉS EN MODE TEST)');
|
|
console.log('🪣 [TEST] S3 upload qui serait fait:', {
|
|
bucket: 'odentas-docs',
|
|
key: contract.contract_pdf_s3_key
|
|
});
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
test_mode: true,
|
|
role: 'Salarié',
|
|
contract_id: contract.id,
|
|
contract_number: contract.contract_number,
|
|
pdf_url: pdfUrl,
|
|
s3_key: contract.contract_pdf_s3_key,
|
|
message: 'TEST MODE : Aucune modification effectuée'
|
|
});
|
|
|
|
} else {
|
|
console.warn('⚠️ [TEST] Rôle inconnu:', role);
|
|
return NextResponse.json({
|
|
received: true,
|
|
error: 'Unknown role',
|
|
role,
|
|
test_mode: true
|
|
}, { status: 400 });
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('❌ [TEST] Erreur dans le webhook:', error);
|
|
return NextResponse.json({
|
|
error: 'Internal server error',
|
|
details: error instanceof Error ? error.message : 'Unknown error',
|
|
test_mode: true
|
|
}, { status: 500 });
|
|
}
|
|
}
|