import { getYearToDateRange } from '../utils/dateUtils'; export const TECHNICIAN_WORKING_HOURS_REPORT = 'Technicians working Hours'; export type TechnicianWorkingHoursRow = { engineer?: string; technician_name?: string; total_hours?: number | string; is_total_row?: number | boolean; }; export type TechnicianWorkingHoursFilters = { work_order_type?: string; from_date?: string; to_date?: string; company?: string; site_name?: string; }; export type TechnicianWorkingHoursChartData = { labels: string[]; datasets: Array<{ name: string; values: number[]; colors?: string[] }>; totalHours: number; rows: TechnicianWorkingHoursRow[]; }; export const getDefaultTechnicianHoursDateRange = () => getYearToDateRange(); export const getTechnicianHoursLabel = (row: TechnicianWorkingHoursRow): string => (row.technician_name || row.engineer || 'Unknown').trim() || 'Unknown'; export const parseTechnicianHours = (value: unknown): number => { if (value == null || value === '') return 0; const parsed = Number(value); return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0; }; export const buildTechnicianWorkingHoursChartData = ( rows: TechnicianWorkingHoursRow[] ): TechnicianWorkingHoursChartData | null => { const dataRows = rows.filter(row => row && !row.is_total_row); if (!dataRows.length) return null; const labels = dataRows.map(getTechnicianHoursLabel); const values = dataRows.map(row => parseTechnicianHours(row.total_hours)); const totalHours = values.reduce((sum, value) => sum + value, 0); return { labels, datasets: [{ name: 'Total Hours', values, colors: ['#6366F1'] }], totalHours, rows: dataRows, }; }; export const runTechnicianWorkingHoursReport = async ( filters: TechnicianWorkingHoursFilters ): Promise => { const csrfToken = typeof window !== 'undefined' && (window as any).csrf_token && (window as any).csrf_token !== 'None' ? (window as any).csrf_token : null; const headers: Record = { 'Content-Type': 'application/json', Accept: 'application/json', }; if (csrfToken) { headers['X-Frappe-CSRF-Token'] = csrfToken; } const cleanedFilters: Record = {}; Object.entries(filters).forEach(([key, value]) => { if (value) cleanedFilters[key] = value; }); const response = await fetch('/api/method/frappe.desk.query_report.run', { method: 'POST', headers, credentials: 'include', body: JSON.stringify({ report_name: TECHNICIAN_WORKING_HOURS_REPORT, filters: cleanedFilters, ignore_prepared_report: 1, }), }); const payload = await response.json(); if (!response.ok) { throw new Error(payload?.message || payload?.exc || 'Failed to load technician working hours'); } const result = payload?.message?.result || payload?.message?.message?.result || []; if (!Array.isArray(result)) return []; return result.filter(row => row && !row.is_total_row); }; export const fetchTechnicianWorkingHoursChart = async ( filters: TechnicianWorkingHoursFilters ): Promise => { const rows = await runTechnicianWorkingHoursReport(filters); return buildTechnicianWorkingHoursChartData(rows); };