diff --git a/src/modules/expenses/services/expenses-command.service.ts b/src/modules/expenses/services/expenses-command.service.ts index bda3c90..1511eb0 100644 --- a/src/modules/expenses/services/expenses-command.service.ts +++ b/src/modules/expenses/services/expenses-command.service.ts @@ -5,7 +5,7 @@ import { UpsertExpenseDto } from "../dtos/upsert-expense.dto"; import { BankCodesResolver } from "src/modules/shared/utils/resolve-bank-type-id.utils"; import { ExpenseResponse, UpsertAction } from "../types and interfaces/expenses.types.interfaces"; import { EmailToIdResolver } from "src/modules/shared/utils/resolve-email-id.utils"; -import { EmployeeTimesheetResolver } from "src/modules/shared/utils/resolve-employee-timesheet.utils"; +import { EmployeeTimesheetResolver } from "src/modules/shared/utils/resolve-timesheet.utils"; import { BadRequestException, Injectable, @@ -66,7 +66,7 @@ export class ExpensesCommandService extends BaseApprovalService { const employee_id = await this.emailResolver.findIdByEmail(email); //make sure a timesheet existes - const timesheet_id = await this.timesheetsResolver.ensureForDate(employee_id, date_only); + const timesheet_id = await this.timesheetsResolver.findTimesheetIdByEmail(email, date_only); if(!timesheet_id) throw new NotFoundException(`no timesheet found for employee #${employee_id}`) const {id} = timesheet_id; diff --git a/src/modules/shared/interfaces/shifts.interface.ts b/src/modules/shared/interfaces/shifts.interface.ts new file mode 100644 index 0000000..40f897e --- /dev/null +++ b/src/modules/shared/interfaces/shifts.interface.ts @@ -0,0 +1,9 @@ +export interface ShiftKey { + timesheet_id: number; + date: Date; + start_time: Date; + end_time: Date; + bank_code_id: number; + is_remote: boolean; + comment?: string | null; +} \ No newline at end of file diff --git a/src/modules/shared/shared.module.ts b/src/modules/shared/shared.module.ts index adf0b68..8d4aa95 100644 --- a/src/modules/shared/shared.module.ts +++ b/src/modules/shared/shared.module.ts @@ -1,6 +1,6 @@ import { Module } from "@nestjs/common"; import { EmailToIdResolver } from "./utils/resolve-email-id.utils"; -import { EmployeeTimesheetResolver } from "./utils/resolve-employee-timesheet.utils"; +import { EmployeeTimesheetResolver } from "./utils/resolve-timesheet.utils"; import { FullNameResolver } from "./utils/resolve-full-name.utils"; import { BankCodesResolver } from "./utils/resolve-bank-type-id.utils"; import { PrismaModule } from "src/prisma/prisma.module"; diff --git a/src/modules/shared/utils/resolve-employee-timesheet.utils.ts b/src/modules/shared/utils/resolve-employee-timesheet.utils.ts deleted file mode 100644 index eb3b305..0000000 --- a/src/modules/shared/utils/resolve-employee-timesheet.utils.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { Prisma, PrismaClient } from "@prisma/client"; -import { weekStartSunday } from "src/modules/shifts/helpers/shifts-date-time-helpers"; -import { PrismaService } from "src/prisma/prisma.service"; - - -type Tx = Prisma.TransactionClient | PrismaClient; - -@Injectable() -export class EmployeeTimesheetResolver { - constructor(private readonly prisma: PrismaService) {} - - //find an existing timesheet linked to the employee - readonly ensureForDate = async (employee_id: number, date: Date, client?: Tx, - ): Promise<{id: number; start_date: Date }> => { - const db = client ?? this.prisma; - const startOfWeek = weekStartSunday(date); - const existing = await db.timesheets.findFirst({ - where: { - employee_id: employee_id, - start_date: startOfWeek, - }, - select: { - id: true, - start_date: true, - }, - }); - if(existing) return existing; - - const created = await db.timesheets.create({ - data: { - employee_id: employee_id, - start_date: startOfWeek, - }, - select: { - id: true, - start_date: true, - }, - }); - return created; - } -} \ No newline at end of file diff --git a/src/modules/shared/utils/resolve-shifts-id.utils.ts b/src/modules/shared/utils/resolve-shifts-id.utils.ts new file mode 100644 index 0000000..4d9d313 --- /dev/null +++ b/src/modules/shared/utils/resolve-shifts-id.utils.ts @@ -0,0 +1,29 @@ +import { Prisma, PrismaClient } from "@prisma/client"; +import { NotFoundException } from "@nestjs/common"; +import { PrismaService } from "src/prisma/prisma.service"; +import { ShiftKey } from "../interfaces/shifts.interface"; + +type Tx = Prisma.TransactionClient | PrismaClient; + +export class ShiftIdResolver { + constructor(private readonly prisma: PrismaService) {} + + readonly findShiftIdByData = async ( key: ShiftKey, client?: Tx ): Promise<{id:number}> => { + const db = client ?? this.prisma; + const shift = await db.shifts.findFirst({ + where: { + timesheet_id: key.timesheet_id, + bank_code_id: key.bank_code_id, + date: key.date, + start_time: key.start_time, + end_time: key.end_time, + is_remote: key.is_remote, + comment: key.comment, + }, + select: { id: true }, + }); + + if(!shift) throw new NotFoundException(`shift not found`); + return { id: shift.id }; + }; +} \ No newline at end of file diff --git a/src/modules/shared/utils/resolve-timesheet.utils.ts b/src/modules/shared/utils/resolve-timesheet.utils.ts new file mode 100644 index 0000000..61f4ce6 --- /dev/null +++ b/src/modules/shared/utils/resolve-timesheet.utils.ts @@ -0,0 +1,28 @@ +import { Injectable, NotFoundException } from "@nestjs/common"; +import { Prisma, PrismaClient } from "@prisma/client"; +import { weekStartSunday } from "src/modules/shifts/helpers/shifts-date-time-helpers"; +import { PrismaService } from "src/prisma/prisma.service"; +import { EmailToIdResolver } from "./resolve-email-id.utils"; + + +type Tx = Prisma.TransactionClient | PrismaClient; + +@Injectable() +export class EmployeeTimesheetResolver { + constructor( + private readonly prisma: PrismaService, + private readonly emailResolver: EmailToIdResolver, + ) {} + + readonly findTimesheetIdByEmail = async (email: string, date: Date, client?: Tx): Promise<{id: number}> => { + const db = client ?? this.prisma; + const employee_id = await this.emailResolver.findIdByEmail(email); + const start_date = weekStartSunday(date); + const timesheet = await db.timesheets.findFirst({ + where: { employee_id : employee_id, start_date: start_date }, + select: { id: true }, + }); + if(!timesheet) throw new NotFoundException(`timesheet not found`); + return { id: timesheet.id }; + } +} \ 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 cf3f26b..8bcd610 100644 --- a/src/modules/shifts/helpers/shifts-date-time-helpers.ts +++ b/src/modules/shifts/helpers/shifts-date-time-helpers.ts @@ -11,7 +11,7 @@ export function toDateOnly(ymd: string): Date { } export function weekStartSunday(date_local: Date): Date { - const start = new Date(date_local.getFullYear(), date_local.getMonth(), date_local.getDate()); + const start = new Date(Date.UTC(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/helpers/shifts.helpers.ts b/src/modules/shifts/helpers/shifts.helpers.ts index 6038db7..09a17e1 100644 --- a/src/modules/shifts/helpers/shifts.helpers.ts +++ b/src/modules/shifts/helpers/shifts.helpers.ts @@ -114,10 +114,13 @@ export class ShiftsHelpersService { async afterWriteOvertimeAndLog(tx: Tx, employee_id: number, date_only: Date) { // Switch regular → weekly overtime si > 40h await this.overtimeService.transformRegularHoursToWeeklyOvertime(employee_id, date_only, tx); - const [daily, weekly] = await Promise.all([ - this.overtimeService.getDailyOvertimeHoursForDay(employee_id, date_only), - this.overtimeService.getWeeklyOvertimeHours(employee_id, date_only), - ]); + const daily = await this.overtimeService.getDailyOvertimeHoursForDay(employee_id, date_only); + const weekly = await this.overtimeService.getWeeklyOvertimeHours(employee_id, date_only); + // const [daily, weekly] = await Promise.all([ + // this.overtimeService.getDailyOvertimeHoursForDay(employee_id, date_only), + // this.overtimeService.getWeeklyOvertimeHours(employee_id, date_only), + // ]); + return { daily, weekly }; } async mapDay( diff --git a/src/modules/timesheets/services/timesheets-command.service.ts b/src/modules/timesheets/services/timesheets-command.service.ts index 045b7b5..f8142b0 100644 --- a/src/modules/timesheets/services/timesheets-command.service.ts +++ b/src/modules/timesheets/services/timesheets-command.service.ts @@ -1,5 +1,5 @@ import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common"; -import { EmployeeTimesheetResolver } from "src/modules/shared/utils/resolve-employee-timesheet.utils"; +import { EmployeeTimesheetResolver } from "src/modules/shared/utils/resolve-timesheet.utils"; import { getWeekEnd, getWeekStart } from "src/common/utils/date-utils"; import { parseISODate, parseHHmm } from "../utils-helpers-others/timesheet.helpers"; import { TimesheetsQueryService } from "./timesheets-query.service"; @@ -69,7 +69,7 @@ export class TimesheetsCommandService extends BaseApprovalService{ const start_week = getWeekStart(base, 0); const end_week = getWeekEnd(start_week); - const timesheet = await this.timesheetResolver.ensureForDate(employee_id, base) + const timesheet = await this.timesheetResolver.findTimesheetIdByEmail(email, base) if(!timesheet) throw new NotFoundException(`no timesheet found for employe ${employee_id}`); //validations and insertions