249 lines
13 KiB
TypeScript
249 lines
13 KiB
TypeScript
// import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
|
// import { LeaveApprovalStatus, LeaveTypes } from "@prisma/client";
|
|
// import { roundToQuarterHour } from "src/common/utils/date-utils";
|
|
// import { UpsertLeaveRequestDto, UpsertResult } from "../dtos/upsert-leave-request.dto";
|
|
// import { LeaveRequestViewDto } from "../dtos/leave-request-view.dto";
|
|
// import { mapRowToView } from "../mappers/leave-requests.mapper";
|
|
// import { leaveRequestsSelect } from "../utils/leave-requests.select";
|
|
// import { HolidayLeaveRequestsService } from "./holiday-leave-requests.service";
|
|
// import { SickLeaveRequestsService } from "./sick-leave-requests.service";
|
|
// import { VacationLeaveRequestsService } from "./vacation-leave-requests.service";
|
|
// import { HolidayService } from "src/modules/business-logics/services/holiday.service";
|
|
// import { SickLeaveService } from "src/modules/business-logics/services/sick-leave.service";
|
|
// import { VacationService } from "src/modules/business-logics/services/vacation.service";
|
|
// import { PrismaService } from "src/prisma/prisma.service";
|
|
// import { LeaveRequestsUtils } from "../utils/leave-request.util";
|
|
// import { normalizeDates, toDateOnly, toISODateKey } from "src/modules/shared/helpers/date-time.helpers";
|
|
// import { EmailToIdResolver } from "src/modules/shared/utils/resolve-email-id.utils";
|
|
// import { BankCodesResolver } from "src/modules/shared/utils/resolve-bank-type-id.utils";
|
|
|
|
// @Injectable()
|
|
// export class LeaveRequestsService {
|
|
// constructor(
|
|
// private readonly prisma: PrismaService,
|
|
// private readonly holidayLeaveService: HolidayLeaveRequestsService,
|
|
// private readonly holidayService: HolidayService,
|
|
// private readonly sickLogic: SickLeaveService,
|
|
// private readonly sickLeaveService: SickLeaveRequestsService,
|
|
// private readonly vacationLeaveService: VacationLeaveRequestsService,
|
|
// private readonly vacationLogic: VacationService,
|
|
// private readonly leaveUtils: LeaveRequestsUtils,
|
|
// private readonly emailResolver: EmailToIdResolver,
|
|
// private readonly typeResolver: BankCodesResolver,
|
|
// ) {}
|
|
|
|
// //handle distribution to the right service according to the selected type and action
|
|
// async handle(dto: UpsertLeaveRequestDto): Promise<UpsertResult> {
|
|
// switch (dto.type) {
|
|
// case LeaveTypes.HOLIDAY:
|
|
// if( dto.action === 'create'){
|
|
// return this.holidayLeaveService.create(dto);
|
|
// } else if (dto.action === 'update') {
|
|
// return this.update(dto, LeaveTypes.HOLIDAY);
|
|
// } else if (dto.action === 'delete'){
|
|
// return this.delete(dto, LeaveTypes.HOLIDAY);
|
|
// }
|
|
// case LeaveTypes.VACATION:
|
|
// if( dto.action === 'create'){
|
|
// return this.vacationLeaveService.create(dto);
|
|
// } else if (dto.action === 'update') {
|
|
// return this.update(dto, LeaveTypes.VACATION);
|
|
// } else if (dto.action === 'delete'){
|
|
// return this.delete(dto, LeaveTypes.VACATION);
|
|
// }
|
|
// case LeaveTypes.SICK:
|
|
// if( dto.action === 'create'){
|
|
// return this.sickLeaveService.create(dto);
|
|
// } else if (dto.action === 'update') {
|
|
// return this.update(dto, LeaveTypes.SICK);
|
|
// } else if (dto.action === 'delete'){
|
|
// return this.delete(dto, LeaveTypes.SICK);
|
|
// }
|
|
// default:
|
|
// throw new BadRequestException(`Unsupported leave type: ${dto.type} or action: ${dto.action}`);
|
|
// }
|
|
// }
|
|
|
|
// async delete(dto: UpsertLeaveRequestDto, type: LeaveTypes): Promise<UpsertResult> {
|
|
// const email = dto.email.trim();
|
|
// const dates = normalizeDates(dto.dates);
|
|
// const employee_id = await this.emailResolver.findIdByEmail(email);
|
|
// if (!dates.length) throw new BadRequestException("Dates array must not be empty");
|
|
|
|
// const rows = await this.prisma.leaveRequests.findMany({
|
|
// where: {
|
|
// employee_id: employee_id,
|
|
// leave_type: type,
|
|
// date: { in: dates.map((d) => toDateOnly(d)) },
|
|
// },
|
|
// select: leaveRequestsSelect,
|
|
// });
|
|
|
|
// if (rows.length !== dates.length) {
|
|
// const missing = dates.filter((isoDate) => !rows.some((row) => toISODateKey(row.date) === isoDate));
|
|
// throw new NotFoundException(`No Leave request found for: ${missing.join(", ")}`);
|
|
// }
|
|
|
|
// for (const row of rows) {
|
|
// if (row.approval_status === LeaveApprovalStatus.APPROVED) {
|
|
// const iso = toISODateKey(row.date);
|
|
// await this.leaveUtils.removeShift(email, employee_id, iso, type);
|
|
// }
|
|
// }
|
|
|
|
// await this.prisma.leaveRequests.deleteMany({
|
|
// where: { id: { in: rows.map((row) => row.id) } },
|
|
// });
|
|
|
|
// const deleted = rows.map((row) => ({ ...mapRowToView(row), action: "delete" as const }));
|
|
// return { action: "delete", leave_requests: deleted };
|
|
// }
|
|
|
|
// async update(dto: UpsertLeaveRequestDto, type: LeaveTypes): Promise<UpsertResult> {
|
|
// const email = dto.email.trim();
|
|
// const employee_id = await this.emailResolver.findIdByEmail(email);
|
|
// const bank_code = await this.typeResolver.findByType(type);
|
|
// if(!bank_code) throw new NotFoundException(`bank_code not found`);
|
|
// const modifier = Number(bank_code.modifier ?? 1);
|
|
// const dates = normalizeDates(dto.dates);
|
|
// if (!dates.length) {
|
|
// throw new BadRequestException("Dates array must not be empty");
|
|
// }
|
|
|
|
// const entries = await Promise.all(
|
|
// dates.map(async (iso_date) => {
|
|
// const date = toDateOnly(iso_date);
|
|
// const existing = await this.prisma.leaveRequests.findUnique({
|
|
// where: {
|
|
// leave_per_employee_date: {
|
|
// employee_id: employee_id,
|
|
// leave_type: type,
|
|
// date,
|
|
// },
|
|
// },
|
|
// select: leaveRequestsSelect,
|
|
// });
|
|
// if (!existing) throw new NotFoundException(`No Leave request found for ${iso_date}`);
|
|
// return { iso_date, date, existing };
|
|
// }),
|
|
// );
|
|
|
|
// const updated: LeaveRequestViewDto[] = [];
|
|
|
|
// if (type === LeaveTypes.SICK) {
|
|
// const firstExisting = entries[0].existing;
|
|
// const fallbackRequested =
|
|
// firstExisting.requested_hours !== null && firstExisting.requested_hours !== undefined
|
|
// ? Number(firstExisting.requested_hours)
|
|
// : 8;
|
|
// const requested_hours_per_day = dto.requested_hours ?? fallbackRequested;
|
|
// const reference_date = entries.reduce(
|
|
// (latest, entry) => (entry.date > latest ? entry.date : latest),
|
|
// entries[0].date,
|
|
// );
|
|
// const total_payable_hours = await this.sickLogic.calculateSickLeavePay(
|
|
// employee_id,
|
|
// reference_date,
|
|
// entries.length,
|
|
// requested_hours_per_day,
|
|
// modifier,
|
|
// );
|
|
// let remaining_payable_hours = roundToQuarterHour(Math.max(0, total_payable_hours));
|
|
// const daily_payable_cap = roundToQuarterHour(requested_hours_per_day * modifier);
|
|
|
|
// for (const { iso_date, existing } of entries) {
|
|
// const previous_status = existing.approval_status;
|
|
// const payable = Math.min(remaining_payable_hours, daily_payable_cap);
|
|
// const payable_rounded = roundToQuarterHour(Math.max(0, payable));
|
|
// remaining_payable_hours = roundToQuarterHour(
|
|
// Math.max(0, remaining_payable_hours - payable_rounded),
|
|
// );
|
|
|
|
// const row = await this.prisma.leaveRequests.update({
|
|
// where: { id: existing.id },
|
|
// data: {
|
|
// comment: dto.comment ?? existing.comment,
|
|
// requested_hours: requested_hours_per_day,
|
|
// payable_hours: payable_rounded,
|
|
// bank_code_id: bank_code.id,
|
|
// approval_status: dto.approval_status ?? existing.approval_status,
|
|
// },
|
|
// select: leaveRequestsSelect,
|
|
// });
|
|
|
|
// const was_approved = previous_status === LeaveApprovalStatus.APPROVED;
|
|
// const is_approved = row.approval_status === LeaveApprovalStatus.APPROVED;
|
|
// const hours = Number(row.payable_hours ?? row.requested_hours ?? 0);
|
|
|
|
// if (!was_approved && is_approved) {
|
|
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours, type, row.comment);
|
|
// } else if (was_approved && !is_approved) {
|
|
// await this.leaveUtils.removeShift(email, employee_id, iso_date, type);
|
|
// } else if (was_approved && is_approved) {
|
|
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours, type, row.comment);
|
|
// }
|
|
// updated.push({ ...mapRowToView(row), action: "update" });
|
|
// }
|
|
// return { action: "update", leave_requests: updated };
|
|
// }
|
|
|
|
// for (const { iso_date, date, existing } of entries) {
|
|
// const previous_status = existing.approval_status;
|
|
// const fallbackRequested =
|
|
// existing.requested_hours !== null && existing.requested_hours !== undefined
|
|
// ? Number(existing.requested_hours)
|
|
// : 8;
|
|
// const requested_hours = dto.requested_hours ?? fallbackRequested;
|
|
|
|
// let payable: number;
|
|
// switch (type) {
|
|
// case LeaveTypes.HOLIDAY:
|
|
// payable = await this.holidayService.calculateHolidayPay(email, date, modifier);
|
|
// break;
|
|
// case LeaveTypes.VACATION: {
|
|
// const days_requested = requested_hours / 8;
|
|
// payable = await this.vacationLogic.calculateVacationPay(
|
|
// employee_id,
|
|
// date,
|
|
// Math.max(0, days_requested),
|
|
// modifier,
|
|
// );
|
|
// break;
|
|
// }
|
|
// default:
|
|
// payable = existing.payable_hours !== null && existing.payable_hours !== undefined
|
|
// ? Number(existing.payable_hours)
|
|
// : requested_hours;
|
|
// }
|
|
|
|
// const row = await this.prisma.leaveRequests.update({
|
|
// where: { id: existing.id },
|
|
// data: {
|
|
// requested_hours,
|
|
// comment: dto.comment ?? existing.comment,
|
|
// payable_hours: payable,
|
|
// bank_code_id: bank_code.id,
|
|
// approval_status: dto.approval_status ?? existing.approval_status,
|
|
// },
|
|
// select: leaveRequestsSelect,
|
|
// });
|
|
|
|
// const was_approved = previous_status === LeaveApprovalStatus.APPROVED;
|
|
// const is_approved = row.approval_status === LeaveApprovalStatus.APPROVED;
|
|
// const hours = Number(row.payable_hours ?? row.requested_hours ?? 0);
|
|
|
|
// if (!was_approved && is_approved) {
|
|
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours, type, row.comment);
|
|
// } else if (was_approved && !is_approved) {
|
|
// await this.leaveUtils.removeShift(email, employee_id, iso_date, type);
|
|
// } else if (was_approved && is_approved) {
|
|
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours, type, row.comment);
|
|
// }
|
|
// updated.push({ ...mapRowToView(row), action: "update" });
|
|
// }
|
|
// return { action: "update", leave_requests: updated };
|
|
// }
|
|
// }
|
|
|
|
|