espace-paie-odentas/app/api/staff/amendments/[id]/upload-signed-pdf/route.ts
odentas 1d9145a0b2 feat: Ajouter upload manuel de PDF signé pour avenants
- Nouvelle modale UploadSignedPdfModal avec drag & drop
- API route /api/staff/amendments/[id]/upload-signed-pdf
- Upload vers S3 avec pattern avenants/{ref}_avenant_signed_{timestamp}.pdf
- Mise à jour automatique statut → 'signed' et signature_status → 'signed'
- Validation du fichier (PDF uniquement, max 10MB)
- Bouton 'Ajouter PDF signé' sur page détail avenant
2025-11-05 19:48:47 +01:00

152 lines
4.1 KiB
TypeScript

import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const s3Client = new S3Client({
region: process.env.AWS_REGION || "eu-west-3",
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
});
const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME || "odentas-documents";
export async function POST(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params;
const supabase = createRouteHandlerClient({ cookies });
// Vérifier l'authentification
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return NextResponse.json(
{ error: "Non authentifié" },
{ status: 401 }
);
}
// Vérifier que l'utilisateur est staff
const { data: staffUser } = await supabase
.from("staff_users")
.select("is_staff")
.eq("user_id", user.id)
.maybeSingle();
if (!staffUser?.is_staff) {
return NextResponse.json(
{ error: "Accès refusé" },
{ status: 403 }
);
}
// Récupérer le fichier depuis le FormData
const formData = await request.formData();
const file = formData.get("file") as File;
if (!file) {
return NextResponse.json(
{ error: "Aucun fichier fourni" },
{ status: 400 }
);
}
// Vérifier que c'est un PDF
if (file.type !== "application/pdf") {
return NextResponse.json(
{ error: "Le fichier doit être un PDF" },
{ status: 400 }
);
}
// Vérifier la taille (max 10MB)
if (file.size > 10 * 1024 * 1024) {
return NextResponse.json(
{ error: "Le fichier ne doit pas dépasser 10 MB" },
{ status: 400 }
);
}
// Récupérer l'avenant
const { data: avenant, error: avenantError } = await supabase
.from("avenants")
.select("numero_avenant, contract_id")
.eq("id", id)
.single();
if (avenantError || !avenant) {
return NextResponse.json(
{ error: "Avenant non trouvé" },
{ status: 404 }
);
}
// Récupérer le contrat pour avoir la référence
const { data: contract } = await supabase
.from("cddu_contracts")
.select("contract_number, reference")
.eq("id", avenant.contract_id)
.single();
const contractRef = contract?.reference || contract?.contract_number || "UNKNOWN";
// Convertir le fichier en Buffer
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
// Générer la clé S3
const timestamp = Date.now();
const s3Key = `avenants/${contractRef}_avenant_signed_${timestamp}.pdf`;
// Upload sur S3
const uploadCommand = new PutObjectCommand({
Bucket: S3_BUCKET_NAME,
Key: s3Key,
Body: buffer,
ContentType: "application/pdf",
});
await s3Client.send(uploadCommand);
const pdfUrl = `https://${S3_BUCKET_NAME}.s3.${process.env.AWS_REGION || "eu-west-3"}.amazonaws.com/${s3Key}`;
// Mettre à jour l'avenant avec la clé S3 du PDF signé
const { error: updateError } = await supabase
.from("avenants")
.update({
signed_pdf_s3_key: s3Key,
signed_pdf_url: pdfUrl,
signature_status: "signed",
statut: "signed",
})
.eq("id", id);
if (updateError) {
console.error("Erreur mise à jour avenant:", updateError);
return NextResponse.json(
{ error: "Erreur lors de la mise à jour de l'avenant" },
{ status: 500 }
);
}
return NextResponse.json({
success: true,
s3Key,
pdfUrl,
message: "PDF signé uploadé avec succès",
});
} catch (error: any) {
console.error("Erreur upload PDF signé:", error);
return NextResponse.json(
{ error: error.message || "Erreur lors de l'upload du PDF" },
{ status: 500 }
);
}
}