refactor(shifts): added date to overlap comparisons
This commit is contained in:
parent
0a3d4e2960
commit
eda1f86235
|
|
@ -5,13 +5,11 @@ import { ShiftsUpsertService } from "src/time-and-attendance/time-tracker/shifts
|
||||||
import { CreateShiftResult, UpdateShiftResult } from "src/time-and-attendance/utils/type.utils";
|
import { CreateShiftResult, UpdateShiftResult } from "src/time-and-attendance/utils/type.utils";
|
||||||
import { Roles as RoleEnum } from '.prisma/client';
|
import { Roles as RoleEnum } from '.prisma/client';
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||||
import { BankCodesResolver } from "src/time-and-attendance/utils/resolve-bank-type-id.utils";
|
|
||||||
|
|
||||||
@Controller('shift')
|
@Controller('shift')
|
||||||
export class ShiftController {
|
export class ShiftController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly upsert_service: ShiftsUpsertService,
|
private readonly upsert_service: ShiftsUpsertService,
|
||||||
private readonly typeResolver: BankCodesResolver,
|
|
||||||
){}
|
){}
|
||||||
|
|
||||||
@Post('create')
|
@Post('create')
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,8 @@ export class ShiftsUpsertService {
|
||||||
return {
|
return {
|
||||||
index: index,
|
index: index,
|
||||||
start: item.normed.start_time,
|
start: item.normed.start_time,
|
||||||
end: item.normed.end_time
|
end: item.normed.end_time,
|
||||||
|
date: item.normed.date,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.sort((a, b) => a.start.getTime() - b.start.getTime());
|
.sort((a, b) => a.start.getTime() - b.start.getTime());
|
||||||
|
|
@ -101,8 +102,8 @@ export class ShiftsUpsertService {
|
||||||
for (let j = 1; j < ordered.length; j++) {
|
for (let j = 1; j < ordered.length; j++) {
|
||||||
if (
|
if (
|
||||||
overlaps(
|
overlaps(
|
||||||
{ start: ordered[j - 1].start, end: ordered[j - 1].end },
|
{ start: ordered[j - 1].start, end: ordered[j - 1].end, date: ordered[j - 1].date },
|
||||||
{ start: ordered[j].start, end: ordered[j].end }
|
{ start: ordered[j].start, end: ordered[j].end, date: ordered[j].date },
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const error = new ConflictException({
|
const error = new ConflictException({
|
||||||
|
|
@ -130,17 +131,17 @@ export class ShiftsUpsertService {
|
||||||
{ length: dtos.length },
|
{ length: dtos.length },
|
||||||
() => ({ ok: false, error: new Error('uninitialized') }));
|
() => ({ ok: false, error: new Error('uninitialized') }));
|
||||||
|
|
||||||
const existing_map = new Map<string, { start_time: Date; end_time: Date }[]>();
|
const existing_map = new Map<string, { start_time: Date; end_time: Date, date: Date }[]>();
|
||||||
|
|
||||||
for (const { timesheet_id, day, key } of timesheet_keys) {
|
for (const { timesheet_id, day, key } of timesheet_keys) {
|
||||||
const day_date = new Date(day);
|
const day_date = new Date(day);
|
||||||
const rows = await tx.shifts.findMany({
|
const rows = await tx.shifts.findMany({
|
||||||
where: { timesheet_id, date: day_date },
|
where: { timesheet_id, date: day_date },
|
||||||
select: { start_time: true, end_time: true, id: true },
|
select: { start_time: true, end_time: true, id: true, date: true },
|
||||||
});
|
});
|
||||||
existing_map.set(
|
existing_map.set(
|
||||||
key,
|
key,
|
||||||
rows.map((row) => ({ start_time: row.start_time, end_time: row.end_time })),
|
rows.map((row) => ({ start_time: row.start_time, end_time: row.end_time, date: row.date })),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,7 +158,12 @@ export class ShiftsUpsertService {
|
||||||
existing = [];
|
existing = [];
|
||||||
existing_map.set(map_key, existing);
|
existing_map.set(map_key, existing);
|
||||||
}
|
}
|
||||||
const hit = existing.find(e => overlaps({ start: e.start_time, end: e.end_time }, { start: normed.start_time, end: normed.end_time }));
|
const hit = existing.find(exist => overlaps({
|
||||||
|
start: exist.start_time, end: exist.end_time, date: exist.date
|
||||||
|
}, {
|
||||||
|
start: normed.start_time, end: normed.end_time, date:normed.date
|
||||||
|
})
|
||||||
|
);
|
||||||
if (hit) {
|
if (hit) {
|
||||||
results[index] = {
|
results[index] = {
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|
@ -167,7 +173,7 @@ export class ShiftsUpsertService {
|
||||||
conflicts: [{
|
conflicts: [{
|
||||||
start_time: toStringFromHHmm(hit.start_time),
|
start_time: toStringFromHHmm(hit.start_time),
|
||||||
end_time: toStringFromHHmm(hit.end_time),
|
end_time: toStringFromHHmm(hit.end_time),
|
||||||
type: 'UNKNOWN',
|
date: toStringFromDate(hit.date),
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
@ -192,13 +198,15 @@ export class ShiftsUpsertService {
|
||||||
for (const { key } of timesheet_keys) {
|
for (const { key } of timesheet_keys) {
|
||||||
existing.push({
|
existing.push({
|
||||||
start_time: normalizeHHmm(row.start_time),
|
start_time: normalizeHHmm(row.start_time),
|
||||||
end_time: normalizeHHmm(row.end_time)
|
end_time: normalizeHHmm(row.end_time),
|
||||||
|
date: toDateFromString(row.date),
|
||||||
});
|
});
|
||||||
existing_map.set(
|
existing_map.set(
|
||||||
key,
|
key,
|
||||||
existing.map(row => ({
|
existing.map(row => ({
|
||||||
start_time: normalizeHHmm(row.start_time),
|
start_time: normalizeHHmm(row.start_time),
|
||||||
end_time: normalizeHHmm(row.end_time),
|
end_time: normalizeHHmm(row.end_time),
|
||||||
|
date: toDateFromString(row.date),
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -291,7 +299,7 @@ export class ShiftsUpsertService {
|
||||||
return { update, exist_shift, normed };
|
return { update, exist_shift, normed };
|
||||||
});
|
});
|
||||||
|
|
||||||
const groups = new Map<string, { existing: { start: Date; end: Date; id: number }[], incoming: typeof planned_updates }>();
|
const groups = new Map<string, { existing: { start: Date; end: Date; id: number; date: Date; }[], incoming: typeof planned_updates }>();
|
||||||
function key(timesheet: number, d: Date) {
|
function key(timesheet: number, d: Date) {
|
||||||
const day_date = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
|
const day_date = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
|
||||||
return `${timesheet}|${day_date.getTime()}`;
|
return `${timesheet}|${day_date.getTime()}`;
|
||||||
|
|
@ -307,9 +315,14 @@ export class ShiftsUpsertService {
|
||||||
const day_date = new Date(group.date.getUTCFullYear(), group.date.getUTCMonth(), group.date.getUTCDate());
|
const day_date = new Date(group.date.getUTCFullYear(), group.date.getUTCMonth(), group.date.getUTCDate());
|
||||||
const existing = await tx.shifts.findMany({
|
const existing = await tx.shifts.findMany({
|
||||||
where: { timesheet_id: group.timesheet_id, date: day_date },
|
where: { timesheet_id: group.timesheet_id, date: day_date },
|
||||||
select: { id: true, start_time: true, end_time: true },
|
select: { id: true, start_time: true, end_time: true, date: true },
|
||||||
});
|
});
|
||||||
groups.set(key(group.timesheet_id, day_date), { existing: existing.map(row => ({ id: row.id, start: row.start_time, end: row.end_time })), incoming: planned_updates });
|
groups.set(key(group.timesheet_id, day_date), { existing: existing.map(row => ({
|
||||||
|
id: row.id,
|
||||||
|
start: row.start_time,
|
||||||
|
end: row.end_time,
|
||||||
|
date: row.date,
|
||||||
|
})), incoming: planned_updates });
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const planned of planned_updates) {
|
for (const planned of planned_updates) {
|
||||||
|
|
@ -317,7 +330,7 @@ export class ShiftsUpsertService {
|
||||||
const group = groups.get(keys)!;
|
const group = groups.get(keys)!;
|
||||||
|
|
||||||
const conflict = group.existing.find(row =>
|
const conflict = group.existing.find(row =>
|
||||||
row.id !== planned.exist_shift.id && overlaps({ start: row.start, end: row.end }, { 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 })
|
||||||
);
|
);
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
return updates.map(exist =>
|
return updates.map(exist =>
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,8 @@ export function listPayYear(pay_year: number, anchorISO = ANCHOR_ISO) {
|
||||||
return Array.from({ length: PERIODS_PER_YEAR }, (_, i) => computePeriod(pay_year, i + 1, anchorISO));
|
return Array.from({ length: PERIODS_PER_YEAR }, (_, i) => computePeriod(pay_year, i + 1, anchorISO));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const overlaps = (a: { start: Date; end: Date }, b: { start: Date; end: Date }) =>
|
export const overlaps = (a: { start: Date; end: Date, date?: Date; }, b: { start: Date; end: Date; date?: Date; }) =>
|
||||||
!(a.end <= b.start || a.start >= b.end);
|
((a.date === b.date) && !(a.end <= b.start || a.start >= b.end));
|
||||||
|
|
||||||
|
|
||||||
export const hhmmFromLocal = (d: Date) =>
|
export const hhmmFromLocal = (d: Date) =>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user