espace-paie-odentas/app/api/signature-salarie/check-status/route.ts
odentas 542e0e963d feat: Stocker et utiliser employee_docuseal_slug pour signature-salarie
- Ajout colonne employee_docuseal_slug dans cddu_contracts
- Stockage automatique du slug lors de création signature DocuSeal
- Recherche directe par slug (+ rapide et fiable)
- Bypass mode maintenance en localhost
- Scripts de migration pour contrats existants (92 contrats migrés)
- Logs détaillés dans verify-birthdate et check-status

Fixes: Erreur 'Document introuvable' pour contrats anciens
Performance: O(n) -> O(1) avec index sur employee_docuseal_slug
2025-10-22 17:35:50 +02:00

201 lines
6.8 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { createSbServiceRole } from '@/lib/supabaseServer';
/**
* GET /api/signature-salarie/check-status?docuseal_id=xxx
*
* Vérifie si un contrat est déjà signé par le salarié
* Retourne les infos du contrat et l'URL de téléchargement si signé
*/
export async function GET(request: NextRequest) {
console.log('=== API Check Signature Status ===');
try {
const { searchParams } = new URL(request.url);
const docuseal_id = searchParams.get('docuseal_id');
if (!docuseal_id) {
console.error('Paramètre manquant: docuseal_id');
return NextResponse.json(
{ error: 'Paramètre docuseal_id requis' },
{ status: 400 }
);
}
console.log('Vérification du statut pour slug:', docuseal_id);
// Créer le client Supabase avec service role
const supabase = createSbServiceRole();
// NOUVELLE APPROCHE: Chercher d'abord le contrat avec le slug dans employee_docuseal_slug
console.log('Recherche du contrat par employee_docuseal_slug:', docuseal_id);
const { data: contract, error: contractError } = await supabase
.from('cddu_contracts')
.select(`
id,
contract_number,
employee_id,
org_id,
contract_pdf_s3_key,
type_de_contrat,
type_d_embauche,
multi_mois,
start_date,
end_date,
net,
gross_pay,
production_name,
structure,
profession,
role,
docuseal_submission_id,
employee_docuseal_slug
`)
.eq('employee_docuseal_slug', docuseal_id)
.maybeSingle();
if (contractError) {
console.error('Erreur lors de la recherche du contrat:', contractError);
return NextResponse.json(
{ error: 'Erreur lors de la recherche du contrat' },
{ status: 500 }
);
}
if (!contract) {
console.error('Aucun contrat trouvé avec employee_docuseal_slug:', docuseal_id);
return NextResponse.json(
{ error: 'Document introuvable' },
{ status: 404 }
);
}
console.log('Contrat trouvé:', {
id: contract.id,
contract_number: contract.contract_number,
docuseal_submission_id: contract.docuseal_submission_id
});
// Maintenant récupérer les infos de la submission DocuSeal si elle existe
let submission: any = null;
let employeeSubmitter: any = null;
if (contract.docuseal_submission_id) {
try {
console.log('Récupération de la submission DocuSeal:', contract.docuseal_submission_id);
const docusealResponse = await fetch(
`${process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'}/api/docuseal/submissions/${contract.docuseal_submission_id}`,
{
method: 'GET',
cache: 'no-store',
}
);
if (docusealResponse.ok) {
submission = await docusealResponse.json();
console.log('Submission récupérée');
// Trouver le submitter salarié avec ce slug
const submitters = submission.submitters || [];
employeeSubmitter = submitters.find((s: any) => s.slug === docuseal_id);
if (employeeSubmitter) {
console.log('Statut signature salarié:', {
status: employeeSubmitter.status,
completed_at: employeeSubmitter.completed_at
});
}
} else {
console.warn('Impossible de récupérer la submission DocuSeal');
}
} catch (error) {
console.warn('Erreur lors de la récupération DocuSeal (non bloquant):', error);
}
}
// 2. Récupérer les infos du salarié
const { data: employee, error: employeeError } = await supabase
.from('salaries')
.select('prenom, nom, adresse_mail, date_naissance')
.eq('id', contract.employee_id)
.maybeSingle();
if (employeeError || !employee) {
console.error('Erreur lors de la récupération du salarié:', employeeError);
}
// 3. Récupérer les infos de l'organisation
const { data: organization, error: organizationError } = await supabase
.from('organizations')
.select('name')
.eq('id', contract.org_id)
.maybeSingle();
if (organizationError || !organization) {
console.error('Erreur lors de la récupération de l organisation:', organizationError);
}
// 4. Vérifier si le salarié a déjà signé
const isSigned = employeeSubmitter && employeeSubmitter.status === 'completed';
console.log('Statut signature salarié:', {
status: employeeSubmitter?.status,
completed_at: employeeSubmitter?.completed_at,
isSigned
});
// 5. Si signé, récupérer l'URL de téléchargement du PDF
let downloadUrl = null;
if (isSigned && contract.contract_pdf_s3_key) {
console.log('Génération URL pré-signée pour:', contract.contract_pdf_s3_key);
try {
const { getS3SignedUrlIfExists } = await import('@/lib/aws-s3');
downloadUrl = await getS3SignedUrlIfExists(contract.contract_pdf_s3_key, 3600);
if (downloadUrl) {
console.log('URL pré-signée générée');
} else {
console.warn('PDF non trouvé dans S3');
}
} catch (s3Error) {
console.error('Erreur lors de la génération de l URL S3:', s3Error);
}
}
// 6. Calculer le régime (comme dans /api/contrats/[id]/route.ts)
const isMulti = contract.multi_mois === "Oui" || contract.multi_mois === true;
const td = String(contract.type_d_embauche || "").toLowerCase();
const isRG = td.includes("régime général") || td.includes("regime general") || td === "rg";
const regime = isRG ? "RG" : (isMulti ? "CDDU_MULTI" : "CDDU_MONO");
// 7. Retourner les infos
return NextResponse.json({
isSigned,
employee_birthdate: employee?.date_naissance || null,
contract: {
contract_number: contract.contract_number,
regime: regime,
start_date: contract.start_date,
end_date: contract.end_date,
gross_amount: contract.gross_pay || contract.net || 0,
employee_name: employee ? `${employee.prenom} ${employee.nom}` : null,
organization_name: organization?.name || null,
production_name: contract.production_name || contract.structure || null,
profession: contract.profession || contract.role || null,
},
signed_at: employeeSubmitter?.completed_at || null,
downloadUrl: isSigned ? downloadUrl : null,
});
} catch (error) {
console.error('Erreur lors de la vérification du statut:', error);
return NextResponse.json(
{
error: 'Erreur serveur lors de la vérification',
details: error instanceof Error ? error.message : 'Unknown error'
},
{ status: 500 }
);
}
}