diff --git a/eslint.config.mjs b/eslint.config.mjs index 1080982..e1d8c31 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -26,6 +26,7 @@ export default tseslint.config( }, { rules: { + "no-unused-vars": "off", '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-floating-promises': 'warn', '@typescript-eslint/no-unsafe-argument': 'warn' diff --git a/src/app.module.ts b/src/app.module.ts index 349a9da..f9e5b34 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -28,7 +28,9 @@ import { CustomerSupportModule } from 'src/customer-support/customer-support.mod ChatbotModule, CustomerSupportModule, ], - controllers: [AppController], + controllers: [ + AppController + ], providers: [ AppService, { diff --git a/src/customer-support/customer-support.module.ts b/src/customer-support/customer-support.module.ts index 8a495cf..ca8da4c 100644 --- a/src/customer-support/customer-support.module.ts +++ b/src/customer-support/customer-support.module.ts @@ -3,8 +3,11 @@ import { TicketController } from "src/customer-support/tickets/ticket.controller import { TicketService } from "src/customer-support/tickets/ticket.service"; @Module({ - imports: [], - controllers: [TicketController], - providers: [TicketService], - exports: [], + controllers: [ + TicketController + ], + providers: [ + TicketService + ], + }) export class CustomerSupportModule { } \ No newline at end of file diff --git a/src/customer-support/tickets/ticket.module.ts b/src/customer-support/tickets/ticket.module.ts index f9e7101..805680b 100644 --- a/src/customer-support/tickets/ticket.module.ts +++ b/src/customer-support/tickets/ticket.module.ts @@ -3,7 +3,11 @@ import { TicketController } from "src/customer-support/tickets/ticket.controller import { TicketService } from "src/customer-support/tickets/ticket.service"; @Module({ - imports: [TicketService], - providers: [TicketController] + imports: [ + TicketService + ], + providers: [ + TicketController + ] }) export class TicketModule { } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 3b9574c..e151a3a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,3 @@ -import 'reflect-metadata'; -// import * as nodeCrypto from 'crypto'; -// if (!(globalThis as any).crypto) { -// (globalThis as any).crypto = nodeCrypto; -// } import { NestFactory, Reflector } from '@nestjs/core'; import { AppModule } from './app.module'; import { ModulesGuard } from './common/guards/modules.guard'; @@ -21,7 +16,7 @@ async function bootstrap() { const reflector = app.get(Reflector); app.useGlobalGuards( - new ModulesGuard(reflector), //deny-by-default and Module-based Access Control + new ModulesGuard(reflector), ); // Authentication and session @@ -46,19 +41,11 @@ async function bootstrap() { // Enable CORS app.enableCors({ - origin: ['http://10.100.251.2:9011', 'http://10.5.14.111:9012', 'http://10.100.251.2:9013', 'http://localhost:9000', 'https://app.targo.ca', 'https://portail.targo.ca','https://staging.app.targo.ca'], + origin: ['http://10.100.251.2:9011', 'http://10.5.14.111:9012', 'http://10.100.251.2:9013', 'http://localhost:9000', 'https://app.targo.ca', 'https://portail.targo.ca', 'https://staging.app.targo.ca'], credentials: true, }); await app.listen(process.env.PORT ?? 3000); - - // migration function calls - // await initializePaidTimeOff(); - // await initializePreferences(); - // await extractOldTimesheets(); - // await extractOldShifts(); - // await extractOldExpenses(); - // await initSupervisor(); } bootstrap(); diff --git a/src/time-and-attendance/bank-codes/bank-codes.dto.ts b/src/time-and-attendance/bank-codes/bank-codes.dto.ts new file mode 100644 index 0000000..1c8c3ea --- /dev/null +++ b/src/time-and-attendance/bank-codes/bank-codes.dto.ts @@ -0,0 +1,3 @@ +export class BankCodeDto { + type:string; +} \ No newline at end of file diff --git a/src/time-and-attendance/exports/services/csv-exports.service.ts b/src/time-and-attendance/exports/services/csv-exports.service.ts index 0b7184a..b9abf04 100644 --- a/src/time-and-attendance/exports/services/csv-exports.service.ts +++ b/src/time-and-attendance/exports/services/csv-exports.service.ts @@ -6,7 +6,8 @@ import { applyHolidayRequalifications, applyOvertimeRequalifications, computeWee import { OvertimeService } from "src/time-and-attendance/domains/services/overtime.service"; import { HolidayService } from "src/time-and-attendance/domains/services/holiday.service"; import { select_csv_expense_lines, select_csv_shift_lines } from "src/time-and-attendance/utils/selects.utils"; -import { BillableShiftType } from "src/time-and-attendance/shifts/shift.types"; +import { BillableShiftType } from "src/time-and-attendance/shifts/shift.dto"; + @Injectable() export class CsvExportService { diff --git a/src/time-and-attendance/paid-time-off/paid-time-off.module.ts b/src/time-and-attendance/paid-time-off/paid-time-off.module.ts index 704f2b9..2d94716 100644 --- a/src/time-and-attendance/paid-time-off/paid-time-off.module.ts +++ b/src/time-and-attendance/paid-time-off/paid-time-off.module.ts @@ -8,7 +8,9 @@ import { PaidTimeOffController } from "src/time-and-attendance/paid-time-off/pai import { PaidTimeOffBankHoursService } from "src/time-and-attendance/paid-time-off/paid-time-off.service"; @Module({ - controllers: [PaidTimeOffController], + controllers: [ + PaidTimeOffController + ], providers: [ PrismaPostgresService, EmailToIdResolver, diff --git a/src/time-and-attendance/paid-time-off/paid-time-off.service.ts b/src/time-and-attendance/paid-time-off/paid-time-off.service.ts index f3ebaa2..609e908 100644 --- a/src/time-and-attendance/paid-time-off/paid-time-off.service.ts +++ b/src/time-and-attendance/paid-time-off/paid-time-off.service.ts @@ -18,7 +18,9 @@ export class PaidTimeOffBankHoursService { private readonly emailResolver: EmailToIdResolver, ) { } - getPaidTimeOffTotalsWithEmployeeEmail = async (email: string): Promise, string>> => { + getPaidTimeOffTotalsWithEmployeeEmail = async ( + email: string + ): Promise, string>> => { const employee_info = await this.emailResolver.findIdByEmail(email); @@ -112,6 +114,7 @@ export class PaidTimeOffBankHoursService { }); return { success: true, data: true }; } catch (error) { + console.error(error); return { success: false, error: 'PAID_TIME_OFF_NOT_FOUND' }; } }; diff --git a/src/time-and-attendance/pay-period/dtos/bulk-crew-approval.dto.ts b/src/time-and-attendance/pay-period/dtos/bulk-crew-approval.dto.ts index 4ba5527..ed627f5 100644 --- a/src/time-and-attendance/pay-period/dtos/bulk-crew-approval.dto.ts +++ b/src/time-and-attendance/pay-period/dtos/bulk-crew-approval.dto.ts @@ -2,25 +2,13 @@ import { Type } from "class-transformer"; import { IsArray, IsBoolean, IsEmail, IsInt, ValidateNested } from "class-validator"; export class BulkCrewApprovalItemDto { - @IsInt() - pay_year: number; - - @IsInt() - period_no: number; - - @IsEmail() - employee_email!: string; - - @IsBoolean() - approve: boolean; + @IsInt() pay_year: number; + @IsInt() period_no: number; + @IsEmail() employee_email: string; + @IsBoolean() approve: boolean; } export class BulkCrewApprovalDto { - @IsBoolean() - include_subtree: boolean = false; - - @IsArray() - @ValidateNested({each: true}) - @Type(()=> BulkCrewApprovalItemDto) - items: BulkCrewApprovalItemDto[] + @IsBoolean() include_subtree: boolean = false; + @IsArray() @ValidateNested({ each: true }) @Type(() => BulkCrewApprovalItemDto) items: BulkCrewApprovalItemDto[] } \ No newline at end of file diff --git a/src/time-and-attendance/pay-period/dtos/overview-pay-period.dto.ts b/src/time-and-attendance/pay-period/dtos/overview-pay-period.dto.ts index be75a7a..9668857 100644 --- a/src/time-and-attendance/pay-period/dtos/overview-pay-period.dto.ts +++ b/src/time-and-attendance/pay-period/dtos/overview-pay-period.dto.ts @@ -27,7 +27,7 @@ export class EmployeePeriodOverviewDto { holiday_hours: number; vacation_hours: number; }; - weekly_hours: number[]; + weekly_hours: number[]; total_hours: number; expenses: number; mileage: number; diff --git a/src/time-and-attendance/pay-period/pay-periods.controller.ts b/src/time-and-attendance/pay-period/pay-periods.controller.ts index 9b5c092..6f18639 100644 --- a/src/time-and-attendance/pay-period/pay-periods.controller.ts +++ b/src/time-and-attendance/pay-period/pay-periods.controller.ts @@ -26,7 +26,9 @@ export class PayPeriodsController { @Get("date/:date") @ModuleAccessAllowed(ModulesEnum.timesheets) - async findByDate(@Param("date") date: string) { + async findByDate( + @Param("date") date: string + ) { return this.queryService.findByDate(date); } diff --git a/src/time-and-attendance/pay-period/pay-periods.mapper.ts b/src/time-and-attendance/pay-period/pay-periods.mapper.ts index 05aef06..c31e949 100644 --- a/src/time-and-attendance/pay-period/pay-periods.mapper.ts +++ b/src/time-and-attendance/pay-period/pay-periods.mapper.ts @@ -1,9 +1,13 @@ import { PayPeriods } from "prisma/postgres/generated/prisma/client/postgres/client"; import { PayPeriodDto } from "src/time-and-attendance/pay-period/dtos/overview-pay-period.dto"; -const toDateString = (date: Date) => date.toISOString().slice(0, 10); // "YYYY-MM-DD" +const toDateString = ( + date: Date +) => date.toISOString().slice(0, 10); // "YYYY-MM-DD" -export function mapPayPeriodToDto(row: PayPeriods): PayPeriodDto { +export function mapPayPeriodToDto( + row: PayPeriods +): PayPeriodDto { const start = toDateString(row.period_start); const end = toDateString(row.period_end); const pay = toDateString(row.payday); @@ -12,12 +16,13 @@ export function mapPayPeriodToDto(row: PayPeriods): PayPeriodDto { period_start: toDateString(row.period_start), period_end: toDateString(row.period_end), payday:pay, - // pay_year: new Date(pay).getFullYear(), pay_year: row.pay_year, label: `${start}.${end}`, }; } -export function mapMany(rows: PayPeriods[]): PayPeriodDto[] { +export function mapMany( + rows: PayPeriods[] +): PayPeriodDto[] { return rows.map(mapPayPeriodToDto); } diff --git a/src/time-and-attendance/pay-period/pay-periods.module.ts b/src/time-and-attendance/pay-period/pay-periods.module.ts index eaba3ce..0622e27 100644 --- a/src/time-and-attendance/pay-period/pay-periods.module.ts +++ b/src/time-and-attendance/pay-period/pay-periods.module.ts @@ -8,8 +8,12 @@ import { GetOverviewService } from "src/time-and-attendance/pay-period/services/ import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service"; @Module({ - imports:[TimesheetsModule], - controllers: [PayPeriodsController], + imports: [ + TimesheetsModule + ], + controllers: [ + PayPeriodsController + ], providers: [ PayPeriodsQueryService, PayPeriodsCommandService, @@ -17,6 +21,4 @@ import { PayPeriodEventService } from "src/time-and-attendance/pay-period/servic PayPeriodEventService, EmailToIdResolver, ], -}) - -export class PayperiodsModule {} +}) export class PayperiodsModule { } diff --git a/src/time-and-attendance/pay-period/services/pay-periods-build-overview.service.ts b/src/time-and-attendance/pay-period/services/pay-periods-build-overview.service.ts index dfd7f18..4fc43b0 100644 --- a/src/time-and-attendance/pay-period/services/pay-periods-build-overview.service.ts +++ b/src/time-and-attendance/pay-period/services/pay-periods-build-overview.service.ts @@ -11,7 +11,10 @@ export class GetOverviewService { private readonly prisma: PrismaPostgresService, ) { } - async getOverviewByYearPeriod(pay_year: number, period_no: number): Promise> { + async getOverviewByYearPeriod( + pay_year: number, + period_no: number + ): Promise> { const period = computePeriod(pay_year, period_no); const overview = await this.buildOverview({ period_start: period.period_start, @@ -26,7 +29,9 @@ export class GetOverviewService { return { success: true, data: overview.data } } - async buildOverview(overview: Overview): Promise> { + async buildOverview( + overview: Overview + ): Promise> { const employee_overviews = await this.prisma.employees.findMany({ where: { OR: [ @@ -103,7 +108,12 @@ export class GetOverviewService { } } - const ensure = (id: number, first_name: string, last_name: string, email: string) => { + const ensure = ( + id: number, + first_name: string, + last_name: string, + email: string + ) => { if (!by_employee.has(id)) { by_employee.set(id, this.createEmployeeSeeds(email, first_name, last_name)); } diff --git a/src/time-and-attendance/pay-period/services/pay-periods-command.service.ts b/src/time-and-attendance/pay-period/services/pay-periods-command.service.ts index 4e992a6..b929fd6 100644 --- a/src/time-and-attendance/pay-period/services/pay-periods-command.service.ts +++ b/src/time-and-attendance/pay-period/services/pay-periods-command.service.ts @@ -14,7 +14,11 @@ export class PayPeriodsCommandService { ) { } //function to approve pay-periods according to selected crew members - async bulkApproveEmployee(email: string, timesheet_ids: number[], is_approved: boolean): Promise> { + async bulkApproveEmployee( + email: string, + timesheet_ids: number[], + is_approved: boolean + ): Promise> { let shifts: Prisma.BatchPayload; let expenses: Prisma.BatchPayload; @@ -56,7 +60,8 @@ export class PayPeriodsCommandService { is_approved: is_approved, } }) - } catch (_error) { + } catch (error) { + console.error(error); return { success: false, error: 'UNKNOWN_ERROR_VALIDATING' } } diff --git a/src/time-and-attendance/pay-period/services/pay-periods-query.service.ts b/src/time-and-attendance/pay-period/services/pay-periods-query.service.ts index 27dfc8b..6a5810f 100644 --- a/src/time-and-attendance/pay-period/services/pay-periods-query.service.ts +++ b/src/time-and-attendance/pay-period/services/pay-periods-query.service.ts @@ -10,7 +10,10 @@ export class PayPeriodsQueryService { constructor( private readonly prisma: PrismaPostgresService) { } - async findOneByYearPeriod(pay_year: number, period_no: number): Promise> { + async findOneByYearPeriod( + pay_year: number, + period_no: number + ): Promise> { const row = await this.prisma.payPeriods.findFirst({ where: { pay_year, pay_period_no: period_no }, }); @@ -32,7 +35,9 @@ export class PayPeriodsQueryService { } //function to cherry pick a Date to find a period - async findByDate(date: string): Promise> { + async findByDate( + date: string + ): Promise> { const dt = new Date(date); const row = await this.prisma.payPeriods.findFirst({ where: { period_start: { lte: dt }, period_end: { gte: dt } }, diff --git a/src/time-and-attendance/schedule-presets/schedule-presets.controller.ts b/src/time-and-attendance/schedule-presets/schedule-presets.controller.ts index e3c87c2..f4ec581 100644 --- a/src/time-and-attendance/schedule-presets/schedule-presets.controller.ts +++ b/src/time-and-attendance/schedule-presets/schedule-presets.controller.ts @@ -1,11 +1,9 @@ import { Controller, Param, Body, Get, Post, Delete, Patch } from "@nestjs/common"; - import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-create.service"; import { SchedulePresetUpdateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-update.service"; import { SchedulePresetDeleteService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service"; import { SchedulePresetsGetService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-get.service"; import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; - import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators"; import { Modules as ModulesEnum } from "prisma/postgres/generated/prisma/client/postgres/client"; import { Access } from "src/common/decorators/module-access.decorators"; @@ -29,21 +27,25 @@ export class SchedulePresetsController { @Post('create') @ModuleAccessAllowed(ModulesEnum.employee_management) - async createPreset(@Body() dto: SchedulePresetsDto) { + async createPreset( + @Body() dto: SchedulePresetsDto + ) { return await this.createService.createPreset(dto); } @Patch('update') @ModuleAccessAllowed(ModulesEnum.employee_management) async updatePreset( - @Body() dto: SchedulePresetsDto) { + @Body() dto: SchedulePresetsDto + ) { return await this.updateService.updatePreset(dto); } @Delete('delete/:id') @ModuleAccessAllowed(ModulesEnum.employee_management) async deletePreset( - @Param('id') id: number) { + @Param('id') id: number + ) { return await this.deleteService.deletePreset(id); } diff --git a/src/time-and-attendance/schedule-presets/schedule-presets.dto.ts b/src/time-and-attendance/schedule-presets/schedule-presets.dto.ts index 6650a7f..516a35f 100644 --- a/src/time-and-attendance/schedule-presets/schedule-presets.dto.ts +++ b/src/time-and-attendance/schedule-presets/schedule-presets.dto.ts @@ -1,5 +1,5 @@ import { Weekday } from "prisma/postgres/generated/prisma/client/postgres/client"; -import { ArrayMinSize, IsArray, IsBoolean, IsEnum, IsInt, IsOptional, IsString, Matches} from "class-validator"; +import { ArrayMinSize, IsArray, IsBoolean, IsEnum, IsInt, IsOptional, IsString, Matches } from "class-validator"; import { HH_MM_REGEX } from "src/common/utils/constants.utils"; export class SchedulePresetsDto { @@ -17,12 +17,12 @@ export class SchedulePresetShiftsDto { @IsOptional() @IsBoolean() is_remote?: boolean; } -export const WEEKDAY_MAP: Record = { - SUN: 0, - MON: 1, - TUE: 2, - WED: 3, - THU: 4, - FRI: 5, - SAT: 6, -}; \ No newline at end of file +export const WEEKDAY_MAP: Weekday[] = [ + 'SUN', + 'MON', + 'TUE', + 'WED', + 'THU', + 'FRI', + 'SAT' +] \ No newline at end of file diff --git a/src/time-and-attendance/schedule-presets/schedule-presets.module.ts b/src/time-and-attendance/schedule-presets/schedule-presets.module.ts index 04085d6..f6f2962 100644 --- a/src/time-and-attendance/schedule-presets/schedule-presets.module.ts +++ b/src/time-and-attendance/schedule-presets/schedule-presets.module.ts @@ -18,7 +18,9 @@ import { PayPeriodEventService } from "../pay-period/services/pay-period-event.s @Module({ - controllers: [SchedulePresetsController], + controllers: [ + SchedulePresetsController + ], providers: [ SchedulePresetsGetService, SchedulePresetsCreateService, diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts index 73f96f2..0e0b4e5 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts @@ -1,17 +1,15 @@ import { Injectable } from "@nestjs/common"; import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; - import { sevenDaysFrom, toDateFromString, toStringFromDate, toStringFromHHmm } from "src/common/utils/date-utils"; import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; import { Result } from "src/common/errors/result-error.factory"; - import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service"; import { timesheet_select } from "src/time-and-attendance/utils/selects.utils"; import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; import { WEEKDAY_MAP } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service"; -import { $Enums, SchedulePresetShifts } from "prisma/postgres/generated/prisma/client/postgres/client"; +import { SchedulePresetShifts } from "prisma/postgres/generated/prisma/client/postgres/client"; @Injectable() @@ -24,7 +22,11 @@ export class SchedulePresetsApplyService { private readonly payPeriodEventService: PayPeriodEventService, ) { } - async applyPresetToTimesheet(email: string, timesheet_id: number, employee_email?: string): Promise> { + async applyPresetToTimesheet( + email: string, + timesheet_id: number, + employee_email?: string + ): Promise> { const user_email = employee_email ?? email; const employee_id = await this.emailResolver.findIdByEmail(user_email); if (!employee_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; @@ -63,15 +65,15 @@ export class SchedulePresetsApplyService { if (timesheet.is_approved) return { success: false, error: 'INVALID_TIMESHEET' }; if (timesheet.shift.length > 0) return { success: false, error: 'INVALID_TIMESHEET' }; - const dated_map = await sevenDaysFrom(timesheet.start_date); + const dated_map = sevenDaysFrom(timesheet.start_date); - let created_shifts: ShiftDto[] = []; + const created_shifts: ShiftDto[] = []; for (const preset_shift of default_preset_shifts) { const date = dated_map.find(date => date.getUTCDay() === WEEKDAY_MAP[preset_shift.week_day]) if (!date) return { success: false, error: 'INVALID_PRESET_DATE' }; - const shift = await this.createShiftFromPreset(preset_shift, date!, timesheet.id) + const shift = await this.createShiftFromPreset(preset_shift, date, timesheet.id) if (!shift.success) return { success: false, error: shift.error }; created_shifts.push(shift.data); @@ -99,7 +101,7 @@ export class SchedulePresetsApplyService { const user_email = employee_email ?? email; const employee_id = await this.emailResolver.findIdByEmail(user_email); if (!employee_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; - const week_day = Object.keys(WEEKDAY_MAP)[week_day_index]; + const week_day = WEEKDAY_MAP[week_day_index]; const preset_shift = await this.prisma.employees.findFirst({ where: { id: employee_id.data, }, @@ -108,7 +110,7 @@ export class SchedulePresetsApplyService { select: { id: true, shifts: { - where: { week_day: $Enums.Weekday[week_day] }, + where: { week_day }, select: { bank_code_id: true, start_time: true, @@ -146,7 +148,11 @@ export class SchedulePresetsApplyService { return { success: true, data: true }; } - private createShiftFromPreset = async (preset: Partial, date: Date, timesheet_id: number): Promise> => { + private createShiftFromPreset = async ( + preset: Partial, + date: Date, + timesheet_id: number + ): Promise> => { const type = await this.typeResolver.findTypeByBankCodeId(preset.bank_code_id!); if (!type.success) return { success: false, error: 'INVALID_PRESET_SHIFT' }; diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-create.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-create.service.ts index 4daf523..2a78222 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-create.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-create.service.ts @@ -1,9 +1,6 @@ import { Injectable } from "@nestjs/common"; - import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; - import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; - import { overlaps, toDateFromHHmm } from "src/common/utils/date-utils"; import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; import { Result } from "src/common/errors/result-error.factory"; @@ -14,10 +11,10 @@ export class SchedulePresetsCreateService { private readonly prisma: PrismaPostgresService, private readonly typeResolver: BankCodesResolver, ) { } - //_________________________________________________________________ - // CREATE - //_________________________________________________________________ - async createPreset(dto: SchedulePresetsDto): Promise> { + + async createPreset( + dto: SchedulePresetsDto + ): Promise> { try { //validate new unique name const existing = await this.prisma.schedulePresets.findFirst({ @@ -80,6 +77,7 @@ export class SchedulePresetsCreateService { }); return { success: true, data: true } } catch (error) { + console.error(error); return { success: false, error: 'INVALID_SCHEDULE_PRESET' } } } diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service.ts index c39dfac..ec3ed2d 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service.ts @@ -6,24 +6,23 @@ import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; export class SchedulePresetDeleteService { constructor(private readonly prisma: PrismaPostgresService) { } - //_________________________________________________________________ - // DELETE - //_________________________________________________________________ - async deletePreset(preset_id: number): Promise> { - + async deletePreset( + preset_id: number + ): Promise> { + const preset = await this.prisma.schedulePresets.findUnique({ where: { id: preset_id }, select: { id: true }, }); if (!preset) return { success: false, error: `SCHEDULE_PRESET_NOT_FOUND` }; - - const updated_employees = await this.prisma.employees.updateMany({ + + await this.prisma.employees.updateMany({ where: { schedule_preset_id: preset_id }, data: { schedule_preset_id: 0, }, }); - + await this.prisma.$transaction(async (tx) => { await tx.schedulePresetShifts.deleteMany({ where: { preset_id: preset_id } }); await tx.schedulePresets.delete({ where: { id: preset_id } }); diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-get.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-get.service.ts index 81fce2b..0653c98 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-get.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-get.service.ts @@ -1,9 +1,6 @@ import { Injectable } from "@nestjs/common"; - import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; - import { SchedulePresetsDto, SchedulePresetShiftsDto } from "../schedule-presets.dto"; - import { Result } from "src/common/errors/result-error.factory"; @Injectable() @@ -40,6 +37,7 @@ export class SchedulePresetsGetService { return { success: true, data: response }; } catch (error) { + console.error(error); return { success: false, error: `SCHEDULE_PRESET_NOT_FOUND` }; } } diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-update.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-update.service.ts index fa08906..75f9217 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-update.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-update.service.ts @@ -1,8 +1,6 @@ import { Injectable } from "@nestjs/common"; import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; - import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; - import { overlaps, toDateFromHHmm } from "src/common/utils/date-utils"; import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; import { Result } from "src/common/errors/result-error.factory"; @@ -14,10 +12,9 @@ export class SchedulePresetUpdateService { private readonly typeResolver: BankCodesResolver, ) { } - //_________________________________________________________________ - // UPDATE - //_________________________________________________________________ - async updatePreset(dto: SchedulePresetsDto): Promise> { + async updatePreset( + dto: SchedulePresetsDto + ): Promise> { const existing = await this.prisma.schedulePresets.findFirst({ where: { id: dto.id }, select: { diff --git a/src/time-and-attendance/shifts/services/shifts-create.service.ts b/src/time-and-attendance/shifts/services/shifts-create.service.ts index 958f989..b4c92b1 100644 --- a/src/time-and-attendance/shifts/services/shifts-create.service.ts +++ b/src/time-and-attendance/shifts/services/shifts-create.service.ts @@ -25,10 +25,11 @@ export class ShiftsCreateService { private readonly payPeriodEventService: PayPeriodEventService, ) { } - //_________________________________________________________________ - // CREATE WRAPPER FUNCTION FOR ONE OR MANY INPUT - //_________________________________________________________________ - async createOneOrManyShifts(email: string, shifts: ShiftDto[], is_from_timesheet: boolean = true): Promise> { + async createOneOrManyShifts( + email: string, + shifts: ShiftDto[], + is_from_timesheet: boolean = true + ): Promise> { try { //verify if array is empty or not if (!Array.isArray(shifts) || shifts.length === 0) return { success: false, error: 'NO_DATA_RECEIVED' }; @@ -71,13 +72,16 @@ export class ShiftsCreateService { // returns array of created shifts return { success: true, data: true } } catch (error) { - return { success: false, error } + return { success: false, error: `${error}` } } } //_________________________________________________________________ // CREATE //_________________________________________________________________ - async createShift(employee_id: number, dto: ShiftDto): Promise> { + async createShift( + employee_id: number, + dto: ShiftDto + ): Promise> { try { //transform string format to date and HHmm const normed_shift = await this.normalizeShiftDto(dto); @@ -99,9 +103,9 @@ export class ShiftsCreateService { select: { id: true, date: true, start_time: true, end_time: true }, }); for (const existing of existing_shifts) { - const existing_start = await toDateFromString(existing.start_time); - const existing_end = await toDateFromString(existing.end_time); - const existing_date = await toDateFromString(existing.date); + const existing_start = toDateFromString(existing.start_time); + const existing_end = toDateFromString(existing.end_time); + const existing_date = toDateFromString(existing.date); const has_overlap = overlaps( { start: normed_shift.data.start_time, end: normed_shift.data.end_time, date: normed_shift.data.date }, @@ -183,13 +187,11 @@ export class ShiftsCreateService { } return { success: true, data: shift }; } catch (error) { + console.error(error); return { success: false, error: `INVALID_SHIFT` }; } } - //_________________________________________________________________ - // LOCAL HELPERS - //_________________________________________________________________ //converts all string hours and date to Date and HHmm formats private normalizeShiftDto = async (dto: ShiftDto): Promise> => { const bank_code_id = await this.typeResolver.findBankCodeIDByType(dto.type); @@ -200,6 +202,14 @@ export class ShiftsCreateService { const start_time = toDateFromHHmm(dto.start_time); const end_time = toDateFromHHmm(dto.end_time); - return { success: true, data: { date, start_time, end_time, bank_code_id: bank_code_id.data } }; + return { + success: true, + data: { + date, + start_time, + end_time, + bank_code_id: bank_code_id.data + } + }; } } diff --git a/src/time-and-attendance/shifts/services/shifts-delete.service.ts b/src/time-and-attendance/shifts/services/shifts-delete.service.ts index b1a03db..abe3d4a 100644 --- a/src/time-and-attendance/shifts/services/shifts-delete.service.ts +++ b/src/time-and-attendance/shifts/services/shifts-delete.service.ts @@ -13,13 +13,12 @@ export class ShiftsDeleteService { private readonly emailResolver: EmailToIdResolver, private readonly payPeriodEventService: PayPeriodEventService, ) { } - //_________________________________________________________________ - // DELETE - //_________________________________________________________________ - //finds shifts using shit_ids - //ajust paid-time-off banks - //blocs deletion if approved - async deleteShift(shift_id: number, email: string, is_from_timesheet: boolean = true): Promise> { + + async deleteShift( + shift_id: number, + email: string, + is_from_timesheet: boolean = true + ): Promise> { try { //verify if email is valid or not @@ -39,7 +38,7 @@ export class ShiftsDeleteService { }); if (!shift || shift.timesheet.employee_id !== employee_id.data) - return { success: false, error: 'SHIFT_NOT_FOUND'} + return { success: false, error: 'SHIFT_NOT_FOUND' } // return deletion result return await this.prisma.$transaction(async (tx) => { @@ -80,6 +79,7 @@ export class ShiftsDeleteService { return { success: true, data: shift.id }; }); } catch (error) { + console.error(error); return { success: false, error: `SHIFT_NOT_FOUND` }; } } diff --git a/src/time-and-attendance/shifts/services/shifts-update.service.ts b/src/time-and-attendance/shifts/services/shifts-update.service.ts index 2044a0e..9569b59 100644 --- a/src/time-and-attendance/shifts/services/shifts-update.service.ts +++ b/src/time-and-attendance/shifts/services/shifts-update.service.ts @@ -1,11 +1,9 @@ import { toDateFromString, toStringFromHHmm, toStringFromDate, toDateFromHHmm, overlaps, computeHours } from "src/common/utils/date-utils"; import { Injectable } from "@nestjs/common"; import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; - import { EmployeeTimesheetResolver } from "src/common/mappers/timesheet.mapper"; import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; import { Result } from "src/common/errors/result-error.factory"; - import { shift_select } from "src/time-and-attendance/utils/selects.utils"; import { Normalized } from "src/time-and-attendance/utils/type.utils"; import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; @@ -25,14 +23,18 @@ export class ShiftsUpdateService { private readonly payPeriodEventService: PayPeriodEventService, ) { } - async updateOneOrManyShifts(shifts: ShiftDto[], email: string, is_from_timesheet: boolean = true): Promise> { + async updateOneOrManyShifts( + shifts: ShiftDto[], + email: string, + is_from_timesheet: boolean = true + ): Promise> { try { //verify if array is empty or not if (!Array.isArray(shifts) || shifts.length === 0) return { success: false, error: 'No data received' }; //check for overlap inside dto objects - const overlap_check = await this.overlapChecker(shifts); - if (!overlap_check.success) return overlap_check; + const overlap_check = this.overlapChecker(shifts); + if (!overlap_check.success) return { success: false, error: `${overlap_check.error}` }; //calls the update functions and await the return of successfull result or not const results = await Promise.allSettled(shifts.map(shift => this.updateShift(shift, email))); @@ -68,12 +70,10 @@ export class ShiftsUpdateService { // returns array of updated shifts return { success: true, data: true } } catch (error) { - return { success: false, error } + return { success: false, error: `${error}` } } } - //_________________________________________________________________ - // UPDATE - //_________________________________________________________________ + async updateShift(dto: ShiftDto, email: string): Promise> { try { const timesheet = await this.timesheetResolver.findTimesheetIdByEmail(email, toDateFromString(dto.date)); @@ -164,6 +164,7 @@ export class ShiftsUpdateService { return { success: true, data: shift }; } catch (error) { + console.error(error); return { success: false, error: `INVALID_SHIFT` }; } } @@ -185,7 +186,7 @@ export class ShiftsUpdateService { }; } - private overlapChecker = async (shifts: ShiftDto[]): Promise> => { + private overlapChecker = (shifts: ShiftDto[]) => { for (let i = 0; i < shifts.length; i++) { for (let j = i + 1; j < shifts.length; j++) { const shift_a = shifts[i]; diff --git a/src/time-and-attendance/shifts/shift.controller.ts b/src/time-and-attendance/shifts/shift.controller.ts index fba290a..bf151b8 100644 --- a/src/time-and-attendance/shifts/shift.controller.ts +++ b/src/time-and-attendance/shifts/shift.controller.ts @@ -1,11 +1,9 @@ import { Body, Controller, Delete, Param, Patch, Post } from "@nestjs/common"; import { Modules as ModulesEnum } from "prisma/postgres/generated/prisma/client/postgres/client"; - import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service"; import { ShiftsUpdateService } from "src/time-and-attendance/shifts/services/shifts-update.service"; import { ShiftsDeleteService } from "src/time-and-attendance/shifts/services/shifts-delete.service"; - import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators"; import { Result } from "src/common/errors/result-error.factory"; import { Access } from "src/common/decorators/module-access.decorators"; @@ -20,37 +18,55 @@ export class ShiftController { @Post('create') @ModuleAccessAllowed(ModulesEnum.timesheets) - createBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise> { + createBatch( + @Access('email') email: string, + @Body() dtos: ShiftDto[] + ): Promise> { return this.create_service.createOneOrManyShifts(email, dtos); } @Post('create/:email') @ModuleAccessAllowed(ModulesEnum.timesheets_approval) - createBatchByTimesheetsApproval(@Param('email') email: string, @Body() dtos: ShiftDto[]): Promise> { + createBatchByTimesheetsApproval( + @Param('email') email: string, + @Body() dtos: ShiftDto[] + ): Promise> { return this.create_service.createOneOrManyShifts(email, dtos, false); } @Patch('update') @ModuleAccessAllowed(ModulesEnum.timesheets) - updateBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise> { + updateBatch( + @Access('email') email: string, + @Body() dtos: ShiftDto[] + ): Promise> { return this.update_service.updateOneOrManyShifts(dtos, email); } @Patch('update/:email') @ModuleAccessAllowed(ModulesEnum.timesheets_approval) - updateBatchByTimesheetApproval(@Param('email') email: string, @Body() dtos: ShiftDto[]): Promise> { + updateBatchByTimesheetApproval( + @Param('email') email: string, + @Body() dtos: ShiftDto[] + ): Promise> { return this.update_service.updateOneOrManyShifts(dtos, email, false); } @Delete(':shift_id') @ModuleAccessAllowed(ModulesEnum.timesheets) - remove(@Access('email') email: string, @Param('shift_id') shift_id: number): Promise> { + remove( + @Access('email') email: string, + @Param('shift_id') shift_id: number + ): Promise> { return this.delete_service.deleteShift(shift_id, email); } @Delete(':shift_id/:email') @ModuleAccessAllowed(ModulesEnum.timesheets) - removeByTimesheetApproval(@Param('shift_id') shift_id: number, @Param('email') email: string): Promise> { + removeByTimesheetApproval( + @Param('shift_id') shift_id: number, + @Param('email') email: string + ): Promise> { return this.delete_service.deleteShift(shift_id, email, false); } } diff --git a/src/time-and-attendance/shifts/shift.dto.ts b/src/time-and-attendance/shifts/shift.dto.ts index 7cc9cd7..aac7a25 100644 --- a/src/time-and-attendance/shifts/shift.dto.ts +++ b/src/time-and-attendance/shifts/shift.dto.ts @@ -2,12 +2,14 @@ import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validat export class ShiftDto { @IsInt() @IsOptional() id?: number; - @IsInt() timesheet_id!: number; - @IsString() type!: string; - @IsString() date!: string; - @IsString() start_time!: string; - @IsString() end_time!: string; - @IsBoolean() is_approved!: boolean; - @IsBoolean() is_remote!: boolean; + @IsInt() timesheet_id: number; + @IsString() type: string; + @IsString() date: string; + @IsString() start_time: string; + @IsString() end_time: string; + @IsBoolean() is_approved: boolean; + @IsBoolean() is_remote: boolean; @IsOptional() @IsString() @MaxLength(280) comment?: string; -} \ No newline at end of file +} + +export type BillableShiftType = 'REGULAR' | 'EVENING' | 'EMERGENCY' | 'VACATION' | 'HOLIDAY' | 'SICK' | 'OVERTIME'; \ No newline at end of file diff --git a/src/time-and-attendance/shifts/shift.types.ts b/src/time-and-attendance/shifts/shift.types.ts deleted file mode 100644 index 744d6f9..0000000 --- a/src/time-and-attendance/shifts/shift.types.ts +++ /dev/null @@ -1 +0,0 @@ -export type BillableShiftType = 'REGULAR' | 'EVENING' | 'EMERGENCY' | 'VACATION' | 'HOLIDAY' | 'SICK' | 'OVERTIME'; \ No newline at end of file diff --git a/src/time-and-attendance/shifts/shifts.module.ts b/src/time-and-attendance/shifts/shifts.module.ts index 2374c38..7bc3863 100644 --- a/src/time-and-attendance/shifts/shifts.module.ts +++ b/src/time-and-attendance/shifts/shifts.module.ts @@ -1,6 +1,5 @@ import { Module } from '@nestjs/common'; - import { ShiftController } from 'src/time-and-attendance/shifts/shift.controller'; import { ShiftsCreateService } from 'src/time-and-attendance/shifts/services/shifts-create.service'; import { ShiftsDeleteService } from 'src/time-and-attendance/shifts/services/shifts-delete.service'; @@ -12,8 +11,12 @@ import { PaidTimeOffBankHoursService } from 'src/time-and-attendance/paid-time-o import { PayPeriodEventService } from 'src/time-and-attendance/pay-period/services/pay-period-event.service'; @Module({ - imports: [PaidTimeOffModule], - controllers: [ShiftController], + imports: [ + PaidTimeOffModule + ], + controllers: [ + ShiftController + ], providers: [ ShiftsCreateService, ShiftsUpdateService, @@ -21,7 +24,7 @@ import { PayPeriodEventService } from 'src/time-and-attendance/pay-period/servic VacationService, BankedHoursService, PaidTimeOffBankHoursService, - PayPeriodEventService, + PayPeriodEventService, ], exports: [ ShiftsCreateService, diff --git a/src/time-and-attendance/time-and-attendance.module.ts b/src/time-and-attendance/time-and-attendance.module.ts index 1fb589d..84908a4 100644 --- a/src/time-and-attendance/time-and-attendance.module.ts +++ b/src/time-and-attendance/time-and-attendance.module.ts @@ -5,38 +5,31 @@ import { BankedHoursService } from "src/time-and-attendance/domains/services/ban import { PaidTimeOffModule } from "src/time-and-attendance/paid-time-off/paid-time-off.module"; import { PaidTimeOffController } from "src/time-and-attendance/paid-time-off/paid-time-off.controller"; import { PaidTimeOffBankHoursService } from "src/time-and-attendance/paid-time-off/paid-time-off.service"; - import { ExpenseController } from "src/time-and-attendance/expenses/expense.controller"; import { ExpenseCreateService } from "src/time-and-attendance/expenses/services/expense-create.service"; import { ExpenseUpdateService } from "src/time-and-attendance/expenses/services/expense-update.service"; import { ExpenseDeleteService } from "src/time-and-attendance/expenses/services/expense-delete.service"; import { ExpensesModule } from "src/time-and-attendance/expenses/expenses.module"; - import { TimesheetController } from "src/time-and-attendance/timesheets/timesheet.controller"; import { TimesheetApprovalService } from "src/time-and-attendance/timesheets/services/timesheet-approval.service"; import { GetTimesheetsOverviewService } from "src/time-and-attendance/timesheets/services/timesheet-employee-overview.service"; import { TimesheetsModule } from "src/time-and-attendance/timesheets/timesheets.module"; - import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; import { EmployeeTimesheetResolver } from "src/common/mappers/timesheet.mapper"; - import { PayperiodsModule } from "src/time-and-attendance/pay-period/pay-periods.module"; import { PayPeriodsController } from "src/time-and-attendance/pay-period/pay-periods.controller"; import { GetOverviewService } from "src/time-and-attendance/pay-period/services/pay-periods-build-overview.service"; import { PayPeriodsQueryService } from "src/time-and-attendance/pay-period/services/pay-periods-query.service"; import { PayPeriodsCommandService } from "src/time-and-attendance/pay-period/services/pay-periods-command.service"; - import { CsvExportModule } from "src/time-and-attendance/exports/csv-exports.module"; import { CsvExportService } from "src/time-and-attendance/exports/services/csv-exports.service"; import { CsvGeneratorService } from "src/time-and-attendance/exports/services/csv-builder.service"; import { CsvExportController } from "src/time-and-attendance/exports/csv-exports.controller"; - import { ShiftController } from "src/time-and-attendance/shifts/shift.controller"; import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service"; import { ShiftsUpdateService } from "src/time-and-attendance/shifts/services/shifts-update.service"; import { ShiftsDeleteService } from "src/time-and-attendance/shifts/services/shifts-delete.service"; - import { SchedulePresetsGetService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-get.service"; import { SchedulePresetsController } from "src/time-and-attendance/schedule-presets/schedule-presets.controller"; import { SchedulePresetsModule } from "src/time-and-attendance/schedule-presets/schedule-presets.module"; @@ -94,5 +87,7 @@ import { PayPeriodEventService } from "./pay-period/services/pay-period-event.se PaidTimeOffBankHoursService, PayPeriodEventService, ], - exports: [TimesheetApprovalService], + exports: [ + TimesheetApprovalService + ], }) export class TimeAndAttendanceModule { }; \ No newline at end of file diff --git a/src/time-and-attendance/timesheets/services/timesheet-approval.service.ts b/src/time-and-attendance/timesheets/services/timesheet-approval.service.ts index 392a616..bc3ba72 100644 --- a/src/time-and-attendance/timesheets/services/timesheet-approval.service.ts +++ b/src/time-and-attendance/timesheets/services/timesheet-approval.service.ts @@ -1,56 +1,62 @@ import { Injectable, NotFoundException } from "@nestjs/common"; -import { Prisma, Timesheets } from "prisma/postgres/generated/prisma/client/postgres/client"; +import { Timesheets } from "prisma/postgres/generated/prisma/client/postgres/client"; import { PrismaPostgresService, TransactionClient } from "prisma/postgres/prisma-postgres.service"; import { BaseApprovalService } from "src/common/shared/base-approval.service"; import { timesheet_select } from "src/time-and-attendance/utils/selects.utils"; - - - - @Injectable() - export class TimesheetApprovalService extends BaseApprovalService{ +@Injectable() +export class TimesheetApprovalService extends BaseApprovalService { constructor( prisma: PrismaPostgresService, - ){super(prisma)} + ) { super(prisma) } - //_____________________________________________________________________________________________ - // APPROVAL AND DELEGATE METHODS - //_____________________________________________________________________________________________ protected get delegate() { return this.prisma.timesheets; } - protected delegateFor(tx: TransactionClient) { + protected delegateFor( + tx: TransactionClient + ) { return tx.timesheets; } - async updateApproval(id: number, is_approved: boolean): Promise { - return this.prisma.$transaction((tx) => + async updateApproval( + id: number, + is_approved: boolean + ): Promise { + return this.prisma.$transaction((tx) => this.updateApprovalWithTransaction(tx, id, is_approved), ); } - async cascadeApprovalWithtx(tx: TransactionClient, timesheet_id: number, is_approved: boolean): Promise { + async cascadeApprovalWithtx( + tx: TransactionClient, + timesheet_id: number, + is_approved: boolean + ): Promise { const timesheet = await this.updateApprovalWithTransaction(tx, timesheet_id, is_approved); await tx.shifts.updateMany({ where: { timesheet_id: timesheet_id }, - data: { is_approved: is_approved }, + data: { is_approved: is_approved }, }); await tx.expenses.updateMany({ where: { timesheet_id: timesheet_id }, - data: { is_approved: is_approved }, + data: { is_approved: is_approved }, }); return timesheet; } - async approveTimesheetById( timesheet_id: number, is_approved: boolean){ + async approveTimesheetById( + timesheet_id: number, + is_approved: boolean + ) { return this.prisma.$transaction(async (tx) => { const timesheet = await tx.timesheets.findUnique({ where: { id: timesheet_id }, select: { id: true }, }); - if(!timesheet) throw new NotFoundException(`Timesheet with id: ${timesheet_id} not found`); - + if (!timesheet) throw new NotFoundException(`Timesheet with id: ${timesheet_id} not found`); + await this.cascadeApprovalWithtx(tx, timesheet_id, is_approved); return tx.timesheets.findUnique({ @@ -59,4 +65,4 @@ import { timesheet_select } from "src/time-and-attendance/utils/selects.utils"; }); }); } - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/time-and-attendance/timesheets/services/timesheet-employee-overview.service.ts b/src/time-and-attendance/timesheets/services/timesheet-employee-overview.service.ts index 716cfe1..1a0b2d0 100644 --- a/src/time-and-attendance/timesheets/services/timesheet-employee-overview.service.ts +++ b/src/time-and-attendance/timesheets/services/timesheet-employee-overview.service.ts @@ -15,10 +15,12 @@ export class GetTimesheetsOverviewService { private readonly emailResolver: EmailToIdResolver, ) { } - //----------------------------------------------------------------------------------- - // GET TIMESHEETS FOR A SELECTED EMPLOYEE - //----------------------------------------------------------------------------------- - async getTimesheetsForEmployeeByPeriod(email: string, pay_year: number, pay_period_no: number, employee_email?: string): Promise> { + async getTimesheetsForEmployeeByPeriod( + email: string, + pay_year: number, + pay_period_no: number, + employee_email?: string + ): Promise> { try { const account_email = employee_email ?? email; @@ -82,11 +84,11 @@ export class GetTimesheetsOverviewService { } } - //----------------------------------------------------------------------------------- - // MAPPERS & HELPERS - //----------------------------------------------------------------------------------- - //fetch timesheet's infos - private async loadTimesheets(employee_id: number, period_start: Date, period_end: Date) { + private async loadTimesheets( + employee_id: number, + period_start: Date, + period_end: Date + ) { return this.prisma.timesheets.findMany({ where: { employee_id, start_date: { gte: period_start, lte: period_end } }, include: { @@ -98,7 +100,10 @@ export class GetTimesheetsOverviewService { }); } - private ensureTimesheet = async (employee_id: number, start_date: Date | string) => { + private ensureTimesheet = async ( + employee_id: number, + start_date: Date | string + ) => { const start = toDateFromString(start_date); let row = await this.prisma.timesheets.findFirst({ diff --git a/src/time-and-attendance/timesheets/timesheet.mapper.ts b/src/time-and-attendance/timesheets/timesheet.mapper.ts index 99d3bfd..ab91fee 100644 --- a/src/time-and-attendance/timesheets/timesheet.mapper.ts +++ b/src/time-and-attendance/timesheets/timesheet.mapper.ts @@ -1,15 +1,18 @@ import { Prisma } from "prisma/postgres/generated/prisma/client/postgres/client"; import { toDateFromString, sevenDaysFrom, toStringFromDate, toHHmmFromDate } from "src/common/utils/date-utils"; +import { BankCodeDto } from "src/time-and-attendance/bank-codes/bank-codes.dto"; import { Timesheet } from "src/time-and-attendance/timesheets/timesheet.dto"; -export const mapOneTimesheet = async (timesheet: Prisma.TimesheetsGetPayload<{ - include: { - employee: { include: { user } }, - shift: { include: { bank_code }, orderBy: { start_time: 'asc' } }, - expense: { include: { bank_code } }, - } -}>): Promise => { +export const mapOneTimesheet = ( + timesheet: Prisma.TimesheetsGetPayload<{ + include: { + employee: { include: { user } }, + shift: { include: { bank_code }, orderBy: { start_time: 'asc' } }, + expense: { include: { bank_code } }, + } + }> +): Timesheet => { //converts string to UTC date format const start = toDateFromString(timesheet.start_date); const day_dates = sevenDaysFrom(start); @@ -23,7 +26,7 @@ export const mapOneTimesheet = async (timesheet: Prisma.TimesheetsGetPayload<{ shifts_by_date.set(date_string, arr); } //map of expenses by days - const expenses_by_date = new Map[]>(); + const expenses_by_date = new Map[]>(); for (const expense of timesheet.expense) { const date_string = toStringFromDate(expense.date); const arr = expenses_by_date.get(date_string) ?? []; @@ -75,11 +78,11 @@ export const mapOneTimesheet = async (timesheet: Prisma.TimesheetsGetPayload<{ const hours = diffOfHours(shift.start_time, shift.end_time); const subgroup = hoursSubGroupFromBankCode(shift.bank_code); const worked_weekly_hours = weekly_hours.regular + weekly_hours.emergency + weekly_hours.banking + weekly_hours.evening + weekly_hours.overtime + weekly_hours.holiday; - + if ((worked_weekly_hours + hours <= 40) && (subgroup === 'regular' || subgroup === 'evening')) { daily_hours['overtime'] += Math.max(daily_hours[subgroup] + hours - 8, 0); weekly_hours['overtime'] += Math.max(daily_hours[subgroup] + hours - 8, 0); - + weekly_hours[subgroup] += Math.min(hours, 8 - daily_hours[subgroup]); daily_hours[subgroup] += Math.min(hours, 8 - daily_hours[subgroup]); } else if (subgroup === 'regular' || subgroup === 'evening') { @@ -150,7 +153,7 @@ const diffOfHours = (a: Date, b: Date): number => { const num = (value: any): number => { return value ? Number(value) : 0 }; // shift's subgroup types -const hoursSubGroupFromBankCode = (bank_code: any): keyof TotalHours => { +const hoursSubGroupFromBankCode = (bank_code: BankCodeDto): keyof TotalHours => { const type = bank_code.type; if (type.includes('EVENING')) return 'evening'; if (type.includes('EMERGENCY')) return 'emergency'; @@ -164,7 +167,7 @@ const hoursSubGroupFromBankCode = (bank_code: any): keyof TotalHours => { } // expense's subgroup types -const expenseSubgroupFromBankCode = (bank_code: any): keyof TotalExpenses => { +const expenseSubgroupFromBankCode = (bank_code: BankCodeDto): keyof TotalExpenses => { const type = bank_code.type; if (type.includes('MILEAGE')) return 'mileage'; if (type.includes('PER_DIEM')) return 'per_diem'; diff --git a/src/time-and-attendance/timesheets/timesheets.module.ts b/src/time-and-attendance/timesheets/timesheets.module.ts index 1654841..3578cde 100644 --- a/src/time-and-attendance/timesheets/timesheets.module.ts +++ b/src/time-and-attendance/timesheets/timesheets.module.ts @@ -6,12 +6,16 @@ import { GetTimesheetsOverviewService } from 'src/time-and-attendance/timesheets import { EmailToIdResolver } from 'src/common/mappers/email-id.mapper'; @Module({ - controllers: [TimesheetController], - providers: [ + controllers: [ + TimesheetController + ], + providers: [ GetTimesheetsOverviewService, EmailToIdResolver, TimesheetApprovalService, ], - exports: [TimesheetApprovalService], + exports: [ + TimesheetApprovalService + ], }) -export class TimesheetsModule {} +export class TimesheetsModule { }