espace-paie-odentas/app/api/staff/facturation/bulk-update-status/route.ts
odentas 897af4b23a feat: Ajout fonctionnalités virements, facturation, signatures et emails
- 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
2025-11-02 23:26:19 +01:00

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 }
);
}
}