espace-paie-odentas/app/api/staff/payslips/[id]/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

75 lines
2.9 KiB
TypeScript

import { NextResponse } from "next/server";
import { createSbServer } from "@/lib/supabaseServer";
export async function GET(req: Request, { params }: { params: { id: string } }) {
try {
const sb = createSbServer();
const { data: { user } } = await sb.auth.getUser();
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
const { data: me } = await sb.from('staff_users').select('is_staff').eq('user_id', user.id).maybeSingle();
if (!me?.is_staff) return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
const payslipId = params.id;
// Fetch payslip with relations
const { data, error } = await sb
.from('payslips')
.select(`
*,
cddu_contracts!contract_id(
id,
contract_number,
employee_name,
employee_id,
structure,
type_de_contrat,
org_id,
salaries!employee_id(salarie, nom, prenom),
organizations!org_id(organization_details(code_employeur))
)
`)
.eq('id', payslipId)
.single();
if (error) return NextResponse.json({ error: error.message }, { status: 500 });
if (!data) return NextResponse.json({ error: 'Not found' }, { status: 404 });
return NextResponse.json(data);
} catch (err: any) {
console.error(err);
return NextResponse.json({ error: 'Internal' }, { status: 500 });
}
}
export async function PATCH(req: Request, { params }: { params: { id: string } }) {
try {
const sb = createSbServer();
const { data: { user } } = await sb.auth.getUser();
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
const { data: me } = await sb.from('staff_users').select('is_staff').eq('user_id', user.id).maybeSingle();
if (!me?.is_staff) return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
const payslipId = params.id;
const body = await req.json().catch(() => ({}));
// Allow patching a limited set of fields to avoid accidental overwrites
const allowed: Record<string, any> = {};
const fields = ['period_start','period_end','period_month','gross_amount','net_amount','processed','paye','traite', 'employer_cost', 'pay_number', 'aem_status', 'transfer_done', 'net_after_withholding', 'pay_date', 'payslip_path', 'contract_id', 'organization_id', 'storage_path', 'storage_url'];
for (const f of fields) {
if (Object.prototype.hasOwnProperty.call(body, f)) allowed[f] = body[f];
}
if (Object.keys(allowed).length === 0) {
return NextResponse.json({ error: 'missing_fields' }, { status: 400 });
}
const { data, error } = await sb.from('payslips').update(allowed).eq('id', payslipId).select().maybeSingle();
if (error) return NextResponse.json({ error: error.message }, { status: 500 });
return NextResponse.json(data);
} catch (err: any) {
console.error(err);
return NextResponse.json({ error: 'Internal' }, { status: 500 });
}
}