From 99e9f1f3bfa65e32c927ccc8c018d4ac0e4abd63 Mon Sep 17 00:00:00 2001 From: Matthieu Haineault Date: Tue, 14 Oct 2025 10:35:30 -0400 Subject: [PATCH] feat(shifts): extract delete logics outside of master upsert method and create a new route for delete requests --- docs/swagger/swagger-spec.json | 46 +++++++++++++++++++ .../shifts/controllers/shifts.controller.ts | 14 +++++- .../helpers/shifts-date-time-helpers.ts | 4 +- .../shifts/services/shifts-command.service.ts | 17 +++---- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/docs/swagger/swagger-spec.json b/docs/swagger/swagger-spec.json index 07055ed..6429d37 100644 --- a/docs/swagger/swagger-spec.json +++ b/docs/swagger/swagger-spec.json @@ -483,6 +483,52 @@ ] } }, + "/shifts/{email}/{date}": { + "delete": { + "operationId": "ShiftsController_remove", + "parameters": [ + { + "name": "email", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + }, + { + "name": "date", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertShiftDto" + } + } + } + }, + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "access-token": [] + } + ], + "tags": [ + "Shifts" + ] + } + }, "/shifts/approval/{id}": { "patch": { "operationId": "ShiftsController_approve", diff --git a/src/modules/shifts/controllers/shifts.controller.ts b/src/modules/shifts/controllers/shifts.controller.ts index c8b7bbf..7884dfb 100644 --- a/src/modules/shifts/controllers/shifts.controller.ts +++ b/src/modules/shifts/controllers/shifts.controller.ts @@ -1,11 +1,11 @@ -import { Body, Controller, Get, Header, Param, ParseBoolPipe, ParseIntPipe, Patch, Put, Query, } from "@nestjs/common"; +import { Body, Controller, Delete, Get, Header, Param, ParseBoolPipe, ParseIntPipe, Patch, Put, Query, } from "@nestjs/common"; import { RolesAllowed } from "src/common/decorators/roles.decorators"; import { Roles as RoleEnum } from '.prisma/client'; import { ApiBearerAuth, ApiTags } from "@nestjs/swagger"; import { ShiftsCommandService } from "../services/shifts-command.service"; import { ShiftsQueryService } from "../services/shifts-query.service"; import { GetShiftsOverviewDto } from "../dtos/get-shift-overview.dto"; -import { UpsertShiftDto } from "../dtos/upsert-shift.dto"; +import { ShiftPayloadDto, UpsertShiftDto } from "../dtos/upsert-shift.dto"; import { OverviewRow } from "../types-and-interfaces/shifts-overview-row.interface"; import { UpsertAction } from "src/modules/shared/types/upsert-actions.types"; @@ -28,6 +28,15 @@ export class ShiftsController { return this.shiftsCommandService.upsertShifts(email_param, action, payload); } + @Delete(':email/:date') + async remove( + @Param('email') email: string, + @Param('date') date: string, + @Body() payload: UpsertShiftDto, + ) { + return this.shiftsCommandService.deleteShift(email, date, payload); + } + @Patch('approval/:id') //@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR) async approve(@Param('id', ParseIntPipe) id: number, @Body('is_approved', ParseBoolPipe) isApproved: boolean) { @@ -74,4 +83,5 @@ export class ShiftsController { return Buffer.from('\uFEFF' + header + body, 'utf8'); } + } \ No newline at end of file diff --git a/src/modules/shifts/helpers/shifts-date-time-helpers.ts b/src/modules/shifts/helpers/shifts-date-time-helpers.ts index d5ba369..cf3f26b 100644 --- a/src/modules/shifts/helpers/shifts-date-time-helpers.ts +++ b/src/modules/shifts/helpers/shifts-date-time-helpers.ts @@ -10,8 +10,8 @@ export function toDateOnly(ymd: string): Date { return new Date(y, m, d, 0, 0, 0, 0); } -export function weekStartSunday(dateLocal: Date): Date { - const start = new Date(dateLocal.getFullYear(), dateLocal.getMonth(), dateLocal.getDate()); +export function weekStartSunday(date_local: Date): Date { + const start = new Date(date_local.getFullYear(), date_local.getMonth(), date_local.getDate()); const dow = start.getDay(); // 0 = dimanche start.setDate(start.getDate() - dow); start.setHours(0, 0, 0, 0); diff --git a/src/modules/shifts/services/shifts-command.service.ts b/src/modules/shifts/services/shifts-command.service.ts index a54f9e9..8870a64 100644 --- a/src/modules/shifts/services/shifts-command.service.ts +++ b/src/modules/shifts/services/shifts-command.service.ts @@ -69,12 +69,6 @@ export class ShiftsCommandService extends BaseApprovalService { } return this.updateShift(employee_id, date, dto); } - if(action === 'delete'){ - if(!dto.old_shift || dto.new_shift) { - throw new BadRequestException('Only old_shift must be provided for delete'); - } - return this.deleteShift(employee_id, date, dto); - } throw new BadRequestException(`Unknown action: ${action}`); } @@ -164,13 +158,14 @@ export class ShiftsCommandService extends BaseApprovalService { //_________________________________________________________________ // DELETE //_________________________________________________________________ - private async deleteShift( - employee_id: number, + async deleteShift( + email: string, date_iso: string, dto: UpsertShiftDto, - ): Promise<{ action: UpsertAction; day: DayShiftResponse[]; }>{ + ): Promise<{ day: DayShiftResponse[]; }>{ return this.prisma.$transaction(async (tx) => { - const date_only = toDateOnly(date_iso); + const date_only = toDateOnly(date_iso); + const employee_id = await this.emailResolver.findIdByEmail(email); const { id: timesheet_id } = await this.helpersService.ensureTimesheet(tx, employee_id, date_only); const old_norm_shift = await this.helpersService.normalizeRequired(dto.old_shift, 'old_shift'); @@ -188,7 +183,7 @@ export class ShiftsCommandService extends BaseApprovalService { await this.helpersService.afterWriteOvertimeAndLog(tx, employee_id, date_only, 'delete'); const fresh_shift = await this.helpersService.getDayShifts(tx, timesheet_id, date_iso); - return { action: 'delete', day: await this.helpersService.mapDay(fresh_shift)}; + return { day: await this.helpersService.mapDay(fresh_shift)}; }); } }