fix(shifts): changed UTC comparison for ISOString
This commit is contained in:
parent
1954d206a8
commit
af8ea95cc4
|
|
@ -1,23 +1,27 @@
|
|||
export function timeFromHHMMUTC(hhmm: string): Date {
|
||||
const [hour, min] = hhmm.split(':').map(Number);
|
||||
return new Date(Date.UTC(1970,0,1,hour, min,0));
|
||||
export function timeFromHHMM(hhmm: string): Date {
|
||||
const [hour, min] = hhmm.split(':').map(Number);
|
||||
return new Date(1970, 0, 1, hour, min, 0, 0);
|
||||
}
|
||||
|
||||
export function weekStartSundayUTC(d: Date): Date {
|
||||
const day = d.getUTCDay();
|
||||
const start = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
|
||||
start.setUTCDate(start.getUTCDate()- day);
|
||||
return start;
|
||||
export function weekStartSunday(d: Date): Date {
|
||||
const start = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
const day = start.getDay(); // 0 = dimanche
|
||||
start.setDate(start.getDate() - day);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
return start;
|
||||
}
|
||||
|
||||
export function toDateOnlyUTC(input: string | Date): Date {
|
||||
const date = new Date(input);
|
||||
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
||||
export function toDateOnly(input: string | Date): Date {
|
||||
const base = (typeof input === 'string') ? new Date(input) : new Date(input);
|
||||
const y = (typeof input === 'string') ? Number(input.slice(0,4)) : base.getFullYear();
|
||||
const m = (typeof input === 'string') ? Number(input.slice(5,7)) - 1 : base.getMonth();
|
||||
const d = (typeof input === 'string') ? Number(input.slice(8,10)) : base.getDate();
|
||||
return new Date(y, m, d, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
export function formatHHmm(time: Date): string {
|
||||
const hh = String(time.getUTCHours()).padStart(2,'0');
|
||||
const mm = String(time.getUTCMinutes()).padStart(2,'0');
|
||||
return `${hh}:${mm}`;
|
||||
const hh = String(time.getHours()).padStart(2,'0');
|
||||
const mm = String(time.getMinutes()).padStart(2,'0');
|
||||
return `${hh}:${mm}`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { BadRequestException, ConflictException, Injectable, Logger, NotFoundException, UnprocessableEntityException } from "@nestjs/common";
|
||||
import { formatHHmm, toDateOnlyUTC, weekStartSundayUTC } from "../helpers/shifts-date-time-helpers";
|
||||
import { normalizeShiftPayload, overlaps } from "../utils/shifts.utils";
|
||||
import { DayShiftResponse, UpsertAction } from "../types-and-interfaces/shifts-upsert.types";
|
||||
import { EmployeeIdEmailResolver } from "src/modules/shared/utils/resolve-email-id.utils";
|
||||
|
|
@ -9,6 +8,7 @@ import { UpsertShiftDto } from "../dtos/upsert-shift.dto";
|
|||
import { BaseApprovalService } from "src/common/shared/base-approval.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { OvertimeService } from "src/modules/business-logics/services/overtime.service";
|
||||
import { formatHHmm, toDateOnly, weekStartSunday } from "../helpers/shifts-date-time-helpers";
|
||||
|
||||
@Injectable()
|
||||
export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
||||
|
|
@ -49,11 +49,11 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
|||
throw new BadRequestException('At least one of old or new shift must be provided');
|
||||
}
|
||||
|
||||
const date_only = toDateOnlyUTC(date_string);
|
||||
const date_only = toDateOnly(date_string);
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
const start_of_week = weekStartSundayUTC(date_only);
|
||||
const start_of_week = weekStartSunday(date_only);
|
||||
|
||||
const timesheet = await tx.timesheets.upsert({
|
||||
where: { employee_id_start_date: { employee_id, start_date: start_of_week } },
|
||||
|
|
@ -65,16 +65,16 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
|||
//validation/sanitation
|
||||
//resolve bank_code_id using type
|
||||
const old_norm_shift = old_shift ? await normalizeShiftPayload(old_shift) : undefined;
|
||||
// if (old_norm_shift && old_norm_shift.end_time.getTime() <= old_norm_shift.start_time.getTime()) {
|
||||
// throw new UnprocessableEntityException(' old_shift.end_time must be > old_shift.start_time');
|
||||
// }
|
||||
if (old_norm_shift && old_norm_shift.end_time.getTime() <= old_norm_shift.start_time.getTime()) {
|
||||
throw new UnprocessableEntityException(' old_shift.end_time must be > old_shift.start_time');
|
||||
}
|
||||
const old_bank_code_id: number | undefined = old_norm_shift ? (await this.bankTypeResolver.findByType(old_norm_shift.type, tx))?.id : undefined;
|
||||
|
||||
|
||||
const new_norm_shift = new_shift ? await normalizeShiftPayload(new_shift) : undefined;
|
||||
// if (new_norm_shift && new_norm_shift.end_time.getTime() <= new_norm_shift.start_time.getTime()) {
|
||||
// throw new UnprocessableEntityException(' new_shift.end_time must be > new_shift.start_time');
|
||||
// }
|
||||
if (new_norm_shift && new_norm_shift.end_time.getTime() <= new_norm_shift.start_time.getTime()) {
|
||||
throw new UnprocessableEntityException(' new_shift.end_time must be > new_shift.start_time');
|
||||
}
|
||||
const new_bank_code_id: number | undefined = new_norm_shift ? (await this.bankTypeResolver.findByType(new_norm_shift.type, tx))?.id : undefined;
|
||||
|
||||
|
||||
|
|
@ -105,28 +105,28 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
|||
});
|
||||
};
|
||||
|
||||
// //checks for overlaping shifts
|
||||
// const assertNoOverlap = (exclude_shift_id?: number)=> {
|
||||
// if (!new_norm_shift) return;
|
||||
// const overlap_with = day_shifts.filter((shift)=> {
|
||||
// if(exclude_shift_id && shift.id === exclude_shift_id) return false;
|
||||
// return overlaps(
|
||||
// new_norm_shift.start_time.getTime(),
|
||||
// new_norm_shift.end_time.getTime(),
|
||||
// shift.start_time.getTime(),
|
||||
// shift.end_time.getTime(),
|
||||
// );
|
||||
// });
|
||||
//checks for overlaping shifts
|
||||
const assertNoOverlap = (exclude_shift_id?: number)=> {
|
||||
if (!new_norm_shift) return;
|
||||
const overlap_with = day_shifts.filter((shift)=> {
|
||||
if(exclude_shift_id && shift.id === exclude_shift_id) return false;
|
||||
return overlaps(
|
||||
new_norm_shift.start_time.getTime(),
|
||||
new_norm_shift.end_time.getTime(),
|
||||
shift.start_time.getTime(),
|
||||
shift.end_time.getTime(),
|
||||
);
|
||||
});
|
||||
|
||||
// if(overlap_with.length > 0) {
|
||||
// const conflicts = overlap_with.map((shift)=> ({
|
||||
// start_time: formatHHmm(shift.start_time),
|
||||
// end_time: formatHHmm(shift.end_time),
|
||||
// type: shift.bank_code?.type ?? 'UNKNOWN',
|
||||
// }));
|
||||
// throw new ConflictException({ error_code: 'SHIFT_OVERLAP', message: 'New shift overlaps with existing shift(s)', conflicts});
|
||||
// }
|
||||
// };
|
||||
if(overlap_with.length > 0) {
|
||||
const conflicts = overlap_with.map((shift)=> ({
|
||||
start_time: formatHHmm(shift.start_time),
|
||||
end_time: formatHHmm(shift.end_time),
|
||||
type: shift.bank_code?.type ?? 'UNKNOWN',
|
||||
}));
|
||||
throw new ConflictException({ error_code: 'SHIFT_OVERLAP', message: 'New shift overlaps with existing shift(s)', conflicts});
|
||||
}
|
||||
};
|
||||
let action: UpsertAction;
|
||||
//_____________________________________________________________________________________________
|
||||
// DELETE
|
||||
|
|
@ -148,7 +148,7 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
|||
//_____________________________________________________________________________________________
|
||||
else if (!old_shift && new_shift) {
|
||||
if (new_bank_code_id === undefined) throw new NotFoundException(`bank code not found for new_shift.type: ${new_norm_shift?.type ?? ''}`);
|
||||
// assertNoOverlap();
|
||||
assertNoOverlap();
|
||||
await tx.shifts.create({
|
||||
data: {
|
||||
timesheet_id: timesheet.id,
|
||||
|
|
@ -170,7 +170,7 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
|||
if (new_bank_code_id === undefined) throw new NotFoundException(`bank code not found for new_shift.type: ${new_norm_shift?.type ?? ''}`);
|
||||
const existing = await findExactOldShift();
|
||||
if(!existing) throw new NotFoundException({ error_code: 'SHIFT_STALE', message: 'The shift was modified or deleted by someone else'});
|
||||
// assertNoOverlap(existing.id);
|
||||
assertNoOverlap(existing.id);
|
||||
|
||||
await tx.shifts.update({
|
||||
where: {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { NotFoundException } from "@nestjs/common";
|
||||
import { ShiftPayloadDto } from "../dtos/upsert-shift.dto";
|
||||
import { timeFromHHMMUTC } from "../helpers/shifts-date-time-helpers";
|
||||
import { timeFromHHMM } from "../helpers/shifts-date-time-helpers";
|
||||
|
||||
export function overlaps(
|
||||
a_start_ms: number,
|
||||
|
|
@ -24,8 +24,8 @@ export function resolveBankCodeByType(type: string): Promise<number> {
|
|||
|
||||
export function normalizeShiftPayload(payload: ShiftPayloadDto) {
|
||||
//normalize shift's infos
|
||||
const start_time = payload.start_time;
|
||||
const end_time = payload.end_time;
|
||||
const start_time = timeFromHHMM(payload.start_time);
|
||||
const end_time = timeFromHHMM(payload.end_time );
|
||||
const type = (payload.type || '').trim().toUpperCase();
|
||||
const is_remote = payload.is_remote === true;
|
||||
const is_approved = payload.is_approved === false;
|
||||
|
|
@ -34,5 +34,5 @@ export function resolveBankCodeByType(type: string): Promise<number> {
|
|||
const trimmed = typeof raw_comment === 'string' ? raw_comment.trim() : null;
|
||||
const comment = trimmed && trimmed.length > 0 ? trimmed: null;
|
||||
|
||||
return { start_time, end_time, type, is_remote, comment, is_approved };
|
||||
return { start_time, end_time, type, is_remote, is_approved, comment };
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user