import { clientAuthFetch } from "@/app/utils/clientAuthFetch"; import { NEXT_PUBLIC_API_URL } from "@/config/api"; const BASE = `${NEXT_PUBLIC_API_URL}/chart`; function buildParams(params: Record) { const p = new URLSearchParams(); Object.entries(params).forEach(([k, v]) => { if (v !== undefined && v !== "") p.set(k, String(v)); }); return p.toString(); } export interface StockTransactionsByDateRow { date: string; inQty: number; outQty: number; totalQty: number; } export interface DeliveryOrderByDateRow { date: string; orderCount: number; totalQty: number; } export interface PurchaseOrderByStatusRow { status: string; count: number; } export interface StockInOutByDateRow { date: string; inQty: number; outQty: number; } export interface TopDeliveryItemsRow { itemCode: string; itemName: string; totalQty: number; } export interface StockBalanceTrendRow { date: string; balance: number; } export interface ConsumptionTrendByMonthRow { month: string; outQty: number; } export interface StaffDeliveryPerformanceRow { date: string; staffName: string; orderCount: number; totalMinutes: number; } export interface StaffOption { staffNo: string; name: string; } export async function fetchStaffDeliveryPerformanceHandlers(): Promise { const res = await clientAuthFetch(`${BASE}/staff-delivery-performance-handlers`); if (!res.ok) throw new Error("Failed to fetch staff list"); const data = await res.json(); if (!Array.isArray(data)) return []; return (data as Record[]).map((r: Record) => ({ staffNo: String(r.staffNo ?? ""), name: String(r.name ?? ""), })); } // Job order export interface JobOrderByStatusRow { status: string; count: number; } export interface JobOrderCountByDateRow { date: string; orderCount: number; } export interface JobOrderCreatedCompletedRow { date: string; createdCount: number; completedCount: number; } export interface ProductionScheduleByDateRow { date: string; scheduledItemCount: number; totalEstProdCount: number; } export interface PlannedDailyOutputRow { itemCode: string; itemName: string; dailyQty: number; } export async function fetchJobOrderByStatus( targetDate?: string ): Promise { const q = targetDate ? buildParams({ targetDate }) : ""; const res = await clientAuthFetch( q ? `${BASE}/job-order-by-status?${q}` : `${BASE}/job-order-by-status` ); if (!res.ok) throw new Error("Failed to fetch job order by status"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ status: String(r.status ?? ""), count: Number(r.count ?? 0), })); } export async function fetchJobOrderCountByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch(`${BASE}/job-order-count-by-date?${q}`); if (!res.ok) throw new Error("Failed to fetch job order count by date"); const data = await res.json(); return normalizeChartRows(data, "date", ["orderCount"]); } export async function fetchJobOrderCreatedCompletedByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch( `${BASE}/job-order-created-completed-by-date?${q}` ); if (!res.ok) throw new Error("Failed to fetch job order created/completed"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ date: String(r.date ?? ""), createdCount: Number(r.createdCount ?? 0), completedCount: Number(r.completedCount ?? 0), })); } export interface JobMaterialPendingPickedRow { date: string; pendingCount: number; pickedCount: number; } export async function fetchJobMaterialPendingPickedByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch(`${BASE}/job-material-pending-picked-by-date?${q}`); if (!res.ok) throw new Error("Failed to fetch job material pending/picked"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ date: String(r.date ?? ""), pendingCount: Number(r.pendingCount ?? 0), pickedCount: Number(r.pickedCount ?? 0), })); } export interface JobProcessPendingCompletedRow { date: string; pendingCount: number; completedCount: number; } export async function fetchJobProcessPendingCompletedByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch(`${BASE}/job-process-pending-completed-by-date?${q}`); if (!res.ok) throw new Error("Failed to fetch job process pending/completed"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ date: String(r.date ?? ""), pendingCount: Number(r.pendingCount ?? 0), completedCount: Number(r.completedCount ?? 0), })); } export interface JobEquipmentWorkingWorkedRow { date: string; workingCount: number; workedCount: number; } export async function fetchJobEquipmentWorkingWorkedByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch(`${BASE}/job-equipment-working-worked-by-date?${q}`); if (!res.ok) throw new Error("Failed to fetch job equipment working/worked"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ date: String(r.date ?? ""), workingCount: Number(r.workingCount ?? 0), workedCount: Number(r.workedCount ?? 0), })); } export async function fetchProductionScheduleByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch( `${BASE}/production-schedule-by-date?${q}` ); if (!res.ok) throw new Error("Failed to fetch production schedule by date"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ date: String(r.date ?? ""), scheduledItemCount: Number(r.scheduledItemCount ?? r.scheduleCount ?? 0), totalEstProdCount: Number(r.totalEstProdCount ?? 0), })); } export async function fetchPlannedDailyOutputByItem( limit = 20 ): Promise { const res = await clientAuthFetch( `${BASE}/planned-daily-output-by-item?limit=${limit}` ); if (!res.ok) throw new Error("Failed to fetch planned daily output"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ itemCode: String(r.itemCode ?? ""), itemName: String(r.itemName ?? ""), dailyQty: Number(r.dailyQty ?? 0), })); } /** Planned production by date and by item (production_schedule). */ export interface PlannedOutputByDateAndItemRow { date: string; itemCode: string; itemName: string; qty: number; } export async function fetchPlannedOutputByDateAndItem( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch( q ? `${BASE}/planned-output-by-date-and-item?${q}` : `${BASE}/planned-output-by-date-and-item` ); if (!res.ok) throw new Error("Failed to fetch planned output by date and item"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ date: String(r.date ?? ""), itemCode: String(r.itemCode ?? ""), itemName: String(r.itemName ?? ""), qty: Number(r.qty ?? 0), })); } export async function fetchStaffDeliveryPerformance( startDate?: string, endDate?: string, staffNos?: string[] ): Promise { const p = new URLSearchParams(); if (startDate) p.set("startDate", startDate); if (endDate) p.set("endDate", endDate); (staffNos ?? []).forEach((no) => p.append("staffNo", no)); const q = p.toString(); const res = await clientAuthFetch( q ? `${BASE}/staff-delivery-performance?${q}` : `${BASE}/staff-delivery-performance` ); if (!res.ok) throw new Error("Failed to fetch staff delivery performance"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => { // Accept camelCase or lowercase keys (JDBC/DB may return different casing) const row = r as Record; return { date: String(row.date ?? row.Date ?? ""), staffName: String(row.staffName ?? row.staffname ?? ""), orderCount: Number(row.orderCount ?? row.ordercount ?? 0), totalMinutes: Number(row.totalMinutes ?? row.totalminutes ?? 0), }; }); } export async function fetchStockTransactionsByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch(`${BASE}/stock-transactions-by-date?${q}`); if (!res.ok) throw new Error("Failed to fetch stock transactions by date"); const data = await res.json(); return normalizeChartRows(data, "date", ["inQty", "outQty", "totalQty"]); } export async function fetchDeliveryOrderByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch(`${BASE}/delivery-order-by-date?${q}`); if (!res.ok) throw new Error("Failed to fetch delivery order by date"); const data = await res.json(); return normalizeChartRows(data, "date", ["orderCount", "totalQty"]); } export async function fetchPurchaseOrderByStatus( targetDate?: string ): Promise { const q = targetDate ? buildParams({ targetDate }) : ""; const res = await clientAuthFetch( q ? `${BASE}/purchase-order-by-status?${q}` : `${BASE}/purchase-order-by-status` ); if (!res.ok) throw new Error("Failed to fetch purchase order by status"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ status: String(r.status ?? ""), count: Number(r.count ?? 0), })); } export async function fetchStockInOutByDate( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch(`${BASE}/stock-in-out-by-date?${q}`); if (!res.ok) throw new Error("Failed to fetch stock in/out by date"); const data = await res.json(); return normalizeChartRows(data, "date", ["inQty", "outQty"]); } export interface TopDeliveryItemOption { itemCode: string; itemName: string; } export async function fetchTopDeliveryItemsItemOptions( startDate?: string, endDate?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "" }); const res = await clientAuthFetch( q ? `${BASE}/top-delivery-items-item-options?${q}` : `${BASE}/top-delivery-items-item-options` ); if (!res.ok) throw new Error("Failed to fetch item options"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ itemCode: String(r.itemCode ?? ""), itemName: String(r.itemName ?? ""), })); } export async function fetchTopDeliveryItems( startDate?: string, endDate?: string, limit = 10, itemCodes?: string[] ): Promise { const p = new URLSearchParams(); if (startDate) p.set("startDate", startDate); if (endDate) p.set("endDate", endDate); p.set("limit", String(limit)); (itemCodes ?? []).forEach((code) => p.append("itemCode", code)); const q = p.toString(); const res = await clientAuthFetch(`${BASE}/top-delivery-items?${q}`); if (!res.ok) throw new Error("Failed to fetch top delivery items"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ itemCode: String(r.itemCode ?? ""), itemName: String(r.itemName ?? ""), totalQty: Number(r.totalQty ?? 0), })); } export async function fetchStockBalanceTrend( startDate?: string, endDate?: string, itemCode?: string ): Promise { const q = buildParams({ startDate: startDate ?? "", endDate: endDate ?? "", itemCode: itemCode ?? "", }); const res = await clientAuthFetch(`${BASE}/stock-balance-trend?${q}`); if (!res.ok) throw new Error("Failed to fetch stock balance trend"); const data = await res.json(); return normalizeChartRows(data, "date", ["balance"]); } export async function fetchConsumptionTrendByMonth( year?: number, startDate?: string, endDate?: string, itemCode?: string ): Promise { const q = buildParams({ year: year ?? "", startDate: startDate ?? "", endDate: endDate ?? "", itemCode: itemCode ?? "", }); const res = await clientAuthFetch(`${BASE}/consumption-trend-by-month?${q}`); if (!res.ok) throw new Error("Failed to fetch consumption trend"); const data = await res.json(); return ((Array.isArray(data) ? data : []) as Record[]).map((r: Record) => ({ month: String(r.month ?? ""), outQty: Number(r.outQty ?? 0), })); } /** Normalize rows: ensure date key is string and numeric keys are numbers (backend may return BigDecimal/Long). */ function normalizeChartRows( rows: unknown[], dateKey: string, numberKeys: string[] ): T[] { if (!Array.isArray(rows)) return []; return rows.map((r: unknown) => { const row = r as Record; const out: Record = {}; out[dateKey] = row[dateKey] != null ? String(row[dateKey]) : ""; numberKeys.forEach((k) => { out[k] = Number(row[k]) || 0; }); return out as T; }); }