clean(): file cleaning

This commit is contained in:
Matthieu Haineault 2025-11-14 09:35:05 -05:00
parent 7968359bfe
commit 1589df979f
10 changed files with 138 additions and 273 deletions

View File

@ -637,25 +637,16 @@
] ]
} }
}, },
"/preferences": { "/preferences/update_preferences": {
"patch": { "patch": {
"operationId": "PreferencesController_updatePreferences", "operationId": "PreferencesController_updatePreferences",
"parameters": [ "parameters": [],
{
"name": "PreferencesDto",
"required": true,
"in": "body",
"schema": {
"$ref": "#/components/schemas/PreferencesDto"
}
}
],
"requestBody": { "requestBody": {
"required": true, "required": true,
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"type": "number" "$ref": "#/components/schemas/PreferencesDto"
} }
} }
} }

View File

@ -1,6 +1,7 @@
import { Controller, Get, Patch, Param, Body, NotFoundException, Req, Post } from "@nestjs/common"; import { Controller, Get, Patch, Param, Body, NotFoundException, Req, Post } from "@nestjs/common";
import { Employees } from "@prisma/client"; import { Employees } from "@prisma/client";
import { RolesAllowed } from "src/common/decorators/roles.decorators"; import { RolesAllowed } from "src/common/decorators/roles.decorators";
import { Result } from "src/common/errors/result-error.factory";
import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes"; import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes";
import { CreateEmployeeDto } from "src/identity-and-account/employees/dtos/create-employee.dto"; import { CreateEmployeeDto } from "src/identity-and-account/employees/dtos/create-employee.dto";
import { EmployeeListItemDto } from "src/identity-and-account/employees/dtos/list-employee.dto"; import { EmployeeListItemDto } from "src/identity-and-account/employees/dtos/list-employee.dto";
@ -18,14 +19,14 @@ export class EmployeesController {
) { } ) { }
@Get('profile') @Get('profile')
findOneProfile(@Req() req): Promise<EmployeeProfileItemDto> { findOneProfile(@Req() req): Promise<Result<EmployeeProfileItemDto,string>> {
const email = req.user?.email; const email = req.user?.email;
return this.employeesService.findOneProfile(email); return this.employeesService.findOneProfile(email);
} }
@Get('employee-list') @Get('employee-list')
@RolesAllowed(...MANAGER_ROLES) @RolesAllowed(...MANAGER_ROLES)
findListEmployees(): Promise<EmployeeListItemDto[]> { findListEmployees(): Promise<Result<EmployeeListItemDto[], string>> {
return this.employeesService.findListEmployees(); return this.employeesService.findListEmployees();
} }

View File

@ -1,5 +1,6 @@
import { Injectable, NotFoundException } from "@nestjs/common"; import { Injectable, NotFoundException } from "@nestjs/common";
import { Employees, Users } from "@prisma/client"; import { Employees, Users } from "@prisma/client";
import { Result } from "src/common/errors/result-error.factory";
import { CreateEmployeeDto } from "src/identity-and-account/employees/dtos/create-employee.dto"; import { CreateEmployeeDto } from "src/identity-and-account/employees/dtos/create-employee.dto";
import { EmployeeListItemDto } from "src/identity-and-account/employees/dtos/list-employee.dto"; import { EmployeeListItemDto } from "src/identity-and-account/employees/dtos/list-employee.dto";
import { EmployeeProfileItemDto } from "src/identity-and-account/employees/dtos/profil-employee.dto"; import { EmployeeProfileItemDto } from "src/identity-and-account/employees/dtos/profil-employee.dto";
@ -9,8 +10,8 @@ import { PrismaService } from "src/prisma/prisma.service";
export class EmployeesService { export class EmployeesService {
constructor(private readonly prisma: PrismaService) { } constructor(private readonly prisma: PrismaService) { }
findListEmployees(): Promise<EmployeeListItemDto[]> { async findListEmployees(): Promise<Result<EmployeeListItemDto[], string>> {
return this.prisma.employees.findMany({ return {success: true, data:await this.prisma.employees.findMany({
select: { select: {
user: { user: {
select: { select: {
@ -41,11 +42,11 @@ export class EmployeesService {
employee_full_name: `${r.user.first_name} ${r.user.last_name}`, employee_full_name: `${r.user.first_name} ${r.user.last_name}`,
supervisor_full_name: r.supervisor ? `${r.supervisor.user.first_name} ${r.supervisor.user.last_name}` : null, supervisor_full_name: r.supervisor ? `${r.supervisor.user.first_name} ${r.supervisor.user.last_name}` : null,
})), })),
); )}
} }
async findOneProfile(email: string): Promise<EmployeeProfileItemDto> { async findOneProfile(email: string): Promise<Result<EmployeeProfileItemDto, string>> {
const emp = await this.prisma.employees.findFirst({ const employee = await this.prisma.employees.findFirst({
where: { user: { email } }, where: { user: { email } },
select: { select: {
user: { user: {
@ -73,20 +74,23 @@ export class EmployeesService {
last_work_day: true, last_work_day: true,
} }
}); });
if (!emp) throw new NotFoundException(`Employee with email ${email} not found`); if (!employee)return {success: false, error: `Employee with email ${email} not found`};
return { return {
first_name: emp.user.first_name, success: true,
last_name: emp.user.last_name, data: {
email: emp.user.email, first_name: employee.user.first_name,
residence: emp.user.residence, last_name: employee.user.last_name,
phone_number: emp.user.phone_number, email: employee.user.email,
company_name: emp.company_code, residence: employee.user.residence,
job_title: emp.job_title, phone_number: employee.user.phone_number,
employee_full_name: `${emp.user.first_name} ${emp.user.last_name}`, company_name: employee.company_code,
first_work_day: emp.first_work_day.toISOString().slice(0, 10), job_title: employee.job_title,
last_work_day: emp.last_work_day ? emp.last_work_day.toISOString().slice(0, 10) : null, employee_full_name: `${employee.user.first_name} ${employee.user.last_name}`,
supervisor_full_name: emp.supervisor ? `${emp.supervisor.user.first_name}, ${emp.supervisor.user.last_name}` : null, first_work_day: employee.first_work_day.toISOString().slice(0, 10),
last_work_day: employee.last_work_day ? employee.last_work_day.toISOString().slice(0, 10) : null,
supervisor_full_name: employee.supervisor ? `${employee.supervisor.user.first_name}, ${employee.supervisor.user.last_name}` : null,
}
}; };
} }
@ -128,107 +132,4 @@ export class EmployeesService {
}); });
}); });
} }
//_____________________________________________________________________________________________
// Deprecated or unused methods
//_____________________________________________________________________________________________
// findAll(): Promise<Employees[]> {
// return this.prisma.employees.findMany({
// include: { user: true },
// });
// }
// async findOne(email: string): Promise<Employees> {
// const emp = await this.prisma.employees.findFirst({
// where: { user: { email } },
// include: { user: true },
// });
// //add search for archived employees
// if (!emp) {
// throw new NotFoundException(`Employee with email: ${email} not found`);
// }
// return emp;
// }
// async update(
// email: string,
// dto: UpdateEmployeeDto,
// ): Promise<Employees> {
// const emp = await this.findOne(email);
// const {
// first_name,
// last_name,
// phone_number,
// residence,
// external_payroll_id,
// company_code,
// job_title,
// first_work_day,
// last_work_day,
// is_supervisor,
// email: new_email,
// } = dto;
// return this.prisma.$transaction(async (transaction) => {
// if(
// first_name !== undefined ||
// last_name !== undefined ||
// new_email !== undefined ||
// phone_number !== undefined ||
// residence !== undefined
// ){
// await transaction.users.update({
// where: { id: emp.user_id },
// data: {
// ...(first_name !== undefined && { first_name }),
// ...(last_name !== undefined && { last_name }),
// ...(email !== undefined && { email }),
// ...(phone_number !== undefined && { phone_number }),
// ...(residence !== undefined && { residence }),
// },
// });
// }
// const updated = await transaction.employees.update({
// where: { id: emp.id },
// data: {
// ...(external_payroll_id !== undefined && { external_payroll_id }),
// ...(company_code !== undefined && { company_code }),
// ...(first_work_day !== undefined && { first_work_day }),
// ...(last_work_day !== undefined && { last_work_day }),
// ...(job_title !== undefined && { job_title }),
// ...(is_supervisor !== undefined && { is_supervisor }),
// },
// });
// return updated;
// });
// }
// async remove(email: string): Promise<Employees> {
// const emp = await this.findOne(email);
// return this.prisma.$transaction(async (transaction) => {
// await transaction.employees.updateMany({
// where: { supervisor_id: emp.id },
// data: { supervisor_id: null },
// });
// const deleted_employee = await transaction.employees.delete({
// where: {id: emp.id },
// });
// await transaction.users.delete({
// where: { id: emp.user_id },
// });
// return deleted_employee;
// });
// }
} }

View File

@ -1,17 +1,19 @@
import { Body, Controller, Patch } from "@nestjs/common"; import { Body, Controller, Patch, Req } from "@nestjs/common";
import { PreferencesService } from "../services/preferences.service"; import { PreferencesService } from "../services/preferences.service";
import { PreferencesDto } from "../dtos/preferences.dto"; import { PreferencesDto } from "../dtos/preferences.dto";
import { Result } from "src/common/errors/result-error.factory";
@Controller('preferences') @Controller('preferences')
export class PreferencesController { export class PreferencesController {
constructor(private readonly service: PreferencesService){} constructor(private readonly service: PreferencesService){}
@Patch() @Patch('update_preferences')
async updatePreferences( async updatePreferences(
@Body() user_id: number, @Req()req,
@Body() payload: PreferencesDto @Body() payload: PreferencesDto
) { ): Promise<Result<PreferencesDto, string>> {
return this.service.updatePreferences(user_id, payload); const email = req.user?.email;
return this.service.updatePreferences(email, payload);
} }
} }

View File

@ -1,25 +1,11 @@
import { IsInt } from "class-validator"; import { IsInt } from "class-validator";
export class PreferencesDto { export class PreferencesDto {
@IsInt()
notifications: number; notifications: number;
@IsInt()
dark_mode: number; dark_mode: number;
@IsInt()
lang_switch: number; lang_switch: number;
@IsInt()
lefty_mode: number; lefty_mode: number;
@IsInt()
employee_list_display: number; employee_list_display: number;
@IsInt()
validation_display: number; validation_display: number;
@IsInt()
timesheet_display: number; timesheet_display: number;
} }

View File

@ -2,14 +2,24 @@ import { PreferencesDto } from "../dtos/preferences.dto";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
import { Preferences } from "@prisma/client"; import { Preferences } from "@prisma/client";
import { Injectable } from "@nestjs/common"; import { Injectable } from "@nestjs/common";
import { Result } from "src/common/errors/result-error.factory";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
@Injectable() @Injectable()
export class PreferencesService { export class PreferencesService {
constructor( private readonly prisma: PrismaService ){} constructor(
private readonly prisma: PrismaService,
private readonly emailResolver: EmailToIdResolver,
async updatePreferences(user_id: number, dto: PreferencesDto ): Promise<Preferences> { ) { }
return this.prisma.preferences.update({
where: { id: user_id }, async updatePreferences(email: string, dto: PreferencesDto): Promise<Result<Preferences, string>> {
const user_id = await this.emailResolver.resolveUserIdWithEmail(email);
if (!user_id.success) return { success: false, error: user_id.error }
return {
success: true,
data: await this.prisma.preferences.update({
where: { user_id: user_id.data },
data: { data: {
notifications: dto.notifications, notifications: dto.notifications,
dark_mode: dto.dark_mode, dark_mode: dto.dark_mode,
@ -20,6 +30,7 @@ export class PreferencesService {
timesheet_display: dto.timesheet_display, timesheet_display: dto.timesheet_display,
}, },
include: { user: true }, include: { user: true },
}); })
}
} }
} }

View File

@ -1,35 +1,25 @@
import { BadRequestException, Injectable, Logger } from "@nestjs/common"; import { Injectable } from "@nestjs/common";
import { Result } from "src/common/errors/result-error.factory";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
@Injectable() @Injectable()
export class MileageService { export class MileageService {
private readonly logger = new Logger(MileageService.name);
constructor(private readonly prisma: PrismaService) {} constructor(private readonly prisma: PrismaService) { }
public async calculateReimbursement(amount: number, bank_code_id: number): Promise<number> { public async calculateReimbursement(amount: number, bank_code_id: number): Promise<Result<number, string>> {
if(amount < 0) { if (amount < 0) return { success: false, error: 'The amount must be higher than 0' };
throw new BadRequestException(`The amount most be higher than 0`);
}
//fetch modifier //fetch modifier
const bank_code = await this.prisma.bankCodes.findUnique({ const bank_code = await this.prisma.bankCodes.findUnique({
where: { id: bank_code_id }, where: { id: bank_code_id },
select: { modifier: true, type: true }, select: { modifier: true, type: true },
}); });
if (!bank_code) return { success: false, error: `bank_code ${bank_code_id} not found` }
if(!bank_code) {
throw new BadRequestException(`bank_code ${bank_code_id} not found`);
}
if(bank_code.type !== 'mileage') {
this.logger.warn(`bank_code ${bank_code_id} of type ${bank_code.type} is used for mileage`)
}
//calculate total amount to reimburs //calculate total amount to reimburs
const reimboursement = amount * bank_code.modifier; const reimboursement = amount * bank_code.modifier;
const result = parseFloat(reimboursement.toFixed(2)); const result = parseFloat(reimboursement.toFixed(2));
this.logger.debug(`calculateReimbursement -> amount= ${amount}, modifier= ${bank_code.modifier}, total= ${result}`); return { success: true, data: result };
return result;
} }
} }

View File

@ -3,19 +3,20 @@ import { Prisma, PrismaClient } from '@prisma/client';
import { getWeekStart, getWeekEnd, computeHours } from 'src/common/utils/date-utils'; import { getWeekStart, getWeekEnd, computeHours } from 'src/common/utils/date-utils';
import { PrismaService } from 'src/prisma/prisma.service'; import { PrismaService } from 'src/prisma/prisma.service';
import { DAILY_LIMIT_HOURS, WEEKLY_LIMIT_HOURS } from 'src/common/utils/constants.utils'; import { DAILY_LIMIT_HOURS, WEEKLY_LIMIT_HOURS } from 'src/common/utils/constants.utils';
import { Result } from 'src/common/errors/result-error.factory';
type Tx = Prisma.TransactionClient | PrismaClient; type Tx = Prisma.TransactionClient | PrismaClient;
type WeekOvertimeSummary = { type WeekOvertimeSummary = {
week_start:string; week_start: string;
week_end: string; week_end: string;
week_total_hours: number; week_total_hours: number;
weekly_overtime: number; weekly_overtime: number;
daily_overtime_kept: number; daily_overtime_kept: number;
total_overtime: number; total_overtime: number;
breakdown: Array<{ breakdown: Array<{
date:string; date: string;
day_hours: number; day_hours: number;
day_overtime: number; day_overtime: number;
daily_kept: number; daily_kept: number;
@ -26,13 +27,11 @@ type WeekOvertimeSummary = {
@Injectable() @Injectable()
export class OvertimeService { export class OvertimeService {
private logger = new Logger(OvertimeService.name); private INCLUDED_TYPES = ['EMERGENCY', 'EVENING', 'OVERTIME', 'REGULAR'] as const; // included types for weekly overtime calculation
private INCLUDED_TYPES = ['EMERGENCY', 'EVENING','OVERTIME','REGULAR'] as const; // included types for weekly overtime calculation constructor(private prisma: PrismaService) { }
constructor(private prisma: PrismaService) {} async getWeekOvertimeSummary(timesheet_id: number, date: Date, tx?: Tx): Promise<Result<WeekOvertimeSummary, string>> {
async getWeekOvertimeSummary( timesheet_id: number, date: Date, tx?: Tx ): Promise<WeekOvertimeSummary>{
const db = tx ?? this.prisma; const db = tx ?? this.prisma;
const week_start = getWeekStart(date); const week_start = getWeekStart(date);
@ -45,23 +44,23 @@ export class OvertimeService {
bank_code: { type: { in: this.INCLUDED_TYPES as unknown as string[] } }, bank_code: { type: { in: this.INCLUDED_TYPES as unknown as string[] } },
}, },
select: { date: true, start_time: true, end_time: true }, select: { date: true, start_time: true, end_time: true },
orderBy: [{date: 'asc'}, {start_time: 'asc'}], orderBy: [{ date: 'asc' }, { start_time: 'asc' }],
}); });
const day_totals = new Map<string, number>(); const day_totals = new Map<string, number>();
for (const shift of shifts){ for (const shift of shifts) {
const key = shift.date.toISOString().slice(0,10); const key = shift.date.toISOString().slice(0, 10);
const hours = computeHours(shift.start_time, shift.end_time, 5); const hours = computeHours(shift.start_time, shift.end_time, 5);
day_totals.set(key, (day_totals.get(key) ?? 0) + hours); day_totals.set(key, (day_totals.get(key) ?? 0) + hours);
} }
const days: string[] = []; const days: string[] = [];
for(let i = 0; i < 7; i++){ for (let i = 0; i < 7; i++) {
const day = new Date(week_start.getTime() + i * 24 * 60 * 60 * 1000); const day = new Date(week_start.getTime() + i * 24 * 60 * 60 * 1000);
days.push(day.toISOString().slice(0,10)); days.push(day.toISOString().slice(0, 10));
} }
const week_total_hours = [ ...day_totals.values()].reduce((a,b) => a + b, 0); const week_total_hours = [...day_totals.values()].reduce((a, b) => a + b, 0);
const weekly_overtime = Math.max(0, week_total_hours - WEEKLY_LIMIT_HOURS); const weekly_overtime = Math.max(0, week_total_hours - WEEKLY_LIMIT_HOURS);
let running = 0; let running = 0;
@ -88,14 +87,9 @@ export class OvertimeService {
} }
const total_overtime = weekly_overtime + daily_kept_sum; const total_overtime = weekly_overtime + daily_kept_sum;
this.logger.debug(
`[OVERTIME][SUMMARY][ts=${timesheet_id}] week=${week_start.toISOString().slice(0,10)}..${week_end
.toISOString()
.slice(0,10)} week_total=${week_total_hours.toFixed(2)}h weekly=${weekly_overtime.toFixed(
2,
)}h daily_kept=${daily_kept_sum.toFixed(2)}h total=${total_overtime.toFixed(2)}h`,
);
return { return {
success: true,
data: {
week_start: week_start.toISOString().slice(0, 10), week_start: week_start.toISOString().slice(0, 10),
week_end: week_end.toISOString().slice(0, 10), week_end: week_end.toISOString().slice(0, 10),
week_total_hours, week_total_hours,
@ -103,6 +97,7 @@ export class OvertimeService {
daily_overtime_kept: daily_kept_sum, daily_overtime_kept: daily_kept_sum,
total_overtime, total_overtime,
breakdown, breakdown,
}
}; };
} }
} }

View File

@ -1,12 +1,11 @@
import { getYearStart, roundToQuarterHour } from "src/common/utils/date-utils"; import { getYearStart, roundToQuarterHour } from "src/common/utils/date-utils";
import { Injectable, Logger } from "@nestjs/common"; import { Injectable, Logger } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
import { Result } from "src/common/errors/result-error.factory";
@Injectable() @Injectable()
export class SickLeaveService { export class SickLeaveService {
constructor(private readonly prisma: PrismaService) {} constructor(private readonly prisma: PrismaService) { }
private readonly logger = new Logger(SickLeaveService.name);
//switch employeeId for email //switch employeeId for email
async calculateSickLeavePay( async calculateSickLeavePay(
@ -15,9 +14,9 @@ export class SickLeaveService {
days_requested: number, days_requested: number,
hours_per_day: number, hours_per_day: number,
modifier: number, modifier: number,
): Promise<number> { ): Promise<Result<number, string>> {
if (days_requested <= 0 || hours_per_day <= 0 || modifier <= 0) { if (days_requested <= 0 || hours_per_day <= 0 || modifier <= 0) {
return 0; return { success: true, data: 0 };
} }
//sets the year to jan 1st to dec 31st //sets the year to jan 1st to dec 31st
@ -38,13 +37,10 @@ export class SickLeaveService {
shifts.map((shift) => shift.date.toISOString().slice(0, 10)), shifts.map((shift) => shift.date.toISOString().slice(0, 10)),
); );
const days_worked = worked_dates.size; const days_worked = worked_dates.size;
this.logger.debug(
`Sick leave: days worked= ${days_worked} in ${period_start.toDateString()} -> ${period_end.toDateString()}`,
);
//less than 30 worked days returns 0 //less than 30 worked days returns 0
if (days_worked < 30) { if (days_worked < 30) {
return 0; return { success: true, data: 0 };
} }
//default 3 days allowed after 30 worked days //default 3 days allowed after 30 worked days
@ -70,16 +66,9 @@ export class SickLeaveService {
//cap of 10 days //cap of 10 days
if (acquired_days > 10) acquired_days = 10; if (acquired_days > 10) acquired_days = 10;
this.logger.debug(
`Sick leave: threshold Date = ${threshold_date.toDateString()}, bonusMonths = ${months}, acquired Days = ${acquired_days}`,
);
const payable_days = Math.min(acquired_days, days_requested); const payable_days = Math.min(acquired_days, days_requested);
const raw_hours = payable_days * hours_per_day * modifier; const raw_hours = payable_days * hours_per_day * modifier;
const rounded = roundToQuarterHour(raw_hours); const rounded = roundToQuarterHour(raw_hours);
this.logger.debug( return {success:true, data: rounded};
`Sick leave pay: days= ${payable_days}, hoursPerDay= ${hours_per_day}, modifier= ${modifier}, hours= ${rounded}`,
);
return rounded;
} }
} }

View File

@ -1,22 +1,27 @@
import { Injectable, Logger, NotFoundException } from "@nestjs/common"; import { Injectable, Logger, NotFoundException } from "@nestjs/common";
import { Result } from "src/common/errors/result-error.factory";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
@Injectable() @Injectable()
export class VacationService { export class VacationService {
constructor(private readonly prisma: PrismaService) {} constructor(
private readonly logger = new Logger(VacationService.name); private readonly prisma: PrismaService,
private readonly emailResolver: EmailToIdResolver,
) {}
//switch employeeId for email //switch employeeId for email
async calculateVacationPay(employee_id: number, start_date: Date, days_requested: number, modifier: number): Promise<number> { async calculateVacationPay(email: string, start_date: Date, days_requested: number, modifier: number): Promise<Result<number, string>> {
const employee_id = await this.emailResolver.findIdByEmail(email);
if(!employee_id.success) return { success: false, error: employee_id.error}
//fetch hiring date //fetch hiring date
const employee = await this.prisma.employees.findUnique({ const employee = await this.prisma.employees.findUnique({
where: { id: employee_id }, where: { id: employee_id.data },
select: { first_work_day: true }, select: { first_work_day: true },
}); });
if(!employee) { if(!employee) return { success:false, error:`Employee #${employee_id} not found`}
throw new NotFoundException(`Employee #${employee_id} not found`);
}
const hire_date = employee.first_work_day; const hire_date = employee.first_work_day;
//sets "year" to may 1st to april 30th //sets "year" to may 1st to april 30th
@ -26,8 +31,6 @@ export class VacationService {
const period_start = new Date(year_of_request, 4, 1); //may = 4 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 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 //steps to reach to get more vacation weeks in years
const checkpoint = [5, 10, 15]; const checkpoint = [5, 10, 15];
const anniversaries = checkpoint.map(years => { const anniversaries = checkpoint.map(years => {
@ -36,8 +39,6 @@ export class VacationService {
return anniversary_date; return anniversary_date;
}).filter(d => d>= period_start && d <= period_end).sort((a,b) => a.getTime() - b.getTime()); }).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]; const boundaries = [period_start, ...anniversaries,period_end];
//calculate prorata per segment //calculate prorata per segment
let total_vacation_days = 0; let total_vacation_days = 0;
@ -67,10 +68,8 @@ export class VacationService {
const raw_hours = payable_days * 8 * modifier; const raw_hours = payable_days * 8 * modifier;
const rounded_hours = Math.round(raw_hours * 4) / 4; 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; return {success:true, data:rounded_hours};
} }