import { Injectable, Logger, NotFoundException } from "@nestjs/common"; import { PrismaService } from "../../../prisma/prisma.service"; import { computeHours, getWeekStart } from "src/common/utils/date-utils"; const WEEK_IN_MS = 7 * 24 * 60 * 60 * 1000; /* le calcul est 1/20 des 4 dernières semaines, précédent la semaine incluant le férier. Un maximum de 08h00 est allouable pour le férier Un maximum de 40hrs par semaine est retenue pour faire le calcul. */ @Injectable() export class HolidayService { private readonly logger = new Logger(HolidayService.name); constructor(private readonly prisma: PrismaService) {} //fetch employee_id by email private async resolveEmployeeByEmail(email: string): Promise { const employee = await this.prisma.employees.findFirst({ where: { user: { email } }, select: { id: true }, }); if(!employee) throw new NotFoundException(`Employee with email : ${email} not found`); return employee.id; } private async computeHoursPrevious4WeeksByEmail(email: string, holiday_date: Date): Promise { const employee_id = await this.resolveEmployeeByEmail(email); return this.computeHoursPrevious4Weeks(employee_id, holiday_date); } private async computeHoursPrevious4Weeks(employee_id: number, holiday_date: Date): Promise { const holiday_week_start = getWeekStart(holiday_date); const window_start = new Date(holiday_week_start.getTime() - 4 * WEEK_IN_MS); const window_end = new Date(holiday_week_start.getTime() - 1); const valid_codes = ['G1', 'G43', 'G56', 'G104', 'G105', 'G700']; const shifts = await this.prisma.shifts.findMany({ where: { timesheet: { employee_id: employee_id }, date: { gte: window_start, lte: window_end }, bank_code: { bank_code: { in: valid_codes } }, }, select: { date: true, start_time: true, end_time: true }, }); const hours_by_week = new Map(); for(const shift of shifts) { const hours = computeHours(shift.start_time, shift.end_time); if(hours <= 0) continue; const shift_week_start = getWeekStart(shift.date); const key = shift_week_start.getTime(); hours_by_week.set(key, (hours_by_week.get(key) ?? 0) + hours); } let capped_total = 0; for(let offset = 1; offset <= 4; offset++) { const week_start = new Date(holiday_week_start.getTime() - offset * WEEK_IN_MS); const key = week_start.getTime(); const weekly_hours = hours_by_week.get(key) ?? 0; capped_total += Math.min(weekly_hours, 40); } const average_daily_hours = capped_total / 20; return average_daily_hours; } async calculateHolidayPay( email: string, holiday_date: Date, modifier: number): Promise { const average_daily_hours = await this.computeHoursPrevious4WeeksByEmail(email, holiday_date); const daily_rate = Math.min(average_daily_hours, 8); this.logger.debug(`Holiday pay calculation: cappedHoursPerDay= ${average_daily_hours.toFixed(2)}, appliedDailyRate= ${daily_rate.toFixed(2)}`); return daily_rate * modifier; } }