fix(shifts): fix a problem with overlaps

This commit is contained in:
Matthieu Haineault 2025-11-04 16:42:14 -05:00
parent 95f369fcbc
commit 407f04ac0b
2 changed files with 22 additions and 28 deletions

View File

@ -1,14 +1,14 @@
import { CreateShiftResult, NormedOk, NormedErr, UpdateShiftResult, UpdateShiftPayload, UpdateShiftChanges, Normalized } from "src/time-and-attendance/utils/type.utils";
import { overlaps, toStringFromHHmm, toStringFromDate, toDateFromString, toHHmmFromString, weekStartSunday } from "src/time-and-attendance/utils/date-time.utils";
import { CreateShiftResult, NormedOk, UpdateShiftResult, UpdateShiftPayload, UpdateShiftChanges, Normalized } from "src/time-and-attendance/utils/type.utils";
import { overlaps, toStringFromHHmm, toStringFromDate, toDateFromString, toHHmmFromString } from "src/time-and-attendance/utils/date-time.utils";
import { Injectable, BadRequestException, ConflictException, NotFoundException } from "@nestjs/common";
import { OvertimeService } from "src/time-and-attendance/domains/services/overtime.service";
import { PrismaService } from "src/prisma/prisma.service";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { ShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-create.dto";
import { GetShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-get.dto";
import { UpdateShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-update.dto";
import { shift_select, timesheet_select } from "src/time-and-attendance/utils/selects.utils";
import { BankCodesResolver } from "src/time-and-attendance/utils/resolve-bank-type-id.utils";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { OvertimeService } from "src/time-and-attendance/domains/services/overtime.service";
import { UpdateShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-update.dto";
import { PrismaService } from "src/prisma/prisma.service";
import { GetShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-get.dto";
import { ShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-create.dto";
@ -49,6 +49,8 @@ export class ShiftsUpsertService {
});
return { index, error };
}
if(!normed.end_time) throw new BadRequestException('A shift needs an end_time');
if(!normed.start_time) throw new BadRequestException('A shift needs a start_time');
const timesheet = await this.prisma.timesheets.findUnique({
where: { id: dto.timesheet_id, employee_id },
@ -191,24 +193,15 @@ export class ShiftsUpsertService {
},
select: shift_select,
});
const normalizeHHmm = (value: Date) => toHHmmFromString(toStringFromHHmm(value));
const normalized_row = {
start_time: normalizeHHmm(row.start_time),
end_time: normalizeHHmm(row.end_time),
date: toDateFromString(row.date),
};
existing.push(normalized_row);
existing_map.set(map_key, existing);
for (const { key } of timesheet_keys) {
existing.push({
start_time: normalizeHHmm(row.start_time),
end_time: normalizeHHmm(row.end_time),
date: toDateFromString(row.date),
});
existing_map.set(
key,
existing.map(row => ({
start_time: normalizeHHmm(row.start_time),
end_time: normalizeHHmm(row.end_time),
date: toDateFromString(row.date),
})),
);
}
const { type: bank_type } = await this.typeResolver.findTypeByBankCodeId(row.bank_code_id);
const summary = await this.overtime.getWeekOvertimeSummary(timesheet_id, normed.date, tx);
@ -327,7 +320,8 @@ export class ShiftsUpsertService {
const group = groups.get(keys)!;
const conflict = group.existing.find(row =>
row.id !== planned.exist_shift.id && overlaps({ start: row.start, end: row.end, date: row.date }, { start: planned.normed.start_time, end: planned.normed.end_time })
row.id !== planned.exist_shift.id && overlaps({ start: row.start, end: row.end, date: row.date },
{ start: planned.normed.start_time, end: planned.normed.end_time, date: planned.normed.date })
);
if (conflict) {
return updates.map(exist =>
@ -432,7 +426,7 @@ export class ShiftsUpsertService {
where: { id: shift_id },
select: { id: true, date: true, timesheet_id: true },
});
if (!shift) throw new NotFoundException(`Shift with id #${shift_id} not found`);
if (!shift) throw new ConflictException({ error_code: 'INVALID_SHIFT'});
await tx.shifts.delete({ where: { id: shift_id } });

View File

@ -89,7 +89,7 @@ export function listPayYear(pay_year: number, anchorISO = ANCHOR_ISO) {
}
export const overlaps = (a: { start: Date; end: Date, date?: Date; }, b: { start: Date; end: Date; date?: Date; }) =>
((a.date === b.date) && !(a.end <= b.start || a.start >= b.end));
((a.date?.getTime() === b.date?.getTime()) && !(a.end <= b.start || a.start >= b.end));
export const hhmmFromLocal = (d: Date) =>