feat(banking_hours): added a function to add or take banked_hours

This commit is contained in:
Matthieu Haineault 2026-01-09 08:00:08 -05:00
parent 41efccac17
commit 70575e1772
11 changed files with 319 additions and 137 deletions

View File

@ -1,4 +1,4 @@
import { BankedHoursService } from "./services/banking-hours.service.service"; import { BankedHoursService } from "./services/banking-hours.service";
import { SickLeaveService } from "./services/sick-leave.service"; import { SickLeaveService } from "./services/sick-leave.service";
import { OvertimeService } from "./services/overtime.service"; import { OvertimeService } from "./services/overtime.service";
import { VacationService } from "./services/vacation.service"; import { VacationService } from "./services/vacation.service";

View File

@ -1,64 +0,0 @@
// import { Injectable } from "@nestjs/common";
// import { Result } from "src/common/errors/result-error.factory";
// import { PrismaService } from "src/prisma/prisma.service";
// @Injectable()
// export class BankedHoursService {
// constructor(private readonly prisma: PrismaService) { }
// //manage shifts with bank_code.type BANKING
// bankingHours = async (employee_id: number, hours: number): Promise<Result<number, string>> => {
// if (hours <= 0) return { success: false, error: 'INVALID_BANKING_HOURS' };
// try {
// const result = await this.prisma.$transaction(async (tx) => {
// const employee = await this.prisma.employees.findUnique({
// where: { id: employee_id },
// select: {
// id: true,
// paid_time_off: {
// select: {
// banked_hours: true
// },
// },
// },
// });
// if (!employee) {
// return { success: false, error: 'EMPLOYEE_NOT_FOUND' } as Result<number, string>
// }
// if (!employee.paid_time_off) {
// return { success: false, error: 'VACATION_HOURS_BANK_NOT_FOUND' } as Result<number, string>
// }
// const new_balance = await tx.paidTimeOff.update({
// where: { employee_id: employee.id },
// data: {
// banked_hours: { increment: hours },
// },
// select: {
// banked_hours: true,
// },
// });
// return { success: true, data: new_balance };
// });
// return result;
// } catch (error) {
// return { success: false, error: 'INVALID_BANKING_SHIFT' };
// }
// }
// //manage shifts with bank_code.type WITHDRAW_BANKED
// withdrawBankedHours = async (employee_id: number, asked_hours: number): Promise<Result<number, string>> => {
// if (asked_hours <= 0) return { success: false, error: 'INVALID_WITHDRAW_BANKED' };
// }
// }

View File

@ -0,0 +1,70 @@
import { Injectable } from "@nestjs/common";
import { Result } from "src/common/errors/result-error.factory";
import { PrismaService } from "src/prisma/prisma.service";
@Injectable()
export class BankedHoursService {
constructor(private readonly prisma: PrismaService) { }
//manage shifts with bank_code.type BANKING
manageBankingHours = async (employee_id: number, asked_hours: number, type: string): Promise<Result<number, string>> => {
if (asked_hours <= 0) return { success: false, error: 'INVALID_BANKING_HOURS' };
try {
const result = await this.prisma.$transaction(async (tx) => {
const employee = await this.prisma.employees.findUnique({
where: { id: employee_id },
select: {
id: true,
paid_time_off: {
select: {
banked_hours: true
},
},
},
});
if (!employee) {
return { success: false, error: 'EMPLOYEE_NOT_FOUND' } as Result<number, string>;
}
if (!employee.paid_time_off) {
return { success: false, error: 'BANKING_HOURS_BANK_NOT_FOUND' } as Result<number, string>;
}
const banked_hours = (employee.paid_time_off.banked_hours).toNumber();
if (banked_hours <= 0) {
return { success: false, error: 'EMPTY_BANKED_HOURS' } as Result<number, string>;
}
if (type === 'BANKING') {
const new_balance = await tx.paidTimeOff.update({
where: { employee_id: employee.id },
data: { banked_hours: { increment: asked_hours } },
select: { banked_hours: true },
});
return { success: true, data: (new_balance.banked_hours).toNumber() } as Result<number, string>;
} else if (type === 'WITHDRAW_BANKED') {
if (asked_hours > banked_hours) {
return { success: true, data: banked_hours } as Result<number, string>;
} else {
}
await tx.paidTimeOff.update({
where: { employee_id: employee.id },
data: { banked_hours: { decrement: asked_hours } },
select: { banked_hours: true },
});
return { success: true, data: asked_hours } as Result<number, string>;
} else {
return { success: false, error: 'INVALID_SHIFT_TYPE' } as Result<number, string>;
}
});
return result;
} catch (error) {
return { success: false, error: 'INVALID_BANKING_SHIFT' };
}
}
}

View File

@ -61,7 +61,7 @@ export class SickLeaveService {
const updated_pto = await this.addHoursToPTO(months_since_last_update * 8, employee.id, today); const updated_pto = await this.addHoursToPTO(months_since_last_update * 8, employee.id, today);
if (updated_pto.success) { if (updated_pto.success) {
return {success: true, data: true} return { success: true, data: true }
} }
} }
@ -111,68 +111,114 @@ export class SickLeaveService {
} }
}; };
// switch employeeId for email takeSickLeaveHours = async (employee_id: number, asked_hours: number): Promise<Result<number, string>> => {
async calculateSickLeavePay( if (asked_hours <= 0) return { success: false, error: 'INVALID_BANKING_HOURS' };
employee_id: number, console.log('also got here')
reference_date: Date, try {
days_requested: number, const result = await this.prisma.$transaction(async (tx) => {
hours_per_day: number, const employee = await this.prisma.employees.findUnique({
modifier: number, where: { id: employee_id },
): Promise<Result<number, string>> { select: {
if (days_requested <= 0 || hours_per_day <= 0 || modifier <= 0) { id: true,
return { success: true, data: 0 }; paid_time_off: {
} select: {
banked_hours: true
//sets the year to jan 1st to dec 31st },
const period_start = getYearStart(reference_date); },
const period_end = reference_date;
//fetches all shifts of a selected employee
const shifts = await this.prisma.shifts.findMany({
where: {
timesheet: { employee_id: employee_id },
date: { gte: period_start, lte: period_end },
}, },
select: { date: true },
}); });
//count the amount of worked days if (!employee) {
const worked_dates = new Set( return { success: false, error: 'EMPLOYEE_NOT_FOUND' } as Result<number, string>;
shifts.map((shift) => shift.date.toISOString().slice(0, 10)), }
); if (!employee.paid_time_off) {
const days_worked = worked_dates.size; return { success: false, error: 'SICK_HOURS_BANK_NOT_FOUND' } as Result<number, string>;
}
const sick_bank = (employee.paid_time_off.banked_hours).toNumber();
if (sick_bank <= 0) return { success: false, error: 'EMPTY_SICK_HOURS_BANK' } as Result<number, string>;
//less than 30 worked days returns 0 if (asked_hours > sick_bank) {
if (days_worked < 30) { return { success: true, data: sick_bank } as Result<number, string>;
return { success: true, data: 0 }; } else {
await tx.paidTimeOff.update({
where: { employee_id: employee.id },
data: { banked_hours: { decrement: asked_hours } },
select: { banked_hours: true },
});
return { success: true, data: asked_hours } as Result<number, string>;
}
});
return result;
} catch (error) {
return { success: false, error: 'INVALID_BANKING_SHIFT' };
} }
//default 3 days allowed after 30 worked days
let acquired_days = 3;
//identify the date of the 30th worked day
const ordered_dates = Array.from(worked_dates).sort();
const threshold_date = new Date(ordered_dates[29]); // index 29 is the 30th day
//calculate each completed month, starting the 1st of the next month
const first_bonus_date = new Date(
threshold_date.getFullYear(),
threshold_date.getMonth() + 1,
1,
);
let months =
(period_end.getFullYear() - first_bonus_date.getFullYear()) * 12 +
(period_end.getMonth() - first_bonus_date.getMonth()) +
1;
if (months < 0) months = 0;
acquired_days += months;
//cap of 10 days
if (acquired_days > 10) acquired_days = 10;
const payable_days = Math.min(acquired_days, days_requested);
const raw_hours = payable_days * hours_per_day * modifier;
const rounded = roundToQuarterHour(raw_hours);
return { success: true, data: rounded };
} }
//LEAVE REQUEST FUNCTION - DEPRECATED
// async calculateSickLeavePay(
// employee_id: number,
// reference_date: Date,
// days_requested: number,
// hours_per_day: number,
// modifier: number,
// ): Promise<Result<number, string>> {
// if (days_requested <= 0 || hours_per_day <= 0 || modifier <= 0) {
// return { success: true, data: 0 };
// }
// //sets the year to jan 1st to dec 31st
// const period_start = getYearStart(reference_date);
// const period_end = reference_date;
// //fetches all shifts of a selected employee
// const shifts = await this.prisma.shifts.findMany({
// where: {
// timesheet: { employee_id: employee_id },
// date: { gte: period_start, lte: period_end },
// },
// select: { date: true },
// });
// //count the amount of worked days
// const worked_dates = new Set(
// shifts.map((shift) => shift.date.toISOString().slice(0, 10)),
// );
// const days_worked = worked_dates.size;
// //less than 30 worked days returns 0
// if (days_worked < 30) {
// return { success: true, data: 0 };
// }
// //default 3 days allowed after 30 worked days
// let acquired_days = 3;
// //identify the date of the 30th worked day
// const ordered_dates = Array.from(worked_dates).sort();
// const threshold_date = new Date(ordered_dates[29]); // index 29 is the 30th day
// //calculate each completed month, starting the 1st of the next month
// const first_bonus_date = new Date(
// threshold_date.getFullYear(),
// threshold_date.getMonth() + 1,
// 1,
// );
// let months =
// (period_end.getFullYear() - first_bonus_date.getFullYear()) * 12 +
// (period_end.getMonth() - first_bonus_date.getMonth()) +
// 1;
// if (months < 0) months = 0;
// acquired_days += months;
// //cap of 10 days
// if (acquired_days > 10) acquired_days = 10;
// const payable_days = Math.min(acquired_days, days_requested);
// const raw_hours = payable_days * hours_per_day * modifier;
// const rounded = roundToQuarterHour(raw_hours);
// return { success: true, data: rounded };
// }
} }

View File

@ -84,16 +84,17 @@ export class VacationService {
select: { paid_time_off: { select: { vacation_hours: true } } }, select: { paid_time_off: { select: { vacation_hours: true } } },
}); });
if (!employee) { if (!employee) {
return { success: false, error: 'EMPLOYEE_NOT_FOUND' } as Result<number, string> return { success: false, error: 'EMPLOYEE_NOT_FOUND' } as Result<number, string>;
} }
if (!employee.paid_time_off) { if (!employee.paid_time_off) {
return { success: false, error: 'VACATION_HOURS_BANK_NOT_FOUND' } as Result<number, string> return { success: false, error: 'VACATION_HOURS_BANK_NOT_FOUND' } as Result<number, string>;
} }
const vacation_bank = employee.paid_time_off.vacation_hours.toNumber() const vacation_bank = employee.paid_time_off.vacation_hours.toNumber()
if (vacation_bank <= 0) return { success: false, error: 'EMPTY_VACATION_BANK' } as Result<number, string>;
//check if remaining hours are less than asked and return maximum available hours //check if remaining hours are less than asked and return maximum available hours
if (asked_hours > vacation_bank) { if (asked_hours > vacation_bank) {
return { success: true, data: vacation_bank } as Result<number, string> return { success: true, data: vacation_bank } as Result<number, string>;
} else { } else {
//update vacation_bank //update vacation_bank
await tx.paidTimeOff.update({ await tx.paidTimeOff.update({

View File

@ -11,6 +11,8 @@ import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-pr
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service"; import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service";
import { VacationService } from "src/time-and-attendance/domains/services/vacation.service"; import { VacationService } from "src/time-and-attendance/domains/services/vacation.service";
import { SickLeaveService } from "src/time-and-attendance/domains/services/sick-leave.service";
import { BankedHoursService } from "src/time-and-attendance/domains/services/banking-hours.service";
@ -26,6 +28,8 @@ import { VacationService } from "src/time-and-attendance/domains/services/vacati
ShiftsCreateService, ShiftsCreateService,
BankCodesResolver, BankCodesResolver,
VacationService, VacationService,
SickLeaveService,
BankedHoursService,
], ],
exports: [ exports: [
SchedulePresetsGetService, SchedulePresetsGetService,

View File

@ -8,6 +8,8 @@ import { Result } from "src/common/errors/result-error.factory";
import { toStringFromHHmm, toStringFromDate, toDateFromString, overlaps, toDateFromHHmm, computeHours } from "src/common/utils/date-utils"; import { toStringFromHHmm, toStringFromDate, toDateFromString, overlaps, toDateFromHHmm, computeHours } from "src/common/utils/date-utils";
import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto";
import { VacationService } from "src/time-and-attendance/domains/services/vacation.service"; import { VacationService } from "src/time-and-attendance/domains/services/vacation.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";
@Injectable() @Injectable()
export class ShiftsCreateService { export class ShiftsCreateService {
@ -16,6 +18,8 @@ export class ShiftsCreateService {
private readonly emailResolver: EmailToIdResolver, private readonly emailResolver: EmailToIdResolver,
private readonly typeResolver: BankCodesResolver, private readonly typeResolver: BankCodesResolver,
private readonly vacationService: VacationService, private readonly vacationService: VacationService,
private readonly bankingService: BankedHoursService,
private readonly sickService: SickLeaveService,
) { } ) { }
//_________________________________________________________________ //_________________________________________________________________
@ -95,15 +99,33 @@ export class ShiftsCreateService {
return { success: false, error: `SHIFT_OVERLAP` }; return { success: false, error: `SHIFT_OVERLAP` };
} }
} }
//api call to validate available hours in vacation_bank and ajust end_time accordingly //api call to validate available hours in vacation_bank and ajust end_time accordingly
if (dto.type === 'VACATION') { if (dto.type === 'VACATION') {
const asked_hours = computeHours(toDateFromString(dto.start_time), toDateFromString(dto.end_time)); const asked_hours = computeHours(toDateFromHHmm(dto.start_time), toDateFromHHmm(dto.end_time));
const vacation_shift = await this.vacationService.manageVacationHoursBank(employee_id, asked_hours) const vacation_shift = await this.vacationService.manageVacationHoursBank(employee_id, asked_hours)
if (!vacation_shift.success) return { success: false, error: vacation_shift.error }; if (!vacation_shift.success) return { success: false, error: vacation_shift.error };
dto.end_time = this.addHourstoDateString(dto.start_time, vacation_shift.data); dto.end_time = this.addHourstoDateString(dto.start_time, vacation_shift.data);
} }
//ADD HERE THE LOGICS TO CHECK FOR AVAILABLE BANK TYPE "PAID_BANKED_HOUR" AND BANKING_HOUR //api call to validate available hours in banked_hours and ajust end_time accordingly
const banking_types: string[] = ['BANKING', 'WITHDRAW_BANKED'];
if (banking_types.includes(dto.type)) {
const hours = computeHours(toDateFromHHmm(dto.start_time), toDateFromHHmm(dto.end_time));
const banking_shift = await this.bankingService.manageBankingHours(employee_id, hours, dto.type);
if (!banking_shift.success) return { success: false, error: banking_shift.error };
dto.end_time = this.addHourstoDateString(dto.start_time, banking_shift.data);
}
//api call to validate available hours in sick_hours and ajust end_time accordingly
if (dto.type === 'SICK') {
console.log('got here')
const hours = computeHours(toDateFromHHmm(dto.start_time), toDateFromHHmm(dto.end_time));
const sick_hours = await this.sickService.takeSickLeaveHours(employee_id, hours);
if (!sick_hours.success) return { success: false, error: sick_hours.error };
console.log(sick_hours.data)
dto.end_time = this.addHourstoDateString(dto.start_time, sick_hours.data);
}
//sends data for creation of a shift in db //sends data for creation of a shift in db
const created_shift = await this.prisma.shifts.create({ const created_shift = await this.prisma.shifts.create({

View File

@ -1,5 +1,6 @@
import { Injectable } from "@nestjs/common"; import { Injectable } from "@nestjs/common";
import { Result } from "src/common/errors/result-error.factory"; 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 { PrismaService } from "src/prisma/prisma.service";
@Injectable() @Injectable()
@ -9,15 +10,64 @@ export class ShiftsDeleteService {
// DELETE // DELETE
//_________________________________________________________________ //_________________________________________________________________
//finds shifts using shit_ids //finds shifts using shit_ids
//ajust paid-time-off banks
//blocs deletion if approved //blocs deletion if approved
async deleteShift(shift_id: number): Promise<Result<number, string>> { async deleteShift(shift_id: number): Promise<Result<number, string>> {
try { try {
return await this.prisma.$transaction(async (tx) => { return await this.prisma.$transaction(async (tx) => {
const paid_time_off_types: string[] = ['SICK', 'VACATION', 'BANKING', 'WITHDRAW_BANKED'];
const shift = await tx.shifts.findUnique({ const shift = await tx.shifts.findUnique({
where: { id: shift_id }, where: { id: shift_id },
select: { id: true, date: true, timesheet_id: true }, select: {
id: true,
date: true,
start_time: true,
end_time: true,
timesheet: true,
bank_code: { select: { type: true } }
},
}); });
if (!shift) return { success: false, error: `SHIFT_NOT_FOUND` }; if (!shift) return { success: false, error: `SHIFT_NOT_FOUND` };
const ajusted_hours = computeHours(shift.start_time, shift.end_time);
//manage banked types, ensures update of amount of hours in bank is ajusted when a paid_time_off shift is deleted
if (paid_time_off_types.includes(shift.bank_code.type)) {
switch (shift.bank_code.type) {
case 'SICK':
await this.prisma.paidTimeOff.update({
where: { employee_id: shift.timesheet.employee_id },
data: {
sick_hours: { increment: ajusted_hours },
},
});
break;
case 'VACATION':
await this.prisma.paidTimeOff.update({
where: { employee_id: shift.timesheet.employee_id },
data: {
vacation_hours: { increment: ajusted_hours },
},
});
break;
case 'WITHDRAW_BANKED':
await this.prisma.paidTimeOff.update({
where: { employee_id: shift.timesheet.employee_id },
data: {
banked_hours: { decrement: ajusted_hours },
},
});
case 'BANKING':
await this.prisma.paidTimeOff.update({
where: { employee_id: shift.timesheet.employee_id },
data: {
banked_hours: { increment: ajusted_hours },
},
});
break;
default:
break;
}
}
await tx.shifts.delete({ where: { id: shift_id } }); await tx.shifts.delete({ where: { id: shift_id } });
return { success: true, data: shift.id }; return { success: true, data: shift.id };

View File

@ -1,4 +1,4 @@
import { toDateFromString, toStringFromHHmm, toStringFromDate, toDateFromHHmm, overlaps } from "src/common/utils/date-utils"; import { toDateFromString, toStringFromHHmm, toStringFromDate, toDateFromHHmm, overlaps, computeHours } from "src/common/utils/date-utils";
import { Injectable } from "@nestjs/common"; import { Injectable } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
@ -9,6 +9,7 @@ import { Result } from "src/common/errors/result-error.factory";
import { shift_select } from "src/time-and-attendance/utils/selects.utils"; import { shift_select } from "src/time-and-attendance/utils/selects.utils";
import { Normalized } from "src/time-and-attendance/utils/type.utils"; import { Normalized } from "src/time-and-attendance/utils/type.utils";
import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
@Injectable() @Injectable()
export class ShiftsUpdateService { export class ShiftsUpdateService {
@ -16,6 +17,7 @@ export class ShiftsUpdateService {
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
private readonly typeResolver: BankCodesResolver, private readonly typeResolver: BankCodesResolver,
private readonly timesheetResolver: EmployeeTimesheetResolver, private readonly timesheetResolver: EmployeeTimesheetResolver,
private readonly emailResolver: EmailToIdResolver,
) { } ) { }
async updateOneOrManyShifts(shifts: ShiftDto[], email: string): Promise<Result<boolean, string>> { async updateOneOrManyShifts(shifts: ShiftDto[], email: string): Promise<Result<boolean, string>> {
@ -60,8 +62,11 @@ export class ShiftsUpdateService {
//_________________________________________________________________ //_________________________________________________________________
async updateShift(dto: ShiftDto, email: string): Promise<Result<ShiftDto, string>> { async updateShift(dto: ShiftDto, email: string): Promise<Result<ShiftDto, string>> {
try { try {
// const paid_time_off_types: string[] = ['SICK', 'VACATION', 'BANKING', 'WITHDRAW_BANKED'];
const timesheet = await this.timesheetResolver.findTimesheetIdByEmail(email, toDateFromString(dto.date)); const timesheet = await this.timesheetResolver.findTimesheetIdByEmail(email, toDateFromString(dto.date));
if (!timesheet.success) return { success: false, error: timesheet.error } if (!timesheet.success) return { success: false, error: timesheet.error };
const employee = await this.emailResolver.findIdByEmail(email);
if (!employee.success) return { success: false, error: employee.error };
//finds original shift //finds original shift
const original = await this.prisma.shifts.findFirst({ const original = await this.prisma.shifts.findFirst({
@ -78,6 +83,51 @@ export class ShiftsUpdateService {
//finds bank_code_id using the type //finds bank_code_id using the type
const bank_code = await this.typeResolver.findBankCodeIDByType(dto.type); const bank_code = await this.typeResolver.findBankCodeIDByType(dto.type);
if (!bank_code.success) return { success: false, error: bank_code.error }; if (!bank_code.success) return { success: false, error: bank_code.error };
// const original_hours = computeHours(original.start_time, original.end_time);
// const ajusted_hours = computeHours(toDateFromHHmm(dto.start_time), toDateFromHHmm(dto.end_time));
// if (paid_time_off_types.includes(dto.type)) {
// switch (dto.type) {
// case 'SICK':
// if (ajusted_hours < original_hours){
// const diff_hours = original_hours - ajusted_hours;
// await this.prisma.paidTimeOff.update({
// where: { employee_id: employee.data },
// data: {
// sick_hours: { decrement: diff_hours },
// },
// });
// } else {
// }
// break;
// case 'VACATION':
// await this.prisma.paidTimeOff.update({
// where: { employee_id: shift.timesheet.employee_id },
// data: {
// vacation_hours: { increment: ajusted_hours },
// },
// });
// break;
// case 'WITHDRAW_BANKED':
// await this.prisma.paidTimeOff.update({
// where: { employee_id: shift.timesheet.employee_id },
// data: {
// banked_hours: { decrement: ajusted_hours },
// },
// });
// case 'BANKING':
// await this.prisma.paidTimeOff.update({
// where: { employee_id: shift.timesheet.employee_id },
// data: {
// banked_hours: { increment: ajusted_hours },
// },
// });
// break;
// default:
// break;
// }
// }
//updates sent to DB //updates sent to DB
const updated = await this.prisma.shifts.update({ const updated = await this.prisma.shifts.update({

View File

@ -6,10 +6,11 @@ import { ShiftsCreateService } from 'src/time-and-attendance/shifts/services/shi
import { ShiftsDeleteService } from 'src/time-and-attendance/shifts/services/shifts-delete.service'; import { ShiftsDeleteService } from 'src/time-and-attendance/shifts/services/shifts-delete.service';
import { ShiftsUpdateService } from 'src/time-and-attendance/shifts/services/shifts-update-delete.service'; import { ShiftsUpdateService } from 'src/time-and-attendance/shifts/services/shifts-update-delete.service';
import { VacationService } from 'src/time-and-attendance/domains/services/vacation.service'; import { VacationService } from 'src/time-and-attendance/domains/services/vacation.service';
import { BankedHoursService } from 'src/time-and-attendance/domains/services/banking-hours.service';
@Module({ @Module({
controllers: [ShiftController], controllers: [ShiftController],
providers: [ShiftsCreateService, ShiftsUpdateService, ShiftsDeleteService, VacationService], providers: [ShiftsCreateService, ShiftsUpdateService, ShiftsDeleteService, VacationService, BankedHoursService],
exports: [ShiftsCreateService, ShiftsUpdateService, ShiftsDeleteService], exports: [ShiftsCreateService, ShiftsUpdateService, ShiftsDeleteService],
}) })
export class ShiftsModule { } export class ShiftsModule { }

View File

@ -40,6 +40,7 @@ import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-p
import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service"; import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service";
import { CsvGeneratorService } from "src/time-and-attendance/exports/services/csv-builder.service"; import { CsvGeneratorService } from "src/time-and-attendance/exports/services/csv-builder.service";
import { VacationService } from "src/time-and-attendance/domains/services/vacation.service"; import { VacationService } from "src/time-and-attendance/domains/services/vacation.service";
import { BankedHoursService } from "src/time-and-attendance/domains/services/banking-hours.service";
@Module({ @Module({
imports: [ imports: [
@ -82,6 +83,7 @@ import { VacationService } from "src/time-and-attendance/domains/services/vacati
CsvExportService, CsvExportService,
CsvGeneratorService, CsvGeneratorService,
VacationService, VacationService,
BankedHoursService,
], ],
exports: [TimesheetApprovalService], exports: [TimesheetApprovalService],
}) export class TimeAndAttendanceModule { }; }) export class TimeAndAttendanceModule { };