168 lines
5.6 KiB
TypeScript
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 }
|
|
);
|
|
}
|
|
}
|