79 lines
3.4 KiB
TypeScript
79 lines
3.4 KiB
TypeScript
import { Injectable, Logger, NotFoundException } from "@nestjs/common";
|
|
import { computeHours, getWeekStart } from "src/common/utils/date-utils";
|
|
import { PrismaService } from "../../../prisma/prisma.service";
|
|
|
|
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.
|
|
le bank-code à soumettre à Desjardins doit être le G104
|
|
*/
|
|
|
|
@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;
|
|
}
|
|
} |