diff --git a/src/business-logic/holiday.service.ts b/src/business-logic/holiday.service.ts index e69de29..235cc8e 100644 --- a/src/business-logic/holiday.service.ts +++ b/src/business-logic/holiday.service.ts @@ -0,0 +1,56 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { PrismaService } from "src/prisma/prisma.service"; + +@Injectable() +export class HolidayService { + private readonly logger = new Logger(HolidayService.name); + + constructor(private readonly prisma: PrismaService) {} + + //return the sunday of the current week that includes the holiday + private getWeekStart(date: Date): Date { + const day = new Date(date); + const offset = day.getDay(); + day.setDate(day.getDate() - offset); + day.setHours(0,0,0,0); + return day; + } + + //rounds minutes to 5s + private computeHours(start: Date, end: Date): number { + const durationMS = end.getTime() - start.getTime(); + const totalMinutes = durationMS / 60000; + const rounded = Math.round(totalMinutes / 5) * 5; + return rounded / 60; + } + + private async computeHoursPrevious4Weeks(employeeId: number, holidayDate: Date): Promise { + //sets the end of the window to 1ms before the week with the holiday + const holidayWeekStart = this.getWeekStart(holidayDate); + const windowEnd = new Date(holidayWeekStart.getTime() - 1); + //sets the start of the window to 28 days ( 4 completed weeks ) before the week with the holiday + const windowStart = new Date(windowEnd.getTime() - 28 * 24 * 60 * 60000 + 1 ) + + const validCodes = ['G1', 'G45', 'G56', 'G104', 'G105', 'G700']; + //fetches all shift of the employee in said window ( 4 completed weeks ) + const shifts = await this.prisma.shifts.findMany({ + where: { timesheet: { employee_id: employeeId } , + date: { gte: windowStart, lte: windowEnd }, + bank_code: { bank_code: { in: validCodes } }, + }, + select: { date: true, start_time: true, end_time: true }, + }); + + const totalHours = shifts.map(s => this.computeHours(s.start_time, s.end_time)).reduce((sum, h)=> sum + h, 0); + const dailyHours = totalHours / 20; + + return dailyHours; + } + + async calculateHolidayPay( employeeId: number, holidayDate: Date, modifier: number): Promise { + const hours = await this. computeHoursPrevious4Weeks(employeeId, holidayDate); + const dailyRate = Math.min(hours, 8); + this.logger.debug(`Holiday pay calculation: hours=${hours.toFixed(2)}`); + return dailyRate * modifier; + } +} \ No newline at end of file diff --git a/src/modules/leave-requests/leave-requests.module.ts b/src/modules/leave-requests/leave-requests.module.ts index 62b994f..27394bf 100644 --- a/src/modules/leave-requests/leave-requests.module.ts +++ b/src/modules/leave-requests/leave-requests.module.ts @@ -2,10 +2,15 @@ import { PrismaService } from "src/prisma/prisma.service"; import { LeaveRequestController } from "./controllers/leave-requests.controller"; import { LeaveRequestsService } from "./services/leave-requests.service"; import { Module } from "@nestjs/common"; +import { HolidayService } from "src/business-logic/holiday.service"; @Module({ controllers: [LeaveRequestController], - providers: [ LeaveRequestsService, PrismaService], + providers: [ + LeaveRequestsService, + PrismaService, + HolidayService, + ], exports: [ LeaveRequestsService], }) diff --git a/src/modules/leave-requests/services/leave-requests.service.ts b/src/modules/leave-requests/services/leave-requests.service.ts index 476a487..4e54e49 100644 --- a/src/modules/leave-requests/services/leave-requests.service.ts +++ b/src/modules/leave-requests/services/leave-requests.service.ts @@ -3,87 +3,78 @@ import { PrismaService } from "src/prisma/prisma.service"; import { CreateLeaveRequestsDto } from "../dtos/create-leave-requests.dto"; import { LeaveRequests, LeaveRequestsArchive } from "@prisma/client"; import { UpdateLeaveRequestsDto } from "../dtos/update-leave-requests.dto"; +import { HolidayService } from "src/business-logic/holiday.service"; @Injectable() export class LeaveRequestsService { - constructor(private readonly prisma: PrismaService) {} + constructor( + private readonly prisma: PrismaService, + private readonly holidayService: HolidayService, + ) {} async create(dto: CreateLeaveRequestsDto): Promise { - const { - employee_id, - bank_code_id, - leave_type, - start_date_time, - end_date_time, - comment, - approval_status, - } = dto; + const { employee_id, bank_code_id, leave_type, start_date_time, + end_date_time, comment, approval_status } = dto; return this.prisma.leaveRequests.create({ - data: { - employee_id, - bank_code_id, - leave_type, - start_date_time, - end_date_time, - comment, - approval_status: approval_status ?? undefined, - }, - include: { - employee: { - include: { - user: true - }, - }, + data: { employee_id, bank_code_id, leave_type, start_date_time, + end_date_time, comment, approval_status: approval_status ?? undefined }, + include: { employee: { include: { user: true } } }, }); } - findAll(): Promise { - return this.prisma.leaveRequests.findMany({ - include: { - employee: { - include: { - user: true - }, - }, - bank_code: true, + async findAll(): Promise { + const list = await this.prisma.leaveRequests.findMany({ + include: { employee: { include: { user: true } }, + bank_code: true, }, }); + + return Promise.all( + list.map(async request => { + if(request.bank_code?.type === 'holiday') { + const cost = await this.holidayService.calculateHolidayPay( + request.employee_id, + request.start_date_time, + request.bank_code.modifier + ); + return { ...request, cost }; + } + return request; + }), + ); } - async findOne(id:number): Promise { - const req = await this.prisma.leaveRequests.findUnique({ + async findOne(id:number): Promise { + const request = await this.prisma.leaveRequests.findUnique({ where: { id }, - include: { - employee: { - include: { - user: true - }, - }, - bank_code: true, + include: { employee: { include: { user: true } }, + bank_code: true, }, }); - if(!req) { + if(!request) { throw new NotFoundException(`LeaveRequest #${id} not found`); } - return req; - } + //search for leave type. if holiday + if (request.bank_code?.type === 'holiday') { + const cost = await this.holidayService.calculateHolidayPay( + request.employee_id, + request.start_date_time, + request.bank_code.modifier, + ); + return { ...request, cost }; + } + return request; + } async update( id: number, dto: UpdateLeaveRequestsDto, ): Promise { await this.findOne(id); - const { - employee_id, - leave_type, - start_date_time, - end_date_time, - comment, - approval_status, - } = dto; + const { employee_id, leave_type, start_date_time, end_date_time, comment, approval_status } = dto; return this.prisma.leaveRequests.update({ where: { id }, data: { @@ -94,13 +85,7 @@ export class LeaveRequestsService { ...(comment !== undefined && { comment }), ...(approval_status == undefined && { approval_status }), }, - include: { - employee: { - include: { - user:true - }, - }, - }, + include: { employee: { include: { user:true } } }, }); }