feat(presets): small ajustements
This commit is contained in:
parent
03d9fa2cf4
commit
6332a42fa7
|
|
@ -55,10 +55,10 @@ export class SchedulePresetsController {
|
||||||
@Post('apply-presets')
|
@Post('apply-presets')
|
||||||
async applyPresets(
|
async applyPresets(
|
||||||
@Req() req,
|
@Req() req,
|
||||||
@Body('preset') preset_name: string,
|
@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_name, start_date);
|
return this.applyPresetsService.applyToTimesheet(email, preset_id, start_date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
import { ArrayMinSize, IsArray, IsBoolean, IsOptional, IsString } from "class-validator";
|
import { ArrayMinSize, IsArray, IsBoolean, IsInt, IsOptional, IsString } from "class-validator";
|
||||||
import { SchedulePresetShiftsDto } from "src/time-and-attendance/time-tracker/schedule-presets/dtos/create-schedule-preset-shifts.dto";
|
import { SchedulePresetShiftsDto } from "src/time-and-attendance/time-tracker/schedule-presets/dtos/create-schedule-preset-shifts.dto";
|
||||||
|
|
||||||
export class SchedulePresetsDto {
|
export class SchedulePresetsDto {
|
||||||
|
|
||||||
|
@IsInt()
|
||||||
|
id!: number;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
name!: string;
|
name!: string;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,19 @@ import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-i
|
||||||
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, preset_name: string, start_date_iso: string ): Promise<ApplyResult> {
|
async applyToTimesheet( email: string, id: number, start_date_iso: string ): Promise<ApplyResult> {
|
||||||
if(!preset_name?.trim()) throw new BadRequestException('A preset_name is required');
|
if(!id) throw new BadRequestException(`Schedule preset with id: ${id} not found`);
|
||||||
if(!DATE_ISO_FORMAT.test(start_date_iso)) throw new BadRequestException('start_date must be of format :YYYY-MM-DD');
|
if(!DATE_ISO_FORMAT.test(start_date_iso)) throw new BadRequestException('start_date must be of format :YYYY-MM-DD');
|
||||||
|
|
||||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||||
|
|
||||||
const preset = await this.prisma.schedulePresets.findFirst({
|
const preset = await this.prisma.schedulePresets.findFirst({
|
||||||
where: { employee_id, name: preset_name },
|
where: { employee_id, id },
|
||||||
include: {
|
include: {
|
||||||
shifts: {
|
shifts: {
|
||||||
orderBy: [{ week_day: 'asc'}, { sort_order: 'asc'}],
|
orderBy: [{ week_day: 'asc'}, { sort_order: 'asc'}],
|
||||||
select: {
|
select: {
|
||||||
|
id: true,
|
||||||
week_day: true,
|
week_day: true,
|
||||||
sort_order: true,
|
sort_order: true,
|
||||||
start_time: true,
|
start_time: true,
|
||||||
|
|
|
||||||
|
|
@ -10,127 +10,131 @@ import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-i
|
||||||
@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<CreatePresetResult> {
|
async createPreset(email: string, dto: SchedulePresetsDto): Promise<CreatePresetResult> {
|
||||||
try {
|
try {
|
||||||
const shifts_data = await this.resolveAndBuildPresetShifts(dto);
|
const shifts_data = await this.resolveAndBuildPresetShifts(dto);
|
||||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||||
if(!shifts_data) throw new BadRequestException(`Employee with email: ${email} or dto not found`);
|
if (!shifts_data) throw new BadRequestException(`Employee with email: ${email} or dto not found`);
|
||||||
|
|
||||||
await this.prisma.$transaction(async (tx)=> {
|
await this.prisma.$transaction(async (tx) => {
|
||||||
if(dto.is_default) {
|
if (dto.is_default) {
|
||||||
await tx.schedulePresets.updateMany({
|
await tx.schedulePresets.updateMany({
|
||||||
where: { is_default: true, employee_id },
|
where: { is_default: true, employee_id },
|
||||||
data: { is_default: false },
|
data: { is_default: false },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const created = await tx.schedulePresets.create({
|
const created = await tx.schedulePresets.create({
|
||||||
data: {
|
data: {
|
||||||
|
id: dto.id,
|
||||||
employee_id,
|
employee_id,
|
||||||
name: dto.name,
|
name: dto.name,
|
||||||
is_default: !!dto.is_default,
|
is_default: !!dto.is_default,
|
||||||
shifts: { create: shifts_data},
|
shifts: { create: shifts_data },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return created;
|
return created;
|
||||||
});
|
});
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return { ok: false, error };
|
return { ok: false, error };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//_________________________________________________________________
|
//_________________________________________________________________
|
||||||
// UPDATE
|
// UPDATE
|
||||||
//_________________________________________________________________
|
//_________________________________________________________________
|
||||||
async updatePreset( preset_id: number, dto: SchedulePresetsDto ): Promise<UpdatePresetResult> {
|
async updatePreset(preset_id: number, dto: SchedulePresetsDto): Promise<UpdatePresetResult> {
|
||||||
try {
|
try {
|
||||||
const existing = await this.prisma.schedulePresets.findFirst({
|
const existing = await this.prisma.schedulePresets.findFirst({
|
||||||
where: { id: preset_id },
|
where: { id: preset_id },
|
||||||
select: {
|
select: {
|
||||||
id:true,
|
id: true,
|
||||||
is_default: true,
|
is_default: true,
|
||||||
employee_id: true,
|
employee_id: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if(!existing) throw new NotFoundException(`Preset "${dto.name}" not found`);
|
if (!existing) throw new NotFoundException(`Preset "${dto.name}" not found`);
|
||||||
|
|
||||||
const shifts_data = await this.resolveAndBuildPresetShifts(dto);
|
const shifts_data = await this.resolveAndBuildPresetShifts(dto);
|
||||||
await this.prisma.$transaction(async (tx) => {
|
await this.prisma.$transaction(async (tx) => {
|
||||||
if(typeof dto.is_default === 'boolean'){
|
if (typeof dto.is_default === 'boolean') {
|
||||||
if(dto.is_default) {
|
if (dto.is_default) {
|
||||||
await tx.schedulePresets.updateMany({
|
await tx.schedulePresets.updateMany({
|
||||||
where: {
|
where: {
|
||||||
employee_id: existing.employee_id,
|
employee_id: existing.employee_id,
|
||||||
is_default: true,
|
is_default: true,
|
||||||
NOT: { id: existing.id },
|
NOT: { id: existing.id },
|
||||||
},
|
},
|
||||||
data: { is_default: false },
|
data: { is_default: false },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await tx.schedulePresets.update({
|
await tx.schedulePresets.update({
|
||||||
where: { id: existing.id },
|
where: { id: existing.id },
|
||||||
data: {
|
data: {
|
||||||
is_default: dto.is_default,
|
is_default: dto.is_default,
|
||||||
name: dto.name,
|
name: dto.name,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(shifts_data.length <= 0) throw new BadRequestException('Preset shifts to update not found');
|
if (shifts_data.length <= 0) throw new BadRequestException('Preset shifts to update not found');
|
||||||
|
|
||||||
await tx.schedulePresetShifts.deleteMany({ where: { preset_id: existing.id } });
|
await tx.schedulePresetShifts.deleteMany({ where: { preset_id: existing.id } });
|
||||||
|
|
||||||
const create_many_data: Prisma.SchedulePresetShiftsCreateManyInput[] =
|
const create_many_data: Prisma.SchedulePresetShiftsCreateManyInput[] =
|
||||||
shifts_data.map((shift)=> {
|
shifts_data.map((shift) => {
|
||||||
if(!shift.bank_code || !('connect' in shift.bank_code) || typeof shift.bank_code.connect?.id !=='number'){
|
if (!shift.bank_code || !('connect' in shift.bank_code) || typeof shift.bank_code.connect?.id !== 'number') {
|
||||||
throw new NotFoundException(`Bank code is required for updates( ${shift.week_day}, ${shift.sort_order})`);
|
throw new NotFoundException(`Bank code is required for updates( ${shift.week_day}, ${shift.sort_order})`);
|
||||||
}
|
}
|
||||||
const bank_code_id = shift.bank_code.connect.id;
|
const bank_code_id = shift.bank_code.connect.id;
|
||||||
return {
|
return {
|
||||||
preset_id: existing.id,
|
preset_id: existing.id,
|
||||||
week_day: shift.week_day,
|
week_day: shift.week_day,
|
||||||
sort_order: shift.sort_order,
|
sort_order: shift.sort_order,
|
||||||
start_time: shift.start_time,
|
start_time: shift.start_time,
|
||||||
end_time: shift.end_time,
|
end_time: shift.end_time,
|
||||||
is_remote: shift.is_remote ?? false,
|
is_remote: shift.is_remote ?? false,
|
||||||
bank_code_id: bank_code_id,
|
bank_code_id: bank_code_id,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
await tx.schedulePresetShifts.createMany({data: create_many_data});
|
await tx.schedulePresetShifts.createMany({ data: create_many_data });
|
||||||
});
|
});
|
||||||
|
|
||||||
const saved = await this.prisma.schedulePresets.findUnique({
|
const saved = await this.prisma.schedulePresets.findUnique({
|
||||||
where: { id: existing.id },
|
where: { id: existing.id },
|
||||||
include: { shifts: {
|
include: {
|
||||||
orderBy: [{ week_day: 'asc' }, { sort_order: 'asc' }],
|
shifts: {
|
||||||
include: { bank_code: { select: { type: true }}},
|
orderBy: [{ week_day: 'asc' }, { sort_order: 'asc' }],
|
||||||
}},
|
include: { bank_code: { select: { type: true } } },
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
if(!saved) throw new NotFoundException(`Preset with id: ${existing.id} not found`);
|
if (!saved) throw new NotFoundException(`Preset with id: ${existing.id} not found`);
|
||||||
|
|
||||||
const response_dto: SchedulePresetsDto = {
|
const response_dto: SchedulePresetsDto = {
|
||||||
|
id: saved.id,
|
||||||
name: saved.name,
|
name: saved.name,
|
||||||
is_default: saved.is_default,
|
is_default: saved.is_default,
|
||||||
preset_shifts: saved.shifts.map((shift) => ({
|
preset_shifts: saved.shifts.map((shift) => ({
|
||||||
preset_id: shift.preset_id,
|
preset_id: shift.preset_id,
|
||||||
week_day: shift.week_day,
|
week_day: shift.week_day,
|
||||||
sort_order: shift.sort_order,
|
sort_order: shift.sort_order,
|
||||||
type: shift.bank_code.type,
|
type: shift.bank_code.type,
|
||||||
start_time: toHHmmFromDate(shift.start_time),
|
start_time: toHHmmFromDate(shift.start_time),
|
||||||
end_time: toHHmmFromDate(shift.end_time),
|
end_time: toHHmmFromDate(shift.end_time),
|
||||||
is_remote: shift.is_remote,
|
is_remote: shift.is_remote,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ok: true, id: existing.id, data: response_dto };
|
return { ok: true, id: existing.id, data: response_dto };
|
||||||
} catch (error){
|
} catch (error) {
|
||||||
return { ok: false, id: preset_id, error }
|
return { ok: false, id: preset_id, error }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -138,22 +142,22 @@ export class SchedulePresetsUpsertService {
|
||||||
//_________________________________________________________________
|
//_________________________________________________________________
|
||||||
// DELETE
|
// DELETE
|
||||||
//_________________________________________________________________
|
//_________________________________________________________________
|
||||||
async deletePreset( preset_id: number ): Promise <DeletePresetResult> {
|
async deletePreset(preset_id: number): Promise<DeletePresetResult> {
|
||||||
try {
|
try {
|
||||||
await this.prisma.$transaction(async (tx) => {
|
await this.prisma.$transaction(async (tx) => {
|
||||||
const preset = await tx.schedulePresets.findFirst({
|
const preset = await tx.schedulePresets.findFirst({
|
||||||
where: { id: preset_id },
|
where: { id: preset_id },
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
});
|
});
|
||||||
if(!preset) throw new NotFoundException(`Preset with id ${ preset_id } not found`);
|
if (!preset) throw new NotFoundException(`Preset with id ${preset_id} not found`);
|
||||||
await tx.schedulePresets.delete({where: { id: preset_id } });
|
await tx.schedulePresets.delete({ where: { id: preset_id } });
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
});
|
});
|
||||||
return { ok: true, id: preset_id };
|
return { ok: true, id: preset_id };
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if(error) throw new NotFoundException(`Preset schedule with id ${ preset_id } not found`);
|
if (error) throw new NotFoundException(`Preset schedule with id ${preset_id} not found`);
|
||||||
return { ok: false, id: preset_id, error };
|
return { ok: false, id: preset_id, error };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -161,19 +165,19 @@ export class SchedulePresetsUpsertService {
|
||||||
//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 resolveAndBuildPresetShifts(
|
private async resolveAndBuildPresetShifts(
|
||||||
dto: SchedulePresetsDto
|
dto: SchedulePresetsDto
|
||||||
): Promise<Prisma.SchedulePresetShiftsCreateWithoutPresetInput[]>{
|
): Promise<Prisma.SchedulePresetShiftsCreateWithoutPresetInput[]> {
|
||||||
|
|
||||||
if(!dto.preset_shifts?.length) throw new NotFoundException(`Empty or preset shifts not found`);
|
if (!dto.preset_shifts?.length) throw new NotFoundException(`Empty or preset shifts not found`);
|
||||||
|
|
||||||
const types = Array.from(new Set(dto.preset_shifts.map((shift)=> shift.type)));
|
const types = Array.from(new Set(dto.preset_shifts.map((shift) => shift.type)));
|
||||||
const bank_code_set = new Map<string, number>();
|
const bank_code_set = new Map<string, number>();
|
||||||
|
|
||||||
for (const type of types) {
|
for (const type of types) {
|
||||||
const { id } = await this.typeResolver.findIdAndModifierByType(type);
|
const { id } = await this.typeResolver.findIdAndModifierByType(type);
|
||||||
bank_code_set.set(type, id)
|
bank_code_set.set(type, id)
|
||||||
}
|
}
|
||||||
const toTime = (hhmm: string) => new Date(`1970-01-01T${hhmm}:00.000Z`);
|
const toTime = (hhmm: string) => new Date(`1970-01-01T${hhmm}:00.000Z`);
|
||||||
|
|
||||||
const pair_set = new Set<string>();
|
const pair_set = new Set<string>();
|
||||||
|
|
@ -185,25 +189,25 @@ export class SchedulePresetsUpsertService {
|
||||||
pair_set.add(key);
|
pair_set.add(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
const items: Prisma.SchedulePresetShiftsCreateWithoutPresetInput[] = dto.preset_shifts.map((shift)=> {
|
const items: Prisma.SchedulePresetShiftsCreateWithoutPresetInput[] = dto.preset_shifts.map((shift) => {
|
||||||
const bank_code_id = bank_code_set.get(shift.type);
|
const bank_code_id = bank_code_set.get(shift.type);
|
||||||
if(!bank_code_id) throw new NotFoundException(`Bank code not found for type ${shift.type}`);
|
if (!bank_code_id) throw new NotFoundException(`Bank code not found for type ${shift.type}`);
|
||||||
if (!shift.start_time || !shift.end_time) {
|
if (!shift.start_time || !shift.end_time) {
|
||||||
throw new BadRequestException(`start_time and end_time are required for (${shift.week_day}, ${shift.sort_order})`);
|
throw new BadRequestException(`start_time and end_time are required for (${shift.week_day}, ${shift.sort_order})`);
|
||||||
}
|
}
|
||||||
const start = toTime(shift.start_time);
|
const start = toTime(shift.start_time);
|
||||||
const end = toTime(shift.end_time);
|
const end = toTime(shift.end_time);
|
||||||
if(end.getTime() <= start.getTime()) {
|
if (end.getTime() <= start.getTime()) {
|
||||||
throw new ConflictException(`end_time must be > start_time ( day: ${shift.week_day}, order: ${shift.sort_order})`);
|
throw new ConflictException(`end_time must be > start_time ( day: ${shift.week_day}, order: ${shift.sort_order})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
week_day: shift.week_day as Weekday,
|
week_day: shift.week_day as Weekday,
|
||||||
sort_order: shift.sort_order,
|
sort_order: shift.sort_order,
|
||||||
bank_code: { connect: { id: bank_code_id} },
|
bank_code: { connect: { id: bank_code_id } },
|
||||||
start_time: start,
|
start_time: start,
|
||||||
end_time: end,
|
end_time: end,
|
||||||
is_remote: !!shift.is_remote,
|
is_remote: !!shift.is_remote,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return items;
|
return items;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user