From aa72651a67607f20315f6c702a9080303f27078f Mon Sep 17 00:00:00 2001 From: Matthieu Haineault Date: Fri, 27 Feb 2026 10:09:24 -0500 Subject: [PATCH] refactor(EsLint): EsLint corrections --- eslint.config.mjs | 4 +- src/app.controller.ts | 2 +- src/app.module.ts | 2 - src/chatbot/chatbot.controller.ts | 41 ++++---- src/chatbot/chatbot.module.ts | 15 ++- src/chatbot/chatbot.service.ts | 35 +------ src/chatbot/dtos/dialog-message.dto.ts | 7 +- src/chatbot/dtos/page-context.dto.ts | 17 +--- src/chatbot/dtos/user-message.dto.ts | 19 ++-- .../decorators/module-access.decorators.ts | 13 ++- src/common/guards/modules.guard.ts | 20 ++-- src/common/mappers/bank-type-id.mapper.ts | 10 +- src/common/mappers/email-id.mapper.ts | 14 +-- src/common/mappers/full-name.mapper.ts | 7 +- src/common/mappers/shifts-id.mapper.ts | 4 +- src/common/mappers/timesheet.mapper.ts | 10 +- src/common/shared/base-approval.service.ts | 11 ++- src/common/shared/build-prisma-where.ts | 21 ----- .../ticket.test.http | 0 .../shared/helpers/boolean.helpers.ts | 38 -------- .../shared/helpers/number.helpers.ts | 1 - .../shared/helpers/string.helpers.ts | 1 - .../authentication/auth.module.ts | 26 +++-- .../controllers/auth.controller.ts | 2 +- .../guards/authentik-auth.guard.ts | 3 +- .../serializers/express-session.serializer.ts | 2 +- .../services/authentik-auth.service.ts | 3 +- .../strategies/authentik.strategy.ts | 8 +- .../employees/employees.controller.ts | 16 +++- .../employees/employees.module.ts | 9 +- .../help/help-page.controller.ts | 4 +- .../help/help-page.module.ts | 13 ++- .../help/help-page.service.ts | 4 +- .../preferences/preferences.controller.ts | 9 +- .../preferences/preferences.module.ts | 13 ++- .../preferences/preferences.service.ts | 10 +- .../user-module-access/module-acces.dto.ts | 12 +-- .../module-access.controller.ts | 11 ++- .../module-access.module.ts | 14 ++- .../services/module-access-get.service.ts | 5 +- .../services/module-access-update.service.ts | 11 ++- .../services/abstract-user.service.ts | 4 +- .../users-management/user.dto.ts | 2 +- .../users-management/users.module.ts | 12 ++- src/main.ts | 10 +- src/shared/archival/archival.module.ts | 34 ------- src/shared/archival/archival.service.ts | 38 -------- .../employees-archive.controller.ts | 32 ------- .../expenses-archive.controller.ts | 31 ------ .../leave-requests-archive.controller.ts | 7 -- .../controllers/shifts-archive.controller.ts | 31 ------ .../timesheets-archive.controller.ts | 32 ------- .../notifications/notification.constants.ts | 4 - .../notifications/notification.types.ts | 9 -- .../notifications/notifications.controller.ts | 21 ----- .../notifications/notifications.module.ts | 9 -- .../notifications/notifications.service.ts | 62 ------------ .../bank-codes/bank-codes.controller.ts | 10 +- .../bank-codes/bank-codes.module.ts | 9 +- .../bank-codes/bank-codes.service.ts | 13 ++- .../domains/business-logics.module.ts | 1 - .../domains/services/banking-hours.service.ts | 11 ++- .../domains/services/holiday.service.ts | 19 +++- .../domains/services/mileage.service.ts | 5 +- .../domains/services/overtime.service.ts | 16 +++- .../domains/services/sick-leave.service.ts | 94 +++++-------------- .../domains/services/vacation.service.ts | 7 +- .../expenses/expense.controller.ts | 7 +- .../expenses/expense.utils.ts | 28 +++--- .../expenses/expenses.module.ts | 4 +- .../services/expense-create.service.ts | 9 +- .../services/expense-delete.service.ts | 15 +-- .../services/expense-update.service.ts | 11 ++- .../exports/csv-exports.controller.ts | 2 +- .../exports/csv-exports.module.ts | 4 +- .../exports/csv-exports.utils.ts | 2 +- .../exports/services/csv-builder.service.ts | 4 +- .../exports/services/csv-exports.service.ts | 26 ++--- src/time-and-attendance/utils/type.utils.ts | 1 - 79 files changed, 401 insertions(+), 702 deletions(-) delete mode 100644 src/common/shared/build-prisma-where.ts rename src/customer-support/{tickets => http-test-files}/ticket.test.http (100%) delete mode 100644 src/customer-support/shared/helpers/boolean.helpers.ts delete mode 100644 src/customer-support/shared/helpers/number.helpers.ts delete mode 100644 src/customer-support/shared/helpers/string.helpers.ts delete mode 100644 src/shared/archival/archival.module.ts delete mode 100644 src/shared/archival/archival.service.ts delete mode 100644 src/shared/archival/controllers/employees-archive.controller.ts delete mode 100644 src/shared/archival/controllers/expenses-archive.controller.ts delete mode 100644 src/shared/archival/controllers/leave-requests-archive.controller.ts delete mode 100644 src/shared/archival/controllers/shifts-archive.controller.ts delete mode 100644 src/shared/archival/controllers/timesheets-archive.controller.ts delete mode 100644 src/shared/notifications/notification.constants.ts delete mode 100644 src/shared/notifications/notification.types.ts delete mode 100644 src/shared/notifications/notifications.controller.ts delete mode 100644 src/shared/notifications/notifications.module.ts delete mode 100644 src/shared/notifications/notifications.service.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index caebf6e..1080982 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,6 +1,6 @@ // @ts-check import eslint from '@eslint/js'; -import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; +// import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; import globals from 'globals'; import tseslint from 'typescript-eslint'; @@ -10,7 +10,7 @@ export default tseslint.config( }, eslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, - eslintPluginPrettierRecommended, + // eslintPluginPrettierRecommended, { languageOptions: { globals: { diff --git a/src/app.controller.ts b/src/app.controller.ts index 0aa298e..2bd8f1e 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get } from '@nestjs/common'; +import { Controller } from '@nestjs/common'; @Controller() export class AppController { } diff --git a/src/app.module.ts b/src/app.module.ts index fd455bd..349a9da 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,7 +1,6 @@ import { BadRequestException, Module, ValidationPipe } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { NotificationsModule } from './shared/notifications/notifications.module'; import { PrismaPostgresModule } from '../prisma/postgres/prisma-postgres.module'; import { ScheduleModule } from '@nestjs/schedule'; import { ConfigModule } from '@nestjs/config'; @@ -21,7 +20,6 @@ import { CustomerSupportModule } from 'src/customer-support/customer-support.mod AuthenticationModule, ConfigModule.forRoot({ isGlobal: true }), ScheduleModule.forRoot(), //cronjobs - NotificationsModule, PrismaPostgresModule, PrismaMariadbModule, PrismaLegacyModule, diff --git a/src/chatbot/chatbot.controller.ts b/src/chatbot/chatbot.controller.ts index 378a7b0..c6b4a2a 100644 --- a/src/chatbot/chatbot.controller.ts +++ b/src/chatbot/chatbot.controller.ts @@ -8,26 +8,29 @@ import { Modules as ModulesEnum } from "prisma/postgres/generated/prisma/client/ @Controller('chatbot') export class ChatbotController { - constructor(private readonly chatbotService: ChatbotService) {} + constructor(private readonly chatbotService: ChatbotService) { } - @Post('') - @ModuleAccessAllowed(ModulesEnum.chatbot) - async testConnection(@Body() body: UserMessageDto, @Access('email') email: string): Promise { - return await this.chatbotService.pingExternalApi(body, email); - } + @Post('') + @ModuleAccessAllowed(ModulesEnum.chatbot) + async testConnection( + @Body() body: UserMessageDto, + @Access('email') email: string, + ): Promise { + return await this.chatbotService.pingExternalApi(body, email); + } - // @Post('context') - // @ModuleAccessAllowed(ModulesEnum.chatbot) - // async sendContext(@Body() body: PageContextDto): Promise { - // const sendPageContext = await this.chatbotService.sendPageContext(body); - // return sendPageContext; - // } + // @Post('context') + // @ModuleAccessAllowed(ModulesEnum.chatbot) + // async sendContext(@Body() body: PageContextDto): Promise { + // const sendPageContext = await this.chatbotService.sendPageContext(body); + // return sendPageContext; + // } - // Will have to modify later on to accomodate newer versions of User Auth/User type Structure - // @Post('user') - // @ModuleAccessAllowed(ModulesEnum.chatbot) - // async sendUserCredentials(@Access('email') email: string,): Promise { - // const sendUserContext = await this.chatbotService.sendUserContext(email); - // return sendUserContext; - // } + // Will have to modify later on to accomodate newer versions of User Auth/User type Structure + // @Post('user') + // @ModuleAccessAllowed(ModulesEnum.chatbot) + // async sendUserCredentials(@Access('email') email: string,): Promise { + // const sendUserContext = await this.chatbotService.sendUserContext(email); + // return sendUserContext; + // } } diff --git a/src/chatbot/chatbot.module.ts b/src/chatbot/chatbot.module.ts index 0e61e04..6dd97e1 100644 --- a/src/chatbot/chatbot.module.ts +++ b/src/chatbot/chatbot.module.ts @@ -4,9 +4,14 @@ import { HttpModule } from '@nestjs/axios'; import { ChatbotService } from 'src/chatbot/chatbot.service'; @Module({ - imports: [HttpModule], - controllers: [ChatbotController], - providers: [ChatbotService], - exports: [], + imports: [ + HttpModule, + ], + controllers: [ + ChatbotController, + ], + providers: [ + ChatbotService, + ], }) -export class ChatbotModule {} +export class ChatbotModule { } diff --git a/src/chatbot/chatbot.service.ts b/src/chatbot/chatbot.service.ts index 6fe900d..fc39bfb 100644 --- a/src/chatbot/chatbot.service.ts +++ b/src/chatbot/chatbot.service.ts @@ -1,8 +1,7 @@ import { Injectable } from '@nestjs/common'; -import { UserMessageDto } from 'src/chatbot/dtos/user-message.dto'; import { HttpService } from '@nestjs/axios'; import { firstValueFrom } from 'rxjs'; -import { PageContextDto } from 'src/chatbot/dtos/page-context.dto'; +import { ChatbotResponseDto, UserMessageDto } from 'src/chatbot/dtos/user-message.dto'; import { Message } from 'src/chatbot/dtos/dialog-message.dto'; @Injectable() @@ -14,41 +13,11 @@ export class ChatbotService { const { data } = await firstValueFrom(this.httpService.post( 'https://n8nai.targo.ca/webhook/chatty-Mcbot', { userInput: body.userInput, userId: email, sessionId: this.sessionId, pageContext: body.pageContext ?? undefined } - )); + )) as ChatbotResponseDto; return { text: data[0].output, sent: false, }; } - - // async sendPageContext(body: PageContextDto, email: string) { - // const { data } = await firstValueFrom( - // this.httpService.post( - // 'https://n8nai.targo.ca/webhook/chatty-Mcbot', - // { features: body, userId: email, userInput: '' }, - // ), - // ); - // return data; - // } - - // Will have to modify later on to accomodate newer versions of User Auth/User type Structure - // async sendUserContext(user_email: string) { - // if (!this.sessionId) { - // this.sessionId = 'SessionId = ' + user_email; - // } - - // const response = await firstValueFrom( - // this.httpService.post( - // 'https://n8nai.targo.ca/webhook/chatty-Mcbot', - // { - // userId: this.sessionId, - // userInput: '', - // features: '', - // }, - // { headers: { 'Content-Tyoe': 'application/json' } }, - // ), - // ); - // return response.data; - // } } diff --git a/src/chatbot/dtos/dialog-message.dto.ts b/src/chatbot/dtos/dialog-message.dto.ts index 0ba70e8..8f34fe6 100644 --- a/src/chatbot/dtos/dialog-message.dto.ts +++ b/src/chatbot/dtos/dialog-message.dto.ts @@ -1,9 +1,6 @@ import { IsBoolean, IsString } from 'class-validator'; export class Message { - @IsString() - text!: string; - - @IsBoolean() - sent!: boolean; + @IsString() text: string; + @IsBoolean() sent: boolean; } diff --git a/src/chatbot/dtos/page-context.dto.ts b/src/chatbot/dtos/page-context.dto.ts index aeee68f..953e477 100644 --- a/src/chatbot/dtos/page-context.dto.ts +++ b/src/chatbot/dtos/page-context.dto.ts @@ -1,15 +1,8 @@ -import { IsArray, IsString } from 'class-validator'; +import { IsArray, IsOptional, IsString } from 'class-validator'; export class PageContextDto { - @IsString() - name: string; - - @IsString() - description: string; - - @IsArray() - features: string[]; - - @IsString() - path?: string; + @IsString() name: string; + @IsString() description: string; + @IsArray() features: string[]; + @IsString() @IsOptional() path?: string; } diff --git a/src/chatbot/dtos/user-message.dto.ts b/src/chatbot/dtos/user-message.dto.ts index 39cb1c6..67a46f7 100644 --- a/src/chatbot/dtos/user-message.dto.ts +++ b/src/chatbot/dtos/user-message.dto.ts @@ -1,11 +1,18 @@ -import { Transform, Type } from 'class-transformer'; +import { Type } from 'class-transformer'; import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; import { PageContextDto } from './page-context.dto'; export class UserMessageDto { - @IsString() - @IsNotEmpty() - @Transform(({ value }) => value.trim()) - userInput!: string; - @IsOptional() @Type(() => PageContextDto) pageContext?: PageContextDto | undefined; + @IsString() + @IsNotEmpty() + @IsString() userInput: string; + @IsOptional() @Type(() => PageContextDto) pageContext?: PageContextDto | undefined; } + +export class ChatbotResponseDto { + @Type(() => ChatbotOutput) data: ChatbotOutput[]; +} + +export class ChatbotOutput { + @IsString() output: string; +} \ No newline at end of file diff --git a/src/common/decorators/module-access.decorators.ts b/src/common/decorators/module-access.decorators.ts index b5cc71d..30219a6 100644 --- a/src/common/decorators/module-access.decorators.ts +++ b/src/common/decorators/module-access.decorators.ts @@ -1,9 +1,14 @@ import { createParamDecorator, ExecutionContext } from "@nestjs/common"; +import { UserDto } from "src/identity-and-account/users-management/user.dto"; -export const Access = createParamDecorator( - (data:string, ctx: ExecutionContext) => { - const request = ctx.switchToHttp().getRequest(); - const user = request.user; +export interface AuthenticatedRequest extends Request { + user: UserDto; +} + +export const Access = createParamDecorator( + (data, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + const user: UserDto = request.user; return data ? user?.[data] : user; }, ); \ No newline at end of file diff --git a/src/common/guards/modules.guard.ts b/src/common/guards/modules.guard.ts index 3471f8d..b3d99b0 100644 --- a/src/common/guards/modules.guard.ts +++ b/src/common/guards/modules.guard.ts @@ -7,13 +7,7 @@ import { import { Reflector } from '@nestjs/core'; import { MODULES_KEY } from '../decorators/modules-guard.decorators'; import { Modules } from "prisma/postgres/generated/prisma/client/postgres/client"; - - - -interface RequestWithUser extends Request { - // TODO: Create an actual user model based on OAuth signin - user: any; -} +import { AuthenticatedRequest } from 'src/common/decorators/module-access.decorators'; @Injectable() export class ModulesGuard implements CanActivate { @@ -27,18 +21,18 @@ export class ModulesGuard implements CanActivate { if (!requiredModules || requiredModules.length === 0) { return true; } - const request = ctx.switchToHttp().getRequest(); + const request = ctx.switchToHttp().getRequest(); const user = request.user; if (!user) { return false; } for (const module of requiredModules) { - if (!user.user_module_access.includes(module)) { - throw new ForbiddenException( - `This account does not have required access to: ${module}. current user modules: ${user.user_module_access} , required modules: ${requiredModules}`, - ); - } + if (!user.user_module_access.includes(module)) { + throw new ForbiddenException( + `This account does not have required access to: ${module}. current user modules: ${user.user_module_access.toString()} , required modules: ${requiredModules.toString()}`, + ); + } } return true; } diff --git a/src/common/mappers/bank-type-id.mapper.ts b/src/common/mappers/bank-type-id.mapper.ts index 9601a2e..bc1dd8a 100644 --- a/src/common/mappers/bank-type-id.mapper.ts +++ b/src/common/mappers/bank-type-id.mapper.ts @@ -1,7 +1,7 @@ import { Injectable } from "@nestjs/common"; import { Prisma, PrismaClient } from "prisma/postgres/generated/prisma/client/postgres/client"; -import { Result } from "src/common/errors/result-error.factory"; import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; +import { Result } from "src/common/errors/result-error.factory"; type Tx = Prisma.TransactionClient | PrismaClient; @@ -25,7 +25,9 @@ export class BankCodesResolver { }; //finds only id by type - readonly findBankCodeIDByType = async (type: string, client?: Tx + readonly findBankCodeIDByType = async ( + type: string, + client?: Tx ): Promise> => { const db = (client ?? this.prisma) as PrismaClient; const bank_code = await db.bankCodes.findFirst({ @@ -37,7 +39,9 @@ export class BankCodesResolver { return { success: true, data: bank_code.id }; } - readonly findTypeByBankCodeId = async (bank_code_id: number, client?: Tx + readonly findTypeByBankCodeId = async ( + bank_code_id: number, + client?: Tx ): Promise> => { const db = (client ?? this.prisma) as PrismaClient; const bank_code = await db.bankCodes.findFirst({ diff --git a/src/common/mappers/email-id.mapper.ts b/src/common/mappers/email-id.mapper.ts index 14f7a9f..cbd5a55 100644 --- a/src/common/mappers/email-id.mapper.ts +++ b/src/common/mappers/email-id.mapper.ts @@ -1,8 +1,8 @@ -import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; import { Injectable } from "@nestjs/common"; -import { Result } from "src/common/errors/result-error.factory"; +import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; import { Prisma, PrismaClient } from "prisma/postgres/generated/prisma/client/postgres/client"; +import { Result } from "src/common/errors/result-error.factory"; type Tx = Prisma.TransactionClient | PrismaClient; @@ -12,7 +12,9 @@ export class EmailToIdResolver { constructor(private readonly prisma: PrismaPostgresService) { } // find employee_id using email - readonly findIdByEmail = async (email: string, client?: Tx + readonly findIdByEmail = async ( + email: string, + client?: Tx ): Promise> => { const db = (client ?? this.prisma) as PrismaClient; const employee = await db.employees.findFirst({ @@ -24,7 +26,9 @@ export class EmailToIdResolver { } // find user_id using email - readonly resolveUserIdWithEmail = async (email: string, client?: Tx + readonly resolveUserIdWithEmail = async ( + email: string, + client?: Tx ): Promise> => { const db = (client ?? this.prisma) as PrismaClient; const user = await db.users.findFirst({ @@ -34,6 +38,4 @@ export class EmailToIdResolver { if (!user) return { success: false, error: `EMPLOYEE_NOT_FOUND` }; return { success: true, data: user.id }; } - - readonly findFullNameByEmail } \ No newline at end of file diff --git a/src/common/mappers/full-name.mapper.ts b/src/common/mappers/full-name.mapper.ts index ba8df89..cc55b41 100644 --- a/src/common/mappers/full-name.mapper.ts +++ b/src/common/mappers/full-name.mapper.ts @@ -1,7 +1,7 @@ import { Injectable } from "@nestjs/common"; -import { Result } from "src/common/errors/result-error.factory"; import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; import { Prisma, PrismaClient } from "prisma/postgres/generated/prisma/client/postgres/client"; +import { Result } from "src/common/errors/result-error.factory"; type Tx = Prisma.TransactionClient | PrismaClient; @@ -9,7 +9,10 @@ type Tx = Prisma.TransactionClient | PrismaClient; export class FullNameResolver { constructor(private readonly prisma: PrismaPostgresService) { } - readonly resolveFullName = async (employee_id: number, client?: Tx): Promise> => { + readonly resolveFullName = async ( + employee_id: number, + client?: Tx + ): Promise> => { const db = (client ?? this.prisma) as PrismaClient; const employee = await db.employees.findUnique({ where: { id: employee_id }, diff --git a/src/common/mappers/shifts-id.mapper.ts b/src/common/mappers/shifts-id.mapper.ts index d8c5a04..1537cdc 100644 --- a/src/common/mappers/shifts-id.mapper.ts +++ b/src/common/mappers/shifts-id.mapper.ts @@ -19,7 +19,9 @@ interface ShiftKey { export class ShiftIdResolver { constructor(private readonly prisma: PrismaPostgresService) { } - readonly findShiftIdByData = async (key: ShiftKey, client?: Tx + readonly findShiftIdByData = async ( + key: ShiftKey, + client?: Tx ): Promise> => { const db = (client ?? this.prisma) as PrismaClient; const shift = await db.shifts.findFirst({ diff --git a/src/common/mappers/timesheet.mapper.ts b/src/common/mappers/timesheet.mapper.ts index ba44d4a..31e8bfc 100644 --- a/src/common/mappers/timesheet.mapper.ts +++ b/src/common/mappers/timesheet.mapper.ts @@ -1,8 +1,8 @@ import { Injectable } from "@nestjs/common"; -import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; import { EmailToIdResolver } from "./email-id.mapper"; -import { Result } from "src/common/errors/result-error.factory"; import { weekStartSunday } from "src/common/utils/date-utils"; +import { Result } from "src/common/errors/result-error.factory"; +import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service"; import { PrismaClient } from "prisma/postgres/generated/prisma/client/postgres/internal/class"; import { Prisma } from "prisma/postgres/generated/prisma/client/postgres/client"; @@ -16,7 +16,11 @@ export class EmployeeTimesheetResolver { private readonly emailResolver: EmailToIdResolver, ) { } - readonly findTimesheetIdByEmail = async (email: string, date: Date, client?: Tx): Promise> => { + readonly findTimesheetIdByEmail = async ( + email: string, + date: Date, + client?: Tx + ): Promise> => { const db = (client ?? this.prisma) as PrismaClient; const employee_id = await this.emailResolver.findIdByEmail(email); if (!employee_id.success) return { success: false, error: employee_id.error } diff --git a/src/common/shared/base-approval.service.ts b/src/common/shared/base-approval.service.ts index 212a4c3..4e25e2c 100644 --- a/src/common/shared/base-approval.service.ts +++ b/src/common/shared/base-approval.service.ts @@ -20,7 +20,10 @@ export abstract class BaseApprovalService { protected abstract delegateFor(tx: TransactionClient): UpdatableDelegate; //standard update Aproval - async updateApproval(id: number, is_approved: boolean): Promise { + async updateApproval( + id: number, + is_approved: boolean + ): Promise { try { return await this.delegate.update({ where: { id }, @@ -34,7 +37,11 @@ export abstract class BaseApprovalService { } } - async updateApprovalWithTransaction(tx: TransactionClient, id: number, is_approved: boolean): Promise { + async updateApprovalWithTransaction( + tx: TransactionClient, + id: number, + is_approved: boolean + ): Promise { try { return await this.delegateFor(tx).update({ where: { id }, diff --git a/src/common/shared/build-prisma-where.ts b/src/common/shared/build-prisma-where.ts deleted file mode 100644 index 1b8f8fc..0000000 --- a/src/common/shared/build-prisma-where.ts +++ /dev/null @@ -1,21 +0,0 @@ -//Prisma 'where' clause for DTO filters -export function buildPrismaWhere>(dto: T): Record { - const where: Record = {}; - - for (const [key,value] of Object.entries(dto)) { - if (value === undefined || value === null) continue; - - if (key.endsWith('_contains')) { - const field = key.slice(0, - '_contains'.length); - where[field] = { constains: value }; - } else if (key === 'start_date' || key === 'end_date') { - where.date = where.date || {}; - const op = key === 'start_date' ? 'gte' : 'lte'; - where.date[op] = new Date(value); - } else { - where[key] = value; - } - } - - return where; -} \ No newline at end of file diff --git a/src/customer-support/tickets/ticket.test.http b/src/customer-support/http-test-files/ticket.test.http similarity index 100% rename from src/customer-support/tickets/ticket.test.http rename to src/customer-support/http-test-files/ticket.test.http diff --git a/src/customer-support/shared/helpers/boolean.helpers.ts b/src/customer-support/shared/helpers/boolean.helpers.ts deleted file mode 100644 index 8b9c595..0000000 --- a/src/customer-support/shared/helpers/boolean.helpers.ts +++ /dev/null @@ -1,38 +0,0 @@ -// //This file is used to store function that help translate MariaDB data to Typescript manipulation requirements for the type "boolean". - -// import { PhoneAddrEnhancedCapable } from "src/customer-support/dtos/phone.dto"; - -// //From MariaDB to Frontend -// export const fromTinyIntToBoolean = async (tinyInt: number): Promise => { -// let booleanValue = true; -// if ((tinyInt = 0) || (tinyInt = -1)) return booleanValue = false; -// return booleanValue; -// } - -// //From Frontend to MariaDB TinyInt boolean 1 - 0 -// export const fromBooleanToTinyInt = async (boolean: boolean): Promise => { -// return boolean ? 1 : 0; -// } - -// //From Frontend to MariaDB TinyInt boolean -1 - 1 -// export const fromBooleanToTinyIntNegative = async (boolean: boolean): Promise => { -// return boolean ? 1 : -1; -// } - -// //From MariaDB to Frontend String boolean yes - no / Y - N / etc... -// export const fromStringToBoolean = async (string: string): Promise => { -// let booleanValue = true; -// let stringValue = string.toLowerCase(); -// if ((stringValue = "n") || (stringValue = "no") || (stringValue = "non")) { -// return booleanValue = false; -// } -// return booleanValue; -// } - -// export const fromBooleanToEnum = async (boolean: boolean): Promise => { -// return boolean ? PhoneAddrEnhancedCapable.Y : PhoneAddrEnhancedCapable.N; -// } - -// export const fromEnumToBoolean = async (enumValue: PhoneAddrEnhancedCapable): Promise => { -// return enumValue ? true : false; -// } \ No newline at end of file diff --git a/src/customer-support/shared/helpers/number.helpers.ts b/src/customer-support/shared/helpers/number.helpers.ts deleted file mode 100644 index b4b775b..0000000 --- a/src/customer-support/shared/helpers/number.helpers.ts +++ /dev/null @@ -1 +0,0 @@ -//This file is used to store function that help translate MariaDB data to Typescript manipulation requirements for the type "number". \ No newline at end of file diff --git a/src/customer-support/shared/helpers/string.helpers.ts b/src/customer-support/shared/helpers/string.helpers.ts deleted file mode 100644 index cd9fa5b..0000000 --- a/src/customer-support/shared/helpers/string.helpers.ts +++ /dev/null @@ -1 +0,0 @@ -//This file is used to store function that help translate MariaDB data to Typescript manipulation requirements for the type "string". \ No newline at end of file diff --git a/src/identity-and-account/authentication/auth.module.ts b/src/identity-and-account/authentication/auth.module.ts index ce27768..e70b417 100644 --- a/src/identity-and-account/authentication/auth.module.ts +++ b/src/identity-and-account/authentication/auth.module.ts @@ -9,17 +9,23 @@ import { UsersService } from 'src/identity-and-account/users-management/services @Module({ - imports: [ PassportModule.register({ - session: true, - defaultStrategy: 'openidconnect' - }), UsersModule, ], - providers: [ - AuthentikAuthService, - AuthentikStrategy, + imports: [ + PassportModule.register({ + session: true, + defaultStrategy: 'openidconnect' + }), UsersModule, + ], + providers: [ + AuthentikAuthService, + AuthentikStrategy, ExpressSessionSerializer, UsersService, ], - exports: [ AuthentikAuthService ], - controllers: [AuthController], + exports: [ + AuthentikAuthService + ], + controllers: [ + AuthController + ], }) -export class AuthenticationModule {} +export class AuthenticationModule { } diff --git a/src/identity-and-account/authentication/controllers/auth.controller.ts b/src/identity-and-account/authentication/controllers/auth.controller.ts index 7abcba6..59966fc 100644 --- a/src/identity-and-account/authentication/controllers/auth.controller.ts +++ b/src/identity-and-account/authentication/controllers/auth.controller.ts @@ -16,7 +16,7 @@ export class AuthController { @Get('callback') @UseGuards(OIDCLoginGuard) - loginCallback(@Req() req: Request, @Res() res: Response) { + loginCallback(@Req() _req: Request, @Res() res: Response) { res.redirect(process.env.REDIRECT_URL_DEV!); } diff --git a/src/identity-and-account/authentication/guards/authentik-auth.guard.ts b/src/identity-and-account/authentication/guards/authentik-auth.guard.ts index ff4f44d..6a71ce6 100644 --- a/src/identity-and-account/authentication/guards/authentik-auth.guard.ts +++ b/src/identity-and-account/authentication/guards/authentik-auth.guard.ts @@ -1,11 +1,12 @@ import { ExecutionContext, Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; +import { Request } from 'express'; @Injectable() export class OIDCLoginGuard extends AuthGuard('openidconnect') { async canActivate(context: ExecutionContext) { const result = (await super.canActivate(context)) as boolean; - const request = context.switchToHttp().getRequest(); + const request = context.switchToHttp().getRequest(); await super.logIn(request); return result; } diff --git a/src/identity-and-account/authentication/serializers/express-session.serializer.ts b/src/identity-and-account/authentication/serializers/express-session.serializer.ts index c3d87c0..4c0a6d7 100644 --- a/src/identity-and-account/authentication/serializers/express-session.serializer.ts +++ b/src/identity-and-account/authentication/serializers/express-session.serializer.ts @@ -9,7 +9,7 @@ export class ExpressSessionSerializer extends PassportSerializer { } done(null, user); } - deserializeUser(payload: any, done: (err: any, payload: string) => void): any { + deserializeUser(payload: any, done: (err: any, payload: any) => void): any { if (!payload){ done(new UnauthorizedException('Deserialize user error'), payload); } diff --git a/src/identity-and-account/authentication/services/authentik-auth.service.ts b/src/identity-and-account/authentication/services/authentik-auth.service.ts index 974a1eb..d450031 100644 --- a/src/identity-and-account/authentication/services/authentik-auth.service.ts +++ b/src/identity-and-account/authentication/services/authentik-auth.service.ts @@ -1,12 +1,13 @@ import { Injectable } from '@nestjs/common'; import { UsersService } from 'src/identity-and-account/users-management/services/users.service'; +import { UserDto } from 'src/identity-and-account/users-management/user.dto'; @Injectable() export class AuthentikAuthService { constructor(private usersService: UsersService) {} - async validateUser(user_email: string): Promise { + async validateUser(user_email: string): Promise> { const user = await this.usersService.findOneByEmail(user_email); return user; diff --git a/src/identity-and-account/authentication/strategies/authentik.strategy.ts b/src/identity-and-account/authentication/strategies/authentik.strategy.ts index 6f9c5b0..47ca526 100644 --- a/src/identity-and-account/authentication/strategies/authentik.strategy.ts +++ b/src/identity-and-account/authentication/strategies/authentik.strategy.ts @@ -39,9 +39,9 @@ export class AuthentikStrategy extends PassportStrategy(OIDCStrategy, 'openidcon async validate( _issuer: string, - profile: Profile, + _profile: Profile, _context: any, - _idToken: string, + idToken: string, _accessToken: string, _refreshToken: string, _params: any, @@ -50,9 +50,9 @@ export class AuthentikStrategy extends PassportStrategy(OIDCStrategy, 'openidcon try { - const components = _idToken.split('.'); + const components = idToken.split('.'); const payload = Buffer.from(components[1], "base64").toString('utf-8'); - const claims = JSON.parse(payload); + const claims = JSON.parse(payload) as AuthentikPayload; if (!claims.email) return cb(new Error('Missing email in OIDC profile'), false); diff --git a/src/identity-and-account/employees/employees.controller.ts b/src/identity-and-account/employees/employees.controller.ts index 42dbd2a..c673ff9 100644 --- a/src/identity-and-account/employees/employees.controller.ts +++ b/src/identity-and-account/employees/employees.controller.ts @@ -18,13 +18,17 @@ export class EmployeesController { @Get('personal-profile') @ModuleAccessAllowed(ModulesEnum.personal_profile) - async findOwnProfile(@Access('email') email: string): Promise, string>> { + async findOwnProfile( + @Access('email') email: string + ): Promise, string>> { return await this.getService.findOwnProfile(email); } @Get('profile') @ModuleAccessAllowed(ModulesEnum.personal_profile) - async findProfile(@Access('email') email: string, @Query('employee_email') employee_email?: string, + async findProfile( + @Access('email') email: string, + @Query('employee_email') employee_email?: string, ): Promise, string>> { return await this.getService.findOneDetailedProfile(email, employee_email); } @@ -37,13 +41,17 @@ export class EmployeesController { @Post('create') @ModuleAccessAllowed(ModulesEnum.employee_management) - async createEmployee(@Body() dto: EmployeeDetailedUpsertDto): Promise> { + async createEmployee( + @Body() dto: EmployeeDetailedUpsertDto + ): Promise> { return await this.createService.createEmployee(dto); } @Patch('update') @ModuleAccessAllowed(ModulesEnum.employee_management) - async updateEmployee(@Body() dto:EmployeeDetailedUpsertDto){ + async updateEmployee( + @Body() dto:EmployeeDetailedUpsertDto + ){ return await this.updateService.updateEmployee(dto); } } diff --git a/src/identity-and-account/employees/employees.module.ts b/src/identity-and-account/employees/employees.module.ts index 235f62a..3962d13 100644 --- a/src/identity-and-account/employees/employees.module.ts +++ b/src/identity-and-account/employees/employees.module.ts @@ -7,8 +7,9 @@ import { EmployeesUpdateService } from 'src/identity-and-account/employees/servi import { EmployeesCreateService } from 'src/identity-and-account/employees/services/employees-create.service'; @Module({ - imports: [], - controllers: [EmployeesController], + controllers: [ + EmployeesController + ], providers: [ EmployeesGetService, EmployeesUpdateService, @@ -16,6 +17,8 @@ import { EmployeesCreateService } from 'src/identity-and-account/employees/servi AccessGetService, EmailToIdResolver ], - exports: [EmployeesGetService], + exports: [ + EmployeesGetService + ], }) export class EmployeesModule { } diff --git a/src/identity-and-account/help/help-page.controller.ts b/src/identity-and-account/help/help-page.controller.ts index b189468..596ad26 100644 --- a/src/identity-and-account/help/help-page.controller.ts +++ b/src/identity-and-account/help/help-page.controller.ts @@ -10,7 +10,9 @@ export class HomePageController { @Get('help') @ModuleAccessAllowed(ModulesEnum.dashboard) - async getIntroductionHelper(@Access('email') email: string) { + async getIntroductionHelper( + @Access('email') email: string + ) { return await this.homePageService.buildHomePageHelpMessage(email); } } \ No newline at end of file diff --git a/src/identity-and-account/help/help-page.module.ts b/src/identity-and-account/help/help-page.module.ts index b1d91e5..02d62bb 100644 --- a/src/identity-and-account/help/help-page.module.ts +++ b/src/identity-and-account/help/help-page.module.ts @@ -4,8 +4,15 @@ import { HomePageController } from "src/identity-and-account/help/help-page.cont import { HomePageService } from "src/identity-and-account/help/help-page.service"; @Module({ - controllers: [HomePageController], - providers: [HomePageService, EmailToIdResolver], - exports: [HomePageService], + controllers: [ + HomePageController + ], + providers: [ + HomePageService, + EmailToIdResolver + ], + exports: [ + HomePageService + ], }) export class HomePageModule { }; \ No newline at end of file diff --git a/src/identity-and-account/help/help-page.service.ts b/src/identity-and-account/help/help-page.service.ts index 085c16d..014724d 100644 --- a/src/identity-and-account/help/help-page.service.ts +++ b/src/identity-and-account/help/help-page.service.ts @@ -10,7 +10,9 @@ export class HomePageService { private readonly emailresolver: EmailToIdResolver, ) { } - buildHomePageHelpMessage = async (email: string): Promise> => { + buildHomePageHelpMessage = async ( + email: string + ): Promise> => { const user_id = await this.emailresolver.resolveUserIdWithEmail(email); if (!user_id.success) return { success: false, error: 'INVALID_EMAIL' }; diff --git a/src/identity-and-account/preferences/preferences.controller.ts b/src/identity-and-account/preferences/preferences.controller.ts index 6c6a814..ffc1292 100644 --- a/src/identity-and-account/preferences/preferences.controller.ts +++ b/src/identity-and-account/preferences/preferences.controller.ts @@ -12,14 +12,19 @@ export class PreferencesController { @Patch('update') @ModuleAccessAllowed(ModulesEnum.personal_profile) - async updatePreferences(@Access('email') email: string, @Body() payload: PreferencesDto + async updatePreferences( + @Access('email') email: string, + @Body() payload: PreferencesDto ): Promise> { return this.service.updatePreferences(email, payload); } @Get() @ModuleAccessAllowed(ModulesEnum.personal_profile) - async findPreferences(@Access('email') email: string, @Query() employee_email?: string) { + async findPreferences( + @Access('email') email: string, + @Query() employee_email?: string + ) { return this.service.findPreferences(email, employee_email); } diff --git a/src/identity-and-account/preferences/preferences.module.ts b/src/identity-and-account/preferences/preferences.module.ts index 51e9117..9a8b6b7 100644 --- a/src/identity-and-account/preferences/preferences.module.ts +++ b/src/identity-and-account/preferences/preferences.module.ts @@ -4,9 +4,16 @@ import { PreferencesService } from "./preferences.service"; import { Module } from "@nestjs/common"; @Module({ - controllers: [ PreferencesController ], - providers: [ PreferencesService, EmailToIdResolver ], - exports: [ PreferencesService ], + controllers: [ + PreferencesController + ], + providers: [ + PreferencesService, + EmailToIdResolver + ], + exports: [ + PreferencesService + ], }) export class PreferencesModule {} \ No newline at end of file diff --git a/src/identity-and-account/preferences/preferences.service.ts b/src/identity-and-account/preferences/preferences.service.ts index ab188df..87cd37a 100644 --- a/src/identity-and-account/preferences/preferences.service.ts +++ b/src/identity-and-account/preferences/preferences.service.ts @@ -11,7 +11,10 @@ export class PreferencesService { private readonly emailResolver: EmailToIdResolver, ) { } - async findPreferences(email: string, employee_email?: string): Promise> { + async findPreferences( + email: string, + employee_email?: string + ): Promise> { const account_email = employee_email ?? email; const user_id = await this.emailResolver.resolveUserIdWithEmail(account_email); if (!user_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; @@ -42,7 +45,10 @@ export class PreferencesService { return { success: true, data: preferences }; } - async updatePreferences(email: string, dto: PreferencesDto): Promise> { + async updatePreferences( + email: string, + dto: PreferencesDto + ): Promise> { const user_id = await this.emailResolver.resolveUserIdWithEmail(email); if (!user_id.success) return { success: false, error: user_id.error } diff --git a/src/identity-and-account/user-module-access/module-acces.dto.ts b/src/identity-and-account/user-module-access/module-acces.dto.ts index 5e1e6be..a97b4ea 100644 --- a/src/identity-and-account/user-module-access/module-acces.dto.ts +++ b/src/identity-and-account/user-module-access/module-acces.dto.ts @@ -1,10 +1,10 @@ import { IsBoolean } from "class-validator"; export class ModuleAccess { - @IsBoolean() timesheets!: boolean; - @IsBoolean() timesheets_approval!: boolean; - @IsBoolean() employee_list!: boolean; - @IsBoolean() employee_management!: boolean; - @IsBoolean() personal_profile!: boolean; - @IsBoolean() dashboard!: boolean; + @IsBoolean() timesheets: boolean; + @IsBoolean() timesheets_approval: boolean; + @IsBoolean() employee_list: boolean; + @IsBoolean() employee_management: boolean; + @IsBoolean() personal_profile: boolean; + @IsBoolean() dashboard: boolean; } \ No newline at end of file diff --git a/src/identity-and-account/user-module-access/module-access.controller.ts b/src/identity-and-account/user-module-access/module-access.controller.ts index 55cd656..fa4fd95 100644 --- a/src/identity-and-account/user-module-access/module-access.controller.ts +++ b/src/identity-and-account/user-module-access/module-access.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Patch, Query, Req } from "@nestjs/common"; +import { Body, Controller, Get, Patch, Query } from "@nestjs/common"; import { Access } from "src/common/decorators/module-access.decorators"; import { Result } from "src/common/errors/result-error.factory"; import { ModuleAccess } from "src/identity-and-account/user-module-access/module-acces.dto"; @@ -16,7 +16,9 @@ export class ModuleAccessController { @Get() @ModuleAccessAllowed(ModulesEnum.employee_management) - async findAccess(@Access('email') email: string, @Query('employee_email') employee_email?: string + async findAccess( + @Access('email') email: string, + @Query('employee_email') employee_email?: string ): Promise> { await this.getService.findModuleAccess(email, employee_email); return { success: true, data: true }; @@ -24,7 +26,10 @@ export class ModuleAccessController { @Patch('update') @ModuleAccessAllowed(ModulesEnum.employee_management) - async updateAccess(@Access('email') email: string, @Body() dto: ModuleAccess, @Query('employee_email') employee_email?: string + async updateAccess( + @Access('email') email: string, + @Body() dto: ModuleAccess, + @Query('employee_email') employee_email?: string ): Promise> { await this.updateService.updateModuleAccess(email, dto, employee_email); return { success: true, data: true }; diff --git a/src/identity-and-account/user-module-access/module-access.module.ts b/src/identity-and-account/user-module-access/module-access.module.ts index 47711e8..d3e6332 100644 --- a/src/identity-and-account/user-module-access/module-access.module.ts +++ b/src/identity-and-account/user-module-access/module-access.module.ts @@ -5,8 +5,16 @@ import { AccessGetService } from "src/identity-and-account/user-module-access/se import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; @Module({ - controllers: [ModuleAccessController], - providers: [AccessUpdateService, AccessGetService, EmailToIdResolver], - exports: [AccessGetService], + controllers: [ + ModuleAccessController + ], + providers: [ + AccessUpdateService, + AccessGetService, + EmailToIdResolver + ], + exports: [ + AccessGetService + ], }) export class ModuleAccessModule { } \ No newline at end of file diff --git a/src/identity-and-account/user-module-access/services/module-access-get.service.ts b/src/identity-and-account/user-module-access/services/module-access-get.service.ts index b7dcdf9..2195683 100644 --- a/src/identity-and-account/user-module-access/services/module-access-get.service.ts +++ b/src/identity-and-account/user-module-access/services/module-access-get.service.ts @@ -12,7 +12,10 @@ export class AccessGetService { private readonly emailResolver: EmailToIdResolver, ) { } - async findModuleAccess(email: string, employee_email?: string): Promise> { + async findModuleAccess( + email: string, + employee_email?: string + ): Promise> { const account_email = employee_email ?? email; const user_id = await this.emailResolver.resolveUserIdWithEmail(account_email); if (!user_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; diff --git a/src/identity-and-account/user-module-access/services/module-access-update.service.ts b/src/identity-and-account/user-module-access/services/module-access-update.service.ts index 9219623..bde6893 100644 --- a/src/identity-and-account/user-module-access/services/module-access-update.service.ts +++ b/src/identity-and-account/user-module-access/services/module-access-update.service.ts @@ -11,7 +11,11 @@ export class AccessUpdateService { private readonly emailResolver: EmailToIdResolver, ) { } - async updateModuleAccess(email: string, dto: ModuleAccess, employee_email?: string): Promise> { + async updateModuleAccess( + email: string, + dto: ModuleAccess, + employee_email?: string + ): Promise> { const account_email = employee_email ?? email; const user_id = await this.emailResolver.resolveUserIdWithEmail(account_email); if (!user_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; @@ -52,7 +56,10 @@ export class AccessUpdateService { return { success: true, data: updated_access }; } - async revokeModuleAccess(email: string, employee_email?: string): Promise> { + async revokeModuleAccess( + email: string, + employee_email?: string + ): Promise> { const account_email = employee_email ?? email; const user_id = await this.emailResolver.resolveUserIdWithEmail(account_email); if (!user_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; diff --git a/src/identity-and-account/users-management/services/abstract-user.service.ts b/src/identity-and-account/users-management/services/abstract-user.service.ts index 565490f..07a88b3 100644 --- a/src/identity-and-account/users-management/services/abstract-user.service.ts +++ b/src/identity-and-account/users-management/services/abstract-user.service.ts @@ -7,7 +7,9 @@ import { PrismaPostgresService } from 'prisma/postgres/prisma-postgres.service'; export abstract class AbstractUserService { constructor(protected readonly prisma: PrismaPostgresService) { } - async findOneByEmail(email: string): Promise> { + async findOneByEmail( + email: string + ): Promise> { const user = await this.prisma.users.findUnique({ where: { email }, include: { diff --git a/src/identity-and-account/users-management/user.dto.ts b/src/identity-and-account/users-management/user.dto.ts index 11663ae..83a3f6a 100644 --- a/src/identity-and-account/users-management/user.dto.ts +++ b/src/identity-and-account/users-management/user.dto.ts @@ -6,5 +6,5 @@ export class UserDto { @IsString() last_name: string; @IsEmail() email: string; @IsEnum(Roles) role: string; - @IsArray() @IsEnum(Modules, { each: true }) user_module_access!: Modules[]; + @IsArray() @IsEnum(Modules, { each: true }) user_module_access: Modules[]; } \ No newline at end of file diff --git a/src/identity-and-account/users-management/users.module.ts b/src/identity-and-account/users-management/users.module.ts index 4feec0f..120aafc 100644 --- a/src/identity-and-account/users-management/users.module.ts +++ b/src/identity-and-account/users-management/users.module.ts @@ -3,8 +3,14 @@ import { UsersService } from './services/users.service'; import { PrismaPostgresModule } from 'prisma/postgres/prisma-postgres.module'; @Module({ - imports: [PrismaPostgresModule], - providers: [UsersService], - exports: [UsersService], + imports: [ + PrismaPostgresModule + ], + providers: [ + UsersService + ], + exports: [ + UsersService + ], }) export class UsersModule {} diff --git a/src/main.ts b/src/main.ts index 599911c..5b0f683 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,8 @@ import 'reflect-metadata'; -import * as nodeCrypto from 'crypto'; -if (!(globalThis as any).crypto) { - (globalThis as any).crypto = nodeCrypto; -} +// 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'; @@ -14,7 +14,7 @@ import { PrismaPostgresService } from 'prisma/postgres/prisma-postgres.service'; const SESSION_TOKEN_DURATION_MINUTES = 180 async function bootstrap() { - (BigInt.prototype as any).toJSON = function () { return Number(this) }; + BigInt.prototype['toJSON'] = function () { return Number(this) }; const app = await NestFactory.create(AppModule); const prisma_postgres = app.get(PrismaPostgresService); diff --git a/src/shared/archival/archival.module.ts b/src/shared/archival/archival.module.ts deleted file mode 100644 index e48e908..0000000 --- a/src/shared/archival/archival.module.ts +++ /dev/null @@ -1,34 +0,0 @@ -// import { Module } from "@nestjs/common"; -// import { ScheduleModule } from "@nestjs/schedule"; -// import { TimesheetsModule } from "../timesheets/timesheets.module"; -// import { ExpensesModule } from "../expenses/expenses.module"; -// import { ShiftsModule } from "../shifts/shifts.module"; -// import { LeaveRequestsModule } from "../leave-requests/leave-requests.module"; -// import { ArchivalService } from "./services/archival.service"; -// import { EmployeesArchiveController } from "./controllers/employees-archive.controller"; -// import { ExpensesArchiveController } from "./controllers/expenses-archive.controller"; -// import { LeaveRequestsArchiveController } from "./controllers/leave-requests-archive.controller"; -// import { ShiftsArchiveController } from "./controllers/shifts-archive.controller"; -// import { TimesheetsArchiveController } from "./controllers/timesheets-archive.controller"; -// import { EmployeesModule } from "../employees/employees.module"; - -// @Module({ -// imports: [ -// EmployeesModule, -// ScheduleModule, -// TimesheetsModule, -// ExpensesModule, -// ShiftsModule, -// LeaveRequestsModule, -// ], -// providers: [ArchivalService], -// controllers: [ -// EmployeesArchiveController, -// ExpensesArchiveController, -// LeaveRequestsArchiveController, -// ShiftsArchiveController, -// TimesheetsArchiveController, -// ], -// }) - -// export class ArchivalModule {} \ No newline at end of file diff --git a/src/shared/archival/archival.service.ts b/src/shared/archival/archival.service.ts deleted file mode 100644 index ebec1e5..0000000 --- a/src/shared/archival/archival.service.ts +++ /dev/null @@ -1,38 +0,0 @@ -// import { TimesheetArchiveService } from "src/time-and-attendance/modules/time-tracker/timesheets/services/timesheet-archive.service"; -// import { ExpensesArchivalService } from "src/time-and-attendance/modules/expenses/services/expenses-archival.service"; -// import { ShiftsArchivalService } from "src/time-and-attendance/modules/time-tracker/shifts/services/shifts-archival.service"; -// import { Injectable, Logger } from "@nestjs/common"; -// import { Cron } from "@nestjs/schedule"; - -// @Injectable() -// export class ArchivalService { -// private readonly logger = new Logger(ArchivalService.name); - -// constructor( -// private readonly timesheetsService: TimesheetArchiveService, -// private readonly expensesService: ExpensesArchivalService, -// private readonly shiftsService: ShiftsArchivalService, -// ) {} - -// @Cron('0 0 3 * * 1', {timeZone:'America/Toronto'}) // chaque premier lundi du mois à 03h00 -// async handleMonthlyArchival() { -// const today = new Date(); -// const dayOfMonth = today.getDate(); - -// if (dayOfMonth > 7) { -// this.logger.warn('Archive {awaiting 1st monday of the month for archivation process}') -// return; -// } - -// this.logger.log('monthly archivation in process'); -// try { -// await this.timesheetsService.archiveOld(); -// await this.expensesService.archiveOld(); -// await this.shiftsService.archiveOld(); -// // await this.leaveRequestsService.archiveExpired(); -// this.logger.log('archivation process done'); -// } catch (err) { -// this.logger.error('an error occured during archivation process ', err); -// } -// } -// } \ No newline at end of file diff --git a/src/shared/archival/controllers/employees-archive.controller.ts b/src/shared/archival/controllers/employees-archive.controller.ts deleted file mode 100644 index 0dc991e..0000000 --- a/src/shared/archival/controllers/employees-archive.controller.ts +++ /dev/null @@ -1,32 +0,0 @@ -// import { Controller, Get, NotFoundException, Param, ParseIntPipe, UseGuards } from "@nestjs/common"; -// import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger"; -// import { RolesAllowed } from "src/common/decorators/roles.decorators"; -// import { EmployeesArchivalService } from "src/modules/employees/services/employees-archival.service"; - -// @ApiTags('Employee Archives') -// // @UseGuards() -// @Controller('archives/employees') -// export class EmployeesArchiveController { -// constructor(private readonly employeesArchiveService: EmployeesArchivalService) {} - -// @Get() -// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR) -// @ApiOperation({ summary: 'List of archived employees'}) -// @ApiResponse({ status: 200, description: 'List of archived employees', isArray: true }) -// async findAllArchived(): Promise { -// return this.employeesArchiveService.findAllArchived(); -// } - -// @Get() -// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR,RoleEnum.SUPERVISOR) -// @ApiOperation({ summary: 'Fetch employee in archives with its Id'}) -// @ApiResponse({ status: 200, description: 'Archived employee found'}) -// async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise { -// try{ -// return await this.employeesArchiveService.findOneArchived(id); -// }catch { -// throw new NotFoundException(`Archived employee #${id} not found`); -// } -// } - -// } \ No newline at end of file diff --git a/src/shared/archival/controllers/expenses-archive.controller.ts b/src/shared/archival/controllers/expenses-archive.controller.ts deleted file mode 100644 index 5cd23d1..0000000 --- a/src/shared/archival/controllers/expenses-archive.controller.ts +++ /dev/null @@ -1,31 +0,0 @@ -// import { UseGuards, Controller, Get, Param, ParseIntPipe, NotFoundException } from "@nestjs/common"; -// import { ApiTags, ApiOperation, ApiResponse } from "@nestjs/swagger"; -// import { RolesAllowed } from "src/common/decorators/roles.decorators"; -// import { ExpensesArchivalService } from "src/time-and-attendance/modules/expenses/services/expenses-archival.service"; - -// @ApiTags('Expense Archives') -// // @UseGuards() -// @Controller('archives/expenses') -// export class ExpensesArchiveController { -// constructor(private readonly expensesService: ExpensesArchivalService) {} - -// @Get() -// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR) -// @ApiOperation({ summary: 'List of archived expenses'}) -// @ApiResponse({ status: 200, description: 'List of archived expenses', isArray: true }) -// async findAllArchived(): Promise { -// return this.expensesService.findAllArchived(); -// } - -// @Get() -// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR) -// @ApiOperation({ summary: 'Fetch expense in archives with its Id'}) -// @ApiResponse({ status: 200, description: 'Archived expense found'}) -// async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise { -// try{ -// return await this.expensesService.findOneArchived(id); -// }catch { -// throw new NotFoundException(`Archived expense #${id} not found`); -// } -// } -// } \ No newline at end of file diff --git a/src/shared/archival/controllers/leave-requests-archive.controller.ts b/src/shared/archival/controllers/leave-requests-archive.controller.ts deleted file mode 100644 index ec1b046..0000000 --- a/src/shared/archival/controllers/leave-requests-archive.controller.ts +++ /dev/null @@ -1,7 +0,0 @@ -// import { Controller } from '@nestjs/common'; -// import { ApiTags } from '@nestjs/swagger'; - -// @ApiTags('LeaveRequests Archives') -// // @UseGuards() -// @Controller('archives/leaveRequests') -// export class LeaveRequestsArchiveController {} \ No newline at end of file diff --git a/src/shared/archival/controllers/shifts-archive.controller.ts b/src/shared/archival/controllers/shifts-archive.controller.ts deleted file mode 100644 index 942b65a..0000000 --- a/src/shared/archival/controllers/shifts-archive.controller.ts +++ /dev/null @@ -1,31 +0,0 @@ -// import { Get, Param, ParseIntPipe, NotFoundException, Controller, UseGuards } from "@nestjs/common"; -// import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger"; -// import { RolesAllowed } from "src/common/decorators/roles.decorators"; -// import { ShiftsArchivalService } from "src/time-and-attendance/modules/time-tracker/shifts/services/shifts-archival.service"; - -// @ApiTags('Shift Archives') -// // @UseGuards() -// @Controller('archives/shifts') -// export class ShiftsArchiveController { -// constructor(private readonly shiftsService: ShiftsArchivalService) {} - -// @Get() -// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR) -// @ApiOperation({ summary: 'List of archived shifts'}) -// @ApiResponse({ status: 200, description: 'List of archived shifts', isArray: true }) -// async findAllArchived(): Promise { -// return this.shiftsService.findAllArchived(); -// } - -// @Get() -// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR,RoleEnum.SUPERVISOR) -// @ApiOperation({ summary: 'Fetch shift in archives with its Id'}) -// @ApiResponse({ status: 200, description: 'Archived shift found'}) -// async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise { -// try{ -// return await this.shiftsService.findOneArchived(id); -// }catch { -// throw new NotFoundException(`Archived shift #${id} not found`); -// } -// } -// } \ No newline at end of file diff --git a/src/shared/archival/controllers/timesheets-archive.controller.ts b/src/shared/archival/controllers/timesheets-archive.controller.ts deleted file mode 100644 index 456cc11..0000000 --- a/src/shared/archival/controllers/timesheets-archive.controller.ts +++ /dev/null @@ -1,32 +0,0 @@ -// import { Controller, Get, NotFoundException, Param, ParseIntPipe, UseGuards } from "@nestjs/common"; -// import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger"; -// import { RolesAllowed } from "src/common/decorators/roles.decorators"; -// import { TimesheetArchiveService } from "src/time-and-attendance/modules/time-tracker/timesheets/services/timesheet-archive.service"; - -// @ApiTags('Timesheet Archives') -// // @UseGuards() -// @Controller('archives/timesheets') -// export class TimesheetsArchiveController { -// constructor(private readonly timesheetsService: TimesheetArchiveService) {} - -// @Get() -// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR) -// @ApiOperation({ summary: 'List of archived timesheets'}) -// @ApiResponse({ status: 200, description: 'List of archived timesheets', isArray: true }) -// async findAllArchived(): Promise { -// return this.timesheetsService.findAllArchived(); -// } - -// @Get() -// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR) -// @ApiOperation({ summary: 'Fetch timesheet in archives with its Id'}) -// @ApiResponse({ status: 200, description: 'Archived timesheet found'}) -// async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise { -// try{ -// return await this.timesheetsService.findOneArchived(id); -// }catch { -// throw new NotFoundException(`Archived timesheet #${id} not found`); -// } -// } - -// } \ No newline at end of file diff --git a/src/shared/notifications/notification.constants.ts b/src/shared/notifications/notification.constants.ts deleted file mode 100644 index 49115e7..0000000 --- a/src/shared/notifications/notification.constants.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const NOTIF_TYPES = { - SHIFT_OVERTIME_DAILY: 'shift.overtime.daily', - -} as const; \ No newline at end of file diff --git a/src/shared/notifications/notification.types.ts b/src/shared/notifications/notification.types.ts deleted file mode 100644 index 871d8ec..0000000 --- a/src/shared/notifications/notification.types.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type NotificationCard = { - type: string; - message: string; - severity?: 'info'|'warn'|'error'; - icon?: string; - link?: string; - meta?: Record - ts: string; //new Date().toISOString() -}; diff --git a/src/shared/notifications/notifications.controller.ts b/src/shared/notifications/notifications.controller.ts deleted file mode 100644 index 9a01808..0000000 --- a/src/shared/notifications/notifications.controller.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Controller, Get, Req, Sse, - MessageEvent as NestMessageEvent } from "@nestjs/common"; -import { Observable } from "rxjs"; -import { map } from 'rxjs/operators'; -import { NotificationsService } from "src/shared/notifications/notifications.service"; - -@Controller('notifications') -export class NotificationsController { - constructor(private readonly notificationsService: NotificationsService) {} - - @Get('summary') - async summary(@Req() req) { - return this.notificationsService.summary(String(req.user.id)); - } - - @Sse('stream') - stream(@Req() req): Observable { - const userId = String(req.user.id); - return this.notificationsService.stream(userId).pipe(map((data): NestMessageEvent => ({ data }))) - } -} \ No newline at end of file diff --git a/src/shared/notifications/notifications.module.ts b/src/shared/notifications/notifications.module.ts deleted file mode 100644 index 01b5de7..0000000 --- a/src/shared/notifications/notifications.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from "@nestjs/common"; -import { NotificationsService } from "./notifications.service"; -import { NotificationsController } from "src/shared/notifications/notifications.controller"; -@Module({ - providers: [NotificationsService], - controllers: [NotificationsController], - exports: [NotificationsService], -}) -export class NotificationsModule {} \ No newline at end of file diff --git a/src/shared/notifications/notifications.service.ts b/src/shared/notifications/notifications.service.ts deleted file mode 100644 index f45cf34..0000000 --- a/src/shared/notifications/notifications.service.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Injectable, Logger } from "@nestjs/common"; -import { Subject } from "rxjs"; -import { NotificationCard } from "./notification.types"; - -@Injectable() -export class NotificationsService { - private readonly logger = new Logger(NotificationsService.name); - - //Server-Sent Events FLUX and a buffer per user - private streams = new Map>(); - private buffers = new Map(); - private readonly BUFFER_MAX = Number(process.env.NOTIF_BUFFER_MAX ?? 50); - - private getOrCreateStream(user_id: string): Subject { - let stream = this.streams.get(user_id); - if (!stream){ - stream = new Subject(); - this.streams.set(user_id, stream); - } - return stream; - } - private getOrCreateBuffer(user_id: string){ - let buffer = this.buffers.get(user_id); - if(!buffer) { - buffer = []; - this.buffers.set(user_id, buffer); - } - return buffer; - } - - //in-app pushes and keep a small history - notify(user_id: string, card: NotificationCard) { - const buffer = this.getOrCreateBuffer(user_id); - buffer.unshift(card); - if (buffer.length > this.BUFFER_MAX) { - buffer.length = this.BUFFER_MAX; - } - this.getOrCreateStream(user_id).next(card); - this.logger.debug(`Notification in-app => user: ${user_id} (${card.type})`); - } - - //SSE flux for current user - stream(user_id: string) { - return this.getOrCreateStream(user_id).asObservable(); - } - - //return a summary of notifications kept in memory - async summary(user_id: string): Promise { - return this.getOrCreateBuffer(user_id); - } - - //clear buffers from memory - clear(user_id: string) { - this.buffers.set(user_id, []); - } - - onModuleDestroy() { - for (const stream of this.streams.values()) stream.complete(); - this.streams.clear(); - this.buffers.clear(); - } -} \ No newline at end of file diff --git a/src/time-and-attendance/bank-codes/bank-codes.controller.ts b/src/time-and-attendance/bank-codes/bank-codes.controller.ts index 45fa27a..db184c5 100644 --- a/src/time-and-attendance/bank-codes/bank-codes.controller.ts +++ b/src/time-and-attendance/bank-codes/bank-codes.controller.ts @@ -8,12 +8,10 @@ import { BankCodesService } from "src/time-and-attendance/bank-codes/bank-codes. @ModuleAccessAllowed(ModulesEnum.employee_management) export class BankCodesControllers { constructor(private readonly bankCodesService: BankCodesService) { } - //_____________________________________________________________________________________________ - // Deprecated or unused methods - //_____________________________________________________________________________________________ @Post() - create(@Body() dto: Prisma.BankCodesCreateInput + create( + @Body() dto: Prisma.BankCodesCreateInput ): Promise> { return this.bankCodesService.create(dto); } @@ -24,7 +22,9 @@ export class BankCodesControllers { } @Patch(':id') - update(@Param('id', ParseIntPipe) id: number, @Body() dto: Prisma.BankCodesUpdateInput + update( + @Param('id', ParseIntPipe) id: number, + @Body() dto: Prisma.BankCodesUpdateInput ): Promise> { return this.bankCodesService.update(id, dto) } diff --git a/src/time-and-attendance/bank-codes/bank-codes.module.ts b/src/time-and-attendance/bank-codes/bank-codes.module.ts index dfacff5..5971780 100644 --- a/src/time-and-attendance/bank-codes/bank-codes.module.ts +++ b/src/time-and-attendance/bank-codes/bank-codes.module.ts @@ -4,8 +4,13 @@ import { BankCodesControllers } from "src/time-and-attendance/bank-codes/bank-co import { BankCodesService } from "src/time-and-attendance/bank-codes/bank-codes.service"; @Module({ - controllers: [BankCodesControllers], - providers: [BankCodesService, PrismaPostgresService], + controllers: [ + BankCodesControllers + ], + providers: [ + BankCodesService, + PrismaPostgresService + ], }) export class BankCodesModule {} \ No newline at end of file diff --git a/src/time-and-attendance/bank-codes/bank-codes.service.ts b/src/time-and-attendance/bank-codes/bank-codes.service.ts index 65f6e5d..f0555d0 100644 --- a/src/time-and-attendance/bank-codes/bank-codes.service.ts +++ b/src/time-and-attendance/bank-codes/bank-codes.service.ts @@ -7,7 +7,9 @@ import { Result } from "src/common/errors/result-error.factory"; export class BankCodesService { constructor(private readonly prisma: PrismaPostgresService) { } - async create(dto: Prisma.BankCodesCreateInput): Promise> { + async create( + dto: Prisma.BankCodesCreateInput + ): Promise> { try { await this.prisma.bankCodes.create({ data: { @@ -27,7 +29,10 @@ export class BankCodesService { return this.prisma.bankCodes.findMany(); } - async update(id: number, dto: Prisma.BankCodesUpdateInput): Promise> { + async update( + id: number, + dto: Prisma.BankCodesUpdateInput + ): Promise> { try { await this.prisma.bankCodes.update({ where: { id }, @@ -44,7 +49,9 @@ export class BankCodesService { } } - async delete(id: number): Promise> { + async delete( + id: number + ): Promise> { try { await this.prisma.bankCodes.delete({ where: { id }, diff --git a/src/time-and-attendance/domains/business-logics.module.ts b/src/time-and-attendance/domains/business-logics.module.ts index f0b9b56..7682556 100644 --- a/src/time-and-attendance/domains/business-logics.module.ts +++ b/src/time-and-attendance/domains/business-logics.module.ts @@ -9,7 +9,6 @@ import { Module } from "@nestjs/common"; @Module({ - imports:[], providers: [ HolidayService, MileageService, diff --git a/src/time-and-attendance/domains/services/banking-hours.service.ts b/src/time-and-attendance/domains/services/banking-hours.service.ts index e7f360d..f7c0b8a 100644 --- a/src/time-and-attendance/domains/services/banking-hours.service.ts +++ b/src/time-and-attendance/domains/services/banking-hours.service.ts @@ -8,7 +8,11 @@ export class BankedHoursService { constructor(private readonly prisma: PrismaPostgresService) { } //manage shifts with bank_code.type BANKING - manageBankingHours = async (employee_id: number, asked_hours: number, type: string): Promise> => { + manageBankingHours = async ( + employee_id: number, + asked_hours: number, + type: string + ): Promise> => { if (asked_hours <= 0) return { success: false, error: 'INVALID_BANKING_HOURS' }; try { @@ -50,8 +54,6 @@ export class BankedHoursService { } else if (type === 'WITHDRAW_BANKED') { if (asked_hours > banked_hours) { return { success: true, data: banked_hours } as Result; - } else { - } await tx.paidTimeOff.update({ where: { employee_id: employee.id }, @@ -69,7 +71,8 @@ export class BankedHoursService { return result; } catch (error) { - return { success: false, error: 'INVALID_BANKING_SHIFT' }; + console.error(error); + return { success: false, error: 'INVALID_BANKING_SHIFT: ' }; } } } \ No newline at end of file diff --git a/src/time-and-attendance/domains/services/holiday.service.ts b/src/time-and-attendance/domains/services/holiday.service.ts index 40ae1e7..277e268 100644 --- a/src/time-and-attendance/domains/services/holiday.service.ts +++ b/src/time-and-attendance/domains/services/holiday.service.ts @@ -24,7 +24,11 @@ export class HolidayService { * * @returns Average daily hours worked in the past four weeks as a `number`, to a maximum of `8` */ - private async computeHoursPrevious4Weeks(external_payroll_id: number, company_code: number, holiday_date: Date): Promise> { + private async computeHoursPrevious4Weeks( + external_payroll_id: number, + company_code: number, + holiday_date: Date + ): Promise> { try { const valid_codes = ['G1', 'G43', 'G56', 'G104', 'G105', 'G305', 'G700', 'G720']; const holiday_week_start = getWeekStart(holiday_date); @@ -42,7 +46,7 @@ export class HolidayService { }); if (!employee) - return {success: false, error: 'EMPLOYEE_NOT_FOUND'}; + return { success: false, error: 'EMPLOYEE_NOT_FOUND' }; const shifts = await this.prisma.shifts.findMany({ where: { @@ -56,8 +60,8 @@ export class HolidayService { const hours_by_week = new Map(); for (const shift of shifts) { const hours = computeHours(shift.start_time, shift.end_time); - - if (hours <= 0) + + if (hours <= 0) continue; const shift_week_start = getWeekStart(shift.date); @@ -76,11 +80,16 @@ export class HolidayService { const average_daily_hours = capped_total / 20; return { success: true, data: average_daily_hours }; } catch (error) { + console.error(error); return { success: false, error: `an error occureded during holiday calculation` } } } - async calculateHolidayPay(employeePayrollID: number, companyCode: number, holiday_date: Date): Promise> { + async calculateHolidayPay( + employeePayrollID: number, + companyCode: number, + holiday_date: Date + ): Promise> { const average_daily_hours = await this.computeHoursPrevious4Weeks(employeePayrollID, companyCode, holiday_date); if (!average_daily_hours.success) return { success: false, error: average_daily_hours.error }; diff --git a/src/time-and-attendance/domains/services/mileage.service.ts b/src/time-and-attendance/domains/services/mileage.service.ts index b946695..1dcd0b1 100644 --- a/src/time-and-attendance/domains/services/mileage.service.ts +++ b/src/time-and-attendance/domains/services/mileage.service.ts @@ -7,7 +7,10 @@ export class MileageService { constructor(private readonly prisma: PrismaPostgresService) { } - public async calculateReimbursement(amount: number, bank_code_id: number): Promise> { + public async calculateReimbursement( + amount: number, + bank_code_id: number + ): Promise> { if (amount < 0) return { success: false, error: 'The amount must be higher than 0' }; //fetch modifier diff --git a/src/time-and-attendance/domains/services/overtime.service.ts b/src/time-and-attendance/domains/services/overtime.service.ts index d4d9cb6..60f4311 100644 --- a/src/time-and-attendance/domains/services/overtime.service.ts +++ b/src/time-and-attendance/domains/services/overtime.service.ts @@ -27,11 +27,21 @@ type WeekOvertimeSummary = { @Injectable() export class OvertimeService { - private INCLUDED_TYPES = ['EMERGENCY', 'EVENING', 'OVERTIME', 'REGULAR', 'HOLIDAY', 'BANKING'] as const; // included types for weekly overtime calculation - + private INCLUDED_TYPES = [ + 'EMERGENCY', + 'EVENING', + 'OVERTIME', + 'REGULAR', + 'HOLIDAY', + 'BANKING' + ] as const; constructor(private prisma: PrismaPostgresService) { } - async getWeekOvertimeSummary(timesheet_id: number, date: Date, tx?: Tx): Promise> { + async getWeekOvertimeSummary( + timesheet_id: number, + date: Date, + tx?: Tx + ): Promise> { const db = (tx ?? this.prisma) as PrismaClient; const week_start = getWeekStart(date); diff --git a/src/time-and-attendance/domains/services/sick-leave.service.ts b/src/time-and-attendance/domains/services/sick-leave.service.ts index 5bd9c82..09c9993 100644 --- a/src/time-and-attendance/domains/services/sick-leave.service.ts +++ b/src/time-and-attendance/domains/services/sick-leave.service.ts @@ -8,7 +8,9 @@ import { Result } from "src/common/errors/result-error.factory"; export class SickLeaveService { constructor(private readonly prisma: PrismaPostgresService) { } - async updateSickLeaveHours(employee_id: number): Promise> { + async updateSickLeaveHours( + employee_id: number + ): Promise> { const THIRTY_DAYS = 1000 * 60 * 60 * 24 * 30; const FOURTEEN_DAYS = 1000 * 60 * 60 * 24 * 14; const today = new Date(); @@ -51,7 +53,7 @@ export class SickLeaveService { if (today.getTime() - employee.first_work_day.getTime() >= THIRTY_DAYS && employee.first_work_day.toISOString() === pto_details?.last_updated?.toISOString()) { const updated_pto = await this.addHoursToPTO(3 * 8, employee.id, today); - if (!updated_pto.success) return { success: updated_pto.success, error: updated_pto.error } + if (!updated_pto.success) return { success: updated_pto.success, error: '' + updated_pto.error } } const year_difference = today.getFullYear() - (pto_details!.last_updated?.getFullYear() ?? today.getFullYear()); @@ -69,7 +71,10 @@ export class SickLeaveService { } // create a new PTO row - async createNewPTORow(employee_id: number, today: Date): Promise, string>> { + async createNewPTORow( + employee_id: number, + today: Date + ): Promise, string>> { try { const new_pto_entry = await this.prisma.paidTimeOff.create({ data: { @@ -88,12 +93,16 @@ export class SickLeaveService { return { success: true, data: new_pto_entry }; } catch (error) { - return { success: false, error }; + return { success: false, error: '' + error }; } } // add n number of sick PTO hours to employee PTO - async addHoursToPTO(sick_hours: number, employee_id: number, last_updated: Date) { + async addHoursToPTO( + sick_hours: number, + employee_id: number, + last_updated: Date + ) { try { const update_pto = await this.prisma.paidTimeOff.update({ where: { @@ -107,11 +116,15 @@ export class SickLeaveService { return { success: true, data: update_pto }; } catch (error) { - return { success: false, error }; + console.error(error); + return { success: false, error: ''}; } }; - takeSickLeaveHours = async (employee_id: number, asked_hours: number): Promise> => { + takeSickLeaveHours = async ( + employee_id: number, + asked_hours: number + ): Promise> => { if (asked_hours <= 0) return { success: false, error: 'INVALID_BANKING_HOURS' }; try { @@ -154,74 +167,9 @@ export class SickLeaveService { return result; } catch (error) { + console.error(error); return { success: false, error: 'INVALID_BANKING_SHIFT' }; } } - - - //LEAVE REQUEST FUNCTION - DEPRECATED - // async calculateSickLeavePay( - // employee_id: number, - // reference_date: Date, - // days_requested: number, - // hours_per_day: number, - // modifier: number, - // ): Promise> { - // if (days_requested <= 0 || hours_per_day <= 0 || modifier <= 0) { - // return { success: true, data: 0 }; - // } - - // //sets the year to jan 1st to dec 31st - // const period_start = getYearStart(reference_date); - // const period_end = reference_date; - - // //fetches all shifts of a selected employee - // const shifts = await this.prisma.shifts.findMany({ - // where: { - // timesheet: { employee_id: employee_id }, - // date: { gte: period_start, lte: period_end }, - // }, - // select: { date: true }, - // }); - - // //count the amount of worked days - // const worked_dates = new Set( - // shifts.map((shift) => shift.date.toISOString().slice(0, 10)), - // ); - // const days_worked = worked_dates.size; - - // //less than 30 worked days returns 0 - // if (days_worked < 30) { - // return { success: true, data: 0 }; - // } - - // //default 3 days allowed after 30 worked days - // let acquired_days = 3; - - // //identify the date of the 30th worked day - // const ordered_dates = Array.from(worked_dates).sort(); - // const threshold_date = new Date(ordered_dates[29]); // index 29 is the 30th day - - // //calculate each completed month, starting the 1st of the next month - // const first_bonus_date = new Date( - // threshold_date.getFullYear(), - // threshold_date.getMonth() + 1, - // 1, - // ); - // let months = - // (period_end.getFullYear() - first_bonus_date.getFullYear()) * 12 + - // (period_end.getMonth() - first_bonus_date.getMonth()) + - // 1; - // if (months < 0) months = 0; - // acquired_days += months; - - // //cap of 10 days - // if (acquired_days > 10) acquired_days = 10; - - // const payable_days = Math.min(acquired_days, days_requested); - // const raw_hours = payable_days * hours_per_day * modifier; - // const rounded = roundToQuarterHour(raw_hours); - // return { success: true, data: rounded }; - // } } diff --git a/src/time-and-attendance/domains/services/vacation.service.ts b/src/time-and-attendance/domains/services/vacation.service.ts index bf87b7c..da5f585 100644 --- a/src/time-and-attendance/domains/services/vacation.service.ts +++ b/src/time-and-attendance/domains/services/vacation.service.ts @@ -10,7 +10,6 @@ export class VacationService { private readonly emailResolver: EmailToIdResolver, ) { } - //switch employeeId for email async calculateVacationPay(email: string, start_date: Date, days_requested: number, modifier: number): Promise> { const employee_id = await this.emailResolver.findIdByEmail(email); if (!employee_id.success) return { success: false, error: employee_id.error } @@ -20,7 +19,7 @@ export class VacationService { where: { id: employee_id.data }, select: { first_work_day: true }, }); - if (!employee) return { success: false, error: `Employee #${employee_id} not found` } + if (!employee) return { success: false, error: `Employee #${employee_id.data} not found` } const hire_date = employee.first_work_day; @@ -110,10 +109,8 @@ export class VacationService { }); return result; } catch (error) { + console.error(error); return { success: false, error: 'INVALID_VACATION_SHIFT' } } } - - - } \ No newline at end of file diff --git a/src/time-and-attendance/expenses/expense.controller.ts b/src/time-and-attendance/expenses/expense.controller.ts index b63594f..7a8caf4 100644 --- a/src/time-and-attendance/expenses/expense.controller.ts +++ b/src/time-and-attendance/expenses/expense.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Post, Param, Body, Patch, Delete, Req, UnauthorizedException, Query } from "@nestjs/common"; +import { Controller, Post, Param, Body, Patch, Delete, UnauthorizedException, Query } from "@nestjs/common"; import { ExpenseDto } from "src/time-and-attendance/expenses/expense-create.dto"; import { Result } from "src/common/errors/result-error.factory"; import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators"; @@ -18,7 +18,10 @@ export class ExpenseController { @Post('create') @ModuleAccessAllowed(ModulesEnum.timesheets) - create(@Access('email') email: string, @Body() dto: ExpenseDto): Promise> { + create( + @Access('email') email: string, + @Body() dto: ExpenseDto + ): Promise> { if (!email) throw new UnauthorizedException('Unauthorized User'); return this.createService.createExpense(dto, email); } diff --git a/src/time-and-attendance/expenses/expense.utils.ts b/src/time-and-attendance/expenses/expense.utils.ts index 8dad1ae..0765706 100644 --- a/src/time-and-attendance/expenses/expense.utils.ts +++ b/src/time-and-attendance/expenses/expense.utils.ts @@ -3,19 +3,6 @@ import { toDateFromString } from "src/common/utils/date-utils"; import { ExpenseDto } from "src/time-and-attendance/expenses/expense-create.dto"; import { NormalizedExpense } from "src/time-and-attendance/utils/type.utils"; -//makes sure that a string cannot exceed 280 chars -export const truncate280 = (input: string): string => { - return input.length > 280 ? input.slice(0, 280) : input; -} - -//makes sure that the type of data of numeric values is valid -export const parseOptionalNumber = (value: unknown, field: string) => { - if (value == null) return undefined; - const parsed = Number(value); - if (Number.isNaN(parsed)) throw new Error(`Invalid value : ${value} for ${field}`); - return parsed; -}; - //makes sure that comments are the right length the date is of Date type export const normalizeAndParseExpenseDto = async (dto: ExpenseDto): Promise> => { const mileage = parseOptionalNumber(dto.mileage, "mileage"); @@ -37,4 +24,17 @@ export const normalizeAndParseExpenseDto = async (dto: ExpenseDto): Promise { + return input.length > 280 ? input.slice(0, 280) : input; +} + +//makes sure that the type of data of numeric values is valid +export const parseOptionalNumber = (value: unknown, field: string) => { + if (value == null) return undefined; + const parsed = Number(value); + if (Number.isNaN(parsed)) throw new Error(`Invalid value for ${field}`); + return parsed; +}; \ No newline at end of file diff --git a/src/time-and-attendance/expenses/expenses.module.ts b/src/time-and-attendance/expenses/expenses.module.ts index c0206a7..f04e12c 100644 --- a/src/time-and-attendance/expenses/expenses.module.ts +++ b/src/time-and-attendance/expenses/expenses.module.ts @@ -9,7 +9,9 @@ import { ExpenseCreateService } from "src/time-and-attendance/expenses/services/ import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service"; @Module({ - controllers: [ExpenseController], + controllers: [ + ExpenseController + ], providers: [ ExpenseCreateService, ExpenseUpdateService, diff --git a/src/time-and-attendance/expenses/services/expense-create.service.ts b/src/time-and-attendance/expenses/services/expense-create.service.ts index a69b7a3..5beb9bd 100644 --- a/src/time-and-attendance/expenses/services/expense-create.service.ts +++ b/src/time-and-attendance/expenses/services/expense-create.service.ts @@ -18,10 +18,10 @@ export class ExpenseCreateService { private readonly payPeriodEventService: PayPeriodEventService, ) { } - //_________________________________________________________________ - // CREATE - //_________________________________________________________________ - async createExpense(dto: ExpenseDto, email: string): Promise> { + async createExpense( + dto: ExpenseDto, + email: string + ): Promise> { try { //fetch employee_id using req.user.email const employee_id = await this.emailResolver.findIdByEmail(email); @@ -75,6 +75,7 @@ export class ExpenseCreateService { return { success: true, data: created }; } catch (error) { + console.error(error); return { success: false, error: 'INVALID_EXPENSE' }; } } diff --git a/src/time-and-attendance/expenses/services/expense-delete.service.ts b/src/time-and-attendance/expenses/services/expense-delete.service.ts index 9662243..4c1a8c1 100644 --- a/src/time-and-attendance/expenses/services/expense-delete.service.ts +++ b/src/time-and-attendance/expenses/services/expense-delete.service.ts @@ -10,12 +10,12 @@ export class ExpenseDeleteService { private readonly prisma: PrismaPostgresService, private readonly payPeriodEventService: PayPeriodEventService, private readonly emailResolver: EmailToIdResolver, - ){} + ) { } - //_________________________________________________________________ - // DELETE - //_________________________________________________________________ - async deleteExpense(expense_id: number, email: string): Promise> { + async deleteExpense( + expense_id: number, + email: string + ): Promise> { // get employee id of employee who made delete request const employee = await this.emailResolver.findIdByEmail(email); @@ -23,7 +23,7 @@ export class ExpenseDeleteService { // confirm ownership of expense to employee who made request const expense = await this.prisma.expenses.findUnique({ - where: { id: expense_id}, + where: { id: expense_id }, select: { timesheet: { select: { @@ -33,7 +33,7 @@ export class ExpenseDeleteService { } }); - if (!expense || expense.timesheet.employee_id !== employee.data) return { success: false, error: 'EXPENSE_NOT_FOUND'}; + if (!expense || expense.timesheet.employee_id !== employee.data) return { success: false, error: 'EXPENSE_NOT_FOUND' }; try { await this.prisma.$transaction(async (tx) => { @@ -56,6 +56,7 @@ export class ExpenseDeleteService { return { success: true, data: expense_id }; } catch (error) { + console.error(error); return { success: false, error: `EXPENSE_NOT_FOUND` }; } } diff --git a/src/time-and-attendance/expenses/services/expense-update.service.ts b/src/time-and-attendance/expenses/services/expense-update.service.ts index 453bd6b..6149e77 100644 --- a/src/time-and-attendance/expenses/services/expense-update.service.ts +++ b/src/time-and-attendance/expenses/services/expense-update.service.ts @@ -17,10 +17,12 @@ export class ExpenseUpdateService { private readonly typeResolver: BankCodesResolver, private readonly payPeriodEventService: PayPeriodEventService, ) { } - //_________________________________________________________________ - // UPDATE - //_________________________________________________________________ - async updateExpense(dto: ExpenseDto, email: string, employee_email?: string): Promise> { + + async updateExpense( + dto: ExpenseDto, + email: string, + employee_email?: string + ): Promise> { try { const account_email = employee_email ?? email; //fetch employee_id using req.user.email @@ -79,6 +81,7 @@ export class ExpenseUpdateService { return { success: true, data: updated }; } catch (error) { + console.error(error); return { success: false, error: 'EXPENSE_NOT_FOUND' }; } } diff --git a/src/time-and-attendance/exports/csv-exports.controller.ts b/src/time-and-attendance/exports/csv-exports.controller.ts index ec9e2f3..6064319 100644 --- a/src/time-and-attendance/exports/csv-exports.controller.ts +++ b/src/time-and-attendance/exports/csv-exports.controller.ts @@ -44,7 +44,7 @@ export class CsvExportController { }, } ); - const csv_buffer = await this.generator.generateCsv(rows); + const csv_buffer = this.generator.generateCsv(rows); response.set({ 'Content-Type': 'text/csv; charset=utf-8', diff --git a/src/time-and-attendance/exports/csv-exports.module.ts b/src/time-and-attendance/exports/csv-exports.module.ts index ad60848..f203b23 100644 --- a/src/time-and-attendance/exports/csv-exports.module.ts +++ b/src/time-and-attendance/exports/csv-exports.module.ts @@ -14,7 +14,9 @@ import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; HolidayService, EmailToIdResolver, ], - controllers: [CsvExportController], + controllers: [ + CsvExportController + ], }) export class CsvExportModule { } diff --git a/src/time-and-attendance/exports/csv-exports.utils.ts b/src/time-and-attendance/exports/csv-exports.utils.ts index 0d4678e..b212c48 100644 --- a/src/time-and-attendance/exports/csv-exports.utils.ts +++ b/src/time-and-attendance/exports/csv-exports.utils.ts @@ -11,7 +11,7 @@ export const consolidateRowHoursAndAmountByType = (rows: InternalCsvRow[]): Inte const map = new Map(); for (const row of rows) { - if (row.code = VACATION) { + if (row.code === VACATION) { map.set(`${row.code}|${row.shift_date}`, row); } else { const key = `${row.code}|${row.semaine_no}`; diff --git a/src/time-and-attendance/exports/services/csv-builder.service.ts b/src/time-and-attendance/exports/services/csv-builder.service.ts index ccc9e17..caf5a1c 100644 --- a/src/time-and-attendance/exports/services/csv-builder.service.ts +++ b/src/time-and-attendance/exports/services/csv-builder.service.ts @@ -4,7 +4,9 @@ import { CsvRow } from "src/time-and-attendance/exports/export-csv-options.dto"; @Injectable() export class CsvGeneratorService { //csv builder and "mise en page" - generateCsv(rows: CsvRow[]): Buffer { + generateCsv( + rows: CsvRow[] + ): Buffer { const body = rows.map(row => { const quantity_hours = (typeof row.quantite_hre === 'number') ? row.quantite_hre.toFixed(2) : ''; const amount = (typeof row.montant === 'number') ? row.montant.toFixed(2) : ''; 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 7ca6019..2920f62 100644 --- a/src/time-and-attendance/exports/services/csv-exports.service.ts +++ b/src/time-and-attendance/exports/services/csv-exports.service.ts @@ -33,7 +33,11 @@ export class CsvExportService { * @returns The desired filtered data in semi-colon-separated format, grouped and sorted by * employee and by bank codes. */ - async collectTransaction(year: number, period_no: number, filters: Filters): Promise { + async collectTransaction( + year: number, + period_no: number, + filters: Filters + ): Promise { const BILLABLE_SHIFT_TYPES: BillableShiftType[] = []; if (filters.types.shifts) BILLABLE_SHIFT_TYPES.push('REGULAR', 'OVERTIME', 'EMERGENCY', 'EVENING', 'SICK'); @@ -70,10 +74,10 @@ export class CsvExportService { }); const rows: InternalCsvRow[] = exportedShifts.map(shift => { - const employee = shift!.timesheet.employee; - const week = computeWeekNumber(start, shift!.date); - const type_transaction = shift!.bank_code.bank_code.charAt(0); - const code = Number(shift!.bank_code.bank_code.slice(1,)); + const employee = shift.timesheet.employee; + const week = computeWeekNumber(start, shift.date); + const type_transaction = shift.bank_code.bank_code.charAt(0); + const code = Number(shift.bank_code.bank_code.slice(1,)); const isPTO = PTO_SHIFT_CODES.includes(shift.bank_code.bank_code) return { @@ -84,7 +88,7 @@ export class CsvExportService { releve: 0, type_transaction: type_transaction, code: code, - quantite_hre: computeHours(shift!.start_time, shift!.end_time), + quantite_hre: computeHours(shift.start_time, shift.end_time), taux_horaire: '', montant: undefined, semaine_no: week, @@ -93,8 +97,8 @@ export class CsvExportService { departem_no: undefined, sous_departem_no: undefined, date_transaction: formatDate(end), - premier_jour_absence: isPTO ? formatDate(shift!.date) : '', - dernier_jour_absence: isPTO ? formatDate(shift!.date) : '', + premier_jour_absence: isPTO ? formatDate(shift.date) : '', + dernier_jour_absence: isPTO ? formatDate(shift.date) : '', } }); @@ -110,8 +114,8 @@ export class CsvExportService { exportedExpenses.map(expense => { const employee = expense.timesheet.employee; - const type_transaction = expense!.bank_code.bank_code.charAt(0); - const code = Number(expense!.bank_code.bank_code.slice(1,)) + const type_transaction = expense.bank_code.bank_code.charAt(0); + const code = Number(expense.bank_code.bank_code.slice(1,)) const week = computeWeekNumber(start, expense.date); rows.push({ @@ -147,7 +151,7 @@ export class CsvExportService { }); const holiday_rows = await applyHolidayRequalifications(rows, this.holiday_service, HOLIDAY_SHIFT_CODE[0]); - const consolidated_rows = await consolidateRowHoursAndAmountByType(holiday_rows); + const consolidated_rows = consolidateRowHoursAndAmountByType(holiday_rows); //requalifies regular hours into overtime when needed const requalified_rows = await applyOvertimeRequalifications(consolidated_rows, this.overtime_service); diff --git a/src/time-and-attendance/utils/type.utils.ts b/src/time-and-attendance/utils/type.utils.ts index d88ea6f..662f445 100644 --- a/src/time-and-attendance/utils/type.utils.ts +++ b/src/time-and-attendance/utils/type.utils.ts @@ -14,7 +14,6 @@ export type NormalizedExpense = { amount?: number | Prisma.Decimal | null; mileage?: number | Prisma.Decimal | null; attachment?: number; - // bank_code_id: number; }; export type NormalizedLeaveRequest = {