refactor(sick-leave): remake methods to calculate and update sick leave available
This commit is contained in:
parent
17f06e7867
commit
53ec64ba1e
|
|
@ -55,6 +55,7 @@ model Employees {
|
||||||
user Users @relation("UserEmployee", fields: [user_id], references: [id])
|
user Users @relation("UserEmployee", fields: [user_id], references: [id])
|
||||||
leave_request LeaveRequests[] @relation("LeaveRequestEmployee")
|
leave_request LeaveRequests[] @relation("LeaveRequestEmployee")
|
||||||
timesheet Timesheets[] @relation("TimesheetEmployee")
|
timesheet Timesheets[] @relation("TimesheetEmployee")
|
||||||
|
paid_time_off PaidTimeOff? @relation("EmployeePaidTimeOff")
|
||||||
|
|
||||||
@@map("employees")
|
@@map("employees")
|
||||||
}
|
}
|
||||||
|
|
@ -321,6 +322,18 @@ model Preferences {
|
||||||
@@map("preferences")
|
@@map("preferences")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model PaidTimeOff {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
employee_id Int @unique
|
||||||
|
vacation_hours Int @default(0)
|
||||||
|
sick_hours Int @default(0)
|
||||||
|
last_updated DateTime @db.Date
|
||||||
|
|
||||||
|
employee Employees @relation("EmployeePaidTimeOff", fields: [employee_id], references: [id])
|
||||||
|
|
||||||
|
@@map("paid_time_off")
|
||||||
|
}
|
||||||
|
|
||||||
view PayPeriods {
|
view PayPeriods {
|
||||||
pay_year Int
|
pay_year Int
|
||||||
pay_period_no Int
|
pay_period_no Int
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,115 @@
|
||||||
import { Injectable, Logger } from "@nestjs/common";
|
import { Injectable, Logger } from "@nestjs/common";
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
import { PrismaService } from "src/prisma/prisma.service";
|
||||||
import { Result } from "src/common/errors/result-error.factory";
|
import { Result } from "src/common/errors/result-error.factory";
|
||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SickLeaveService {
|
export class SickLeaveService {
|
||||||
constructor(private readonly prisma: PrismaService) { }
|
constructor(private readonly prisma: PrismaService) { }
|
||||||
|
|
||||||
//switch employeeId for email
|
async updateSickLeaveHours(employee_id: number): Promise<Result<boolean, string>> {
|
||||||
|
const THIRTY_DAYS = 1000 * 60 * 60 * 24 * 30;
|
||||||
|
const FOURTEEN_DAYS = 1000 * 60 * 60 * 24 * 14;
|
||||||
|
const today = new Date();
|
||||||
|
|
||||||
|
// get employee info
|
||||||
|
const employee = await this.prisma.employees.findUnique({
|
||||||
|
where: { id: employee_id },
|
||||||
|
select: {
|
||||||
|
first_work_day: true,
|
||||||
|
last_work_day: true,
|
||||||
|
id: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!employee) return { success: false, error: 'EMPLOYEE_NOT_FOUND' };
|
||||||
|
|
||||||
|
// check if employee has been inactive for more than 2 weeks
|
||||||
|
if (employee.last_work_day) {
|
||||||
|
if (today.getTime() - employee.last_work_day.getTime() >= FOURTEEN_DAYS) {
|
||||||
|
return { success: false, error: "EMPLOYEE_NOT_ACTIVE" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get employee's PTO info, or create new details if not yet existing
|
||||||
|
let pto_details: Prisma.Result<typeof this.prisma.paidTimeOff, Prisma.PaidTimeOffDefaultArgs, 'findUnique' | 'create'>;
|
||||||
|
|
||||||
|
pto_details = await this.prisma.paidTimeOff.findUnique({
|
||||||
|
where: { employee_id: employee.id },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!pto_details) {
|
||||||
|
const new_pto_entry = await this.createNewPTORow(employee.id, today);
|
||||||
|
|
||||||
|
if (!new_pto_entry.success) return { success: false, error: "FAILED_TO_CREATE_EMPLOYEE_PTO" };
|
||||||
|
|
||||||
|
pto_details = new_pto_entry.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if employee has gotten his 3 days from completing his 30-day qualifying period from hiring date
|
||||||
|
if (today.getTime() - employee.first_work_day.getTime() >= THIRTY_DAYS && employee.first_work_day.toISOString() === pto_details?.last_updated?.toISOString()) {
|
||||||
|
const updated_pto = await this.addHoursToPTO(3 * 8, employee.id, today);
|
||||||
|
|
||||||
|
if (!updated_pto.success) return { success: updated_pto.success, error: updated_pto.error }
|
||||||
|
}
|
||||||
|
|
||||||
|
const year_difference = today.getFullYear() - (pto_details!.last_updated.getFullYear() ?? today.getFullYear());
|
||||||
|
const months_since_last_update = (today.getMonth() + year_difference * 12) - pto_details!.last_updated.getMonth();
|
||||||
|
|
||||||
|
if (months_since_last_update > 0) {
|
||||||
|
const updated_pto = await this.addHoursToPTO(months_since_last_update * 8, employee.id, today);
|
||||||
|
|
||||||
|
if (updated_pto.success) {
|
||||||
|
return {success: true, data: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: false, error: 'UNKNOWN_PTO_UPDATE_ERROR' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new PTO row
|
||||||
|
async createNewPTORow(employee_id: number, today: Date): Promise<Result<Prisma.Result<typeof this.prisma.paidTimeOff, Prisma.PaidTimeOffDefaultArgs, 'findUnique' | 'create'>, string>> {
|
||||||
|
try {
|
||||||
|
const new_pto_entry = await this.prisma.paidTimeOff.create({
|
||||||
|
data: {
|
||||||
|
employee_id: employee_id,
|
||||||
|
last_updated: today,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
employee_id: true,
|
||||||
|
sick_hours: true,
|
||||||
|
vacation_hours: true,
|
||||||
|
last_updated: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { success: true, data: new_pto_entry };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add n number of sick PTO hours to employee PTO
|
||||||
|
async addHoursToPTO(sick_hours: number, employee_id: number, last_updated: Date) {
|
||||||
|
try {
|
||||||
|
const update_pto = await this.prisma.paidTimeOff.update({
|
||||||
|
where: {
|
||||||
|
employee_id,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
sick_hours,
|
||||||
|
last_updated,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { success: true, data: update_pto };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// switch employeeId for email
|
||||||
async calculateSickLeavePay(
|
async calculateSickLeavePay(
|
||||||
employee_id: number,
|
employee_id: number,
|
||||||
reference_date: Date,
|
reference_date: Date,
|
||||||
|
|
@ -69,6 +172,6 @@ export class SickLeaveService {
|
||||||
const payable_days = Math.min(acquired_days, days_requested);
|
const payable_days = Math.min(acquired_days, days_requested);
|
||||||
const raw_hours = payable_days * hours_per_day * modifier;
|
const raw_hours = payable_days * hours_per_day * modifier;
|
||||||
const rounded = roundToQuarterHour(raw_hours);
|
const rounded = roundToQuarterHour(raw_hours);
|
||||||
return {success:true, data: rounded};
|
return { success: true, data: rounded };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user