Merge branch 'main' of https://git.targo.ca/Targo/targo_backend
This commit is contained in:
commit
e8bd0403ea
|
|
@ -454,24 +454,16 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/schedule-presets/{email}": {
|
||||
"put": {
|
||||
"operationId": "SchedulePresetsController_upsert",
|
||||
"/schedule-presets/create/{employee_id}": {
|
||||
"post": {
|
||||
"operationId": "SchedulePresetsController_createPreset",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "email",
|
||||
"name": "employee_id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "action",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
@ -485,6 +477,39 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"SchedulePresets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/schedule-presets/update/{preset_id}": {
|
||||
"patch": {
|
||||
"operationId": "SchedulePresetsController_updatePreset",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "preset_id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SchedulePresetsUpdateDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
|
|
@ -493,16 +518,18 @@
|
|||
"tags": [
|
||||
"SchedulePresets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"operationId": "SchedulePresetsController_findListByEmail",
|
||||
"/schedule-presets/delete/{preset_id}": {
|
||||
"delete": {
|
||||
"operationId": "SchedulePresetsController_deletePreset",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "email",
|
||||
"name": "preset_id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
@ -516,16 +543,39 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/schedule-presets/apply-presets/{email}": {
|
||||
"/schedule-presets/find/{employee_id}": {
|
||||
"get": {
|
||||
"operationId": "SchedulePresetsController_findListById",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "employee_id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"SchedulePresets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/schedule-presets/apply-presets/{employee_id}": {
|
||||
"post": {
|
||||
"operationId": "SchedulePresetsController_applyPresets",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "email",
|
||||
"name": "employee_id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -853,6 +903,10 @@
|
|||
"type": "object",
|
||||
"properties": {}
|
||||
},
|
||||
"SchedulePresetsUpdateDto": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
},
|
||||
"ExpenseDto": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
||||
import { PrismaService } from "../../../prisma/prisma.service";
|
||||
import { Decimal } from "@prisma/client/runtime/library";
|
||||
import { PrismaService } from '../../../prisma/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class MileageService {
|
||||
|
|
|
|||
|
|
@ -2,16 +2,11 @@
|
|||
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { LeaveTypes } from "@prisma/client";
|
||||
// import { toDateOnly, toStringFromDate } from "src/time-and-attendance/modules/shared/helpers/date-time.helpers";
|
||||
import { UpsertAction } from "src/time-and-attendance/modules/shared/types/upsert-actions.types";
|
||||
import { toDateFromString, toStringFromDate } from "src/time-and-attendance/utils/date-time.utils";
|
||||
// import { ShiftsUpsertService } from "src/time-and-attendance/modules/time-tracker/shifts/services/shifts-upsert.service";
|
||||
|
||||
@Injectable()
|
||||
export class LeaveRequestsUtils {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
// private readonly shiftsService: ShiftsUpsertService,
|
||||
){}
|
||||
|
||||
async syncShift(
|
||||
|
|
@ -47,7 +42,6 @@ export class LeaveRequestsUtils {
|
|||
include: { bank_code: true },
|
||||
});
|
||||
|
||||
const action: UpsertAction = existing ? 'update' : 'create';
|
||||
|
||||
// await this.shiftsService.upsertShifts(email, action, {
|
||||
// old_shift: existing
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { Module } from "@nestjs/common";
|
||||
import { EmailToIdResolver } from "./utils/resolve-email-id.utils";
|
||||
import { EmployeeTimesheetResolver } from "./utils/resolve-timesheet.utils";
|
||||
import { FullNameResolver } from "./utils/resolve-full-name.utils";
|
||||
import { EmailToIdResolver } from "./utils/resolve-email-id.utils";
|
||||
import { BankCodesResolver } from "./utils/resolve-bank-type-id.utils";
|
||||
import { FullNameResolver } from "./utils/resolve-full-name.utils";
|
||||
import { PrismaModule } from "src/prisma/prisma.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule],
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export type UpsertAction = 'create' | 'update' | 'delete';
|
||||
|
|
@ -1,44 +1,63 @@
|
|||
import { BadRequestException, Body, Controller, Get, NotFoundException, Param, Post, Put, Query } from "@nestjs/common";
|
||||
import { SchedulePresetsCommandService } from "../services/schedule-presets-command.service";
|
||||
import { SchedulePresetsQueryService } from "../services/schedule-presets-query.service";
|
||||
import { SchedulePresetsDto } from "../dtos/create-schedule-presets.dto";
|
||||
import { UpsertAction } from "src/time-and-attendance/modules/shared/types/upsert-actions.types";
|
||||
import { Controller, Param, Query, Body, Get, Post, BadRequestException, ParseIntPipe, Delete, Patch } from "@nestjs/common";
|
||||
import { SchedulePresetsCommandService } from "src/time-and-attendance/modules/time-tracker/schedule-presets/services/schedule-presets-command.service";
|
||||
import { SchedulePresetsApplyService } from "src/time-and-attendance/modules/time-tracker/schedule-presets/services/schedule-presets-apply.service";
|
||||
import { SchedulePresetsQueryService } from "src/time-and-attendance/modules/time-tracker/schedule-presets/services/schedule-presets-query.service";
|
||||
import { SchedulePresetsUpdateDto } from "src/time-and-attendance/modules/time-tracker/schedule-presets/dtos/update-schedule-presets.dto";
|
||||
import { SchedulePresetsDto } from "src/time-and-attendance/modules/time-tracker/schedule-presets/dtos/create-schedule-presets.dto";
|
||||
|
||||
@Controller('schedule-presets')
|
||||
export class SchedulePresetsController {
|
||||
constructor(
|
||||
private readonly commandService: SchedulePresetsCommandService,
|
||||
private readonly applyPresetsService: SchedulePresetsApplyService,
|
||||
private readonly queryService: SchedulePresetsQueryService,
|
||||
){}
|
||||
|
||||
//used to create, update or delete a schedule preset
|
||||
@Put(':email')
|
||||
async upsert(
|
||||
@Param('email') email: string,
|
||||
@Query('action') action: UpsertAction,
|
||||
//used to create a schedule preset
|
||||
@Post('create/:employee_id')
|
||||
async createPreset(
|
||||
@Param('employee_id', ParseIntPipe) employee_id: number,
|
||||
@Body() dto: SchedulePresetsDto,
|
||||
) {
|
||||
const actions: UpsertAction[] = ['create','update','delete'];
|
||||
if(!actions) throw new NotFoundException(`No action found for ${actions}`)
|
||||
return this.commandService.upsertSchedulePreset(email, action, dto);
|
||||
return await this.commandService.createPreset(employee_id, dto);
|
||||
}
|
||||
|
||||
//used to show the list of available schedule presets
|
||||
@Get(':email')
|
||||
async findListByEmail(
|
||||
@Param('email') email: string,
|
||||
//used to update an already existing schedule preset
|
||||
@Patch('update/:preset_id')
|
||||
async updatePreset(
|
||||
@Param('preset_id', ParseIntPipe) preset_id: number,
|
||||
@Body() dto: SchedulePresetsUpdateDto,
|
||||
) {
|
||||
return this.queryService.findSchedulePresetsByEmail(email);
|
||||
return await this.commandService.updatePreset(preset_id, dto);
|
||||
}
|
||||
|
||||
//used to delete a schedule preset
|
||||
@Delete('delete/:preset_id')
|
||||
async deletePreset(
|
||||
@Param('preset_id') preset_id: number,
|
||||
) {
|
||||
return await this.commandService.deletePreset(preset_id);
|
||||
}
|
||||
|
||||
|
||||
//used to show the list of available schedule presets
|
||||
@Get('find/:employee_id')
|
||||
async findListById(
|
||||
@Param('employee_id', ParseIntPipe) employee_id: number,
|
||||
) {
|
||||
return this.queryService.findSchedulePresets(employee_id);
|
||||
}
|
||||
|
||||
|
||||
//used to apply a preset to a timesheet
|
||||
@Post('/apply-presets/:email')
|
||||
@Post('/apply-presets/:employee_id')
|
||||
async applyPresets(
|
||||
@Param('email') email: string,
|
||||
@Param('employee_id') employee_id: number,
|
||||
@Query('preset') preset_name: string,
|
||||
@Query('start') start_date: string,
|
||||
) {
|
||||
if(!preset_name?.trim()) throw new BadRequestException('Query "preset" is required');
|
||||
if(!start_date?.trim()) throw new BadRequestException('Query "start" is required YYYY-MM-DD');
|
||||
return this.applyPresets(email, preset_name, start_date);
|
||||
return this.applyPresetsService.applyToTimesheet(employee_id, preset_name, start_date);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
import { IsBoolean, IsEnum, IsInt, IsOptional, IsString, Matches, Min } from "class-validator";
|
||||
import { HH_MM_REGEX } from "src/time-and-attendance/utils/constants.utils";
|
||||
import { Weekday } from "@prisma/client";
|
||||
|
||||
export class SchedulePresetShiftsDto {
|
||||
@IsEnum(Weekday)
|
||||
week_day!: Weekday;
|
||||
|
||||
@IsInt()
|
||||
preset_id!: number;
|
||||
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
sort_order!: number;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
import { SchedulePresetsDto } from "src/time-and-attendance/modules/time-tracker/schedule-presets/dtos/create-schedule-presets.dto";
|
||||
|
||||
export class SchedulePresetsUpdateDto extends SchedulePresetsDto{}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
import { Module } from "@nestjs/common";
|
||||
import { SchedulePresetsCommandService } from "./services/schedule-presets-command.service";
|
||||
import { SchedulePresetsQueryService } from "./services/schedule-presets-query.service";
|
||||
import { SchedulePresetsController } from "./controller/schedule-presets.controller";
|
||||
import { SchedulePresetsApplyService } from "./services/schedule-presets-apply.service";
|
||||
import { SchedulePresetsCommandService } from "src/time-and-attendance/modules/time-tracker/schedule-presets/services/schedule-presets-command.service";
|
||||
import { SchedulePresetsApplyService } from "src/time-and-attendance/modules/time-tracker/schedule-presets/services/schedule-presets-apply.service";
|
||||
import { SchedulePresetsQueryService } from "src/time-and-attendance/modules/time-tracker/schedule-presets/services/schedule-presets-query.service";
|
||||
import { SchedulePresetsController } from "src/time-and-attendance/modules/time-tracker/schedule-presets/controller/schedule-presets.controller";
|
||||
import { SharedModule } from "src/time-and-attendance/modules/shared/shared.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
|
||||
@Module({
|
||||
imports: [SharedModule],
|
||||
|
|
|
|||
|
|
@ -1,28 +1,23 @@
|
|||
import { BadRequestException, ConflictException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { EmailToIdResolver } from "src/time-and-attendance/modules/shared/utils/resolve-email-id.utils";
|
||||
import { Injectable, BadRequestException, NotFoundException, ConflictException } from "@nestjs/common";
|
||||
import { Weekday, Prisma } from "@prisma/client";
|
||||
import { DATE_ISO_FORMAT } from "src/time-and-attendance/utils/constants.utils";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { Prisma, Weekday } from "@prisma/client";
|
||||
import { WEEKDAY } from "../../../../utils/mappers.utils";
|
||||
import { ApplyResult } from "src/time-and-attendance/utils/type.utils";
|
||||
import { WEEKDAY } from "src/time-and-attendance/utils/mappers.utils";
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class SchedulePresetsApplyService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly emailResolver: EmailToIdResolver,
|
||||
) {}
|
||||
constructor( private readonly prisma: PrismaService) {}
|
||||
|
||||
async applyToTimesheet(
|
||||
email: string,
|
||||
employee_id: number,
|
||||
preset_name: string,
|
||||
start_date_iso: string,
|
||||
): Promise<ApplyResult> {
|
||||
if(!preset_name?.trim()) throw new BadRequestException('A preset_name is required');
|
||||
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);
|
||||
if(!employee_id) throw new NotFoundException(`Employee with email: ${email} not found`);
|
||||
|
||||
const preset = await this.prisma.schedulePresets.findFirst({
|
||||
where: { employee_id, name: preset_name },
|
||||
include: {
|
||||
|
|
|
|||
|
|
@ -1,73 +1,31 @@
|
|||
import { BadRequestException, ConflictException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Injectable, BadRequestException, NotFoundException, ConflictException } from "@nestjs/common";
|
||||
import { SchedulePresetsDto } from "src/time-and-attendance/modules/time-tracker/schedule-presets/dtos/create-schedule-presets.dto";
|
||||
import { BankCodesResolver } from "src/time-and-attendance/modules/shared/utils/resolve-bank-type-id.utils";
|
||||
import { EmailToIdResolver } from "src/time-and-attendance/modules/shared/utils/resolve-email-id.utils";
|
||||
import { UpsertAction } from "src/time-and-attendance/modules/shared/types/upsert-actions.types";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { SchedulePresetsDto } from "../dtos/create-schedule-presets.dto";
|
||||
import { Prisma, Weekday } from "@prisma/client";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { toHHmmFromDate } from "src/time-and-attendance/utils/date-time.utils";
|
||||
|
||||
type DeleteResult = { ok: true; id: number; } | { ok: false; id: number; error: any };
|
||||
type CreateResult = { ok: true; } | { ok: false; error: any };
|
||||
type UpdateResult = { ok: true; id: number; data: SchedulePresetsDto } | { ok: false; id: number; error: any };
|
||||
|
||||
@Injectable()
|
||||
export class SchedulePresetsCommandService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly emailResolver: EmailToIdResolver,
|
||||
private readonly typeResolver : BankCodesResolver,
|
||||
){}
|
||||
|
||||
//_________________________________________________________________
|
||||
// MASTER CRUD FUNCTION
|
||||
//_________________________________________________________________
|
||||
async upsertSchedulePreset(
|
||||
email: string,
|
||||
action: UpsertAction,
|
||||
dto: SchedulePresetsDto,
|
||||
): Promise<{
|
||||
action: UpsertAction;
|
||||
preset_id?: number;
|
||||
total_items?: number;
|
||||
}>{
|
||||
if(!dto.name?.trim()) throw new BadRequestException(`A Name is required`);
|
||||
|
||||
//resolve employee_id using email
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
if(!employee_id) throw new NotFoundException(`employee with email: ${email} not found`);
|
||||
|
||||
//DELETE
|
||||
if(action === 'delete') {
|
||||
return this.deletePreset(employee_id, dto.name);
|
||||
}
|
||||
|
||||
if(!Array.isArray(dto.preset_shifts) || dto.preset_shifts.length === 0) {
|
||||
throw new BadRequestException(`Empty array, no detected shifts`);
|
||||
}
|
||||
const shifts_data = await this.resolveAndBuildPresetShifts(dto);
|
||||
|
||||
//CREATE AND UPDATE
|
||||
if(action === 'create') {
|
||||
return this.createPreset(employee_id, dto, shifts_data);
|
||||
} else if (action === 'update') {
|
||||
return this.updatePreset(employee_id, dto, shifts_data);
|
||||
}
|
||||
throw new BadRequestException(`Unknown action: ${ action }`);
|
||||
}
|
||||
|
||||
//_________________________________________________________________
|
||||
// CREATE
|
||||
//_________________________________________________________________
|
||||
private async createPreset(
|
||||
employee_id: number,
|
||||
dto: SchedulePresetsDto,
|
||||
shifts_data: Prisma.SchedulePresetShiftsCreateWithoutPresetInput[],
|
||||
): Promise<{
|
||||
action: UpsertAction;
|
||||
preset_id: number;
|
||||
total_items: number;
|
||||
}> {
|
||||
async createPreset( employee_id: number, dto: SchedulePresetsDto): Promise<CreateResult> {
|
||||
try {
|
||||
const result = await this.prisma.$transaction(async (tx)=> {
|
||||
const shifts_data = await this.resolveAndBuildPresetShifts(dto);
|
||||
if(!shifts_data) throw new BadRequestException(`Employee with id: ${employee_id} or dto not found`);
|
||||
await this.prisma.$transaction(async (tx)=> {
|
||||
if(dto.is_default) {
|
||||
await tx.schedulePresets.updateMany({
|
||||
where: { employee_id, is_default: true },
|
||||
where: { is_default: true, employee_id },
|
||||
data: { is_default: false },
|
||||
});
|
||||
}
|
||||
|
|
@ -78,56 +36,53 @@ export class SchedulePresetsCommandService {
|
|||
is_default: !!dto.is_default,
|
||||
shifts: { create: shifts_data},
|
||||
},
|
||||
include: { shifts: true },
|
||||
});
|
||||
return created;
|
||||
});
|
||||
return { action: 'create', preset_id: result.id, total_items: result.shifts.length };
|
||||
return { ok: true };
|
||||
|
||||
} catch (error: unknown) {
|
||||
if(error instanceof Prisma.PrismaClientKnownRequestError){
|
||||
if(error?.code === 'P2002') {
|
||||
throw new ConflictException(`The name ${dto.name} is already used for another schedule preset`);
|
||||
}
|
||||
if (error.code === 'P2003' || error.code === 'P2011') {
|
||||
throw new ConflictException('Invalid constraint on preset shifts');
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
return { ok: false, error };
|
||||
}
|
||||
}
|
||||
|
||||
//_________________________________________________________________
|
||||
// UPDATE
|
||||
//_________________________________________________________________
|
||||
private async updatePreset(
|
||||
employee_id: number,
|
||||
dto: SchedulePresetsDto,
|
||||
shifts_data: Prisma.SchedulePresetShiftsCreateWithoutPresetInput[],
|
||||
): Promise<{
|
||||
action: UpsertAction;
|
||||
preset_id?: number;
|
||||
total_items?: number;
|
||||
}> {
|
||||
async updatePreset( preset_id: number, dto: SchedulePresetsDto ): Promise<UpdateResult> {
|
||||
try {
|
||||
const existing = await this.prisma.schedulePresets.findFirst({
|
||||
where: { employee_id, name: dto.name },
|
||||
select: { id:true, is_default: true },
|
||||
where: { id: preset_id },
|
||||
select: {
|
||||
id:true,
|
||||
is_default: true,
|
||||
employee_id: true,
|
||||
},
|
||||
});
|
||||
if(!existing) throw new NotFoundException(`Preset "${dto.name}" not found`);
|
||||
|
||||
try {
|
||||
const result = await this.prisma.$transaction(async (tx) => {
|
||||
const shifts_data = await this.resolveAndBuildPresetShifts(dto);
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
if(typeof dto.is_default === 'boolean'){
|
||||
if(dto.is_default) {
|
||||
await tx.schedulePresets.updateMany({
|
||||
where: { employee_id, is_default: true, NOT: { id: existing.id } },
|
||||
where: {
|
||||
employee_id: existing.employee_id,
|
||||
is_default: true,
|
||||
NOT: { id: existing.id },
|
||||
},
|
||||
data: { is_default: false },
|
||||
});
|
||||
}
|
||||
await tx.schedulePresets.update({
|
||||
where: { id: existing.id },
|
||||
data: { is_default: dto.is_default },
|
||||
data: {
|
||||
is_default: dto.is_default,
|
||||
name: dto.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
if(shifts_data.length <= 0) throw new BadRequestException('Preset shifts to update not found');
|
||||
|
||||
await tx.schedulePresetShifts.deleteMany({ where: { preset_id: existing.id } });
|
||||
|
||||
|
|
@ -148,45 +103,62 @@ export class SchedulePresetsCommandService {
|
|||
};
|
||||
});
|
||||
await tx.schedulePresetShifts.createMany({data: create_many_data});
|
||||
|
||||
const count = await tx.schedulePresetShifts.count({ where: { preset_id: existing.id } });
|
||||
return { id: existing.id, total: count };
|
||||
});
|
||||
return { action: 'update', preset_id: result.id, total_items: result.total };
|
||||
} catch (error: unknown){
|
||||
if(error instanceof Prisma.PrismaClientKnownRequestError){
|
||||
if(error?.code === 'P2003' || error?.code === 'P2011') {
|
||||
throw new ConflictException(`Invalid constraint on preset shifts`);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
|
||||
const saved = await this.prisma.schedulePresets.findUnique({
|
||||
where: { id: existing.id },
|
||||
include: { shifts: {
|
||||
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`);
|
||||
|
||||
const response_dto: SchedulePresetsDto = {
|
||||
name: saved.name,
|
||||
is_default: saved.is_default,
|
||||
preset_shifts: saved.shifts.map((shift) => ({
|
||||
preset_id: shift.preset_id,
|
||||
week_day: shift.week_day,
|
||||
sort_order: shift.sort_order,
|
||||
type: shift.bank_code.type,
|
||||
start_time: toHHmmFromDate(shift.start_time),
|
||||
end_time: toHHmmFromDate(shift.end_time),
|
||||
is_remote: shift.is_remote,
|
||||
})),
|
||||
};
|
||||
|
||||
return { ok: true, id: existing.id, data: response_dto };
|
||||
} catch (error){
|
||||
return { ok: false, id: preset_id, error }
|
||||
}
|
||||
}
|
||||
|
||||
//_________________________________________________________________
|
||||
// DELETE
|
||||
//_________________________________________________________________
|
||||
private async deletePreset(
|
||||
employee_id: number,
|
||||
name: string,
|
||||
): Promise<{
|
||||
action: UpsertAction;
|
||||
preset_id?: number;
|
||||
total_items?: number;
|
||||
}> {
|
||||
const existing = await this.prisma.schedulePresets.findFirst({
|
||||
where: { employee_id, name },
|
||||
async deletePreset( preset_id: number ): Promise <DeleteResult> {
|
||||
try {
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
const preset = await tx.schedulePresets.findFirst({
|
||||
where: { id: preset_id },
|
||||
select: { id: true },
|
||||
});
|
||||
if(!existing) throw new NotFoundException(`Preset "${name}" not found`);
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
await tx.schedulePresetShifts.deleteMany({ where: { preset_id: existing.id } });
|
||||
await tx.schedulePresets.delete({where: { id: existing.id } });
|
||||
if(!preset) throw new NotFoundException(`Preset with id ${ preset_id } not found`);
|
||||
await tx.schedulePresets.delete({where: { id: preset_id } });
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
return { action: 'delete', preset_id: existing.id, total_items: 0 };
|
||||
return { ok: true, id: preset_id };
|
||||
|
||||
} catch (error) {
|
||||
if(error) throw new NotFoundException(`Preset schedule with id ${ preset_id } not found`);
|
||||
return { ok: false, id: preset_id, error };
|
||||
}
|
||||
}
|
||||
|
||||
//PRIVATE HELPER
|
||||
//PRIVATE HELPERS
|
||||
|
||||
//resolve bank_code_id using type and convert hours to TIME and valid shifts end/start
|
||||
private async resolveAndBuildPresetShifts(
|
||||
dto: SchedulePresetsDto
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { EmailToIdResolver } from "src/time-and-attendance/modules/shared/utils/resolve-email-id.utils";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { PresetResponse, ShiftResponse } from "src/time-and-attendance/utils/type.utils";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class SchedulePresetsQueryService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly emailResolver: EmailToIdResolver,
|
||||
){}
|
||||
|
||||
async findSchedulePresetsByEmail(email:string): Promise<PresetResponse[]> {
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
if(!employee_id) throw new NotFoundException(`Employee with email: ${email} not found`);
|
||||
constructor( private readonly prisma: PrismaService ){}
|
||||
|
||||
async findSchedulePresets(employee_id: number): Promise<PresetResponse[]> {
|
||||
try {
|
||||
const presets = await this.prisma.schedulePresets.findMany({
|
||||
where: { employee_id },
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { BadRequestException, Body, Controller, Delete, Param, Patch, Post } from "@nestjs/common";
|
||||
import { CreateResult, UpdateResult } from "src/time-and-attendance/utils/type.utils";
|
||||
import { ShiftsUpsertService } from "src/time-and-attendance/modules/time-tracker/shifts/services/shifts-upsert.service";
|
||||
import { ShiftDto } from "../dtos/shift-create.dto";
|
||||
import { UpdateShiftDto } from "src/time-and-attendance/modules/time-tracker/shifts/dtos/shift-update.dto";
|
||||
import { ShiftDto } from "../dtos/shift-create.dto";
|
||||
|
||||
|
||||
@Controller('shift')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { PartialType, OmitType } from "@nestjs/swagger";
|
||||
import { IsInt } from "class-validator";
|
||||
import { ShiftDto } from "./shift-create.dto";
|
||||
import { IsInt } from "class-validator";
|
||||
|
||||
export class UpdateShiftDto extends PartialType(
|
||||
// allows update using ShiftDto and preventing OmitType variables to be modified
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
import { ShiftsArchive } from "@prisma/client";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { ShiftsArchive } from "@prisma/client";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
/**
|
||||
* _____________________________________________________________________________________
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { toStringFromDate, toStringFromHHmm } from "../../../../utils/date-time.utils";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { GetShiftDto } from "../dtos/shift-get.dto";
|
||||
import { toStringFromDate, toStringFromHHmm } from "../../../../utils/date-time.utils";
|
||||
import { shift_select } from "src/time-and-attendance/utils/selects.utils";
|
||||
import { GetShiftDto } from "../dtos/shift-get.dto";
|
||||
|
||||
/**
|
||||
* _____________________________________________________________________________________
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import { CreateResult, NormedOk, NormedErr, UpdatePayload, UpdateResult, Normalized, UpdateChanges } from "src/time-and-attendance/utils/type.utils";
|
||||
import { toDateFromString, toHHmmFromString, toStringFromDate, toStringFromHHmm } from "../../../../utils/date-time.utils";
|
||||
import { overlaps, toDateFromString, toHHmmFromString, toStringFromDate, toStringFromHHmm } from "../../../../utils/date-time.utils";
|
||||
import { BadRequestException, ConflictException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { OvertimeService } from "src/time-and-attendance/domains/services/overtime.service";
|
||||
import { UpdateShiftDto } from "src/time-and-attendance/modules/time-tracker/shifts/dtos/shift-update.dto";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { shift_select } from "src/time-and-attendance/utils/selects.utils";
|
||||
import { GetShiftDto } from "../dtos/shift-get.dto";
|
||||
import { ShiftDto } from "../dtos/shift-create.dto";
|
||||
import { UpdateShiftDto } from "src/time-and-attendance/modules/time-tracker/shifts/dtos/shift-update.dto";
|
||||
|
||||
const overlaps = (a: { start: Date; end: Date }, b: { start: Date; end: Date }) =>
|
||||
!(a.end <= b.start || a.start >= b.end);
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class ShiftsUpsertService {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { NUMBER_OF_TIMESHEETS_TO_RETURN } from "src/time-and-attendance/utils/constants.utils";
|
||||
import { sevenDaysFrom, toStringFromDate, toHHmmFromDate, toDateFromString } from "src/time-and-attendance/utils/date-time.utils";
|
||||
import { TotalExpenses, TotalHours } from "src/time-and-attendance/utils/type.utils";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
const NUMBER_OF_TIMESHEETS_TO_RETURN = 2;
|
||||
const DAILY_LIMIT_HOURS = 8;
|
||||
const WEEKLY_LIMIT_HOURS = 40;
|
||||
const PAY_PERIOD_ANCHOR = 2023-12-17;
|
||||
const ANCHOR_ISO = '2023-12-17'; // ancre date
|
||||
const PERIOD_DAYS = 14;
|
||||
const PERIODS_PER_YEAR = 26;
|
||||
const MS_PER_DAY = 86_400_000;
|
||||
export const NUMBER_OF_TIMESHEETS_TO_RETURN = 2;
|
||||
export const DAILY_LIMIT_HOURS = 8;
|
||||
export const WEEKLY_LIMIT_HOURS = 40;
|
||||
export const PAY_PERIOD_ANCHOR = 2023-12-17;
|
||||
export const ANCHOR_ISO = '2023-12-17'; // ancre date
|
||||
export const PERIOD_DAYS = 14;
|
||||
export const PERIODS_PER_YEAR = 26;
|
||||
export const MS_PER_DAY = 86_400_000;
|
||||
|
||||
//REGEX CONSTANTS
|
||||
const DATE_ISO_FORMAT = /^\d{4}-\d{2}-\d{2}$/;
|
||||
const HH_MM_REGEX = /^([01]\d|2[0-3]):[0-5]\d$/;
|
||||
export const DATE_ISO_FORMAT = /^\d{4}-\d{2}-\d{2}$/;
|
||||
export const HH_MM_REGEX = /^([01]\d|2[0-3]):[0-5]\d$/;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { ANCHOR_ISO, MS_PER_DAY, PERIODS_PER_YEAR, PERIOD_DAYS } from "src/time-and-attendance/utils/constants.utils";
|
||||
|
||||
//ensures the week starts from sunday
|
||||
export function weekStartSunday(date_local: Date): Date {
|
||||
const start = new Date(Date.UTC(date_local.getFullYear(), date_local.getMonth(), date_local.getDate()));
|
||||
|
|
@ -84,3 +86,6 @@ export function computePeriod(pay_year: number, period_no: number, anchorISO = A
|
|||
export function listPayYear(pay_year: number, anchorISO = ANCHOR_ISO) {
|
||||
return Array.from({ length: PERIODS_PER_YEAR }, (_, i) => computePeriod(pay_year, i + 1, anchorISO));
|
||||
}
|
||||
|
||||
export const overlaps = (a: { start: Date; end: Date }, b: { start: Date; end: Date }) =>
|
||||
!(a.end <= b.start || a.start >= b.end);
|
||||
|
|
@ -62,3 +62,5 @@ export type ApplyResult = {
|
|||
}
|
||||
|
||||
export type LeaveRequestRow = Prisma.LeaveRequestsGetPayload<{ select: typeof leaveRequestsSelect}>;
|
||||
|
||||
export type UpsertAction = 'create' | 'update' | 'delete';
|
||||
Loading…
Reference in New Issue
Block a user