targo-backend/src/modules/business-logics/services/overtime.service.ts
2025-08-01 16:17:58 -04:00

83 lines
3.2 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../../../prisma/prisma.service';
@Injectable()
export class OvertimeService {
private logger = new Logger(OvertimeService.name);
private dailyMax = 8; // maximum for regular hours per day
private weeklyMax = 40; //maximum for regular hours per week
constructor(private prisma: PrismaService) {}
// calculate decimal hours rounded to nearest 5 min
computedHours(start: Date, end: Date): number {
const durationMs = end.getTime() - start.getTime();
const totalMinutes = durationMs / 60000;
//rounded to 5 min
const rounded = Math.round(totalMinutes / 5) * 5;
const hours = rounded / 60;
this.logger.debug(`computedHours: raw=${totalMinutes.toFixed(1)}min rounded = ${rounded}min (${hours.toFixed(2)}h)`);
return hours;
}
//calculate Daily overtime
getDailyOvertimeHours(start: Date, end: Date): number {
const hours = this.computedHours(start, end);
const overtime = Math.max(0, hours - this.dailyMax);
this.logger.debug(`getDailyOvertimeHours : ${overtime.toFixed(2)}h (threshold ${this.dailyMax})`);
return overtime;
}
//sets first day of the week to be sunday
private getWeekStart(date:Date): Date {
const d = new Date(date);
const day = d.getDay(); // return sunday = 0, monday = 1, etc
d.setDate(d.getDate() - day);
d.setHours(0,0,0,0,); // puts start of the week at sunday morning at 00:00
return d;
}
//sets last day of the week to be saturday
private getWeekEnd(startDate:Date): Date {
const d = new Date(startDate);
d.setDate(d.getDate() +6); //sets last day to be saturday
d.setHours(23,59,59,999); //puts end of the week at saturday night at 00:00 minus 1ms
return d;
}
//calculate Weekly overtime
async getWeeklyOvertimeHours(employeeId: number, refDate: Date): Promise<number> {
const weekStart = this.getWeekStart(refDate);
const weekEnd = this.getWeekEnd(weekStart);
//fetches all shifts containing hours
const shifts = await this.prisma.shifts.findMany({
where: { timesheet: { employee_id: employeeId, shift: {
every: {date: { gte: weekStart, lte: weekEnd } }
},
},
},
select: { start_time: true, end_time: true },
});
//calculate total hours of those shifts minus weekly Max to find total overtime hours
const total = shifts.map(shift => this.computedHours(shift.start_time, shift.end_time))
.reduce((sum, hours)=> sum+hours, 0);
const overtime = Math.max(0, total - this.weeklyMax);
this.logger.debug(`weekly total = ${total.toFixed(2)}h, weekly Overtime= ${overtime.toFixed(2)}h`);
return overtime;
}
//apply modifier to overtime hours
calculateOvertimePay(overtimeHours: number, modifier: number): number {
const pay = overtimeHours * modifier;
this.logger.debug(`Overtime payable hours = ${pay.toFixed(2)} (hours ${overtimeHours}, modifier ${modifier})`);
return pay;
}
}