feat(schedule-presets): added a service that applies a preset to an existing timesheet. did some cleaning in utils and dtos
This commit is contained in:
parent
74e16d7960
commit
b6132c8b35
|
|
@ -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": {
|
"/expense/create": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "ExpenseController_create",
|
"operationId": "ExpenseController_create",
|
||||||
|
|
|
||||||
|
|
@ -167,13 +167,12 @@ model SchedulePresetShifts {
|
||||||
bank_code BankCodes @relation("SchedulePresetShiftsBankCodes", fields: [bank_code_id], references: [id])
|
bank_code BankCodes @relation("SchedulePresetShiftsBankCodes", fields: [bank_code_id], references: [id])
|
||||||
bank_code_id Int
|
bank_code_id Int
|
||||||
|
|
||||||
sort_order Int
|
|
||||||
start_time DateTime @db.Time(0)
|
start_time DateTime @db.Time(0)
|
||||||
end_time DateTime @db.Time(0)
|
end_time DateTime @db.Time(0)
|
||||||
is_remote Boolean @default(false)
|
is_remote Boolean @default(false)
|
||||||
week_day Weekday
|
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])
|
@@index([preset_id, week_day])
|
||||||
@@map("schedule_preset_shifts")
|
@@map("schedule_preset_shifts")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
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
|
//lenght of a shift, rouded to nearest 'x' minute
|
||||||
export function computeHours(start: Date, end: Date, roundToMinutes?: number): number {
|
export function computeHours(start: Date, end: Date, roundToMinutes?: number): number {
|
||||||
|
|
@ -11,16 +14,16 @@ export function computeHours(start: Date, end: Date, roundToMinutes?: number): n
|
||||||
|
|
||||||
//round the amount of hours to quarter
|
//round the amount of hours to quarter
|
||||||
export function roundToQuarterHour(hours: number): number {
|
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)
|
// fetch firts day of the week (Sunday)
|
||||||
export function getWeekStart(date:Date, firstDayOfWeek = 0): Date {
|
export function getWeekStart(date: Date, firstDayOfWeek = 0): Date {
|
||||||
const d = new Date(date);
|
const d = new Date(date);
|
||||||
const day = d.getDay();
|
const day = d.getDay();
|
||||||
const diff = (day < firstDayOfWeek ? 7 : 0) + (day - firstDayOfWeek);
|
const diff = (day < firstDayOfWeek ? 7 : 0) + (day - firstDayOfWeek);
|
||||||
d.setDate(d.getDate() - diff);
|
d.setDate(d.getDate() - diff);
|
||||||
d.setHours(0,0,0,0);
|
d.setHours(0, 0, 0, 0);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,13 +31,13 @@ export function getWeekStart(date:Date, firstDayOfWeek = 0): Date {
|
||||||
export function getWeekEnd(startOfWeek: Date): Date {
|
export function getWeekEnd(startOfWeek: Date): Date {
|
||||||
const d = new Date(startOfWeek);
|
const d = new Date(startOfWeek);
|
||||||
d.setDate(d.getDate() + 6);
|
d.setDate(d.getDate() + 6);
|
||||||
d.setHours(23,59,59,999);
|
d.setHours(23, 59, 59, 999);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
//returns january 1st of the selected date's year
|
//returns january 1st of the selected date's year
|
||||||
export function getYearStart(date:Date): Date {
|
export function getYearStart(date: Date): Date {
|
||||||
return new Date(date.getFullYear(),0,1,0,0,0,0);
|
return new Date(date.getFullYear(), 0, 1, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//to be used to calculate breaks time
|
//to be used to calculate breaks time
|
||||||
|
|
@ -51,9 +54,6 @@ export function hoursBetweenSameDay(day: Date, startTime: Date, endTime: Date):
|
||||||
return ms / 3_600_000; // decimal hours
|
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
|
//ensures the week starts from sunday
|
||||||
export function weekStartSunday(date_local: Date): Date {
|
export function weekStartSunday(date_local: Date): Date {
|
||||||
const start_date = new 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));
|
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; }) =>
|
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));
|
((a.date?.getTime() === b.date?.getTime()) && !(a.end <= b.start || a.start >= b.end));
|
||||||
|
|
||||||
|
export const is_same_week_day = (date: Date, week_day: Weekday): boolean => {
|
||||||
export const hhmmFromLocal = (d: Date) =>
|
return date.getUTCDay() !== WEEKDAY_MAP[week_day];
|
||||||
`${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)))));
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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[];
|
|
||||||
}
|
|
||||||
|
|
@ -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 { 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 { 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 { 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 { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||||
import { Modules as ModulesEnum } from ".prisma/client";
|
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')
|
@Controller('schedule-presets')
|
||||||
export class SchedulePresetsController {
|
export class SchedulePresetsController {
|
||||||
|
|
@ -16,6 +18,7 @@ export class SchedulePresetsController {
|
||||||
private readonly createService: SchedulePresetsCreateService,
|
private readonly createService: SchedulePresetsCreateService,
|
||||||
private readonly updateService: SchedulePresetUpdateService,
|
private readonly updateService: SchedulePresetUpdateService,
|
||||||
private readonly deleteService: SchedulePresetDeleteService,
|
private readonly deleteService: SchedulePresetDeleteService,
|
||||||
|
private readonly applyService: SchedulePresetsApplyService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@Get('find-list')
|
@Get('find-list')
|
||||||
|
|
@ -43,4 +46,12 @@ export class SchedulePresetsController {
|
||||||
@Param('id', ParseIntPipe) id: number) {
|
@Param('id', ParseIntPipe) id: number) {
|
||||||
return await this.deleteService.deletePreset(id);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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<Weekday, number> = {
|
||||||
|
SUN: 0,
|
||||||
|
MON: 1,
|
||||||
|
TUE: 2,
|
||||||
|
WED: 3,
|
||||||
|
THU: 4,
|
||||||
|
FRI: 5,
|
||||||
|
SAT: 6,
|
||||||
|
};
|
||||||
|
|
@ -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 { 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 { 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 { 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,
|
SchedulePresetsCreateService,
|
||||||
SchedulePresetUpdateService,
|
SchedulePresetUpdateService,
|
||||||
SchedulePresetDeleteService,
|
SchedulePresetDeleteService,
|
||||||
|
SchedulePresetsApplyService,
|
||||||
|
EmailToIdResolver,
|
||||||
|
ShiftsCreateService,
|
||||||
BankCodesResolver,
|
BankCodesResolver,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
|
|
|
||||||
|
|
@ -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<Result<boolean, string>> {
|
||||||
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import { Injectable } from "@nestjs/common";
|
||||||
|
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
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 { overlaps, toDateFromHHmm } from "src/common/utils/date-utils";
|
||||||
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
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 };
|
const result = bank_code_results[index] as { success: true, data: number };
|
||||||
return {
|
return {
|
||||||
week_day: shift.week_day,
|
week_day: shift.week_day,
|
||||||
sort_order: shift.sort_order,
|
|
||||||
start_time: toDateFromHHmm(shift.start_time),
|
start_time: toDateFromHHmm(shift.start_time),
|
||||||
end_time: toDateFromHHmm(shift.end_time),
|
end_time: toDateFromHHmm(shift.end_time),
|
||||||
is_remote: shift.is_remote ?? false,
|
is_remote: shift.is_remote ?? false,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export class SchedulePresetsGetService {
|
||||||
orderBy: [{ is_default: 'desc' }, { name: 'asc' }],
|
orderBy: [{ is_default: 'desc' }, { name: 'asc' }],
|
||||||
include: {
|
include: {
|
||||||
shifts: {
|
shifts: {
|
||||||
orderBy: [{ week_day: 'asc' }, { sort_order: 'asc' }],
|
orderBy: [{ week_day: 'asc' }],
|
||||||
include: { bank_code: { select: { type: true } } },
|
include: { bank_code: { select: { type: true } } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -31,7 +31,6 @@ export class SchedulePresetsGetService {
|
||||||
is_default: preset.is_default,
|
is_default: preset.is_default,
|
||||||
shifts: preset.shifts.map<ShiftResponse>((shift) => ({
|
shifts: preset.shifts.map<ShiftResponse>((shift) => ({
|
||||||
week_day: shift.week_day,
|
week_day: shift.week_day,
|
||||||
sort_order: shift.sort_order,
|
|
||||||
start_time: hhmm(shift.start_time),
|
start_time: hhmm(shift.start_time),
|
||||||
end_time: hhmm(shift.end_time),
|
end_time: hhmm(shift.end_time),
|
||||||
is_remote: shift.is_remote,
|
is_remote: shift.is_remote,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
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 { overlaps, toDateFromHHmm } from "src/common/utils/date-utils";
|
||||||
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
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 };
|
const result = bank_code_results[index] as { success: true, data: number };
|
||||||
return {
|
return {
|
||||||
week_day: shift.week_day,
|
week_day: shift.week_day,
|
||||||
sort_order: shift.sort_order,
|
|
||||||
start_time: toDateFromHHmm(shift.start_time),
|
start_time: toDateFromHHmm(shift.start_time),
|
||||||
end_time: toDateFromHHmm(shift.end_time),
|
end_time: toDateFromHHmm(shift.end_time),
|
||||||
is_remote: shift.is_remote ?? false,
|
is_remote: shift.is_remote ?? false,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
import { PrismaService } from "src/prisma/prisma.service";
|
||||||
import { Result } from "src/common/errors/result-error.factory";
|
import { Result } from "src/common/errors/result-error.factory";
|
||||||
import { toStringFromHHmm, toStringFromDate, toDateFromString, overlaps, toDateFromHHmm } from "src/common/utils/date-utils";
|
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()
|
@Injectable()
|
||||||
export class ShiftsCreateService {
|
export class ShiftsCreateService {
|
||||||
|
|
|
||||||
|
|
@ -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 { shift_select } from "src/time-and-attendance/utils/selects.utils";
|
||||||
import { Normalized } from "src/time-and-attendance/utils/type.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()
|
@Injectable()
|
||||||
export class ShiftsUpdateService {
|
export class ShiftsUpdateService {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Body, Controller, Delete, Param, Patch, Post } from "@nestjs/common";
|
import { Body, Controller, Delete, Param, Patch, Post } from "@nestjs/common";
|
||||||
import { Modules as ModulesEnum } from ".prisma/client";
|
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 { 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 { ShiftsUpdateService } from "src/time-and-attendance/shifts/services/shifts-update-delete.service";
|
||||||
import { ShiftsDeleteService } from "src/time-and-attendance/shifts/services/shifts-delete.service";
|
import { ShiftsDeleteService } from "src/time-and-attendance/shifts/services/shifts-delete.service";
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validator";
|
import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validator";
|
||||||
|
|
||||||
export class ShiftDto {
|
export class ShiftDto {
|
||||||
@IsInt() @IsOptional() id: number;
|
@IsInt() @IsOptional() id?: number;
|
||||||
@IsInt() timesheet_id!: number;
|
@IsInt() timesheet_id!: number;
|
||||||
@IsString() type!: string;
|
@IsString() type!: string;
|
||||||
|
|
||||||
@IsString() date!: string;
|
@IsString() date!: string;
|
||||||
@IsString() start_time!: string;
|
@IsString() start_time!: string;
|
||||||
@IsString() end_time!: string;
|
@IsString() end_time!: string;
|
||||||
|
|
||||||
@IsBoolean() is_approved!: boolean;
|
@IsBoolean() is_approved!: boolean;
|
||||||
@IsBoolean() is_remote!: boolean;
|
@IsBoolean() is_remote!: boolean;
|
||||||
|
|
||||||
@IsOptional() @IsString() @MaxLength(280) comment?: string;
|
@IsOptional() @IsString() @MaxLength(280) comment?: string;
|
||||||
}
|
}
|
||||||
|
|
@ -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 { 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 { 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 { 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({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
|
@ -65,6 +66,7 @@ import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-p
|
||||||
ExpenseUpsertService,
|
ExpenseUpsertService,
|
||||||
SchedulePresetsGetService,
|
SchedulePresetsGetService,
|
||||||
SchedulePresetDeleteService,
|
SchedulePresetDeleteService,
|
||||||
|
SchedulePresetsApplyService,
|
||||||
SchedulePresetUpdateService,
|
SchedulePresetUpdateService,
|
||||||
SchedulePresetsCreateService,
|
SchedulePresetsCreateService,
|
||||||
EmailToIdResolver,
|
EmailToIdResolver,
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ export type NormalizedLeaveRequest = {
|
||||||
|
|
||||||
export type ShiftResponse = {
|
export type ShiftResponse = {
|
||||||
week_day: string;
|
week_day: string;
|
||||||
sort_order: number;
|
|
||||||
start_time: string;
|
start_time: string;
|
||||||
end_time: string;
|
end_time: string;
|
||||||
is_remote: boolean;
|
is_remote: boolean;
|
||||||
|
|
@ -40,8 +39,3 @@ export type PresetResponse = {
|
||||||
shifts: ShiftResponse[];
|
shifts: ShiftResponse[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ApplyResult = {
|
|
||||||
timesheet_id: number;
|
|
||||||
created: number;
|
|
||||||
skipped: number;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user