- Ajout sous-header total net à payer sur page virements-salaires - Migration transfer_done_at pour tracking précis des virements - Nouvelle page saisie tableau pour création factures en masse - APIs bulk pour mise à jour dates signature et jours technicien - API demande mandat SEPA avec email template - Webhook DocuSeal pour signature contrats (mode TEST) - Composants modaux détails et vérification PDF fiches de paie - Upload/suppression/remplacement PDFs dans PayslipsGrid - Amélioration affichage colonnes et filtres grilles contrats/paies - Template email mandat SEPA avec sous-texte CTA - APIs bulk facturation (création, update statut/date paiement) - API clients sans facture pour période donnée - Corrections calculs dates et montants avec auto-remplissage
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
// app/api/staff/facturation/bulk-update-status/route.ts
|
|
import { NextResponse } from "next/server";
|
|
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
|
import { cookies } from "next/headers";
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
export const revalidate = 0;
|
|
export const runtime = 'nodejs';
|
|
|
|
async function isStaffUser(supabase: any, userId: string): Promise<boolean> {
|
|
try {
|
|
const { data: staffRow } = await supabase
|
|
.from('staff_users')
|
|
.select('is_staff')
|
|
.eq('user_id', userId)
|
|
.maybeSingle();
|
|
return !!staffRow?.is_staff;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// POST - Mise à jour en masse du statut des factures
|
|
export async function POST(req: Request) {
|
|
try {
|
|
const body = await req.json();
|
|
const { invoiceIds, status } = body;
|
|
|
|
// Validation des données
|
|
if (!Array.isArray(invoiceIds) || invoiceIds.length === 0) {
|
|
return NextResponse.json({ error: 'invalid_invoice_ids' }, { status: 400 });
|
|
}
|
|
|
|
if (!status || typeof status !== 'string') {
|
|
return NextResponse.json({ error: 'invalid_status' }, { status: 400 });
|
|
}
|
|
|
|
// Validation des statuts autorisés
|
|
const validStatuses = ['payee', 'annulee', 'prete', 'emise', 'en_cours', 'brouillon'];
|
|
if (!validStatuses.includes(status)) {
|
|
return NextResponse.json({ error: 'invalid_status_value' }, { status: 400 });
|
|
}
|
|
|
|
const supabase = createRouteHandlerClient({ cookies });
|
|
|
|
// Auth et vérification staff
|
|
const { data: { session }, error: sessionError } = await supabase.auth.getSession();
|
|
if (sessionError || !session?.user?.id) {
|
|
return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
|
|
}
|
|
|
|
const isStaff = await isStaffUser(supabase, session.user.id);
|
|
if (!isStaff) {
|
|
return NextResponse.json({ error: 'forbidden' }, { status: 403 });
|
|
}
|
|
|
|
// Vérifier que toutes les factures existent
|
|
const { data: existingInvoices, error: fetchError } = await supabase
|
|
.from('invoices')
|
|
.select('id')
|
|
.in('id', invoiceIds);
|
|
|
|
if (fetchError) {
|
|
console.error('Erreur lors de la vérification des factures:', fetchError);
|
|
return NextResponse.json({ error: 'database_error' }, { status: 500 });
|
|
}
|
|
|
|
if (!existingInvoices || existingInvoices.length !== invoiceIds.length) {
|
|
return NextResponse.json({ error: 'some_invoices_not_found' }, { status: 404 });
|
|
}
|
|
|
|
// Mettre à jour les statuts
|
|
const { data: updatedInvoices, error: updateError } = await supabase
|
|
.from('invoices')
|
|
.update({
|
|
status: status,
|
|
updated_at: new Date().toISOString()
|
|
})
|
|
.in('id', invoiceIds)
|
|
.select();
|
|
|
|
if (updateError) {
|
|
console.error('Erreur lors de la mise à jour des statuts:', updateError);
|
|
return NextResponse.json({ error: 'update_failed' }, { status: 500 });
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
updated: updatedInvoices?.length || 0,
|
|
message: `${updatedInvoices?.length || 0} facture(s) mise(s) à jour avec succès`
|
|
});
|
|
|
|
} catch (error: any) {
|
|
console.error('Erreur dans bulk-update-status:', error);
|
|
return NextResponse.json(
|
|
{ error: 'internal_server_error', details: error.message },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|