import { Injectable } from "@nestjs/common"; import { Result } from "src/common/errors/result-error.factory"; import { computeHours } from "src/common/utils/date-utils"; import { PrismaService } from "src/prisma/prisma.service"; import { BankedHoursService } from "src/time-and-attendance/domains/services/banking-hours.service"; import { SickLeaveService } from "src/time-and-attendance/domains/services/sick-leave.service"; import { VacationService } from "src/time-and-attendance/domains/services/vacation.service"; import { paid_time_off_mapping, paid_time_off_types } from "src/time-and-attendance/paid-time-off/paid-time-off.dto"; @Injectable() export class PaidTimeOFfBankHoursService { constructor( private readonly prisma: PrismaService, private readonly bankingService: BankedHoursService, private readonly vacationService: VacationService, private readonly sickLeaveService: SickLeaveService, ) { } //called during update function of Shifts Module updatePaidTimeOffBankHoursWhenShiftUpdate = async ( start_time: Date, end_time: Date, type: string, employee_id: number, og_start: Date, og_end: Date ): Promise> => { let original_hours = computeHours(og_start, og_end); let ajusted_hours = computeHours(start_time, end_time); if (type === 'BANKING') { original_hours = original_hours * 1.5; ajusted_hours = ajusted_hours * 1.5; } const diff_hours = Math.abs(ajusted_hours - original_hours); if (diff_hours === 0) return { success: true, data: true }; if (!paid_time_off_types.includes(type)) return { success: false, error: 'INVALID_SHIFT_TYPE' }; if (ajusted_hours > original_hours) { const validation = await this.validateAndDeductPaidTimeOff(employee_id, type, diff_hours); if (!validation.success) return { success: false, error: validation.error }; } else { const restoration = await this.restorePaidTimeOffHours(employee_id, type, diff_hours); if (!restoration.success) return { success: false, error: restoration.error }; } return { success: true, data: true }; } validateAndDeductPaidTimeOff = async (employee_id: number, type: string, hours: number): Promise> => { const banking_types: string[] = ['BANKING', 'WITHDRAW_BANKED']; if (banking_types.includes(type)) { return await this.bankingService.manageBankingHours(employee_id, hours, type); } switch (type) { case 'VACATION': { return await this.vacationService.manageVacationHoursBank(employee_id, hours); } case 'SICK': { return await this.sickLeaveService.takeSickLeaveHours(employee_id, hours); } default: return { success: false, error: 'INVALID_PAID_TIME_OFF_TYPE' }; } } restorePaidTimeOffHours = async (employee_id: number, type: string, hours: number): Promise> => { try { const config = paid_time_off_mapping[type]; if (!config) return { success: false, error: 'INVALID_PAID_TIME_OFF_TYPE' } const operation = config.invert_logic ? 'decrement' : 'increment'; await this.prisma.paidTimeOff.update({ where: { employee_id }, data: { [config.field]: { [operation]: hours }, last_updated: new Date(), }, }); return { success: true, data: true }; } catch (error) { return { success: false, error: 'PAID_TIME_OFF_NOT_FOUND' }; } }; //called during delete function of Shifts Module updatePaidTimeoffBankHoursWhenShiftDelete = async (start: Date, end: Date, type: string, employee_id: number) => { let ajusted_hours = computeHours(start, end); if (!paid_time_off_types.includes(type)) return; if (type === 'BANKING') { ajusted_hours = ajusted_hours * 1.5; } const config = paid_time_off_mapping[type]; await this.prisma.paidTimeOff.update({ where: { employee_id }, data: { [config.field]: { [config.operation]: ajusted_hours }, last_updated: new Date(), }, }); } }