targo-backend/src/modules/business-logics/services/holiday.service.ts

78 lines
3.3 KiB
TypeScript

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<number> {
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<number> {
const employee_id = await this.resolveEmployeeByEmail(email);
return this.computeHoursPrevious4Weeks(employee_id, holiday_date);
}
private async computeHoursPrevious4Weeks(employee_id: number, holiday_date: Date): Promise<number> {
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<number, number>();
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<number> {
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;
}
}