refactor(helpers): moved helpers to a shared file
This commit is contained in:
parent
78a335a47c
commit
71d86f7fed
|
|
@ -437,7 +437,7 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/shifts/upsert/{email}/{date}": {
|
||||
"/shifts/upsert/{email}": {
|
||||
"put": {
|
||||
"operationId": "ShiftsController_upsert_by_date",
|
||||
"parameters": [
|
||||
|
|
@ -448,14 +448,6 @@
|
|||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "date",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ import { HolidayService } from 'src/modules/business-logics/services/holid
|
|||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { mapRowToView } from '../mappers/leave-requests.mapper';
|
||||
import { leaveRequestsSelect } from '../utils/leave-requests.select';
|
||||
import { LeaveRequestsUtils, normalizeDates, toDateOnly } from '../utils/leave-request.util';
|
||||
import { LeaveRequestsUtils} from '../utils/leave-request.util';
|
||||
import { normalizeDates, toDateOnly } from 'src/modules/shared/helpers/date-time.helpers';
|
||||
|
||||
|
||||
@Injectable()
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ import { HolidayService } from "src/modules/business-logics/services/holiday.ser
|
|||
import { SickLeaveService } from "src/modules/business-logics/services/sick-leave.service";
|
||||
import { VacationService } from "src/modules/business-logics/services/vacation.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { LeaveRequestsUtils, normalizeDates, toDateOnly, toISODateKey } from "../utils/leave-request.util";
|
||||
import { LeaveRequestsUtils } from "../utils/leave-request.util";
|
||||
import { normalizeDates, toDateOnly, toISODateKey } from "src/modules/shared/helpers/date-time.helpers";
|
||||
|
||||
@Injectable()
|
||||
export class LeaveRequestsService {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import { mapRowToView } from "../mappers/leave-requests.mapper";
|
|||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { SickLeaveService } from "src/modules/business-logics/services/sick-leave.service";
|
||||
import { roundToQuarterHour } from "src/common/utils/date-utils";
|
||||
import { LeaveRequestsUtils, normalizeDates, toDateOnly } from "../utils/leave-request.util";
|
||||
import { LeaveRequestsUtils } from "../utils/leave-request.util";
|
||||
import { normalizeDates, toDateOnly } from "src/modules/shared/helpers/date-time.helpers";
|
||||
|
||||
@Injectable()
|
||||
export class SickLeaveRequestsService {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import { PrismaService } from "src/prisma/prisma.service";
|
|||
import { mapRowToView } from "../mappers/leave-requests.mapper";
|
||||
import { leaveRequestsSelect } from "../utils/leave-requests.select";
|
||||
import { roundToQuarterHour } from "src/common/utils/date-utils";
|
||||
import { LeaveRequestsUtils, normalizeDates, toDateOnly } from "../utils/leave-request.util";
|
||||
import { LeaveRequestsUtils } from "../utils/leave-request.util";
|
||||
import { normalizeDates, toDateOnly } from "src/modules/shared/helpers/date-time.helpers";
|
||||
|
||||
@Injectable()
|
||||
export class VacationLeaveRequestsService {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { LeaveTypes } from "@prisma/client";
|
||||
import { hhmmFromLocal, toDateOnly, toStringFromDate } from "src/modules/shared/helpers/date-time.helpers";
|
||||
import { ShiftsCommandService } from "src/modules/shifts/services/shifts-command.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ export class LeaveRequestsUtils {
|
|||
async syncShift(
|
||||
email: string,
|
||||
employee_id: number,
|
||||
iso_date: string,
|
||||
date: string,
|
||||
hours: number,
|
||||
type: LeaveTypes,
|
||||
comment?: string,
|
||||
|
|
@ -44,6 +45,10 @@ export class LeaveRequestsUtils {
|
|||
if (duration_minutes > 8 * 60) {
|
||||
throw new BadRequestException("Amount of hours cannot exceed 8 hours per day.");
|
||||
}
|
||||
const date_only = toDateOnly(date);
|
||||
const yyyy_mm_dd = toStringFromDate(date_only);
|
||||
|
||||
|
||||
|
||||
const start_minutes = 8 * 60;
|
||||
const end_minutes = start_minutes + duration_minutes;
|
||||
|
|
@ -52,25 +57,27 @@ export class LeaveRequestsUtils {
|
|||
|
||||
const existing = await this.prisma.shifts.findFirst({
|
||||
where: {
|
||||
date: new Date(iso_date),
|
||||
date: date_only,
|
||||
bank_code: { type },
|
||||
timesheet: { employee_id: employee_id },
|
||||
},
|
||||
include: { bank_code: true },
|
||||
});
|
||||
|
||||
await this.shiftsCommand.upsertShiftsByDate(email, iso_date, {
|
||||
await this.shiftsCommand.upsertShiftsByDate(email, {
|
||||
old_shift: existing
|
||||
? {
|
||||
start_time: existing.start_time.toISOString().slice(11, 16),
|
||||
end_time: existing.end_time.toISOString().slice(11, 16),
|
||||
type: existing.bank_code?.type ?? type,
|
||||
is_remote: existing.is_remote,
|
||||
is_approved:existing.is_approved,
|
||||
comment: existing.comment ?? undefined,
|
||||
}
|
||||
date: yyyy_mm_dd,
|
||||
start_time: existing.start_time.toISOString().slice(11, 16),
|
||||
end_time: existing.end_time.toISOString().slice(11, 16),
|
||||
type: existing.bank_code?.type ?? type,
|
||||
is_remote: existing.is_remote,
|
||||
is_approved:existing.is_approved,
|
||||
comment: existing.comment ?? undefined,
|
||||
}
|
||||
: undefined,
|
||||
new_shift: {
|
||||
date: yyyy_mm_dd,
|
||||
start_time: toHHmm(start_minutes),
|
||||
end_time: toHHmm(end_minutes),
|
||||
is_remote: existing?.is_remote ?? false,
|
||||
|
|
@ -87,9 +94,11 @@ export class LeaveRequestsUtils {
|
|||
iso_date: string,
|
||||
type: LeaveTypes,
|
||||
) {
|
||||
const date_only = toDateOnly(iso_date);
|
||||
const yyyy_mm_dd = toStringFromDate(date_only);
|
||||
const existing = await this.prisma.shifts.findFirst({
|
||||
where: {
|
||||
date: new Date(iso_date),
|
||||
date: date_only,
|
||||
bank_code: { type },
|
||||
timesheet: { employee_id: employee_id },
|
||||
},
|
||||
|
|
@ -97,10 +106,11 @@ export class LeaveRequestsUtils {
|
|||
});
|
||||
if (!existing) return;
|
||||
|
||||
await this.shiftsCommand.upsertShiftsByDate(email, iso_date, {
|
||||
await this.shiftsCommand.upsertShiftsByDate(email, {
|
||||
old_shift: {
|
||||
start_time: existing.start_time.toISOString().slice(11, 16),
|
||||
end_time: existing.end_time.toISOString().slice(11, 16),
|
||||
date: yyyy_mm_dd,
|
||||
start_time: hhmmFromLocal(existing.start_time),
|
||||
end_time: hhmmFromLocal(existing.end_time),
|
||||
type: existing.bank_code?.type ?? type,
|
||||
is_remote: existing.is_remote,
|
||||
is_approved:existing.is_approved,
|
||||
|
|
@ -110,18 +120,3 @@ export class LeaveRequestsUtils {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export const toDateOnly = (iso: string): Date => {
|
||||
const date = new Date(iso);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
throw new BadRequestException(`Invalid date: ${iso}`);
|
||||
}
|
||||
date.setHours(0, 0, 0, 0);
|
||||
return date;
|
||||
};
|
||||
|
||||
export const toISODateKey = (date: Date): string => date.toISOString().slice(0, 10);
|
||||
|
||||
export const normalizeDates = (dates: string[]): string[] =>
|
||||
Array.from(new Set(dates.map((iso) => toISODateKey(toDateOnly(iso)))));
|
||||
34
src/modules/shared/helpers/date-time.helpers.ts
Normal file
34
src/modules/shared/helpers/date-time.helpers.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { BadRequestException } from "@nestjs/common";
|
||||
|
||||
export const hhmmFromLocal = (d: Date) =>
|
||||
`${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
|
||||
|
||||
export const toDateOnly = (s: string): Date => {
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) {
|
||||
const y = Number(s.slice(0,4));
|
||||
const m = Number(s.slice(5,7)) - 1;
|
||||
const d = Number(s.slice(8,10));
|
||||
return new Date(y, m, d, 0, 0, 0, 0);
|
||||
}
|
||||
const dt = new Date(s);
|
||||
if (Number.isNaN(dt.getTime())) throw new BadRequestException(`Invalid date: ${s}`);
|
||||
return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), 0,0,0,0);
|
||||
};
|
||||
|
||||
export const toStringFromDate = (d: Date) =>
|
||||
`${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
|
||||
|
||||
|
||||
export const toISOtoDateOnly = (iso: string): Date => {
|
||||
const date = new Date(iso);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
throw new BadRequestException(`Invalid date: ${iso}`);
|
||||
}
|
||||
date.setHours(0, 0, 0, 0);
|
||||
return date;
|
||||
};
|
||||
|
||||
export const toISODateKey = (date: Date): string => date.toISOString().slice(0, 10);
|
||||
|
||||
export const normalizeDates = (dates: string[]): string[] =>
|
||||
Array.from(new Set(dates.map((iso) => toISODateKey(toISOtoDateOnly(iso)))));
|
||||
|
|
@ -18,13 +18,12 @@ export class ShiftsController {
|
|||
private readonly shiftsCommandService: ShiftsCommandService,
|
||||
){}
|
||||
|
||||
@Put('upsert/:email/:date')
|
||||
@Put('upsert/:email')
|
||||
async upsert_by_date(
|
||||
@Param('email') email_param: string,
|
||||
@Param('date') date_param: string,
|
||||
@Body() payload: UpsertShiftDto,
|
||||
) {
|
||||
return this.shiftsCommandService.upsertShiftsByDate(email_param, date_param, payload);
|
||||
return this.shiftsCommandService.upsertShiftsByDate(email_param, payload);
|
||||
}
|
||||
|
||||
@Patch('approval/:id')
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ export const COMMENT_MAX_LENGTH = 280;
|
|||
|
||||
export class ShiftPayloadDto {
|
||||
|
||||
@Matches(/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/)
|
||||
date!: string;
|
||||
|
||||
@Matches(/^([01]\d|2[0-3]):([0-5]\d)$/)
|
||||
start_time!: string;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,25 @@
|
|||
export function timeFromHHMM(hhmm: string): Date {
|
||||
const [hour, min] = hhmm.split(':').map(Number);
|
||||
return new Date(1970, 0, 1, hour, min, 0, 0);
|
||||
const [h, m] = hhmm.split(':').map(Number);
|
||||
return new Date(1970, 0, 1, h, m, 0, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
export function toDateOnly(ymd: string): Date {
|
||||
const y = Number(ymd.slice(0, 4));
|
||||
const m = Number(ymd.slice(5, 7)) - 1;
|
||||
const d = Number(ymd.slice(8, 10));
|
||||
return new Date(y, m, d, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
export function weekStartSunday(dateLocal: Date): Date {
|
||||
const start = new Date(dateLocal.getFullYear(), dateLocal.getMonth(), dateLocal.getDate());
|
||||
const dow = start.getDay(); // 0 = dimanche
|
||||
start.setDate(start.getDate() - dow);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
return start;
|
||||
}
|
||||
|
||||
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.getHours()).padStart(2,'0');
|
||||
const mm = String(time.getMinutes()).padStart(2,'0');
|
||||
export function formatHHmm(t: Date): string {
|
||||
const hh = String(t.getHours()).padStart(2, '0');
|
||||
const mm = String(t.getMinutes()).padStart(2, '0');
|
||||
return `${hh}:${mm}`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
|||
//_____________________________________________________________________________________________
|
||||
// MASTER CRUD METHOD
|
||||
//_____________________________________________________________________________________________
|
||||
async upsertShiftsByDate(email:string, date_string: string, dto: UpsertShiftDto):
|
||||
async upsertShiftsByDate(email:string, dto: UpsertShiftDto):
|
||||
Promise<{ action: UpsertAction; day: DayShiftResponse[] }> {
|
||||
const { old_shift, new_shift } = dto;
|
||||
|
||||
|
|
@ -49,7 +49,14 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
|||
throw new BadRequestException('At least one of old or new shift must be provided');
|
||||
}
|
||||
|
||||
const date_only = toDateOnly(date_string);
|
||||
const date = new_shift?.date ?? old_shift?.date;
|
||||
if (!date) throw new BadRequestException("A date (YYYY-MM-DD) must be provided in old_shift or new_shift");
|
||||
if (old_shift?.date
|
||||
&& new_shift?.date
|
||||
&& old_shift.date
|
||||
!== new_shift.date) throw new BadRequestException("old_shift.date and new_shift.date must be identical");
|
||||
|
||||
const date_only = toDateOnly(date);
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export function resolveBankCodeByType(type: string): Promise<number> {
|
|||
|
||||
export function normalizeShiftPayload(payload: ShiftPayloadDto) {
|
||||
//normalize shift's infos
|
||||
const date = payload.date;
|
||||
const start_time = timeFromHHMM(payload.start_time);
|
||||
const end_time = timeFromHHMM(payload.end_time );
|
||||
const type = (payload.type || '').trim().toUpperCase();
|
||||
|
|
@ -34,5 +35,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, is_approved, comment };
|
||||
return { date, start_time, end_time, type, is_remote, is_approved, comment };
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user