83 lines
3.2 KiB
TypeScript
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;
|
|
}
|
|
|
|
}
|