espace-paie-odentas/app/api/staff/salary-transfers/search/route.ts

68 lines
No EOL
3.3 KiB
TypeScript

import { NextResponse } from "next/server";
import { createSbServer } from "@/lib/supabaseServer";
export async function GET(req: Request) {
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 url = new URL(req.url);
const q = url.searchParams.get("q");
const org_id = url.searchParams.get("org_id");
const period_month = url.searchParams.get("period_month");
const mode = url.searchParams.get("mode");
const notification_sent = url.searchParams.get("notification_sent");
const notification_ok = url.searchParams.get("notification_ok");
const has_client_wire = url.searchParams.get("has_client_wire");
const deadline_from = url.searchParams.get("deadline_from");
const deadline_to = url.searchParams.get("deadline_to");
const sort = url.searchParams.get("sort") || "period_month";
const order = (url.searchParams.get("order") || "desc").toLowerCase() === "asc" ? "asc" : "desc";
const limit = Math.min(500, parseInt(url.searchParams.get("limit") || "100", 10));
const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0", 10));
// Build base query with organization name
let query = sb.from("salary_transfers").select(`
*,
organizations!org_id(name)
`, { count: "exact" });
if (q) {
// simple ilike search on period_label, callsheet_url, notes
query = query.or(`period_label.ilike.%${q}%,callsheet_url.ilike.%${q}%,notes.ilike.%${q}%`);
}
if (org_id) query = query.eq("org_id", org_id);
if (period_month) query = query.eq("period_month", period_month);
if (mode) query = query.eq("mode", mode);
if (notification_sent !== null) {
if (notification_sent === "true") query = query.eq("notification_sent", true);
if (notification_sent === "false") query = query.eq("notification_sent", false);
}
if (notification_ok !== null) {
if (notification_ok === "true") query = query.eq("notification_ok", true);
if (notification_ok === "false") query = query.eq("notification_ok", false);
}
if (has_client_wire === "true") query = query.not("client_wire_received_at", "is", null);
if (has_client_wire === "false") query = query.is("client_wire_received_at", null);
if (deadline_from) query = query.gte("deadline", deadline_from);
if (deadline_to) query = query.lte("deadline", deadline_to);
// allowed sort columns
const allowedSorts = new Set(["period_month", "deadline", "total_net", "created_at", "updated_at", "client_wire_received_at"]);
const sortCol = allowedSorts.has(sort) ? sort : "period_month";
query = query.order(sortCol, { ascending: order === "asc" });
query = query.range(offset, offset + limit - 1);
const { data, error, count } = await query;
if (error) return NextResponse.json({ error: error.message }, { status: 500 });
return NextResponse.json({ rows: data ?? [], count: count ?? (data ? data.length : 0) });
} catch (err: any) {
console.error(err);
return NextResponse.json({ error: "Internal" }, { status: 500 });
}
}