diff --git a/docs/swagger/swagger-spec.json b/docs/swagger/swagger-spec.json index 4033b53..b4c431e 100644 --- a/docs/swagger/swagger-spec.json +++ b/docs/swagger/swagger-spec.json @@ -286,6 +286,30 @@ ] } }, + "/schedule-presets/apply-preset": { + "post": { + "operationId": "SchedulePresetsController_applyPresetToTimesheet", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "number" + } + } + } + }, + "responses": { + "201": { + "description": "" + } + }, + "tags": [ + "SchedulePresets" + ] + } + }, "/expense/create": { "post": { "operationId": "ExpenseController_create", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c74e43b..80cc967 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -167,13 +167,12 @@ model SchedulePresetShifts { bank_code BankCodes @relation("SchedulePresetShiftsBankCodes", fields: [bank_code_id], references: [id]) bank_code_id Int - sort_order Int start_time DateTime @db.Time(0) end_time DateTime @db.Time(0) is_remote Boolean @default(false) week_day Weekday - @@unique([preset_id, week_day, sort_order], name: "unique_preset_shift_per_day_order") + @@unique([preset_id, week_day], name: "unique_preset_shift_per_day") @@index([preset_id, week_day]) @@map("schedule_preset_shifts") } diff --git a/src/common/utils/date-utils.ts b/src/common/utils/date-utils.ts index 60afab9..e642e8f 100644 --- a/src/common/utils/date-utils.ts +++ b/src/common/utils/date-utils.ts @@ -1,26 +1,29 @@ +import { Weekday } from "@prisma/client"; +import { ANCHOR_ISO, MS_PER_DAY, PERIODS_PER_YEAR, PERIOD_DAYS } from "src/common/utils/constants.utils"; +import { WEEKDAY_MAP } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; //lenght of a shift, rouded to nearest 'x' minute export function computeHours(start: Date, end: Date, roundToMinutes?: number): number { const diffMs = end.getTime() - start.getTime(); const totalMinutes = diffMs / 60000; const minutes = roundToMinutes ? - Math.round(totalMinutes / roundToMinutes) * roundToMinutes : - totalMinutes; + Math.round(totalMinutes / roundToMinutes) * roundToMinutes : + totalMinutes; return +(minutes / 60).toFixed(2); } //round the amount of hours to quarter export function roundToQuarterHour(hours: number): number { - return Math.round(hours *4) / 4; + return Math.round(hours * 4) / 4; } -//fetch firts day of the week (Sunday) -export function getWeekStart(date:Date, firstDayOfWeek = 0): Date { +// fetch firts day of the week (Sunday) +export function getWeekStart(date: Date, firstDayOfWeek = 0): Date { const d = new Date(date); const day = d.getDay(); const diff = (day < firstDayOfWeek ? 7 : 0) + (day - firstDayOfWeek); d.setDate(d.getDate() - diff); - d.setHours(0,0,0,0); + d.setHours(0, 0, 0, 0); return d; } @@ -28,32 +31,29 @@ export function getWeekStart(date:Date, firstDayOfWeek = 0): Date { export function getWeekEnd(startOfWeek: Date): Date { const d = new Date(startOfWeek); d.setDate(d.getDate() + 6); - d.setHours(23,59,59,999); + d.setHours(23, 59, 59, 999); return d; } //returns january 1st of the selected date's year -export function getYearStart(date:Date): Date { - return new Date(date.getFullYear(),0,1,0,0,0,0); +export function getYearStart(date: Date): Date { + return new Date(date.getFullYear(), 0, 1, 0, 0, 0, 0); } //to be used to calculate breaks time export function hoursBetweenSameDay(day: Date, startTime: Date, endTime: Date): number { - const start = new Date(day); start.setHours(startTime.getHours(), - startTime.getMinutes(), - startTime.getSeconds(), - startTime.getMilliseconds()); - const end = new Date(day); end.setHours(endTime.getHours(), - endTime.getMinutes(), - endTime.getSeconds(), - endTime.getMilliseconds()); - const ms = Math.max(0, end.getTime() - start.getTime()); - return ms / 3_600_000; // decimal hours + const start = new Date(day); start.setHours(startTime.getHours(), + startTime.getMinutes(), + startTime.getSeconds(), + startTime.getMilliseconds()); + const end = new Date(day); end.setHours(endTime.getHours(), + endTime.getMinutes(), + endTime.getSeconds(), + endTime.getMilliseconds()); + const ms = Math.max(0, end.getTime() - start.getTime()); + return ms / 3_600_000; // decimal hours } -import { BadRequestException } from "@nestjs/common"; -import { ANCHOR_ISO, MS_PER_DAY, PERIODS_PER_YEAR, PERIOD_DAYS } from "src/common/utils/constants.utils"; - //ensures the week starts from sunday export function weekStartSunday(date_local: Date): Date { const start_date = new Date(); @@ -140,39 +140,10 @@ export function listPayYear(pay_year: number, anchorISO = ANCHOR_ISO) { return Array.from({ length: PERIODS_PER_YEAR }, (_, i) => computePeriod(pay_year, i + 1, anchorISO)); } +//checks for shifts overlaping one another export const overlaps = (a: { start: Date; end: Date, date?: Date; }, b: { start: Date; end: Date; date?: Date; }) => ((a.date?.getTime() === b.date?.getTime()) && !(a.end <= b.start || a.start >= b.end)); - -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))))); \ No newline at end of file +export const is_same_week_day = (date: Date, week_day: Weekday): boolean => { + return date.getUTCDay() !== WEEKDAY_MAP[week_day]; +} \ No newline at end of file diff --git a/src/time-and-attendance/schedule-presets/dtos/create-schedule-preset-shifts.dto.ts b/src/time-and-attendance/schedule-presets/dtos/create-schedule-preset-shifts.dto.ts deleted file mode 100644 index 19adf4d..0000000 --- a/src/time-and-attendance/schedule-presets/dtos/create-schedule-preset-shifts.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { IsBoolean, IsEnum, IsInt, IsOptional, IsString, Matches, Min } from "class-validator"; -import { HH_MM_REGEX } from "src/common/utils/constants.utils"; -import { Weekday } from "@prisma/client"; - -export class SchedulePresetShiftsDto { - @IsInt() preset_id!: number; - @IsEnum(Weekday) week_day!: Weekday; - @IsInt() @Min(1) sort_order!: number; - @IsString() type!: string; - @IsString() @Matches(HH_MM_REGEX) start_time!: string; - @IsString() @Matches(HH_MM_REGEX) end_time!: string; - @IsOptional() @IsBoolean() is_remote?: boolean; -} \ No newline at end of file diff --git a/src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto.ts b/src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto.ts deleted file mode 100644 index 5da3f2f..0000000 --- a/src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ArrayMinSize, IsArray, IsBoolean, IsInt, IsOptional, IsString } from "class-validator"; - -import { SchedulePresetShiftsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-preset-shifts.dto"; - -export class SchedulePresetsDto { - @IsInt() id!: number; - @IsString() name!: string; - @IsBoolean() @IsOptional() is_default: boolean; - @IsArray() @ArrayMinSize(1) preset_shifts: SchedulePresetShiftsDto[]; -} \ No newline at end of file diff --git a/src/time-and-attendance/schedule-presets/schedule-presets.controller.ts b/src/time-and-attendance/schedule-presets/schedule-presets.controller.ts index 0e43e1d..f1eab4a 100644 --- a/src/time-and-attendance/schedule-presets/schedule-presets.controller.ts +++ b/src/time-and-attendance/schedule-presets/schedule-presets.controller.ts @@ -4,10 +4,12 @@ import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-p import { SchedulePresetUpdateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-update.service"; import { SchedulePresetDeleteService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service"; import { SchedulePresetsGetService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-get.service"; -import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto"; +import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators"; import { Modules as ModulesEnum } from ".prisma/client"; +import { Access } from "src/common/decorators/module-access.decorators"; +import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service"; @Controller('schedule-presets') export class SchedulePresetsController { @@ -16,6 +18,7 @@ export class SchedulePresetsController { private readonly createService: SchedulePresetsCreateService, private readonly updateService: SchedulePresetUpdateService, private readonly deleteService: SchedulePresetDeleteService, + private readonly applyService: SchedulePresetsApplyService, ) { } @Get('find-list') @@ -43,4 +46,12 @@ export class SchedulePresetsController { @Param('id', ParseIntPipe) id: number) { return await this.deleteService.deletePreset(id); } + + @Post('apply-preset') + @ModuleAccessAllowed(ModulesEnum.timesheets) + async applyPresetToTimesheet( + @Access('email') email: string, @Body() timesheet_id: number, + ) { + return await this.applyService.ApplyPresetToTimesheet(email, timesheet_id); + } } \ No newline at end of file diff --git a/src/time-and-attendance/schedule-presets/schedule-presets.dto.ts b/src/time-and-attendance/schedule-presets/schedule-presets.dto.ts new file mode 100644 index 0000000..98f4937 --- /dev/null +++ b/src/time-and-attendance/schedule-presets/schedule-presets.dto.ts @@ -0,0 +1,29 @@ +import { Weekday } from "@prisma/client"; +import { ArrayMinSize, IsArray, IsBoolean, IsEnum, IsInt, IsOptional, IsString, Matches, Min } from "class-validator"; +import { HH_MM_REGEX } from "src/common/utils/constants.utils"; + +export class SchedulePresetsDto { + @IsInt() id!: number; + @IsString() name!: string; + @IsBoolean() @IsOptional() is_default: boolean; + @IsArray() @ArrayMinSize(1) preset_shifts: SchedulePresetShiftsDto[]; +} + +export class SchedulePresetShiftsDto { + @IsInt() preset_id!: number; + @IsEnum(Weekday) week_day!: Weekday; + @IsString() type!: string; + @IsString() @Matches(HH_MM_REGEX) start_time!: string; + @IsString() @Matches(HH_MM_REGEX) end_time!: string; + @IsOptional() @IsBoolean() is_remote?: boolean; +} + +export const WEEKDAY_MAP: Record = { + SUN: 0, + MON: 1, + TUE: 2, + WED: 3, + THU: 4, + FRI: 5, + SAT: 6, +}; \ No newline at end of file diff --git a/src/time-and-attendance/schedule-presets/schedule-presets.module.ts b/src/time-and-attendance/schedule-presets/schedule-presets.module.ts index cc97de6..531c5e3 100644 --- a/src/time-and-attendance/schedule-presets/schedule-presets.module.ts +++ b/src/time-and-attendance/schedule-presets/schedule-presets.module.ts @@ -7,6 +7,9 @@ import { SchedulePresetsGetService } from "src/time-and-attendance/schedule-pres import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-create.service"; import { SchedulePresetUpdateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-update.service"; import { SchedulePresetDeleteService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service"; +import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service"; +import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; +import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service"; @@ -17,6 +20,9 @@ import { SchedulePresetDeleteService } from "src/time-and-attendance/schedule-pr SchedulePresetsCreateService, SchedulePresetUpdateService, SchedulePresetDeleteService, + SchedulePresetsApplyService, + EmailToIdResolver, + ShiftsCreateService, BankCodesResolver, ], exports: [ diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts new file mode 100644 index 0000000..206cd68 --- /dev/null +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts @@ -0,0 +1,87 @@ +import { Injectable } from "@nestjs/common"; +import { PrismaService } from "src/prisma/prisma.service"; + +import { is_same_week_day, sevenDaysFrom, toStringFromDate } from "src/common/utils/date-utils"; +import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; +import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; +import { Result } from "src/common/errors/result-error.factory"; + +import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service"; +import { timesheet_select } from "src/time-and-attendance/utils/selects.utils"; +import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; + + +@Injectable() +export class SchedulePresetsApplyService { + constructor( + private readonly prisma: PrismaService, + private readonly emailResolver: EmailToIdResolver, + private readonly shiftService: ShiftsCreateService, + private readonly typeResolver: BankCodesResolver, + ) { } + + async ApplyPresetToTimesheet(email: string, timesheet_id: number): Promise> { + const employee_id = await this.emailResolver.findIdByEmail(email); + if (!employee_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; + + const employee_default_schedule_preset = await this.prisma.employees.findFirst({ + where: { id: employee_id.data }, + select: { + schedule_preset: { + select: { + id: true, + is_default: true, + shifts: true, + }, + }, + }, + }); + if (!employee_default_schedule_preset) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; + if (!employee_default_schedule_preset.schedule_preset) return { success: false, error: 'SCHEDULE_PRESET_NOT_FOUND' }; + + const default_preset_shifts = await this.prisma.schedulePresetShifts.findMany({ + where: { preset_id: employee_default_schedule_preset.schedule_preset.id }, + select: { + bank_code_id: true, + start_time: true, + end_time: true, + is_remote: true, + week_day: true, + }, + }); + if (default_preset_shifts.length <= 0) return { success: false, error: 'INVALID_SCHEDULE_PRESET' }; + + const timesheet = await this.prisma.timesheets.findUnique({ + where: { id: timesheet_id }, + select: timesheet_select, + }); + if (!timesheet) return { success: false, error: 'TIMESHEET_NOT_FOUND' }; + if (timesheet.is_approved) return { success: false, error: 'INVALID_TIMESHEET' }; + if (timesheet.shift.length > 0) return { success: false, error: 'INVALID_TIMESHEET' }; + + const dated_map = await sevenDaysFrom(timesheet.start_date); + + for (const date of dated_map) { + for (const preset_shift of default_preset_shifts) { + if (!is_same_week_day(date, preset_shift.week_day)) continue; + + const type = await this.typeResolver.findTypeByBankCodeId(preset_shift.bank_code_id); + if (!type.success) return { success: false, error: 'INVALID_PRESET_SHIFT' }; + + const shift: ShiftDto = { + timesheet_id: timesheet.id, + type: type.data, + date: toStringFromDate(date), + start_time: toStringFromDate(preset_shift.start_time), + end_time: toStringFromDate(preset_shift.end_time), + is_approved: false, + is_remote: preset_shift.is_remote, + }; + await this.shiftService.createShift(employee_id.data, shift); + } + } + + return { success: true, data: true }; + } + +} \ No newline at end of file diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-create.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-create.service.ts index 8ef60c1..5b19a77 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-create.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-create.service.ts @@ -2,7 +2,7 @@ import { Injectable } from "@nestjs/common"; import { PrismaService } from "src/prisma/prisma.service"; -import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto"; +import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; import { overlaps, toDateFromHHmm } from "src/common/utils/date-utils"; import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; @@ -73,7 +73,6 @@ export class SchedulePresetsCreateService { const result = bank_code_results[index] as { success: true, data: number }; return { week_day: shift.week_day, - sort_order: shift.sort_order, start_time: toDateFromHHmm(shift.start_time), end_time: toDateFromHHmm(shift.end_time), is_remote: shift.is_remote ?? false, diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-get.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-get.service.ts index 211d64d..2220c36 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-get.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-get.service.ts @@ -18,7 +18,7 @@ export class SchedulePresetsGetService { orderBy: [{ is_default: 'desc' }, { name: 'asc' }], include: { shifts: { - orderBy: [{ week_day: 'asc' }, { sort_order: 'asc' }], + orderBy: [{ week_day: 'asc' }], include: { bank_code: { select: { type: true } } }, }, }, @@ -31,7 +31,6 @@ export class SchedulePresetsGetService { is_default: preset.is_default, shifts: preset.shifts.map((shift) => ({ week_day: shift.week_day, - sort_order: shift.sort_order, start_time: hhmm(shift.start_time), end_time: hhmm(shift.end_time), is_remote: shift.is_remote, diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-update.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-update.service.ts index 740ff49..386853b 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-update.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-update.service.ts @@ -1,7 +1,7 @@ import { Injectable } from "@nestjs/common"; import { PrismaService } from "src/prisma/prisma.service"; -import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto"; +import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; import { overlaps, toDateFromHHmm } from "src/common/utils/date-utils"; import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; @@ -73,7 +73,6 @@ export class SchedulePresetUpdateService { const result = bank_code_results[index] as { success: true, data: number }; return { week_day: shift.week_day, - sort_order: shift.sort_order, start_time: toDateFromHHmm(shift.start_time), end_time: toDateFromHHmm(shift.end_time), is_remote: shift.is_remote ?? false, diff --git a/src/time-and-attendance/shifts/services/shifts-create.service.ts b/src/time-and-attendance/shifts/services/shifts-create.service.ts index e512e94..a32ffa7 100644 --- a/src/time-and-attendance/shifts/services/shifts-create.service.ts +++ b/src/time-and-attendance/shifts/services/shifts-create.service.ts @@ -6,7 +6,7 @@ import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; import { PrismaService } from "src/prisma/prisma.service"; import { Result } from "src/common/errors/result-error.factory"; import { toStringFromHHmm, toStringFromDate, toDateFromString, overlaps, toDateFromHHmm } from "src/common/utils/date-utils"; -import { ShiftDto } from "src/time-and-attendance/shifts/shift-create.dto"; +import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; @Injectable() export class ShiftsCreateService { diff --git a/src/time-and-attendance/shifts/services/shifts-update-delete.service.ts b/src/time-and-attendance/shifts/services/shifts-update-delete.service.ts index f882bd0..572e04e 100644 --- a/src/time-and-attendance/shifts/services/shifts-update-delete.service.ts +++ b/src/time-and-attendance/shifts/services/shifts-update-delete.service.ts @@ -8,7 +8,7 @@ import { Result } from "src/common/errors/result-error.factory"; import { shift_select } from "src/time-and-attendance/utils/selects.utils"; import { Normalized } from "src/time-and-attendance/utils/type.utils"; -import { ShiftDto } from "src/time-and-attendance/shifts/shift-create.dto"; +import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; @Injectable() export class ShiftsUpdateService { diff --git a/src/time-and-attendance/shifts/shift.controller.ts b/src/time-and-attendance/shifts/shift.controller.ts index e94d7b4..ccd6799 100644 --- a/src/time-and-attendance/shifts/shift.controller.ts +++ b/src/time-and-attendance/shifts/shift.controller.ts @@ -1,7 +1,7 @@ import { Body, Controller, Delete, Param, Patch, Post } from "@nestjs/common"; import { Modules as ModulesEnum } from ".prisma/client"; -import { ShiftDto } from "src/time-and-attendance/shifts/shift-create.dto"; +import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service"; import { ShiftsUpdateService } from "src/time-and-attendance/shifts/services/shifts-update-delete.service"; import { ShiftsDeleteService } from "src/time-and-attendance/shifts/services/shifts-delete.service"; diff --git a/src/time-and-attendance/shifts/shift-create.dto.ts b/src/time-and-attendance/shifts/shift.dto.ts similarity index 91% rename from src/time-and-attendance/shifts/shift-create.dto.ts rename to src/time-and-attendance/shifts/shift.dto.ts index c762b0f..7cc9cd7 100644 --- a/src/time-and-attendance/shifts/shift-create.dto.ts +++ b/src/time-and-attendance/shifts/shift.dto.ts @@ -1,16 +1,13 @@ import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validator"; export class ShiftDto { - @IsInt() @IsOptional() id: number; + @IsInt() @IsOptional() id?: number; @IsInt() timesheet_id!: number; @IsString() type!: string; - @IsString() date!: string; @IsString() start_time!: string; @IsString() end_time!: string; - @IsBoolean() is_approved!: boolean; @IsBoolean() is_remote!: boolean; - @IsOptional() @IsString() @MaxLength(280) comment?: string; } \ No newline at end of file diff --git a/src/time-and-attendance/time-and-attendance.module.ts b/src/time-and-attendance/time-and-attendance.module.ts index 3783142..bdc20fd 100644 --- a/src/time-and-attendance/time-and-attendance.module.ts +++ b/src/time-and-attendance/time-and-attendance.module.ts @@ -36,6 +36,7 @@ import { SchedulePresetsModule } from "src/time-and-attendance/schedule-presets/ import { SchedulePresetDeleteService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service"; import { SchedulePresetUpdateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-update.service"; import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-create.service"; +import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service"; @Module({ imports: [ @@ -65,6 +66,7 @@ import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-p ExpenseUpsertService, SchedulePresetsGetService, SchedulePresetDeleteService, + SchedulePresetsApplyService, SchedulePresetUpdateService, SchedulePresetsCreateService, EmailToIdResolver, diff --git a/src/time-and-attendance/utils/type.utils.ts b/src/time-and-attendance/utils/type.utils.ts index 543f52c..e8b518a 100644 --- a/src/time-and-attendance/utils/type.utils.ts +++ b/src/time-and-attendance/utils/type.utils.ts @@ -26,7 +26,6 @@ export type NormalizedLeaveRequest = { export type ShiftResponse = { week_day: string; - sort_order: number; start_time: string; end_time: string; is_remote: boolean; @@ -40,8 +39,3 @@ export type PresetResponse = { shifts: ShiftResponse[]; } -export type ApplyResult = { - timesheet_id: number; - created: number; - skipped: number; -}