espace-paie-odentas/app/api/odentas-sign/requests/create/route.ts

168 lines
5.6 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { supabaseAdmin, logSignEvent } from '@/lib/odentas-sign/supabase';
import { generateRequestRef } from '@/lib/odentas-sign/crypto';
import { uploadToS3, S3_PREFIXES, fileExistsInS3 } from '@/lib/odentas-sign/s3';
import type { CreateSignRequestInput } from '@/lib/odentas-sign/types';
/**
* POST /api/odentas-sign/requests/create
*
* Crée une nouvelle demande de signature électronique
*/
export async function POST(request: NextRequest) {
try {
const body: CreateSignRequestInput = await request.json();
// Validation
if (!body.contractId || !body.pdfS3Key || !body.title) {
return NextResponse.json(
{ error: 'Champs requis manquants: contractId, pdfS3Key, title' },
{ status: 400 }
);
}
if (!body.signers || body.signers.length === 0) {
return NextResponse.json(
{ error: 'Au moins un signataire est requis' },
{ status: 400 }
);
}
// Vérifier que le PDF source existe dans S3
const sourceExists = await fileExistsInS3(body.pdfS3Key);
if (!sourceExists) {
return NextResponse.json(
{ error: `Le fichier PDF source n'existe pas: ${body.pdfS3Key}` },
{ status: 404 }
);
}
// Générer une référence unique
const ref = generateRequestRef(body.contractRef);
console.log(`[CREATE REQUEST] Création demande: ${ref}`);
// 1. Créer la demande de signature dans sign_requests
const { data: signRequest, error: requestError } = await supabaseAdmin
.from('sign_requests')
.insert({
ref,
title: body.title,
source_s3_key: body.pdfS3Key,
status: 'pending',
})
.select()
.single();
if (requestError || !signRequest) {
console.error('[SUPABASE] Erreur création sign_request:', requestError);
return NextResponse.json(
{ error: 'Erreur lors de la création de la demande', details: requestError },
{ status: 500 }
);
}
console.log(`[CREATE REQUEST] ✅ sign_request créé: ${signRequest.id}`);
// 2. Créer les signataires
const signersData = body.signers.map(signer => ({
request_id: signRequest.id,
role: signer.role,
name: signer.name,
email: signer.email.toLowerCase(),
otp_attempts: 0,
// Métadonnées PAdES pour la signature
signature_name: signer.name, // Par défaut, même nom (peut être changé pour l'employeur)
signature_reason: `Signature du contrat ${ref} en tant que ${signer.role.toLowerCase()}`,
signature_location: 'France',
signature_contact_info: signer.email.toLowerCase(),
}));
const { data: createdSigners, error: signersError } = await supabaseAdmin
.from('signers')
.insert(signersData)
.select();
if (signersError || !createdSigners) {
console.error('[SUPABASE] Erreur création signers:', signersError);
// Rollback : supprimer la demande
await supabaseAdmin.from('sign_requests').delete().eq('id', signRequest.id);
return NextResponse.json(
{ error: 'Erreur lors de la création des signataires', details: signersError },
{ status: 500 }
);
}
console.log(`[CREATE REQUEST] ✅ ${createdSigners.length} signataires créés`);
// 3. Créer les positions de signature
if (body.positions && body.positions.length > 0) {
const positionsData = body.positions.map(pos => ({
request_id: signRequest.id,
role: pos.role,
page: pos.page,
x: pos.x,
y: pos.y,
w: pos.w,
h: pos.h,
kind: pos.kind || 'signature',
label: pos.label || null,
}));
const { error: positionsError } = await supabaseAdmin
.from('sign_positions')
.insert(positionsData);
if (positionsError) {
console.error('[SUPABASE] Erreur création positions:', positionsError);
// On continue quand même, les positions ne sont pas critiques
} else {
console.log(`[CREATE REQUEST] ✅ ${positionsData.length} positions créées`);
}
}
// 4. Logger l'événement de création
await logSignEvent({
requestId: signRequest.id,
event: 'request_created',
ip: request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || undefined,
userAgent: request.headers.get('user-agent') || undefined,
metadata: {
contract_id: body.contractId,
signers_count: createdSigners.length,
positions_count: body.positions?.length || 0,
},
});
// 5. Générer les URLs de signature pour chaque signataire
const signerUrls = createdSigners.map(signer => ({
signerId: signer.id,
role: signer.role,
name: signer.name,
email: signer.email,
signatureUrl: `${process.env.NEXT_PUBLIC_APP_URL || 'https://espace-paie.odentas.fr'}/signer/${signRequest.id}/${signer.id}`,
}));
// 6. Retourner la réponse
return NextResponse.json({
success: true,
request: {
id: signRequest.id,
ref: signRequest.ref,
title: signRequest.title,
status: signRequest.status,
created_at: signRequest.created_at,
},
signers: signerUrls,
}, { status: 201 });
} catch (error) {
console.error('[CREATE REQUEST] Erreur:', error);
return NextResponse.json(
{ error: 'Erreur serveur lors de la création de la demande', details: error instanceof Error ? error.message : String(error) },
{ status: 500 }
);
}
}