- Ajout détails cachets/répétitions/heures au modal ContractDetails - Card verte avec validation quand tous les contrats ont une fiche de paie - Système complet de création de fiches de paie avec recherche et vérification - Modal liste des contrats sans paie avec création directe - Amélioration édition dates dans PayslipDetailsModal - Optimisation recherche contrats (ordre des filtres) - Augmentation limite pagination ContractsGrid à 200 - Ajout logs debug génération PDF logo - Script SQL vérification cohérence structure/organisation
211 lines
7.1 KiB
TypeScript
211 lines
7.1 KiB
TypeScript
// app/api/staff/payslips/search-contracts/route.ts
|
|
import { createSbServer } from "@/lib/supabaseServer";
|
|
import { NextRequest, NextResponse } from "next/server";
|
|
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
const sb = createSbServer();
|
|
|
|
// Vérifier l'authentification
|
|
const { data: { user } } = await sb.auth.getUser();
|
|
if (!user) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
// Vérifier que c'est un staff
|
|
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 searchParams = request.nextUrl.searchParams;
|
|
const query = searchParams.get("q");
|
|
|
|
console.log("[GET /api/staff/payslips/search-contracts] Query:", query);
|
|
|
|
if (!query || query.trim().length < 2) {
|
|
console.log("[GET /api/staff/payslips/search-contracts] Query too short, returning empty");
|
|
return NextResponse.json({ contracts: [] });
|
|
}
|
|
|
|
const searchTerm = query.trim();
|
|
const searchPattern = `%${searchTerm}%`;
|
|
|
|
console.log("[GET /api/staff/payslips/search-contracts] Search pattern:", searchPattern);
|
|
|
|
// Rechercher dans les contrats avec jointures
|
|
// On utilise une recherche textuelle simple sur les champs directs du contrat
|
|
const { data: contracts, error } = await sb
|
|
.from("cddu_contracts")
|
|
.select(`
|
|
id,
|
|
contract_number,
|
|
employee_name,
|
|
employee_id,
|
|
structure,
|
|
type_de_contrat,
|
|
start_date,
|
|
end_date,
|
|
production_name,
|
|
n_objet,
|
|
objet_spectacle,
|
|
org_id,
|
|
salaries!employee_id(
|
|
salarie,
|
|
nom,
|
|
prenom
|
|
),
|
|
organizations!org_id(
|
|
name
|
|
)
|
|
`)
|
|
.or(`contract_number.ilike.${searchPattern},employee_name.ilike.${searchPattern},structure.ilike.${searchPattern},production_name.ilike.${searchPattern},n_objet.ilike.${searchPattern},objet_spectacle.ilike.${searchPattern}`)
|
|
.order("created_at", { ascending: false })
|
|
.limit(50);
|
|
|
|
if (error) {
|
|
console.error("[GET /api/staff/payslips/search-contracts] Database error:", error);
|
|
return NextResponse.json({ error: "Database error", details: error.message }, { status: 500 });
|
|
}
|
|
|
|
console.log("[GET /api/staff/payslips/search-contracts] Initial contracts found:", contracts?.length || 0);
|
|
|
|
// Filtrer aussi par nom/prénom de salarié côté serveur si pas de résultat
|
|
let finalContracts = contracts || [];
|
|
|
|
// Si on a peu de résultats, essayer une recherche sur les salariés
|
|
if (finalContracts.length < 10) {
|
|
console.log("[GET /api/staff/payslips/search-contracts] Searching in salaries table...");
|
|
const { data: contractsBySalaries, error: salariesError } = await sb
|
|
.from("salaries")
|
|
.select(`
|
|
id,
|
|
salarie,
|
|
nom,
|
|
prenom,
|
|
cddu_contracts!employee_id(
|
|
id,
|
|
contract_number,
|
|
employee_name,
|
|
employee_id,
|
|
structure,
|
|
type_de_contrat,
|
|
start_date,
|
|
end_date,
|
|
production_name,
|
|
n_objet,
|
|
objet_spectacle,
|
|
org_id,
|
|
organizations!org_id(
|
|
name
|
|
)
|
|
)
|
|
`)
|
|
.or(`salarie.ilike.${searchPattern},nom.ilike.${searchPattern},prenom.ilike.${searchPattern}`)
|
|
.limit(50);
|
|
|
|
if (salariesError) {
|
|
console.error("[GET /api/staff/payslips/search-contracts] Salaries search error:", salariesError);
|
|
}
|
|
|
|
if (!salariesError && contractsBySalaries) {
|
|
console.log("[GET /api/staff/payslips/search-contracts] Salaries found:", contractsBySalaries.length);
|
|
// Aplatir les résultats et ajouter les infos du salarié
|
|
const additionalContracts = contractsBySalaries.flatMap(salarie => {
|
|
if (!salarie.cddu_contracts || !Array.isArray(salarie.cddu_contracts)) return [];
|
|
return salarie.cddu_contracts.map((contract: any) => ({
|
|
...contract,
|
|
salaries: {
|
|
salarie: salarie.salarie,
|
|
nom: salarie.nom,
|
|
prenom: salarie.prenom
|
|
}
|
|
}));
|
|
});
|
|
|
|
// Fusionner et dédupliquer par ID
|
|
const existingIds = new Set(finalContracts.map(c => c.id));
|
|
additionalContracts.forEach(contract => {
|
|
if (!existingIds.has(contract.id)) {
|
|
finalContracts.push(contract);
|
|
existingIds.add(contract.id);
|
|
}
|
|
});
|
|
console.log("[GET /api/staff/payslips/search-contracts] After salaries merge:", finalContracts.length);
|
|
}
|
|
}
|
|
|
|
// Filtrer aussi par nom d'organisation si peu de résultats
|
|
if (finalContracts.length < 10) {
|
|
console.log("[GET /api/staff/payslips/search-contracts] Searching in organizations table...");
|
|
const { data: contractsByOrgs, error: orgsError } = await sb
|
|
.from("organizations")
|
|
.select(`
|
|
id,
|
|
name,
|
|
cddu_contracts!org_id(
|
|
id,
|
|
contract_number,
|
|
employee_name,
|
|
employee_id,
|
|
structure,
|
|
type_de_contrat,
|
|
start_date,
|
|
end_date,
|
|
production_name,
|
|
n_objet,
|
|
objet_spectacle,
|
|
org_id,
|
|
salaries!employee_id(
|
|
salarie,
|
|
nom,
|
|
prenom
|
|
)
|
|
)
|
|
`)
|
|
.ilike('name', searchPattern)
|
|
.limit(50);
|
|
|
|
if (orgsError) {
|
|
console.error("[GET /api/staff/payslips/search-contracts] Organizations search error:", orgsError);
|
|
}
|
|
|
|
if (!orgsError && contractsByOrgs) {
|
|
console.log("[GET /api/staff/payslips/search-contracts] Organizations found:", contractsByOrgs.length);
|
|
const additionalContracts = contractsByOrgs.flatMap(org => {
|
|
if (!org.cddu_contracts || !Array.isArray(org.cddu_contracts)) return [];
|
|
return org.cddu_contracts.map((contract: any) => ({
|
|
...contract,
|
|
organizations: {
|
|
name: org.name
|
|
}
|
|
}));
|
|
});
|
|
|
|
const existingIds = new Set(finalContracts.map(c => c.id));
|
|
additionalContracts.forEach(contract => {
|
|
if (!existingIds.has(contract.id)) {
|
|
finalContracts.push(contract);
|
|
existingIds.add(contract.id);
|
|
}
|
|
});
|
|
console.log("[GET /api/staff/payslips/search-contracts] After organizations merge:", finalContracts.length);
|
|
}
|
|
}
|
|
|
|
// Limiter à 50 résultats
|
|
finalContracts = finalContracts.slice(0, 50);
|
|
|
|
console.log("[GET /api/staff/payslips/search-contracts] Final contracts count:", finalContracts.length);
|
|
|
|
return NextResponse.json({ contracts: finalContracts });
|
|
} catch (error) {
|
|
console.error("[GET /api/staff/payslips/search-contracts] Error:", error);
|
|
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
|
}
|
|
}
|