diff --git a/backend/src/lib/workforce.js b/backend/src/lib/workforce.js index 10f1436..28a87c2 100644 --- a/backend/src/lib/workforce.js +++ b/backend/src/lib/workforce.js @@ -94,9 +94,10 @@ function weeklyFetchDates(from, to) { } // Fetch timesheets for a single date — no location param (mirrors PBI pattern). -// include_oncosts=true is required to get cost_with_oncosts on nested shifts[]. +// Returns the weekly timesheet record(s) containing this date. +// Each record: { id, user_id, shifts: [{ department_id, date, cost, leave_request_id, ... }] } async function fetchTimesheetsForDate(dateStr) { - try { return await wfFetchPaged(`/api/v2/timesheets/on/${dateStr}?show_costs=true&include_oncosts=true`) } + try { return await wfFetchPaged(`/api/v2/timesheets/on/${dateStr}?show_costs=true`) } catch { return [] } } @@ -468,42 +469,13 @@ export async function compareEndpoints(from, to) { // A3: Same shifts, no client-side dept filter (trust the API filter entirely) // B: Per-day timesheets + shift.id dedup, filtered by locationDeptIds - // C: Salaried staff — users with salary field, report_department_id in location depts - const [a, a2, a3, b, allUsers] = await Promise.all([ + const [a, a2, a3, b] = await Promise.all([ fetchShiftsAndSummarise(shiftsReportLoc, locationDeptIds), fetchShiftsAndSummarise(shiftsReportLoc, reportLocationDeptIds), - fetchShiftsAndSummarise(shiftsReportLoc, null), + fetchShiftsAndSummarise(shiftsReportLoc, null), // trust API filter entirely fetchTimesheetsByDay(from, to, locationDeptIds), - wfFetchPaged('/api/v2/users?show_wages=true&show_inactive=false'), ]) - // Find salaried staff based at this location (report_department_id in a location dept) - const salaryUsers = locationDeptIds - ? allUsers.filter(u => u.salary != null && locationDeptIds.has(String(u.report_department_id))) - : allUsers.filter(u => u.salary != null) - - // Prorate salary for the query period: annual / 365 * days, or monthly / 31 * days - const days = Math.max(1, Math.ceil((new Date(to) - new Date(from)) / 86_400_000) + 1) - const salaryDetails = salaryUsers.map(u => { - const sal = u.salary - // salary field structure unknown until we see it — expose the raw value - return { - user_id: u.id, - name: u.name || `${u.legal_first_name || ''} ${u.legal_last_name || ''}`.trim(), - report_department_id: u.report_department_id, - salary_raw: sal, - // Attempt prorations based on common WF salary field shapes - // If salary is a number: assume annual amount - annual_if_number: typeof sal === 'number' ? sal : null, - monthly_if_number: typeof sal === 'number' ? +(sal / 12).toFixed(2) : null, - period_prorated: typeof sal === 'number' ? +(sal / 365 * days).toFixed(2) : null, - } - }) - - const totalSalaryAnnual = salaryDetails.reduce((s, u) => s + (u.annual_if_number ?? 0), 0) - const totalSalaryMonthly = salaryDetails.reduce((s, u) => s + (u.monthly_if_number ?? 0), 0) - const totalSalaryProrated = salaryDetails.reduce((s, u) => s + (u.period_prorated ?? 0), 0) - // Dept breakdown for report_location_id depts — to see which extra depts A2 picks up vs A const extraDepts = reportLocationDeptIds && locationDeptIds ? allDepts @@ -521,17 +493,6 @@ export async function compareEndpoints(from, to) { A2_shifts_api_filtered_report_dept_filter: { ...a2, note: 'shifts + report_location_id API filter + client dept filter (location_id OR report_location_id match)' }, A3_shifts_api_filtered_no_client_filter: { ...a3, note: 'shifts + report_location_id API filter only — no client-side dept filter' }, B_timesheets_per_day_dept_filter: b, - C_salaried_staff: { - count: salaryUsers.length, - period_days: days, - total_annual: +totalSalaryAnnual.toFixed(2), - total_monthly: +totalSalaryMonthly.toFixed(2), - total_prorated: +totalSalaryProrated.toFixed(2), - // Combined: A shifts oncostExLeave + prorated salary - combined_oncostExLeave_plus_salary_prorated: +(a.oncostExLeave + totalSalaryProrated).toFixed(2), - note: 'users with salary field set, report_department_id in location depts. salary_raw shows the actual API field shape.', - staff: salaryDetails, - }, wf_report_reference: { note: 'Target: WF "Cost by Location and Team" — Timesheet exc. leave inc. allowances', timesheet_exc_leave: 51005.72,