78 lines
3.6 KiB
TypeScript
78 lines
3.6 KiB
TypeScript
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<number> {
|
|
//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;
|
|
}
|
|
|
|
|
|
|
|
} |