espace-paie-odentas/app/api/staff/naa/[id]/route.ts
odentas 6485db4a75 feat(naa): Amélioration UX modal EditNAA - replier/déplier
- Tous les clients repliés par défaut à l'ouverture du modal
- Boutons 'Tout replier' / 'Tout déplier' pour gérer tous les clients
- Section factures repliable avec bouton Afficher/Masquer
- Affichage résumé facture sélectionnée quand section repliée
- Nouveau client déplié automatiquement pour faciliter la saisie
- Améliore la lisibilité pour NAA avec nombreux clients
2025-10-31 15:28:44 +01:00

266 lines
7.7 KiB
TypeScript

import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
export const dynamic = "force-dynamic";
// GET - Récupérer les détails d'une NAA avec toutes ses données
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } }
) {
try {
const cookieStore = cookies();
const supabase = createRouteHandlerClient({ cookies: () => cookieStore });
// Vérifier l'authentification staff
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
const { data: staffUser } = await supabase
.from("staff_users")
.select("user_id")
.eq("user_id", user.id)
.single();
if (!staffUser) {
return NextResponse.json({ error: "Accès non autorisé" }, { status: 403 });
}
// Récupérer le document NAA
const { data: naaDoc, error: naaError } = await supabase
.from("naa_documents")
.select("*")
.eq("id", params.id)
.single();
if (naaError || !naaDoc) {
return NextResponse.json({ error: "NAA non trouvée" }, { status: 404 });
}
// Récupérer les prestations
const { data: prestations, error: prestationsError } = await supabase
.from("naa_prestations")
.select("*")
.eq("naa_id", params.id)
.order("created_at");
if (prestationsError) {
console.error("Error fetching prestations:", prestationsError);
}
return NextResponse.json({
...naaDoc,
prestations: prestations || []
});
} catch (error: any) {
console.error("Error GET /api/staff/naa/[id]:", error);
return NextResponse.json(
{ error: error.message || "Erreur serveur" },
{ status: 500 }
);
}
}
// DELETE - Supprimer une NAA
export async function DELETE(
request: NextRequest,
{ params }: { params: { id: string } }
) {
try {
const cookieStore = cookies();
const supabase = createRouteHandlerClient({ cookies: () => cookieStore });
// Vérifier l'authentification staff
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
const { data: staffUser } = await supabase
.from("staff_users")
.select("user_id")
.eq("user_id", user.id)
.single();
if (!staffUser) {
return NextResponse.json({ error: "Accès non autorisé" }, { status: 403 });
}
// Supprimer le document NAA (les prestations et line items seront supprimés en cascade)
const { error } = await supabase
.from("naa_documents")
.delete()
.eq("id", params.id);
if (error) {
console.error("Error deleting NAA:", error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ success: true });
} catch (error: any) {
console.error("Error DELETE /api/staff/naa/[id]:", error);
return NextResponse.json(
{ error: error.message || "Erreur serveur" },
{ status: 500 }
);
}
}
// PUT - Mettre à jour une NAA et ses prestations
export async function PUT(
request: NextRequest,
{ params }: { params: { id: string } }
) {
try {
const cookieStore = cookies();
const supabase = createRouteHandlerClient({ cookies: () => cookieStore });
// Vérifier l'authentification staff
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
const { data: staffUser } = await supabase
.from("staff_users")
.select("user_id")
.eq("user_id", user.id)
.single();
if (!staffUser) {
return NextResponse.json({ error: "Accès non autorisé" }, { status: 403 });
}
const body = await request.json();
const {
prestations,
solde_compte_apporteur,
deposit,
included_invoices
} = body;
// Vérifier que la NAA existe
const { data: naaDoc, error: naaCheckError } = await supabase
.from("naa_documents")
.select("*")
.eq("id", params.id)
.single();
if (naaCheckError || !naaDoc) {
return NextResponse.json({ error: "NAA non trouvée" }, { status: 404 });
}
// 1. Récupérer les IDs des prestations existantes
const { data: existingPrestations } = await supabase
.from("naa_prestations")
.select("id")
.eq("naa_id", params.id);
const existingIds = existingPrestations?.map(p => p.id) || [];
// 2. Identifier les prestations à conserver (celles qui ont un ID existant)
const prestationsWithIds = prestations.filter((p: any) => p.id && existingIds.includes(p.id));
const prestationIdsToKeep = prestationsWithIds.map((p: any) => p.id);
// 3. Supprimer les prestations qui ne sont plus dans la liste
const idsToDelete = existingIds.filter(id => !prestationIdsToKeep.includes(id));
if (idsToDelete.length > 0) {
await supabase
.from("naa_prestations")
.delete()
.in("id", idsToDelete);
}
// 4. Mettre à jour les prestations existantes qui ont changé
for (const prest of prestationsWithIds) {
await supabase
.from("naa_prestations")
.update({
client_name: prest.client,
client_code: prest.code,
type_prestation: prest.type_prestation,
quantite: prest.quantite,
tarif: prest.tarif,
total: prest.total
})
.eq("id", prest.id);
}
// 5. Insérer les nouvelles prestations (celles sans ID)
const newPrestations = prestations.filter((p: any) => !p.id);
if (newPrestations.length > 0) {
const prestationsToInsert = newPrestations.map((p: any) => ({
naa_id: params.id,
client_name: p.client,
client_code: p.code,
type_prestation: p.type_prestation,
quantite: p.quantite,
tarif: p.tarif,
total: p.total
}));
await supabase.from("naa_prestations").insert(prestationsToInsert);
}
// 6. Calculer les nouveaux totaux
const nbrePrestations = prestations.length;
const uniqueClients = [...new Set(prestations.map((p: any) => p.code))];
const nbreClients = uniqueClients.length;
// 7. Mettre à jour le document NAA avec les nouveaux totaux
await supabase
.from("naa_documents")
.update({
nbre_prestations: nbrePrestations,
nbre_clients: nbreClients,
solde_compte_apporteur: solde_compte_apporteur || 0,
deposit: deposit || 0,
updated_at: new Date().toISOString(),
status: "draft" // Remettre en draft car le PDF doit être régénéré
})
.eq("id", params.id);
// 8. Régénérer le PDF
const regenerateRes = await fetch(
`${request.nextUrl.origin}/api/staff/naa/${params.id}/regenerate`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
cookie: request.headers.get("cookie") || ""
},
body: JSON.stringify({ included_invoices })
}
);
if (!regenerateRes.ok) {
console.error("Erreur lors de la régénération du PDF");
return NextResponse.json({
success: true,
warning: "NAA mise à jour mais erreur lors de la régénération du PDF"
});
}
const regenerateData = await regenerateRes.json();
return NextResponse.json({
success: true,
presigned_url: regenerateData.presigned_url
});
} catch (error: any) {
console.error("Error PUT /api/staff/naa/[id]:", error);
return NextResponse.json(
{ error: error.message || "Erreur serveur" },
{ status: 500 }
);
}
}