clean(modules): clean module imports and clean utils files

This commit is contained in:
Matthieu Haineault 2025-11-13 15:23:17 -05:00
parent 30cc41955b
commit 1a88e02411
39 changed files with 835 additions and 638 deletions

View File

@ -15,48 +15,6 @@
]
}
},
"/auth/v1/login": {
"get": {
"operationId": "AuthController_login",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Auth"
]
}
},
"/auth/callback": {
"get": {
"operationId": "AuthController_loginCallback",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Auth"
]
}
},
"/auth/me": {
"get": {
"operationId": "AuthController_getProfile",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Auth"
]
}
},
"/notifications/summary": {
"get": {
"operationId": "NotificationsController_summary",
@ -85,169 +43,6 @@
]
}
},
"/pay-periods/current-and-all": {
"get": {
"operationId": "PayPeriodsController_getCurrentAndAll",
"parameters": [
{
"name": "date",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/date/{date}": {
"get": {
"operationId": "PayPeriodsController_findByDate",
"parameters": [
{
"name": "date",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/{year}/{periodNumber}": {
"get": {
"operationId": "PayPeriodsController_findOneByYear",
"parameters": [
{
"name": "year",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
},
{
"name": "periodNumber",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/crew/pay-period-approval": {
"patch": {
"operationId": "PayPeriodsController_bulkApproval",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkCrewApprovalDto"
}
}
}
},
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/crew/{year}/{periodNumber}": {
"get": {
"operationId": "PayPeriodsController_getCrewOverview",
"parameters": [
{
"name": "year",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
},
{
"name": "periodNumber",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/overview/{year}/{periodNumber}": {
"get": {
"operationId": "PayPeriodsController_getOverviewByYear",
"parameters": [
{
"name": "year",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
},
{
"name": "periodNumber",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/timesheets/{year}/{period_number}": {
"get": {
"operationId": "TimesheetController_getTimesheetByPayPeriod",
@ -293,39 +88,6 @@
]
}
},
"/preferences": {
"patch": {
"operationId": "PreferencesController_updatePreferences",
"parameters": [
{
"name": "PreferencesDto",
"required": true,
"in": "body",
"schema": {
"$ref": "#/components/schemas/PreferencesDto"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "number"
}
}
}
},
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Preferences"
]
}
},
"/shift/create": {
"post": {
"operationId": "ShiftController_createBatch",
@ -581,6 +343,332 @@
"Expense"
]
}
},
"/pay-periods/current-and-all": {
"get": {
"operationId": "PayPeriodsController_getCurrentAndAll",
"parameters": [
{
"name": "date",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/date/{date}": {
"get": {
"operationId": "PayPeriodsController_findByDate",
"parameters": [
{
"name": "date",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/{year}/{periodNumber}": {
"get": {
"operationId": "PayPeriodsController_findOneByYear",
"parameters": [
{
"name": "year",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
},
{
"name": "periodNumber",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/crew/pay-period-approval": {
"patch": {
"operationId": "PayPeriodsController_bulkApproval",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BulkCrewApprovalDto"
}
}
}
},
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/crew/{year}/{periodNumber}": {
"get": {
"operationId": "PayPeriodsController_getCrewOverview",
"parameters": [
{
"name": "year",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
},
{
"name": "periodNumber",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/pay-periods/overview/{year}/{periodNumber}": {
"get": {
"operationId": "PayPeriodsController_getOverviewByYear",
"parameters": [
{
"name": "year",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
},
{
"name": "periodNumber",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"PayPeriods"
]
}
},
"/exports/csv": {
"get": {
"operationId": "CsvExportController_exportCsv",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"CsvExport"
]
}
},
"/auth/v1/login": {
"get": {
"operationId": "AuthController_login",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Auth"
]
}
},
"/auth/callback": {
"get": {
"operationId": "AuthController_loginCallback",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Auth"
]
}
},
"/auth/me": {
"get": {
"operationId": "AuthController_getProfile",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Auth"
]
}
},
"/employees/profile": {
"get": {
"operationId": "EmployeesController_findOneProfile",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Employees"
]
}
},
"/employees/employee-list": {
"get": {
"operationId": "EmployeesController_findListEmployees",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Employees"
]
}
},
"/employees": {
"patch": {
"operationId": "EmployeesController_updateOrArchiveOrRestore",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateEmployeeDto"
}
}
}
},
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Employees"
]
},
"post": {
"operationId": "EmployeesController_create",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateEmployeeDto"
}
}
}
},
"responses": {
"201": {
"description": ""
}
},
"tags": [
"Employees"
]
}
},
"/preferences": {
"patch": {
"operationId": "PreferencesController_updatePreferences",
"parameters": [
{
"name": "PreferencesDto",
"required": true,
"in": "body",
"schema": {
"$ref": "#/components/schemas/PreferencesDto"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "number"
}
}
}
},
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Preferences"
]
}
}
},
"info": {
@ -640,14 +728,6 @@
}
},
"schemas": {
"BulkCrewApprovalDto": {
"type": "object",
"properties": {}
},
"PreferencesDto": {
"type": "object",
"properties": {}
},
"SchedulePresetsDto": {
"type": "object",
"properties": {}
@ -659,6 +739,162 @@
"ExpenseDto": {
"type": "object",
"properties": {}
},
"BulkCrewApprovalDto": {
"type": "object",
"properties": {}
},
"UpdateEmployeeDto": {
"type": "object",
"properties": {
"id": {
"type": "number",
"example": 1,
"description": "Unique ID of an employee(primary-key, auto-incremented)"
},
"user_id": {
"type": "string",
"example": "0e6e2e1f-b157-4c7c-ae3f-999b3e4f914d",
"description": "UUID of the user linked to that employee"
},
"first_name": {
"type": "string",
"example": "Frodo",
"description": "Employee`s first name"
},
"last_name": {
"type": "string",
"example": "Baggins",
"description": "Employee`s last name"
},
"email": {
"type": "string",
"example": "i_cant_do_this_sam@targointernet.com",
"description": "Employee`s email"
},
"phone_number": {
"type": "string",
"example": "82538437464",
"description": "Employee`s phone number"
},
"residence": {
"type": "string",
"example": "1 Bagshot Row, Hobbiton, The Shire, Middle-earth",
"description": "Employee`s residence"
},
"external_payroll_id": {
"type": "number",
"example": 7464,
"description": "external ID for the pay system"
},
"company_code": {
"type": "number",
"example": 335567447,
"description": "Employee`s company code"
},
"job_title": {
"type": "string",
"example": "technicient",
"description": "employee`s job title"
},
"first_work_day": {
"format": "date-time",
"type": "string",
"example": "23/09/3018",
"description": "New hire date or undefined"
},
"last_work_day": {
"format": "date-time",
"type": "string",
"example": "25/03/3019",
"description": "Termination date (null to restore)"
},
"supervisor_id": {
"type": "number",
"description": "Supervisor ID"
}
}
},
"CreateEmployeeDto": {
"type": "object",
"properties": {
"id": {
"type": "number",
"example": 1,
"description": "Unique ID of an employee(primary-key, auto-incremented)"
},
"user_id": {
"type": "string",
"example": "0e6e2e1f-b157-4c7c-ae3f-999b3e4f914d",
"description": "UUID of the user linked to that employee"
},
"first_name": {
"type": "string",
"example": "Frodo",
"description": "Employee`s first name"
},
"last_name": {
"type": "string",
"example": "Baggins",
"description": "Employee`s last name"
},
"email": {
"type": "string",
"example": "i_cant_do_this_sam@targointernet.com",
"description": "Employee`s email"
},
"phone_number": {
"type": "string",
"example": "82538437464",
"description": "Employee`s phone number"
},
"residence": {
"type": "string",
"example": "1 Bagshot Row, Hobbiton, The Shire, Middle-earth",
"description": "Employee`s residence"
},
"external_payroll_id": {
"type": "number",
"example": 7464,
"description": "external ID for the pay system"
},
"company_code": {
"type": "number",
"example": 335567447,
"description": "Employee`s company code"
},
"job_title": {
"type": "string",
"example": "technicient",
"description": "employee`s job title"
},
"first_work_day": {
"type": "string",
"example": "23/09/3018",
"description": "Employee`s first working day"
},
"last_work_day": {
"type": "string",
"example": "25/03/3019",
"description": "Employee`s last working day"
}
},
"required": [
"id",
"user_id",
"first_name",
"last_name",
"email",
"phone_number",
"external_payroll_id",
"company_code",
"job_title",
"first_work_day"
]
},
"PreferencesDto": {
"type": "object",
"properties": {}
}
}
}

View File

@ -1,36 +1,26 @@
import { BadRequestException, Module, ValidationPipe } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthenticationModule } from './identity-and-account/authentication/auth.module';
// import { CsvExportModule } from './modules/exports/csv-exports.module';
import { HealthModule } from './health/health.module';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { HealthController } from './health/health.controller';
import { NotificationsModule } from './modules/notifications/notifications.module';
import { PreferencesModule } from './identity-and-account/preferences/preferences.module';
import { PrismaModule } from './prisma/prisma.module';
import { ScheduleModule } from '@nestjs/schedule';
import { UsersModule } from './identity-and-account/users-management/users.module';
import { ConfigModule } from '@nestjs/config';
import { PrismaModule } from './prisma/prisma.module';
import { ScheduleModule } from '@nestjs/schedule';
import { ConfigModule } from '@nestjs/config';
import { APP_FILTER, APP_PIPE } from '@nestjs/core';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
import { ValidationError } from 'class-validator';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
import { ValidationError } from 'class-validator';
import { TimeAndAttendanceModule } from 'src/time-and-attendance/time-and-attendance.module';
import { PayperiodsModule } from 'src/time-and-attendance/pay-period/pay-periods.module';
import { IdentityAndAccountModule } from 'src/identity-and-account/identity-and-account.module';
@Module({
imports: [
AuthenticationModule,
ConfigModule.forRoot({isGlobal: true}),
// CsvExportModule,
HealthModule,
NotificationsModule,
PayperiodsModule,
PreferencesModule,
PrismaModule,
ConfigModule.forRoot({ isGlobal: true }),
ScheduleModule.forRoot(), //cronjobs
NotificationsModule,
PrismaModule,
TimeAndAttendanceModule,
UsersModule,
],
IdentityAndAccountModule,
],
controllers: [AppController, HealthController],
providers: [
AppService,
@ -44,9 +34,9 @@ import { PayperiodsModule } from 'src/time-and-attendance/pay-period/pay-periods
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
exceptionFactory: (errors: ValidationError[] = [])=> {
const messages = errors.flatMap((e)=> Object.values(e.constraints ?? {}));
return new BadRequestException({
exceptionFactory: (errors: ValidationError[] = []) => {
const messages = errors.flatMap((e) => Object.values(e.constraints ?? {}));
return new BadRequestException({
statusCode: 400,
error: 'Bad Request',
message: messages.length ? messages : errors,
@ -56,4 +46,4 @@ import { PayperiodsModule } from 'src/time-and-attendance/pay-period/pay-periods
},
],
})
export class AppModule {}
export class AppModule { }

View File

@ -1,9 +1,9 @@
import { Injectable, NotFoundException } from "@nestjs/common";
import { Prisma, PrismaClient } from "@prisma/client";
import { weekStartSunday } from "src/time-and-attendance/utils/date-time.utils";
import { PrismaService } from "src/prisma/prisma.service";
import { EmailToIdResolver } from "./resolve-email-id.utils";
import { EmailToIdResolver } from "./email-id.mapper";
import { Result } from "src/common/errors/result-error.factory";
import { weekStartSunday } from "src/common/utils/date-utils";
type Tx = Prisma.TransactionClient | PrismaClient;

View File

@ -13,3 +13,8 @@ export const MANAGER_ROLES: readonly RoleEnum[] = [
RoleEnum.SUPERVISOR,
RoleEnum.ADMIN,
]
export const PAY_SERVICE: readonly RoleEnum[] = [
RoleEnum.HR,
RoleEnum.ACCOUNTING,
]

View File

@ -1,3 +1,5 @@
import { Weekday } from "@prisma/client";
export const NUMBER_OF_TIMESHEETS_TO_RETURN = 2;
export const DAILY_LIMIT_HOURS = 8;
export const WEEKLY_LIMIT_HOURS = 40;
@ -12,3 +14,6 @@ export const MS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;
//REGEX CONSTANTS
export const DATE_ISO_FORMAT = /^\d{4}-\d{2}-\d{2}$/;
export const HH_MM_REGEX = /^([01]\d|2[0-3]):[0-5]\d$/;
export const WEEKDAY: Weekday[] = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];

View File

@ -14,18 +14,6 @@ export function roundToQuarterHour(hours: number): number {
return Math.round(hours *4) / 4;
}
//calculate the number of the week (1 or 2)
export function computeWeekNumber(periodStart: Date, targetDate: Date): number {
const days = Math.floor( targetDate.getTime() - periodStart.getTime()) /
(1000 * 60 * 60 * 24);
return Math.floor(days / 7) +1;
}
//Date format YYY-MM-DD
export function formatDateISO(d:Date): string {
return d.toISOString().split('T')[0];
}
//fetch firts day of the week (Sunday)
export function getWeekStart(date:Date, firstDayOfWeek = 0): Date {
const d = new Date(date);
@ -49,29 +37,7 @@ export function getYearStart(date:Date): Date {
return new Date(date.getFullYear(),0,1,0,0,0,0);
}
export function getCurrentWeek(): { start_date_week: Date; end_date_week: Date } {
const now = new Date();
const start_date_week = getWeekStart(now, 0);
const end_date_week = getWeekEnd(start_date_week);
return { start_date_week, end_date_week };
}
//cloning methods (helps with notify for overtime in a single day)
// export function toDateOnly(day: Date): Date {
// const d = new Date(day);
// d.setHours(0, 0, 0, 0);
// return d;
// }
// export function composeDateWithTime(day: Date, timeOnly: Date): Date {
// const base = toDateOnly(day);
// base.setHours(timeOnly.getHours(),
// timeOnly.getMinutes(),
// timeOnly.getSeconds(),
// timeOnly.getMilliseconds());
// return base;
// }
//to be used to calculate breaks time
export function hoursBetweenSameDay(day: Date, startTime: Date, endTime: Date): number {
const start = new Date(day); start.setHours(startTime.getHours(),
startTime.getMinutes(),
@ -85,7 +51,127 @@ export function hoursBetweenSameDay(day: Date, startTime: Date, endTime: Date):
return ms / 3_600_000; // decimal hours
}
// //utils to print Date into locale date format
// export function fmtDayLocal(day:Date, locale = 'fr-CA'): string {
// return new Date(day).toLocaleDateString(locale, { year: 'numeric', month: '2-digit', day: '2-digit'});
// }
import { BadRequestException } from "@nestjs/common";
import { ANCHOR_ISO, MS_PER_DAY, PERIODS_PER_YEAR, PERIOD_DAYS } from "src/common/utils/constants.utils";
//ensures the week starts from sunday
export function weekStartSunday(date_local: Date): Date {
const start_date = new Date();
start_date.setDate(date_local.getDate() - date_local.getDay());
return start_date;
}
//converts string to HHmm format
export const toStringFromHHmm = (date: Date): string => {
const hh = date.getUTCHours().toString().padStart(2, '0');
const mm = date.getUTCMinutes().toString().padStart(2, '0');
return `${hh}:${mm}`;
}
//converts string to Date format
export const toStringFromDate = (date: Date) =>
date.toISOString().slice(0, 10);
//converts HHmm format to string
export const toHHmmFromString = (hhmm: string): Date => {
const [hh, mm] = hhmm.split(':').map(Number);
const date = new Date('1970-01-01T00:00:00.000Z');
date.setUTCHours(hh, mm, 0, 0);
return new Date(date);
}
//converts string to HHmm format
export const toHHmmFromDate = (input: Date | string): string => {
const date = new Date(input);
const hh = String(date.getUTCHours()).padStart(2, '0');
const mm = String(date.getUTCMinutes()).padStart(2, '0');
return `${hh}:${mm}`;
}
//converts to Date format from string
export const toDateFromString = (ymd: string | Date): Date => {
return new Date(ymd);
}
export const toUTCDateFromString = (iso: string | Date) => {
const d = typeof iso === 'string' ? new Date(iso + 'T00:00:00.000Z') : iso;
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
};
export const sevenDaysFrom = (date: Date | string): Date[] => {
return Array.from({ length: 7 }, (_, i) => {
const d = new Date(date);
d.setUTCDate(d.getUTCDate() + i);
return d;
});
}
export function payYearOfDate(date: string | Date, anchorISO = ANCHOR_ISO): number {
const ANCHOR = toUTCDateFromString(anchorISO);
const d = toUTCDateFromString(date);
const days = Math.floor((+d - +ANCHOR) / MS_PER_DAY);
const cycles = Math.floor(days / (PERIODS_PER_YEAR * PERIOD_DAYS));
return ANCHOR.getUTCFullYear() + 1 + cycles;
}
//compute labels for periods
export function computePeriod(pay_year: number, period_no: number, anchorISO = ANCHOR_ISO) {
const ANCHOR = toUTCDateFromString(anchorISO);
const cycles = pay_year - (ANCHOR.getUTCFullYear() + 1);
const offsetPeriods = cycles * PERIODS_PER_YEAR + (period_no - 1);
const start = new Date(+ANCHOR + offsetPeriods * PERIOD_DAYS * MS_PER_DAY);
const end = new Date(+start + (PERIOD_DAYS - 1) * MS_PER_DAY);
const pay = new Date(end.getTime() + 6 * MS_PER_DAY);
return {
period_no: period_no,
pay_year: pay_year,
payday: toStringFromDate(pay),
period_start: toStringFromDate(start),
period_end: toStringFromDate(end),
label: `${toStringFromDate(start)}.${toStringFromDate(end)}`,
start, end,
};
}
//list of all 26 periods for a full year
export function listPayYear(pay_year: number, anchorISO = ANCHOR_ISO) {
return Array.from({ length: PERIODS_PER_YEAR }, (_, i) => computePeriod(pay_year, i + 1, anchorISO));
}
export const overlaps = (a: { start: Date; end: Date, date?: Date; }, b: { start: Date; end: Date; date?: Date; }) =>
((a.date?.getTime() === b.date?.getTime()) && !(a.end <= b.start || a.start >= b.end));
export const hhmmFromLocal = (d: Date) =>
`${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
export const toDateOnly = (s: string): Date => {
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) {
const y = Number(s.slice(0,4));
const m = Number(s.slice(5,7)) - 1;
const d = Number(s.slice(8,10));
return new Date(y, m, d, 0, 0, 0, 0);
}
const dt = new Date(s);
if (Number.isNaN(dt.getTime())) throw new BadRequestException(`Invalid date: ${s}`);
return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), 0,0,0,0);
};
// export const toStringFromDate = (d: Date) =>
// `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
export const toISOtoDateOnly = (iso: string): Date => {
const date = new Date(iso);
if (Number.isNaN(date.getTime())) {
throw new BadRequestException(`Invalid date: ${iso}`);
}
date.setHours(0, 0, 0, 0);
return date;
};
export const toISODateKey = (date: Date): string => date.toISOString().slice(0, 10);
export const normalizeDates = (dates: string[]): string[] =>
Array.from(new Set(dates.map((iso) => toISODateKey(toISOtoDateOnly(iso)))));

View File

@ -1,12 +1,12 @@
// import { Module } from '@nestjs/common';
// import { EmployeesController } from './controllers/employees.controller';
// import { EmployeesService } from './services/employees.service';
// import { SharedModule } from '../../time-and-attendance/modules/shared/shared.module';
import { Module } from '@nestjs/common';
import { EmployeesController } from './controllers/employees.controller';
import { EmployeesService } from './services/employees.service';
import { EmployeesArchivalService } from 'src/identity-and-account/employees/services/employees-archival.service';
// @Module({
// imports: [SharedModule],
// controllers: [EmployeesController],
// providers: [EmployeesService],
// exports: [EmployeesService ],
// })
// export class EmployeesModule {}
@Module({
imports: [],
controllers: [EmployeesController],
providers: [EmployeesService, EmployeesArchivalService],
exports: [EmployeesService ],
})
export class EmployeesModule {}

View File

@ -0,0 +1,35 @@
import { Module } from "@nestjs/common";
import { AuthModuleOptions } from "@nestjs/passport";
import { AuthController } from "src/identity-and-account/authentication/controllers/auth.controller";
import { AuthentikAuthService } from "src/identity-and-account/authentication/services/authentik-auth.service";
import { EmployeesController } from "src/identity-and-account/employees/controllers/employees.controller";
import { EmployeesModule } from "src/identity-and-account/employees/employees.module";
import { EmployeesArchivalService } from "src/identity-and-account/employees/services/employees-archival.service";
import { EmployeesService } from "src/identity-and-account/employees/services/employees.service";
import { PreferencesController } from "src/identity-and-account/preferences/controllers/preferences.controller";
import { PreferencesModule } from "src/identity-and-account/preferences/preferences.module";
import { PreferencesService } from "src/identity-and-account/preferences/services/preferences.service";
import { UsersService } from "src/identity-and-account/users-management/services/users.service";
import { UsersModule } from "src/identity-and-account/users-management/users.module";
@Module({
imports: [
UsersModule,
EmployeesModule,
PreferencesModule,
AuthModuleOptions,
],
controllers: [
AuthController,
EmployeesController,
PreferencesController,
],
providers: [
AuthentikAuthService,
EmployeesArchivalService,
EmployeesService,
PreferencesService,
UsersService,
],
})
export class IdentityAndAccountModule { };

View File

@ -1,49 +1,39 @@
// import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from "@nestjs/common";
// import { BankCodesService } from "../services/bank-codes.service";
// import { CreateBankCodeDto } from "../dtos/create-bank-code.dto";
// import { UpdateBankCodeDto } from "../dtos/update-bank-code.dto";
// import { ApiBadRequestResponse, ApiNotFoundResponse, ApiOperation, ApiResponse } from "@nestjs/swagger";
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from "@nestjs/common";
import { BankCodesService } from "../services/bank-codes.service";
import { BankCodeDto } from "../dtos/bank-code.dto";
import { RolesAllowed } from "src/common/decorators/roles.decorators";
import { PAY_SERVICE } from "src/common/shared/role-groupes";
// @Controller('bank-codes')
// export class BankCodesControllers {
// constructor(private readonly bankCodesService: BankCodesService) {}
// //_____________________________________________________________________________________________
// // Deprecated or unused methods
// //_____________________________________________________________________________________________
@Controller('bank-codes')
@RolesAllowed(...PAY_SERVICE)
export class BankCodesControllers {
constructor(private readonly bankCodesService: BankCodesService) {}
//_____________________________________________________________________________________________
// Deprecated or unused methods
//_____________________________________________________________________________________________
// // @Post()
// // @ApiOperation({ summary: 'Create a new bank code' })
// // @ApiResponse({ status: 201, description: 'Bank code successfully created.' })
// // @ApiBadRequestResponse({ description: 'Invalid input data.' })
// // create(@Body() dto: CreateBankCodeDto) {
// // return this.bankCodesService.create(dto);
// // }
@Post()
create(@Body() dto: BankCodeDto) {
return this.bankCodesService.create(dto);
}
// // @Get()
// // @ApiOperation({ summary: 'Retrieve all bank codes' })
// // @ApiResponse({ status: 200, description: 'List of bank codes.' })
// // findAll() {
// // return this.bankCodesService.findAll();
// // }
@Get()
findAll() {
return this.bankCodesService.findAll();
}
// // @Get(':id')
// // @ApiOperation({ summary: 'Retrieve a bank code by its ID' })
// // @ApiNotFoundResponse({ description: 'Bank code not found.' })
// // findOne(@Param('id', ParseIntPipe) id: number){
// // return this.bankCodesService.findOne(id);
// // }
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number){
return this.bankCodesService.findOne(id);
}
// // @Patch(':id')
// // @ApiOperation({ summary: 'Update an existing bank code' })
// // @ApiNotFoundResponse({ description: 'Bank code not found.' })
// // update(@Param('id', ParseIntPipe) id: number, @Body() dto: UpdateBankCodeDto) {
// // return this.bankCodesService.update(id, dto)
// // }
@Patch(':id')
update(@Param('id', ParseIntPipe) id: number, @Body() dto: BankCodeDto) {
return this.bankCodesService.update(id, dto)
}
// // @Delete(':id')
// // @ApiOperation({ summary: 'Delete a bank code' })
// // @ApiNotFoundResponse({ description: 'Bank code not found.' })
// // remove(@Param('id', ParseIntPipe) id: number) {
// // return this.bankCodesService.remove(id);
// // }
// }
@Delete(':id')
remove(@Param('id', ParseIntPipe) id: number) {
return this.bankCodesService.remove(id);
}
}

View File

@ -1,7 +0,0 @@
export class BankCodeEntity {
id: number;
type: string;
categorie: string;
modifier: number;
bank_code: string;
}

View File

@ -0,0 +1,24 @@
import { Type } from "class-transformer";
import { Allow, IsNotEmpty, IsNumber, IsString } from "class-validator";
export class BankCodeDto {
@Allow()
id: number;
@IsString()
@IsNotEmpty()
type: string;
@IsString()
@IsNotEmpty()
categorie: string;
@Type(()=> Number)
@IsNumber()
@IsNotEmpty()
modifier: number;
@IsString()
@IsNotEmpty()
bank_code: string;
}

View File

@ -1,46 +0,0 @@
// import { ApiProperty } from "@nestjs/swagger";
// import { Type } from "class-transformer";
// import { Allow, IsNotEmpty, IsNumber, IsString } from "class-validator";
// export class CreateBankCodeDto {
// @ApiProperty({
// example: 1,
// description: 'Unique ID of a bank-code (auto-generated)',
// readOnly: true,
// })
// @Allow()
// id: number;
// @ApiProperty({
// example: 'regular, vacation, emergency, sick, parental, etc',
// description: 'Type of codes',
// })
// @IsString()
// @IsNotEmpty()
// type: string;
// @ApiProperty({
// example: 'shift, expense, leave',
// description: 'categorie of the related code',
// })
// @IsString()
// @IsNotEmpty()
// categorie: string;
// @ApiProperty({
// example: '0, 0.72, 1, 1.5, 2',
// description: 'modifier number to apply to salary',
// })
// @Type(()=> Number)
// @IsNumber()
// @IsNotEmpty()
// modifier: number;
// @ApiProperty({
// example: 'G1, G345, G501, G43, G700',
// description: 'codes given by the bank',
// })
// @IsString()
// @IsNotEmpty()
// bank_code: string;
// }

View File

@ -1,4 +0,0 @@
// import { PartialType } from "@nestjs/swagger";
// import { CreateBankCodeDto } from "./create-bank-code.dto";
// export class UpdateBankCodeDto extends PartialType(CreateBankCodeDto) {}

View File

@ -1,51 +1,50 @@
// import { Injectable, NotFoundException } from "@nestjs/common";
// import { PrismaService } from "src/prisma/prisma.service";
// import { CreateBankCodeDto } from "../dtos/create-bank-code.dto";
// import { BankCodes } from "@prisma/client";
// import { UpdateBankCodeDto } from "../dtos/update-bank-code.dto";
import { Injectable, NotFoundException } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service";
import { BankCodeDto } from "../dtos/bank-code.dto";
import { BankCodes } from "@prisma/client";
// @Injectable()
// export class BankCodesService {
// constructor(private readonly prisma: PrismaService) {}
@Injectable()
export class BankCodesService {
constructor(private readonly prisma: PrismaService) {}
// async create(dto: CreateBankCodeDto): Promise<BankCodes>{
// return this.prisma.bankCodes.create({
// data: {
// type: dto.type,
// categorie: dto.categorie,
// modifier: dto.modifier,
// bank_code: dto.bank_code,
// },
// });
// }
async create(dto: BankCodeDto): Promise<BankCodes>{
return this.prisma.bankCodes.create({
data: {
type: dto.type,
categorie: dto.categorie,
modifier: dto.modifier,
bank_code: dto.bank_code,
},
});
}
// findAll() {
// return this.prisma.bankCodes.findMany();
// }
findAll() {
return this.prisma.bankCodes.findMany();
}
// async findOne(id: number) {
// const bankCode = await this.prisma.bankCodes.findUnique({ where: {id} });
async findOne(id: number) {
const bankCode = await this.prisma.bankCodes.findUnique({ where: {id} });
// if(!bankCode) throw new NotFoundException(`Bank Code #${id} not found`);
if(!bankCode) throw new NotFoundException(`Bank Code #${id} not found`);
// return bankCode;
// }
return bankCode;
}
// async update(id:number, dto: UpdateBankCodeDto) {
// return await this.prisma.bankCodes.update({
// where: { id },
// data: {
// type: dto.type,
// categorie: dto.categorie,
// modifier: dto.modifier as any,
// bank_code: dto.bank_code,
// },
// });
// }
async update(id:number, dto: BankCodeDto) {
return await this.prisma.bankCodes.update({
where: { id },
data: {
type: dto.type,
categorie: dto.categorie,
modifier: dto.modifier as any,
bank_code: dto.bank_code,
},
});
}
// async remove(id: number) {
// await this.findOne(id);
// return this.prisma.bankCodes.delete({ where: {id} });
// }
async remove(id: number) {
await this.findOne(id);
return this.prisma.bankCodes.delete({ where: {id} });
}
// }
}

View File

@ -1,21 +1,18 @@
import { Controller, Get, Header, Query, UseGuards } from "@nestjs/common";
import { RolesGuard } from "src/common/guards/roles.guard";
import { Roles as RoleEnum } from '.prisma/client';
import { Controller, Get, Header, Query} from "@nestjs/common";
import { CsvExportService } from "../services/csv-exports.service";
// import { ExportCompany, ExportCsvOptionsDto, ExportType } from "../dtos/export-csv-options.dto";
import { RolesAllowed } from "src/common/decorators/roles.decorators";
import { ExportCsvOptionsDto } from "../dtos/export-csv-options.dto";
import { RolesAllowed } from "src/common/decorators/roles.decorators";
import { PAY_SERVICE } from "src/common/shared/role-groupes";
@Controller('exports')
@UseGuards(RolesGuard)
@RolesAllowed(...PAY_SERVICE)
export class CsvExportController {
constructor(private readonly csvService: CsvExportService) {}
@Get('csv')
@Header('Content-Type', 'text/csv; charset=utf-8')
@Header('Content-Disposition', 'attachment; filename="export.csv"')
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.ACCOUNTING, RoleEnum.HR)
async exportCsv(@Query() query: ExportCsvOptionsDto ): Promise<Buffer> {
const rows = await this.csvService.collectTransaction(
query.year,

View File

@ -4,7 +4,7 @@ import { VacationService } from "./services/vacation.service";
import { HolidayService } from "./services/holiday.service";
import { MileageService } from "./services/mileage.service";
import { Module } from "@nestjs/common";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
@Module({

View File

@ -1,8 +1,8 @@
import { Injectable } from "@nestjs/common";
import { computeHours, getWeekStart } from "src/common/utils/date-utils";
import { PrismaService } from "src/prisma/prisma.service";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { MS_PER_WEEK } from "src/time-and-attendance/utils/constants.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { MS_PER_WEEK } from "src/common/utils/constants.utils";
import { Result } from "src/common/errors/result-error.factory";
/*
le calcul est 1/20 des 4 dernières semaines, précédent la semaine incluant le férier.

View File

@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { Prisma, PrismaClient } from '@prisma/client';
import { getWeekStart, getWeekEnd, computeHours } from 'src/common/utils/date-utils';
import { PrismaService } from 'src/prisma/prisma.service';
import { DAILY_LIMIT_HOURS, WEEKLY_LIMIT_HOURS } from 'src/time-and-attendance/utils/constants.utils';
import { DAILY_LIMIT_HOURS, WEEKLY_LIMIT_HOURS } from 'src/common/utils/constants.utils';
type Tx = Prisma.TransactionClient | PrismaClient;

View File

@ -1,10 +1,11 @@
import { ExpenseUpsertService } from "src/time-and-attendance/expenses/services/expense-upsert.service";
import { ExpenseController } from "src/time-and-attendance/expenses/controllers/expense.controller";
import { Module } from "@nestjs/common";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
@Module({
controllers: [ ExpenseController ],
providers: [ ExpenseUpsertService ],
providers: [ ExpenseUpsertService, EmailToIdResolver ],
})
export class ExpensesModule {}

View File

@ -1,5 +1,5 @@
import { toDateFromString, toStringFromDate, weekStartSunday } from "src/time-and-attendance/utils/date-time.utils";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { expense_select } from "src/time-and-attendance/utils/selects.utils";
import { PrismaService } from "src/prisma/prisma.service";
import { GetExpenseDto } from "src/time-and-attendance/expenses/dtos/expense-get.dto";
@ -8,6 +8,7 @@ import { ExpenseDto } from "src/time-and-attendance/expenses/dtos/expense-create
import { Injectable } from "@nestjs/common";
import { Result } from "src/common/errors/result-error.factory";
import { NormalizedExpense } from "src/time-and-attendance/utils/type.utils";
import { weekStartSunday, toStringFromDate, toDateFromString } from "src/common/utils/date-utils";
@Injectable()

View File

@ -2,7 +2,7 @@
import { BadRequestException, Injectable } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service";
import { LeaveTypes } from "@prisma/client";
import { toDateFromString, toStringFromDate } from "src/time-and-attendance/utils/date-time.utils";
import { toDateFromString, toStringFromDate } from "src/common/utils/date-utils";
@Injectable()
export class LeaveRequestsUtils {
constructor(

View File

@ -3,7 +3,7 @@ import { PayPeriodsController } from "./controllers/pay-periods.controller";
import { Module } from "@nestjs/common";
import { PayPeriodsCommandService } from "src/time-and-attendance/pay-period/services/pay-periods-command.service";
import { TimesheetsModule } from "src/time-and-attendance/time-tracker/timesheets/timesheets.module";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
@Module({
imports:[TimesheetsModule],

View File

@ -1,12 +1,10 @@
import { ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service";
import { computeHours } from "src/common/utils/date-utils";
import { computeHours, computePeriod, listPayYear, payYearOfDate } from "src/common/utils/date-utils";
import { PayPeriodOverviewDto } from "../dtos/overview-pay-period.dto";
import { EmployeePeriodOverviewDto } from "../dtos/overview-employee-period.dto";
import { PayPeriodDto } from "../dtos/pay-period.dto";
import { mapPayPeriodToDto } from "../mappers/pay-periods.mapper";
import { computePeriod, listPayYear, payYearOfDate } from "src/time-and-attendance/utils/date-time.utils";
@Injectable()
export class PayPeriodsQueryService {
constructor(private readonly prisma: PrismaService) { }

View File

@ -16,21 +16,34 @@ import { TimesheetController } from "src/time-and-attendance/time-tracker/timesh
import { TimesheetApprovalService } from "src/time-and-attendance/time-tracker/timesheets/services/timesheet-approval.service";
import { GetTimesheetsOverviewService } from "src/time-and-attendance/time-tracker/timesheets/services/timesheet-get-overview.service";
import { TimesheetsModule } from "src/time-and-attendance/time-tracker/timesheets/timesheets.module";
import { BankCodesResolver } from "src/time-and-attendance/utils/resolve-bank-type-id.utils";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { EmployeeTimesheetResolver } from "src/time-and-attendance/utils/resolve-timesheet.utils";
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 { PayPeriodsController } from "src/time-and-attendance/pay-period/controllers/pay-periods.controller";
import { ExpensesModule } from "src/time-and-attendance/expenses/expenses.module";
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/modules/exports/csv-exports.module";
import { CsvExportService } from "src/modules/exports/services/csv-exports.service";
import { CsvExportController } from "src/modules/exports/controllers/csv-exports.controller";
@Module({
imports: [
BusinessLogicsModule,
PayperiodsModule,
TimesheetsModule,
ExpensesModule,
PayperiodsModule,
CsvExportModule,
],
controllers: [
TimesheetController,
ShiftController,
SchedulePresetsController,
ExpenseController,
PayPeriodsController,
CsvExportController,
],
providers: [
GetTimesheetsOverviewService,
@ -45,6 +58,9 @@ import { EmployeeTimesheetResolver } from "src/time-and-attendance/utils/resolve
BankCodesResolver,
TimesheetApprovalService,
EmployeeTimesheetResolver,
PayPeriodsQueryService,
PayPeriodsCommandService,
CsvExportService,
],
exports: [TimesheetApprovalService ],
}) export class TimeAndAttendanceModule { };

View File

@ -1,5 +1,5 @@
import { IsBoolean, IsEnum, IsInt, IsOptional, IsString, Matches, Min } from "class-validator";
import { HH_MM_REGEX } from "src/time-and-attendance/utils/constants.utils";
import { HH_MM_REGEX } from "src/common/utils/constants.utils";
import { Weekday } from "@prisma/client";
export class SchedulePresetShiftsDto {

View File

@ -1,10 +1,9 @@
import { Injectable, BadRequestException, NotFoundException, ConflictException } from "@nestjs/common";
import { Weekday, Prisma } from "@prisma/client";
import { DATE_ISO_FORMAT } from "src/time-and-attendance/utils/constants.utils";
import { DATE_ISO_FORMAT, WEEKDAY } from "src/common/utils/constants.utils";
import { PrismaService } from "src/prisma/prisma.service";
import { ApplyResult } from "src/time-and-attendance/utils/type.utils";
import { WEEKDAY } from "src/time-and-attendance/utils/mappers.utils";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { Result } from "src/common/errors/result-error.factory";

View File

@ -1,7 +1,7 @@
import { PresetResponse, ShiftResponse } from "src/time-and-attendance/utils/type.utils";
import { PrismaService } from "src/prisma/prisma.service";
import { Injectable } from "@nestjs/common";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { Result } from "src/common/errors/result-error.factory";
@Injectable()

View File

@ -1,11 +1,11 @@
import { Injectable, BadRequestException, NotFoundException, ConflictException } from "@nestjs/common";
import { Prisma, Weekday } from "@prisma/client";
import { toDateFromString, toHHmmFromDate } from "src/time-and-attendance/utils/date-time.utils";
import { PrismaService } from "src/prisma/prisma.service";
import { BankCodesResolver } from "src/time-and-attendance/utils/resolve-bank-type-id.utils";
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
import { SchedulePresetsDto } from "src/time-and-attendance/time-tracker/schedule-presets/dtos/create-schedule-presets.dto";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { Result } from "src/common/errors/result-error.factory";
import { toHHmmFromDate, toDateFromString } from "src/common/utils/date-utils";
@Injectable()
export class SchedulePresetsUpsertService {

View File

@ -1,12 +1,12 @@
import { Normalized } from "src/time-and-attendance/utils/type.utils";
import { overlaps, toStringFromHHmm, toStringFromDate, toDateFromString, toHHmmFromString } from "src/time-and-attendance/utils/date-time.utils";
import { Injectable } from "@nestjs/common";
import { timesheet_select } from "src/time-and-attendance/utils/selects.utils";
import { BankCodesResolver } from "src/time-and-attendance/utils/resolve-bank-type-id.utils";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { PrismaService } from "src/prisma/prisma.service";
import { ShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-create.dto";
import { Result } from "src/common/errors/result-error.factory";
import { toStringFromHHmm, toStringFromDate, toDateFromString, overlaps, toHHmmFromString } from "src/common/utils/date-utils";
@Injectable()
export class ShiftsCreateService {

View File

@ -1,8 +1,6 @@
import { toStringFromDate, toStringFromHHmm } from "src/time-and-attendance/utils/date-time.utils";
import { Injectable, NotFoundException } from "@nestjs/common";
import { Injectable } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service";
import { shift_select } from "src/time-and-attendance/utils/selects.utils";
import { GetShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-get.dto";
/**

View File

@ -1,12 +1,12 @@
import { toDateFromString, toHHmmFromString, toStringFromHHmm, toStringFromDate, overlaps, toUTCDateFromString } from "src/time-and-attendance/utils/date-time.utils";
import { BankCodesResolver } from "src/time-and-attendance/utils/resolve-bank-type-id.utils";
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
import { PrismaService } from "src/prisma/prisma.service";
import { shift_select } from "src/time-and-attendance/utils/selects.utils";
import { Injectable } from "@nestjs/common";
import { Normalized } from "src/time-and-attendance/utils/type.utils";
import { ShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-create.dto";
import { Result } from "src/common/errors/result-error.factory";
import { EmployeeTimesheetResolver } from "src/time-and-attendance/utils/resolve-timesheet.utils";
import { EmployeeTimesheetResolver } from "src/common/mappers/timesheet.mapper";
import { toDateFromString, toStringFromHHmm, toStringFromDate, toHHmmFromString, overlaps } from "src/common/utils/date-utils";
@Injectable()
export class ShiftsUpdateDeleteService {

View File

@ -1,11 +1,12 @@
import { sevenDaysFrom, toStringFromDate, toHHmmFromDate, toDateFromString } from "src/time-and-attendance/utils/date-time.utils";
import { NUMBER_OF_TIMESHEETS_TO_RETURN } from "src/time-and-attendance/utils/constants.utils";
import { NUMBER_OF_TIMESHEETS_TO_RETURN } from "src/common/utils/constants.utils";
import { Injectable } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service";
import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-id.utils";
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { Timesheet, Timesheets } from "src/time-and-attendance/time-tracker/timesheets/dtos/timesheet.dto";
import { Result } from "src/common/errors/result-error.factory";
import { Prisma } from "@prisma/client";
import { toDateFromString, sevenDaysFrom, toStringFromDate, toHHmmFromDate } from "src/common/utils/date-utils";
export type TotalHours = {
regular: number;

View File

@ -3,7 +3,7 @@ import { Module } from '@nestjs/common';
import { TimesheetController } from 'src/time-and-attendance/time-tracker/timesheets/controllers/timesheet.controller';
import { TimesheetApprovalService } from 'src/time-and-attendance/time-tracker/timesheets/services/timesheet-approval.service';
import { GetTimesheetsOverviewService } from 'src/time-and-attendance/time-tracker/timesheets/services/timesheet-get-overview.service';
import { EmailToIdResolver } from 'src/time-and-attendance/utils/resolve-email-id.utils';
import { EmailToIdResolver } from 'src/common/mappers/email-id.mapper';
@Module({
controllers: [TimesheetController],

View File

@ -1,124 +0,0 @@
import { BadRequestException } from "@nestjs/common";
import { ANCHOR_ISO, MS_PER_DAY, PERIODS_PER_YEAR, PERIOD_DAYS } from "src/time-and-attendance/utils/constants.utils";
//ensures the week starts from sunday
export function weekStartSunday(date_local: Date): Date {
const start_date = new Date();
start_date.setDate(date_local.getDate() - date_local.getDay());
return start_date;
}
//converts string to HHmm format
export const toStringFromHHmm = (date: Date): string => {
const hh = date.getUTCHours().toString().padStart(2, '0');
const mm = date.getUTCMinutes().toString().padStart(2, '0');
return `${hh}:${mm}`;
}
//converts string to Date format
export const toStringFromDate = (date: Date) =>
date.toISOString().slice(0, 10);
//converts HHmm format to string
export const toHHmmFromString = (hhmm: string): Date => {
const [hh, mm] = hhmm.split(':').map(Number);
const date = new Date('1970-01-01T00:00:00.000Z');
date.setUTCHours(hh, mm, 0, 0);
return new Date(date);
}
//converts string to HHmm format
export const toHHmmFromDate = (input: Date | string): string => {
const date = new Date(input);
const hh = String(date.getUTCHours()).padStart(2, '0');
const mm = String(date.getUTCMinutes()).padStart(2, '0');
return `${hh}:${mm}`;
}
//converts to Date format from string
export const toDateFromString = (ymd: string | Date): Date => {
return new Date(ymd);
}
export const toUTCDateFromString = (iso: string | Date) => {
const d = typeof iso === 'string' ? new Date(iso + 'T00:00:00.000Z') : iso;
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
};
export const sevenDaysFrom = (date: Date | string): Date[] => {
return Array.from({ length: 7 }, (_, i) => {
const d = new Date(date);
d.setUTCDate(d.getUTCDate() + i);
return d;
});
}
export function payYearOfDate(date: string | Date, anchorISO = ANCHOR_ISO): number {
const ANCHOR = toUTCDateFromString(anchorISO);
const d = toUTCDateFromString(date);
const days = Math.floor((+d - +ANCHOR) / MS_PER_DAY);
const cycles = Math.floor(days / (PERIODS_PER_YEAR * PERIOD_DAYS));
return ANCHOR.getUTCFullYear() + 1 + cycles;
}
//compute labels for periods
export function computePeriod(pay_year: number, period_no: number, anchorISO = ANCHOR_ISO) {
const ANCHOR = toUTCDateFromString(anchorISO);
const cycles = pay_year - (ANCHOR.getUTCFullYear() + 1);
const offsetPeriods = cycles * PERIODS_PER_YEAR + (period_no - 1);
const start = new Date(+ANCHOR + offsetPeriods * PERIOD_DAYS * MS_PER_DAY);
const end = new Date(+start + (PERIOD_DAYS - 1) * MS_PER_DAY);
const pay = new Date(end.getTime() + 6 * MS_PER_DAY);
return {
period_no: period_no,
pay_year: pay_year,
payday: toStringFromDate(pay),
period_start: toStringFromDate(start),
period_end: toStringFromDate(end),
label: `${toStringFromDate(start)}.${toStringFromDate(end)}`,
start, end,
};
}
//list of all 26 periods for a full year
export function listPayYear(pay_year: number, anchorISO = ANCHOR_ISO) {
return Array.from({ length: PERIODS_PER_YEAR }, (_, i) => computePeriod(pay_year, i + 1, anchorISO));
}
export const overlaps = (a: { start: Date; end: Date, date?: Date; }, b: { start: Date; end: Date; date?: Date; }) =>
((a.date?.getTime() === b.date?.getTime()) && !(a.end <= b.start || a.start >= b.end));
export const hhmmFromLocal = (d: Date) =>
`${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
export const toDateOnly = (s: string): Date => {
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) {
const y = Number(s.slice(0,4));
const m = Number(s.slice(5,7)) - 1;
const d = Number(s.slice(8,10));
return new Date(y, m, d, 0, 0, 0, 0);
}
const dt = new Date(s);
if (Number.isNaN(dt.getTime())) throw new BadRequestException(`Invalid date: ${s}`);
return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), 0,0,0,0);
};
// export const toStringFromDate = (d: Date) =>
// `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
export const toISOtoDateOnly = (iso: string): Date => {
const date = new Date(iso);
if (Number.isNaN(date.getTime())) {
throw new BadRequestException(`Invalid date: ${iso}`);
}
date.setHours(0, 0, 0, 0);
return date;
};
export const toISODateKey = (date: Date): string => date.toISOString().slice(0, 10);
export const normalizeDates = (dates: string[]): string[] =>
Array.from(new Set(dates.map((iso) => toISODateKey(toISOtoDateOnly(iso)))));

View File

@ -1,3 +0,0 @@
import { Weekday } from "@prisma/client";
export const WEEKDAY: Weekday[] = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];