Adds complete initial codebase for the RJ Bulk Supplies fuel delivery backoffice: - Authentication pages and protected route layouts - Customer, supplier, fuel purchase, and delivery note management - Custom reporting and customer statement sending tools - Full UI component library and Tailwind styling - Server actions, API routes, and PocketBase integration - Development scripts and project configuration updates - Updated README and package metadata
78 lines
3 KiB
TypeScript
78 lines
3 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { getAuth } from "@/lib/auth";
|
|
import { pbList } from "@/lib/pocketbase";
|
|
import { generateCustomerStatement } from "@/lib/pdf/customer-statement";
|
|
import type { Customer, DeliveryNote, FuelSettings } from "@/lib/types";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
function rangeDates(range: string, start?: string, end?: string) {
|
|
const now = new Date();
|
|
if (range === "this-month") {
|
|
return {
|
|
start: new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10),
|
|
end: new Date(now.getFullYear(), now.getMonth() + 1, 0).toISOString().slice(0, 10),
|
|
};
|
|
}
|
|
if (range === "last-month") {
|
|
return {
|
|
start: new Date(now.getFullYear(), now.getMonth() - 1, 1).toISOString().slice(0, 10),
|
|
end: new Date(now.getFullYear(), now.getMonth(), 0).toISOString().slice(0, 10),
|
|
};
|
|
}
|
|
if (start && end) return { start, end };
|
|
return { start: start || "", end: end || "" };
|
|
}
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const { token } = await getAuth();
|
|
if (!token) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
|
|
const { searchParams } = req.nextUrl;
|
|
const customerId = searchParams.get("customer");
|
|
const range = searchParams.get("range") || "this-month";
|
|
const startParam = searchParams.get("start");
|
|
const endParam = searchParams.get("end");
|
|
const includePricing = searchParams.get("include_pricing") !== "false";
|
|
|
|
if (!customerId) return NextResponse.json({ error: "customer required" }, { status: 400 });
|
|
|
|
const { start, end } = rangeDates(range, startParam || undefined, endParam || undefined);
|
|
if (!start || !end) return NextResponse.json({ error: "Date range required" }, { status: 400 });
|
|
|
|
try {
|
|
const [customerRes, notesRes, settingsRes] = await Promise.all([
|
|
pbList<Customer>("customers", { perPage: 1, filter: `id = "${customerId}"` }, token),
|
|
pbList<DeliveryNote>("delivery_notes", {
|
|
perPage: 1000,
|
|
filter: `customer = "${customerId}" && date >= "${start}" && date <= "${end}"`,
|
|
sort: "date",
|
|
}, token),
|
|
pbList<FuelSettings>("fuel_settings", { perPage: 1 }, token),
|
|
]);
|
|
|
|
if (customerRes.items.length === 0) {
|
|
return NextResponse.json({ error: "Customer not found" }, { status: 404 });
|
|
}
|
|
|
|
const pdfBytes = await generateCustomerStatement({
|
|
customer: customerRes.items[0],
|
|
notes: notesRes.items,
|
|
startDate: start,
|
|
endDate: end,
|
|
includePricing,
|
|
companySettings: settingsRes.items[0] || null,
|
|
});
|
|
|
|
const filename = `delivery_statement_${customerRes.items[0].name.replace(/\s+/g, "_")}_${start.replace(/-/g, "")}.pdf`;
|
|
return new NextResponse(Buffer.from(pdfBytes), {
|
|
headers: {
|
|
"Content-Type": "application/pdf",
|
|
"Content-Disposition": `inline; filename="${filename}"`,
|
|
"Cache-Control": "no-store",
|
|
},
|
|
});
|
|
} catch (err: any) {
|
|
return NextResponse.json({ error: err?.message || "PDF generation failed" }, { status: 500 });
|
|
}
|
|
}
|