fix(shifts): small return fixes

This commit is contained in:
Matthieu Haineault 2025-12-04 10:45:47 -05:00
parent d913f59eb5
commit 245d671f0b
2 changed files with 111 additions and 111 deletions

View File

@ -16,13 +16,13 @@ export class ShiftController {
@Post('create') @Post('create')
@ModuleAccessAllowed(ModulesEnum.timesheets) @ModuleAccessAllowed(ModulesEnum.timesheets)
createBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<ShiftDto[], string>> { createBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<boolean, string>> {
return this.create_service.createOneOrManyShifts(email, dtos) return this.create_service.createOneOrManyShifts(email, dtos)
} }
@Patch('update') @Patch('update')
@ModuleAccessAllowed(ModulesEnum.timesheets) @ModuleAccessAllowed(ModulesEnum.timesheets)
updateBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<ShiftDto[], string>> { updateBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<boolean, string>> {
return this.update_delete_service.updateOneOrManyShifts(dtos, email); return this.update_delete_service.updateOneOrManyShifts(dtos, email);
} }

View File

@ -1,126 +1,126 @@
import { Injectable } from "@nestjs/common"; // import { Injectable } from "@nestjs/common";
import { Weekday, Prisma } from "@prisma/client"; // import { Weekday, Prisma } from "@prisma/client";
import { DATE_ISO_FORMAT, WEEKDAY } from "src/common/utils/constants.utils"; // import { DATE_ISO_FORMAT, WEEKDAY } from "src/common/utils/constants.utils";
import { PrismaService } from "src/prisma/prisma.service"; // import { PrismaService } from "src/prisma/prisma.service";
import { ApplyResult } from "src/time-and-attendance/utils/type.utils"; // import { ApplyResult } from "src/time-and-attendance/utils/type.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; // import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { Result } from "src/common/errors/result-error.factory"; // import { Result } from "src/common/errors/result-error.factory";
@Injectable() // @Injectable()
export class SchedulePresetsApplyService { // export class SchedulePresetsApplyService {
constructor( // constructor(
private readonly prisma: PrismaService, // private readonly prisma: PrismaService,
private readonly emailResolver: EmailToIdResolver // private readonly emailResolver: EmailToIdResolver
) { } // ) { }
async applyToTimesheet(email: string, id: number, start_date_iso: string): Promise<Result<ApplyResult, string>> { // async applyToTimesheet(email: string, id: number, start_date_iso: string): Promise<Result<ApplyResult, string>> {
if (!DATE_ISO_FORMAT.test(start_date_iso)) return { success: false, error: 'INVALID_PRESET' }; // if (!DATE_ISO_FORMAT.test(start_date_iso)) return { success: false, error: 'INVALID_PRESET' };
const employee_id = await this.emailResolver.findIdByEmail(email); // const employee_id = await this.emailResolver.findIdByEmail(email);
if (!employee_id.success) return { success: false, error: employee_id.error } // if (!employee_id.success) return { success: false, error: employee_id.error }
const preset = await this.prisma.schedulePresets.findFirst({ // const preset = await this.prisma.schedulePresets.findFirst({
where: { employee_id: employee_id.data, id }, // where: { id },
include: { // include: {
shifts: { // shifts: {
orderBy: [{ week_day: 'asc' }, { sort_order: 'asc' }], // orderBy: [{ week_day: 'asc' }, { sort_order: 'asc' }],
select: { // select: {
id: true, // id: true,
week_day: true, // week_day: true,
sort_order: true, // sort_order: true,
start_time: true, // start_time: true,
end_time: true, // end_time: true,
is_remote: true, // is_remote: true,
bank_code_id: true, // bank_code_id: true,
}, // },
}, // },
}, // },
}); // });
if (!preset) return { success: false, error: `PRESET_NOT_FOUND` }; // if (!preset) return { success: false, error: `PRESET_NOT_FOUND` };
const start_date = new Date(`${start_date_iso}T00:00:00.000Z`); // const start_date = new Date(`${start_date_iso}T00:00:00.000Z`);
const timesheet = await this.prisma.timesheets.upsert({ // const timesheet = await this.prisma.timesheets.upsert({
where: { employee_id_start_date: { employee_id: employee_id.data, start_date: start_date } }, // where: { employee_id_start_date: { employee_id: employee_id.data, start_date: start_date } },
update: {}, // update: {},
create: { employee_id: employee_id.data, start_date: start_date }, // create: { employee_id: employee_id.data, start_date: start_date },
select: { id: true }, // select: { id: true },
}); // });
//index shifts by weekday // //index shifts by weekday
const index_by_day = new Map<Weekday, typeof preset.shifts>(); // const index_by_day = new Map<Weekday, typeof preset.shifts>();
for (const shift of preset.shifts) { // for (const shift of preset.shifts) {
const list = index_by_day.get(shift.week_day) ?? []; // const list = index_by_day.get(shift.week_day) ?? [];
list.push(shift); // list.push(shift);
index_by_day.set(shift.week_day, list); // index_by_day.set(shift.week_day, list);
} // }
const addDays = (date: Date, days: number) => // const addDays = (date: Date, days: number) =>
new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days)); // new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days));
const overlaps = (aStart: Date, aEnd: Date, bStart: Date, bEnd: Date) => // const overlaps = (aStart: Date, aEnd: Date, bStart: Date, bEnd: Date) =>
aStart.getTime() < bEnd.getTime() && aEnd.getTime() > bStart.getTime(); // aStart.getTime() < bEnd.getTime() && aEnd.getTime() > bStart.getTime();
let created = 0; // let created = 0;
let skipped = 0; // let skipped = 0;
await this.prisma.$transaction(async (tx) => { // await this.prisma.$transaction(async (tx) => {
for (let i = 0; i < 7; i++) { // for (let i = 0; i < 7; i++) {
const date = addDays(start_date, i); // const date = addDays(start_date, i);
const week_day = WEEKDAY[date.getUTCDay()]; // const week_day = WEEKDAY[date.getUTCDay()];
const shifts = index_by_day.get(week_day) ?? []; // const shifts = index_by_day.get(week_day) ?? [];
if (shifts.length === 0) continue; // if (shifts.length === 0) continue;
const existing = await tx.shifts.findMany({ // const existing = await tx.shifts.findMany({
where: { timesheet_id: timesheet.id, date: date }, // where: { timesheet_id: timesheet.id, date: date },
orderBy: { start_time: 'asc' }, // orderBy: { start_time: 'asc' },
select: { // select: {
start_time: true, // start_time: true,
end_time: true, // end_time: true,
bank_code_id: true, // bank_code_id: true,
is_remote: true, // is_remote: true,
comment: true, // comment: true,
}, // },
}); // });
const payload: Prisma.ShiftsCreateManyInput[] = []; // const payload: Prisma.ShiftsCreateManyInput[] = [];
for (const shift of shifts) { // for (const shift of shifts) {
if (shift.end_time.getTime() <= shift.start_time.getTime()) { // if (shift.end_time.getTime() <= shift.start_time.getTime()) {
return { // return {
success: false, // success: false,
error: `INVALID_PRESET_SHIFT` // error: `INVALID_PRESET_SHIFT`
}; // };
} // }
const conflict = existing.find((existe) => overlaps( // const conflict = existing.find((existe) => overlaps(
shift.start_time, shift.end_time, // shift.start_time, shift.end_time,
existe.start_time, existe.end_time, // existe.start_time, existe.end_time,
)); // ));
if (conflict) // if (conflict)
return { // return {
success: false, // success: false,
error: `OVERLAPING_SHIFT` // error: `OVERLAPING_SHIFT`
}; // };
payload.push({ // payload.push({
timesheet_id: timesheet.id, // timesheet_id: timesheet.id,
date: date, // date: date,
start_time: shift.start_time, // start_time: shift.start_time,
end_time: shift.end_time, // end_time: shift.end_time,
is_remote: shift.is_remote, // is_remote: shift.is_remote,
comment: null, // comment: null,
bank_code_id: shift.bank_code_id, // bank_code_id: shift.bank_code_id,
}); // });
} // }
if (payload.length) { // if (payload.length) {
const response = await tx.shifts.createMany({ data: payload, skipDuplicates: true }); // const response = await tx.shifts.createMany({ data: payload, skipDuplicates: true });
created += response.count; // created += response.count;
skipped += payload.length - response.count; // skipped += payload.length - response.count;
} // }
} // }
}); // });
return { success: true, data: { timesheet_id: timesheet.id, created, skipped } }; // return { success: true, data: { timesheet_id: timesheet.id, created, skipped } };
} // }
} // }