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 { 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; } }