import { Injectable, Logger, NotFoundException } from "@nestjs/common"; import { PrismaService } from "../../../prisma/prisma.service"; @Injectable() export class VacationService { constructor(private readonly prisma: PrismaService) {} private readonly logger = new Logger(VacationService.name); //switch employeeId for email async calculateVacationPay(employee_id: number, start_date: Date, days_requested: number, modifier: number): Promise { //fetch hiring date const employee = await this.prisma.employees.findUnique({ where: { id: employee_id }, select: { first_work_day: true }, }); if(!employee) { throw new NotFoundException(`Employee #${employee_id} not found`); } const hire_date = employee.first_work_day; //sets "year" to may 1st to april 30th //check if hiring date is in may or later, we use hiring year, otherwise we use the year before const year_of_request = start_date.getMonth() >= 4 ? start_date.getFullYear() : start_date.getFullYear() -1; const period_start = new Date(year_of_request, 4, 1); //may = 4 const period_end = new Date(year_of_request + 1, 4, 0); //day 0 of may == april 30th this.logger.debug(`Vacation period for request: ${period_start.toDateString()} -> ${period_end.toDateString()}`); //steps to reach to get more vacation weeks in years const checkpoint = [5, 10, 15]; const anniversaries = checkpoint.map(years => { const anniversary_date = new Date(hire_date); anniversary_date.setFullYear(anniversary_date.getFullYear() + years); return anniversary_date; }).filter(d => d>= period_start && d <= period_end).sort((a,b) => a.getTime() - b.getTime()); this.logger.debug(`anniversatries steps during the period: ${anniversaries.map(date => date.toDateString()).join(',') || 'aucun'}`); const boundaries = [period_start, ...anniversaries,period_end]; //calculate prorata per segment let total_vacation_days = 0; const ms_per_day = 1000 * 60 * 60 * 24; for (let i = 0; i < boundaries.length -1; i++) { const segment_start = boundaries[i]; const segment_end = boundaries[i+1]; //number of days in said segment const days_in_segment = Math.round((segment_end.getTime() - segment_start.getTime())/ ms_per_day); const years_since_hire = (segment_start.getFullYear() - hire_date.getFullYear()) - (segment_start < new Date(segment_start.getFullYear(), hire_date.getMonth()) ? 1 : 0); let alloc_days: number; if(years_since_hire < 5) alloc_days = 10; else if(years_since_hire < 10) alloc_days = 15; else if(years_since_hire < 15) alloc_days = 20; else alloc_days = 25; //prorata for said segment const prorata = (alloc_days / 365) * days_in_segment; total_vacation_days += prorata; } //compares allowed vacation pools with requested days const payable_days = Math.min(total_vacation_days, days_requested); const raw_hours = payable_days * 8 * modifier; const rounded_hours = Math.round(raw_hours * 4) / 4; this.logger.debug(`Vacation pay: entitledDays=${total_vacation_days.toFixed(2)}, requestedDays=${days_requested}, payableDays=${payable_days.toFixed(2)}, hours=${rounded_hours}`); return rounded_hours; } }