feat(schedulePresets): ajusted the create function. added validation of the name and overlaps checking
This commit is contained in:
parent
35665d49dd
commit
c5c96cce22
|
|
@ -1,40 +1,40 @@
|
||||||
// import { Controller, Param, Query, Body, Get, Post, ParseIntPipe, Delete, Patch, Req } from "@nestjs/common";
|
import { Controller, Param, Query, Body, Get, Post, ParseIntPipe, Delete, Patch, Req } from "@nestjs/common";
|
||||||
// import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||||
// import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes";
|
import { GLOBAL_CONTROLLER_ROLES, MANAGER_ROLES } from "src/common/shared/role-groupes";
|
||||||
// import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto";
|
import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto";
|
||||||
// import { SchedulePresetsUpdateDto } from "src/time-and-attendance/schedule-presets/dtos/update-schedule-presets.dto";
|
// import { SchedulePresetsUpdateDto } from "src/time-and-attendance/schedule-presets/dtos/update-schedule-presets.dto";
|
||||||
// import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service";
|
import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.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 { SchedulePresetsUpsertService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-upsert.service";
|
import { SchedulePresetsUpsertService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-upsert.service";
|
||||||
|
|
||||||
// @Controller('schedule-presets')
|
@Controller('schedule-presets')
|
||||||
// @RolesAllowed(...GLOBAL_CONTROLLER_ROLES)
|
@RolesAllowed(...GLOBAL_CONTROLLER_ROLES)
|
||||||
// export class SchedulePresetsController {
|
export class SchedulePresetsController {
|
||||||
// constructor(
|
constructor(
|
||||||
// private readonly upsertService: SchedulePresetsUpsertService,
|
private readonly upsertService: SchedulePresetsUpsertService,
|
||||||
// private readonly getService: SchedulePresetsGetService,
|
private readonly getService: SchedulePresetsGetService,
|
||||||
// private readonly applyPresetsService: SchedulePresetsApplyService,
|
private readonly applyPresetsService: SchedulePresetsApplyService,
|
||||||
// ) { }
|
) { }
|
||||||
|
|
||||||
// //used to create a schedule preset
|
// used to create a schedule preset
|
||||||
// @Post('create')
|
@Post('create')
|
||||||
|
@RolesAllowed(...MANAGER_ROLES)
|
||||||
|
async createPreset(@Req() req, @Body() dto: SchedulePresetsDto) {
|
||||||
|
const email = req.user?.email;
|
||||||
|
return await this.upsertService.createPreset(email, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
// //used to update an already existing schedule preset
|
||||||
|
// @Patch('update/:preset_id')
|
||||||
// @RolesAllowed(...MANAGER_ROLES)
|
// @RolesAllowed(...MANAGER_ROLES)
|
||||||
// async createPreset(@Req() req, @Body() dto: SchedulePresetsDto) {
|
// async updatePreset(
|
||||||
// const email = req.user?.email;
|
// @Param('preset_id', ParseIntPipe) preset_id: number,
|
||||||
// return await this.upsertService.createPreset(email, dto);
|
// @Body() dto: SchedulePresetsUpdateDto
|
||||||
|
// ) {
|
||||||
|
// return await this.upsertService.updatePreset(preset_id, dto);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // //used to update an already existing schedule preset
|
//used to delete a schedule preset
|
||||||
// // @Patch('update/:preset_id')
|
|
||||||
// // @RolesAllowed(...MANAGER_ROLES)
|
|
||||||
// // async updatePreset(
|
|
||||||
// // @Param('preset_id', ParseIntPipe) preset_id: number,
|
|
||||||
// // @Body() dto: SchedulePresetsUpdateDto
|
|
||||||
// // ) {
|
|
||||||
// // return await this.upsertService.updatePreset(preset_id, dto);
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// //used to delete a schedule preset
|
|
||||||
// @Delete('delete/:preset_id')
|
// @Delete('delete/:preset_id')
|
||||||
// @RolesAllowed(...MANAGER_ROLES)
|
// @RolesAllowed(...MANAGER_ROLES)
|
||||||
// async deletePreset(
|
// async deletePreset(
|
||||||
|
|
@ -43,22 +43,24 @@
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
// //used to show the list of available schedule presets
|
//used to show the list of available schedule presets
|
||||||
// @Get('find-list')
|
@Get('find-list')
|
||||||
// @RolesAllowed(...MANAGER_ROLES)
|
@RolesAllowed(...MANAGER_ROLES)
|
||||||
// async findListById(@Req() req) {
|
async findListById(
|
||||||
// const email = req.user?.email;
|
@Req() req
|
||||||
// return this.getService.getSchedulePresets(email);
|
) {
|
||||||
// }
|
const email = req.user?.email;
|
||||||
|
return this.getService.getSchedulePresets(email);
|
||||||
|
}
|
||||||
|
|
||||||
// //used to apply a preset to a timesheet
|
//used to apply a preset to a timesheet
|
||||||
// @Post('apply-presets')
|
@Post('apply-presets')
|
||||||
// async applyPresets(
|
async applyPresets(
|
||||||
// @Req() req,
|
@Req() req,
|
||||||
// @Body('preset') preset_id: number,
|
@Body('preset') preset_id: number,
|
||||||
// @Body('start') start_date: string
|
@Body('start') start_date: string
|
||||||
// ) {
|
) {
|
||||||
// const email = req.user?.email;
|
const email = req.user?.email;
|
||||||
// return this.applyPresetsService.applyToTimesheet(email, preset_id, start_date);
|
return this.applyPresetsService.applyToTimesheet(email, preset_id, start_date);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
@ -3,28 +3,11 @@ import { HH_MM_REGEX } from "src/common/utils/constants.utils";
|
||||||
import { Weekday } from "@prisma/client";
|
import { Weekday } from "@prisma/client";
|
||||||
|
|
||||||
export class SchedulePresetShiftsDto {
|
export class SchedulePresetShiftsDto {
|
||||||
@IsEnum(Weekday)
|
@IsInt() preset_id!: number;
|
||||||
week_day!: Weekday;
|
@IsEnum(Weekday) week_day!: Weekday;
|
||||||
|
@IsInt() @Min(1) sort_order!: number;
|
||||||
@IsInt()
|
@IsString() type!: string;
|
||||||
preset_id!: number;
|
@IsString() @Matches(HH_MM_REGEX) start_time!: string;
|
||||||
|
@IsString() @Matches(HH_MM_REGEX) end_time!: string;
|
||||||
@IsInt()
|
@IsOptional() @IsBoolean() is_remote?: boolean;
|
||||||
@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;
|
|
||||||
}
|
}
|
||||||
|
|
@ -2,18 +2,8 @@ import { ArrayMinSize, IsArray, IsBoolean, IsInt, IsOptional, IsString } from "c
|
||||||
import { SchedulePresetShiftsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-preset-shifts.dto";
|
import { SchedulePresetShiftsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-preset-shifts.dto";
|
||||||
|
|
||||||
export class SchedulePresetsDto {
|
export class SchedulePresetsDto {
|
||||||
|
@IsInt() id!: number;
|
||||||
@IsInt()
|
@IsString() name!: string;
|
||||||
id!: number;
|
@IsBoolean() @IsOptional() is_default: boolean;
|
||||||
|
@IsArray() @ArrayMinSize(1) preset_shifts: SchedulePresetShiftsDto[];
|
||||||
@IsString()
|
|
||||||
name!: string;
|
|
||||||
|
|
||||||
@IsBoolean()
|
|
||||||
@IsOptional()
|
|
||||||
is_default: boolean;
|
|
||||||
|
|
||||||
@IsArray()
|
|
||||||
@ArrayMinSize(1)
|
|
||||||
preset_shifts: SchedulePresetShiftsDto[];
|
|
||||||
}
|
}
|
||||||
|
|
@ -9,7 +9,10 @@ import { Result } from "src/common/errors/result-error.factory";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SchedulePresetsApplyService {
|
export class SchedulePresetsApplyService {
|
||||||
constructor(private readonly prisma: PrismaService, private readonly emailResolver: EmailToIdResolver) { }
|
constructor(
|
||||||
|
private readonly prisma: PrismaService,
|
||||||
|
private readonly emailResolver: EmailToIdResolver
|
||||||
|
) { }
|
||||||
|
|
||||||
async applyToTimesheet(email: string, id: number, start_date_iso: string): Promise<Result<ApplyResult, string>> {
|
async applyToTimesheet(email: string, id: number, start_date_iso: string): Promise<Result<ApplyResult, string>> {
|
||||||
if (!DATE_ISO_FORMAT.test(start_date_iso)) return { success: false, error: 'start_date must be of format :YYYY-MM-DD' };
|
if (!DATE_ISO_FORMAT.test(start_date_iso)) return { success: false, error: 'start_date must be of format :YYYY-MM-DD' };
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,97 @@
|
||||||
// import { Injectable, BadRequestException, NotFoundException, ConflictException } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
// import { Prisma, Weekday } from "@prisma/client";
|
import { Weekday } from "@prisma/client";
|
||||||
// import { PrismaService } from "src/prisma/prisma.service";
|
import { PrismaService } from "src/prisma/prisma.service";
|
||||||
// import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
||||||
// import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
|
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
|
||||||
// import { Result } from "src/common/errors/result-error.factory";
|
import { Result } from "src/common/errors/result-error.factory";
|
||||||
// import { toHHmmFromDate, toDateFromString } from "src/common/utils/date-utils";
|
import { overlaps, toDateFromHHmm } from "src/common/utils/date-utils";
|
||||||
// import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto";
|
import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/dtos/create-schedule-presets.dto";
|
||||||
|
|
||||||
// @Injectable()
|
@Injectable()
|
||||||
// export class SchedulePresetsUpsertService {
|
export class SchedulePresetsUpsertService {
|
||||||
// constructor(
|
constructor(
|
||||||
// private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
// private readonly typeResolver: BankCodesResolver,
|
private readonly typeResolver: BankCodesResolver,
|
||||||
// private readonly emailResolver: EmailToIdResolver,
|
private readonly emailResolver: EmailToIdResolver,
|
||||||
// ) { }
|
) { }
|
||||||
// //_________________________________________________________________
|
//_________________________________________________________________
|
||||||
// // CREATE
|
// CREATE
|
||||||
// //_________________________________________________________________
|
//_________________________________________________________________
|
||||||
// async createPreset(email: string, dto: SchedulePresetsDto): Promise<Result<SchedulePresetsDto, string>> {
|
async createPreset(email: string, dto: SchedulePresetsDto): Promise<Result<boolean, string>> {
|
||||||
// try {
|
//validate email and fetch employee_id
|
||||||
// const shifts_data = await this.normalizePresetShifts(dto);
|
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||||
// if (!shifts_data.success) return { success: false, error: `Employee with email: ${email} or dto not found` };
|
if (!employee_id.success) return { success: false, error: employee_id.error };
|
||||||
|
|
||||||
// const employee_id = await this.emailResolver.findIdByEmail(email);
|
//validate new unique name
|
||||||
// if (!employee_id.success) return { success: false, error: employee_id.error };
|
const existing = await this.prisma.schedulePresets.findFirst({
|
||||||
|
where: { name: dto.name, employee_id: employee_id.data },
|
||||||
|
select: { name: true },
|
||||||
|
});
|
||||||
|
if (!existing) return { success: false, error: 'INVALID_SCHEDULE_PRESET' };
|
||||||
|
|
||||||
// const created = await this.prisma.$transaction(async (tx) => {
|
const normalized_shifts = dto.preset_shifts.map((shift) => ({
|
||||||
// if (dto.is_default) {
|
...shift,
|
||||||
// await tx.schedulePresets.updateMany({
|
start: toDateFromHHmm(shift.start_time),
|
||||||
// where: { is_default: true, employee_id: employee_id.data },
|
end: toDateFromHHmm(shift.end_time),
|
||||||
// data: { is_default: false },
|
}));
|
||||||
// });
|
|
||||||
// await tx.schedulePresets.create({
|
for (const preset_shifts of normalized_shifts) {
|
||||||
// data: {
|
for (const other_shifts of normalized_shifts) {
|
||||||
// id: dto.id,
|
//skip if same object or id week_day is not the same
|
||||||
// employee_id: employee_id.data,
|
if (preset_shifts === other_shifts) continue;
|
||||||
// name: dto.name,
|
if (preset_shifts.week_day !== other_shifts.week_day) continue;
|
||||||
// is_default: !!dto.is_default,
|
//check overlaping possibilities
|
||||||
// shifts: { create: shifts_data.data },
|
const has_overlap = overlaps(
|
||||||
// },
|
{ start: preset_shifts.start, end: preset_shifts.end },
|
||||||
// });
|
{ start: other_shifts.start, end: other_shifts.end },
|
||||||
// return { success: true, data: created }
|
)
|
||||||
// }
|
if (has_overlap) return { success: false, error: 'SCHEDULE_PRESET_OVERLAP' };
|
||||||
// });
|
}
|
||||||
// return { success: true, data: created }
|
}
|
||||||
// } catch (error) {
|
//validate bank_code_id/type and map them
|
||||||
// return { success: false, error: ' An error occured during create. Invalid Schedule data' };
|
const bank_code_results = await Promise.all(dto.preset_shifts.map((shift) =>
|
||||||
// }
|
this.typeResolver.findBankCodeIDByType(shift.type),
|
||||||
// }
|
));
|
||||||
|
for (const result of bank_code_results) {
|
||||||
|
if (!result.success) return { success: false, error: 'INVALID_SCHEDULE_PRESET' }
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.prisma.$transaction(async (tx) => {
|
||||||
|
//check if employee chose this preset has a default preset and ensure all others are false
|
||||||
|
if (dto.is_default) {
|
||||||
|
await tx.schedulePresets.updateMany({
|
||||||
|
where: { employee_id: employee_id.data, is_default: true },
|
||||||
|
data: { is_default: false },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await tx.schedulePresets.create({
|
||||||
|
data: {
|
||||||
|
employee_id: employee_id.data,
|
||||||
|
name: dto.name,
|
||||||
|
is_default: dto.is_default ?? false,
|
||||||
|
shifts: {
|
||||||
|
create: dto.preset_shifts.map((shift, index) => {
|
||||||
|
//validated bank_codes sent as a Result Array to access its data
|
||||||
|
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,
|
||||||
|
bank_code: {
|
||||||
|
//connect uses the FK links to set the bank_code_id
|
||||||
|
connect: { id: result.data },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return { success: true, data: true }
|
||||||
|
}
|
||||||
|
|
||||||
// //_________________________________________________________________
|
// //_________________________________________________________________
|
||||||
// // UPDATE
|
// // UPDATE
|
||||||
|
|
@ -173,55 +217,24 @@
|
||||||
|
|
||||||
// //PRIVATE HELPERS
|
// //PRIVATE HELPERS
|
||||||
|
|
||||||
// //resolve bank_code_id using type and convert hours to TIME and valid shifts end/start
|
//resolve bank_code_id using type and convert hours to TIME and valid shifts end/start
|
||||||
// private async normalizePresetShifts(
|
// private async normalizePresetShifts(preset_shift: SchedulePresetShiftsDto, schedul_preset: SchedulePresetsDto): Promise<Result<Normalized, string>> {
|
||||||
// dto: SchedulePresetsDto
|
|
||||||
// ): Promise<Result<Prisma.SchedulePresetShiftsCreateWithoutPresetInput[], string>> {
|
|
||||||
// if (!dto.preset_shifts?.length) return { success: false, error: `Empty or preset shifts not found` }
|
|
||||||
|
|
||||||
// const types = Array.from(new Set(dto.preset_shifts.map((shift) => shift.type)));
|
// const bank_code = await this.typeResolver.findIdAndModifierByType(preset_shift.type);
|
||||||
// const bank_code_set = new Map<string, number>();
|
// if (!bank_code.success) return { success: false, error: 'INVALID_SCHEDULE_PRESET_SHIFT' };
|
||||||
|
|
||||||
// for (const type of types) {
|
// const start = await toDateFromHHmm(preset_shift.start_time);
|
||||||
// const bank_code = await this.typeResolver.findIdAndModifierByType(type);
|
// const end = await toDateFromHHmm(preset_shift.end_time);
|
||||||
// if (!bank_code.success) return { success: false, error: 'Bank_code not found' }
|
|
||||||
// bank_code_set.set(type, bank_code.data.id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const pair_set = new Set<string>();
|
// //TODO: add a way to fetch
|
||||||
// for (const shift of dto.preset_shifts) {
|
|
||||||
// const key = `${shift.week_day}:${shift.sort_order}`;
|
|
||||||
// if (pair_set.has(key)) {
|
|
||||||
// return { success: false, error: `Duplicate shift for day/order (${shift.week_day}, ${shift.sort_order})` }
|
|
||||||
// }
|
|
||||||
// pair_set.add(key);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const items = await dto.preset_shifts.map((shift) => {
|
|
||||||
// try {
|
// const normalized_preset_shift:Normalized = {
|
||||||
// const bank_code_id = bank_code_set.get(shift.type);
|
// date: ,
|
||||||
// if (!bank_code_id) return { success: false, error: `Bank code not found for type ${shift.type}` }
|
|
||||||
// if (!shift.start_time || !shift.end_time) {
|
|
||||||
// return { success: false, error: `start_time and end_time are required for (${shift.week_day}, ${shift.sort_order})` }
|
|
||||||
// }
|
|
||||||
// const start = toDateFromString(shift.start_time);
|
|
||||||
// const end = toDateFromString(shift.end_time);
|
|
||||||
// if (end.getTime() <= start.getTime()) {
|
|
||||||
// return { success: false, error: `end_time must be > start_time ( day: ${shift.week_day}, order: ${shift.sort_order})` }
|
|
||||||
// }
|
|
||||||
// return {
|
|
||||||
// sort_order: shift.sort_order,
|
|
||||||
// start_time : start,
|
// start_time : start,
|
||||||
// end_time: end,
|
// end_time: end,
|
||||||
// is_remote: !!shift.is_remote,
|
// bank_code_id: bank_code.data.id,
|
||||||
// week_day: shift.week_day as Weekday,
|
|
||||||
// bank_code: { connect: { id: bank_code_id } },
|
|
||||||
// }
|
|
||||||
|
|
||||||
// } catch (error) {
|
|
||||||
// return { success: false, error: '' }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// return { success: true, data: items};
|
|
||||||
// }
|
// }
|
||||||
|
// return { success: true data: normalized_preset_shift }
|
||||||
// }
|
// }
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user