import { WEEKLY_LIMIT_HOURS } from "src/common/utils/constants.utils"; import { HolidayService } from "src/time-and-attendance/domains/services/holiday.service"; import { CsvRow, InternalCsvRow } from "src/time-and-attendance/exports/export-csv-options.dto"; const REGULAR = 1; const EVENING = 140; const EMERGENCY = 48; const HOLIDAY = 104; const OVERTIME = 43; const VACATION = 109; const SICK = 105; export const consolidateRowHoursAndAmountByType = (rows: InternalCsvRow[]): InternalCsvRow[] => { const map = new Map(); for (const row of rows) { if (row.code === VACATION || row.code === SICK) { map.set(`${row.code}|${row.shift_date.toString()}|${row.timesheet_id}`, row); } else { const key = `${row.code}|${row.timesheet_id}`; if (!map.has(key)) { map.set(key, row); } else { const existing = map.get(key)!; existing.quantite_hre = (existing.quantite_hre ?? 0) + (row.quantite_hre ?? 0); existing.montant = (existing.montant ?? 0) + (row.montant ?? 0); } } } return Array.from(map.values()); } export const applyHolidayRequalifications = async ( rows: InternalCsvRow[], holiday_service: HolidayService, holiday_bank_code: string, ): Promise => { const result: InternalCsvRow[] = []; const HOLIDAY_BANK_CODE = Number(holiday_bank_code.slice(1,)); for (const row of rows) { if (row.code !== HOLIDAY_BANK_CODE) { result.push(row); continue; } if (!row.premier_jour_absence || !row.dernier_jour_absence || !row.employee_matricule || !row.compagnie_no) { result.push(row); continue; } const calculated = await holiday_service.calculateHolidayPay(row.employee_matricule, row.compagnie_no, new Date(row.premier_jour_absence)); if (!calculated.success) { result.push({ ...row, quantite_hre: 0 }); continue; } result.push({ ...row, quantite_hre: calculated.data }); } return result; } export const applyOvertimeRequalifications = ( consolidated_rows: InternalCsvRow[], ): CsvRow[] => { const result: InternalCsvRow[] = []; //regroup rows by timesheet and week number const grouped_rows = new Map(); for (const row of consolidated_rows) { const key = `${row.timesheet_id}|${row.semaine_no}`; if (!grouped_rows.has(key)) { grouped_rows.set(key, []); } grouped_rows.get(key)!.push({ ...row }); } for (const [, rows] of grouped_rows) { const evening_hours = rows.find(r => r.code === EVENING); const emergency_hours = rows.find(r => r.code === EMERGENCY); const holiday_hours = rows.find(r => r.code === HOLIDAY); const regular_hours = rows.find(r => r.code === REGULAR); const vacation_hours = rows.find(r => r.code === VACATION); // if no regular hours row, push as is if (!regular_hours?.quantite_hre) { result.push(...rows); continue; } const total_hours = ( regular_hours.quantite_hre + (evening_hours?.quantite_hre ?? 0) + (emergency_hours?.quantite_hre ?? 0) + (holiday_hours?.quantite_hre ?? 0) + (vacation_hours?.quantite_hre ?? 0) ) // calculate overtime directly from consolidated hours const overtime_hours = Math.max(0, total_hours - WEEKLY_LIMIT_HOURS); // if no overtime, push as is if (overtime_hours <= 0) { result.push(...rows); continue; } // ensures that its not possible to deduct more hours than the amount of regular or evening hours const deducted_regular = Math.min(overtime_hours, regular_hours.quantite_hre); const remaining_overtime = overtime_hours - deducted_regular; const deducted_evening = Math.min(remaining_overtime, evening_hours?.quantite_hre ?? 0); const remaining_regular = (regular_hours.quantite_hre ?? 0) - deducted_regular; const remaining_evening = (evening_hours?.quantite_hre ?? 0) - deducted_evening; for (const row of rows) { if (row === regular_hours) { // pushes the regular row with subtracted overtime hours, if enough hours remaining if (remaining_regular > 0) { result.push({ ...regular_hours, quantite_hre: remaining_regular }); } } else if (row === evening_hours) { // pushes the evening row with subtracted overtime hours, if enough not enough regular hours remaining if (remaining_evening > 0) { result.push({ ...evening_hours, quantite_hre: remaining_evening }); } } else { // other rows are left unchanged result.push(row); } } //adds a new row with overtime hours deducted from the regular hours if (deducted_regular + deducted_evening > 0) { result.push({ ...regular_hours, code: OVERTIME, quantite_hre: deducted_regular + deducted_evening, }); } } return result; } export const resolveCompanyCode = (company: 'Targo' | 'Solucom'): number => { return company === 'Targo' ? 271583 : 271585; } export const computeWeekNumber = (start: Date, date: Date): number => { const dayMS = 86400000; const days = Math.floor((toUTC(date).getTime() - toUTC(start).getTime()) / dayMS); return Math.floor(days / 7) + 1; } export const toUTC = (date: Date) => { return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())); } export const formatDate = (d: Date): string => { return d.toISOString().split('T')[0]; }