reafactor(EsLint): Eslint corrections
This commit is contained in:
parent
368c5b1a2a
commit
c427cc7718
|
|
@ -26,6 +26,7 @@ export default tseslint.config(
|
|||
},
|
||||
{
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn'
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ import { CustomerSupportModule } from 'src/customer-support/customer-support.mod
|
|||
ChatbotModule,
|
||||
CustomerSupportModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
controllers: [
|
||||
AppController
|
||||
],
|
||||
providers: [
|
||||
AppService,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@ import { TicketController } from "src/customer-support/tickets/ticket.controller
|
|||
import { TicketService } from "src/customer-support/tickets/ticket.service";
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [TicketController],
|
||||
providers: [TicketService],
|
||||
exports: [],
|
||||
controllers: [
|
||||
TicketController
|
||||
],
|
||||
providers: [
|
||||
TicketService
|
||||
],
|
||||
|
||||
}) export class CustomerSupportModule { }
|
||||
|
|
@ -3,7 +3,11 @@ import { TicketController } from "src/customer-support/tickets/ticket.controller
|
|||
import { TicketService } from "src/customer-support/tickets/ticket.service";
|
||||
|
||||
@Module({
|
||||
imports: [TicketService],
|
||||
providers: [TicketController]
|
||||
imports: [
|
||||
TicketService
|
||||
],
|
||||
providers: [
|
||||
TicketController
|
||||
]
|
||||
})
|
||||
export class TicketModule { }
|
||||
15
src/main.ts
15
src/main.ts
|
|
@ -1,8 +1,3 @@
|
|||
import 'reflect-metadata';
|
||||
// import * as nodeCrypto from 'crypto';
|
||||
// if (!(globalThis as any).crypto) {
|
||||
// (globalThis as any).crypto = nodeCrypto;
|
||||
// }
|
||||
import { NestFactory, Reflector } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { ModulesGuard } from './common/guards/modules.guard';
|
||||
|
|
@ -21,7 +16,7 @@ async function bootstrap() {
|
|||
const reflector = app.get(Reflector);
|
||||
|
||||
app.useGlobalGuards(
|
||||
new ModulesGuard(reflector), //deny-by-default and Module-based Access Control
|
||||
new ModulesGuard(reflector),
|
||||
);
|
||||
|
||||
// Authentication and session
|
||||
|
|
@ -52,13 +47,5 @@ async function bootstrap() {
|
|||
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
|
||||
|
||||
// migration function calls
|
||||
// await initializePaidTimeOff();
|
||||
// await initializePreferences();
|
||||
// await extractOldTimesheets();
|
||||
// await extractOldShifts();
|
||||
// await extractOldExpenses();
|
||||
// await initSupervisor();
|
||||
}
|
||||
bootstrap();
|
||||
|
|
|
|||
3
src/time-and-attendance/bank-codes/bank-codes.dto.ts
Normal file
3
src/time-and-attendance/bank-codes/bank-codes.dto.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export class BankCodeDto {
|
||||
type:string;
|
||||
}
|
||||
|
|
@ -6,7 +6,8 @@ import { applyHolidayRequalifications, applyOvertimeRequalifications, computeWee
|
|||
import { OvertimeService } from "src/time-and-attendance/domains/services/overtime.service";
|
||||
import { HolidayService } from "src/time-and-attendance/domains/services/holiday.service";
|
||||
import { select_csv_expense_lines, select_csv_shift_lines } from "src/time-and-attendance/utils/selects.utils";
|
||||
import { BillableShiftType } from "src/time-and-attendance/shifts/shift.types";
|
||||
import { BillableShiftType } from "src/time-and-attendance/shifts/shift.dto";
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class CsvExportService {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import { PaidTimeOffController } from "src/time-and-attendance/paid-time-off/pai
|
|||
import { PaidTimeOffBankHoursService } from "src/time-and-attendance/paid-time-off/paid-time-off.service";
|
||||
|
||||
@Module({
|
||||
controllers: [PaidTimeOffController],
|
||||
controllers: [
|
||||
PaidTimeOffController
|
||||
],
|
||||
providers: [
|
||||
PrismaPostgresService,
|
||||
EmailToIdResolver,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ export class PaidTimeOffBankHoursService {
|
|||
private readonly emailResolver: EmailToIdResolver,
|
||||
) { }
|
||||
|
||||
getPaidTimeOffTotalsWithEmployeeEmail = async (email: string): Promise<Result<Partial<PaidTimeOffDto>, string>> => {
|
||||
getPaidTimeOffTotalsWithEmployeeEmail = async (
|
||||
email: string
|
||||
): Promise<Result<Partial<PaidTimeOffDto>, string>> => {
|
||||
const employee_info = await this.emailResolver.findIdByEmail(email);
|
||||
|
||||
|
||||
|
|
@ -112,6 +114,7 @@ export class PaidTimeOffBankHoursService {
|
|||
});
|
||||
return { success: true, data: true };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { success: false, error: 'PAID_TIME_OFF_NOT_FOUND' };
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,25 +2,13 @@ import { Type } from "class-transformer";
|
|||
import { IsArray, IsBoolean, IsEmail, IsInt, ValidateNested } from "class-validator";
|
||||
|
||||
export class BulkCrewApprovalItemDto {
|
||||
@IsInt()
|
||||
pay_year: number;
|
||||
|
||||
@IsInt()
|
||||
period_no: number;
|
||||
|
||||
@IsEmail()
|
||||
employee_email!: string;
|
||||
|
||||
@IsBoolean()
|
||||
approve: boolean;
|
||||
@IsInt() pay_year: number;
|
||||
@IsInt() period_no: number;
|
||||
@IsEmail() employee_email: string;
|
||||
@IsBoolean() approve: boolean;
|
||||
}
|
||||
|
||||
export class BulkCrewApprovalDto {
|
||||
@IsBoolean()
|
||||
include_subtree: boolean = false;
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({each: true})
|
||||
@Type(()=> BulkCrewApprovalItemDto)
|
||||
items: BulkCrewApprovalItemDto[]
|
||||
@IsBoolean() include_subtree: boolean = false;
|
||||
@IsArray() @ValidateNested({ each: true }) @Type(() => BulkCrewApprovalItemDto) items: BulkCrewApprovalItemDto[]
|
||||
}
|
||||
|
|
@ -26,7 +26,9 @@ export class PayPeriodsController {
|
|||
|
||||
@Get("date/:date")
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||
async findByDate(@Param("date") date: string) {
|
||||
async findByDate(
|
||||
@Param("date") date: string
|
||||
) {
|
||||
return this.queryService.findByDate(date);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
import { PayPeriods } from "prisma/postgres/generated/prisma/client/postgres/client";
|
||||
import { PayPeriodDto } from "src/time-and-attendance/pay-period/dtos/overview-pay-period.dto";
|
||||
|
||||
const toDateString = (date: Date) => date.toISOString().slice(0, 10); // "YYYY-MM-DD"
|
||||
const toDateString = (
|
||||
date: Date
|
||||
) => date.toISOString().slice(0, 10); // "YYYY-MM-DD"
|
||||
|
||||
export function mapPayPeriodToDto(row: PayPeriods): PayPeriodDto {
|
||||
export function mapPayPeriodToDto(
|
||||
row: PayPeriods
|
||||
): PayPeriodDto {
|
||||
const start = toDateString(row.period_start);
|
||||
const end = toDateString(row.period_end);
|
||||
const pay = toDateString(row.payday);
|
||||
|
|
@ -12,12 +16,13 @@ export function mapPayPeriodToDto(row: PayPeriods): PayPeriodDto {
|
|||
period_start: toDateString(row.period_start),
|
||||
period_end: toDateString(row.period_end),
|
||||
payday:pay,
|
||||
// pay_year: new Date(pay).getFullYear(),
|
||||
pay_year: row.pay_year,
|
||||
label: `${start}.${end}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function mapMany(rows: PayPeriods[]): PayPeriodDto[] {
|
||||
export function mapMany(
|
||||
rows: PayPeriods[]
|
||||
): PayPeriodDto[] {
|
||||
return rows.map(mapPayPeriodToDto);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,12 @@ import { GetOverviewService } from "src/time-and-attendance/pay-period/services/
|
|||
import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service";
|
||||
|
||||
@Module({
|
||||
imports:[TimesheetsModule],
|
||||
controllers: [PayPeriodsController],
|
||||
imports: [
|
||||
TimesheetsModule
|
||||
],
|
||||
controllers: [
|
||||
PayPeriodsController
|
||||
],
|
||||
providers: [
|
||||
PayPeriodsQueryService,
|
||||
PayPeriodsCommandService,
|
||||
|
|
@ -17,6 +21,4 @@ import { PayPeriodEventService } from "src/time-and-attendance/pay-period/servic
|
|||
PayPeriodEventService,
|
||||
EmailToIdResolver,
|
||||
],
|
||||
})
|
||||
|
||||
export class PayperiodsModule {}
|
||||
}) export class PayperiodsModule { }
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ export class GetOverviewService {
|
|||
private readonly prisma: PrismaPostgresService,
|
||||
) { }
|
||||
|
||||
async getOverviewByYearPeriod(pay_year: number, period_no: number): Promise<Result<PayPeriodOverviewDto, string>> {
|
||||
async getOverviewByYearPeriod(
|
||||
pay_year: number,
|
||||
period_no: number
|
||||
): Promise<Result<PayPeriodOverviewDto, string>> {
|
||||
const period = computePeriod(pay_year, period_no);
|
||||
const overview = await this.buildOverview({
|
||||
period_start: period.period_start,
|
||||
|
|
@ -26,7 +29,9 @@ export class GetOverviewService {
|
|||
return { success: true, data: overview.data }
|
||||
}
|
||||
|
||||
async buildOverview(overview: Overview): Promise<Result<PayPeriodOverviewDto, string>> {
|
||||
async buildOverview(
|
||||
overview: Overview
|
||||
): Promise<Result<PayPeriodOverviewDto, string>> {
|
||||
const employee_overviews = await this.prisma.employees.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
|
|
@ -103,7 +108,12 @@ export class GetOverviewService {
|
|||
}
|
||||
}
|
||||
|
||||
const ensure = (id: number, first_name: string, last_name: string, email: string) => {
|
||||
const ensure = (
|
||||
id: number,
|
||||
first_name: string,
|
||||
last_name: string,
|
||||
email: string
|
||||
) => {
|
||||
if (!by_employee.has(id)) {
|
||||
by_employee.set(id, this.createEmployeeSeeds(email, first_name, last_name));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,11 @@ export class PayPeriodsCommandService {
|
|||
) { }
|
||||
|
||||
//function to approve pay-periods according to selected crew members
|
||||
async bulkApproveEmployee(email: string, timesheet_ids: number[], is_approved: boolean): Promise<Result<{ shifts: number, expenses: number }, string>> {
|
||||
async bulkApproveEmployee(
|
||||
email: string,
|
||||
timesheet_ids: number[],
|
||||
is_approved: boolean
|
||||
): Promise<Result<{ shifts: number, expenses: number }, string>> {
|
||||
let shifts: Prisma.BatchPayload;
|
||||
let expenses: Prisma.BatchPayload;
|
||||
|
||||
|
|
@ -56,7 +60,8 @@ export class PayPeriodsCommandService {
|
|||
is_approved: is_approved,
|
||||
}
|
||||
})
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { success: false, error: 'UNKNOWN_ERROR_VALIDATING' }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ export class PayPeriodsQueryService {
|
|||
constructor(
|
||||
private readonly prisma: PrismaPostgresService) { }
|
||||
|
||||
async findOneByYearPeriod(pay_year: number, period_no: number): Promise<Result<PayPeriodDto, string>> {
|
||||
async findOneByYearPeriod(
|
||||
pay_year: number,
|
||||
period_no: number
|
||||
): Promise<Result<PayPeriodDto, string>> {
|
||||
const row = await this.prisma.payPeriods.findFirst({
|
||||
where: { pay_year, pay_period_no: period_no },
|
||||
});
|
||||
|
|
@ -32,7 +35,9 @@ export class PayPeriodsQueryService {
|
|||
}
|
||||
|
||||
//function to cherry pick a Date to find a period
|
||||
async findByDate(date: string): Promise<Result<PayPeriodDto, string>> {
|
||||
async findByDate(
|
||||
date: string
|
||||
): Promise<Result<PayPeriodDto, string>> {
|
||||
const dt = new Date(date);
|
||||
const row = await this.prisma.payPeriods.findFirst({
|
||||
where: { period_start: { lte: dt }, period_end: { gte: dt } },
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import { Controller, Param, Body, Get, Post, Delete, Patch } from "@nestjs/common";
|
||||
|
||||
import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-create.service";
|
||||
import { SchedulePresetUpdateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-update.service";
|
||||
import { SchedulePresetDeleteService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-delete.service";
|
||||
import { SchedulePresetsGetService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-get.service";
|
||||
import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto";
|
||||
|
||||
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||
import { Modules as ModulesEnum } from "prisma/postgres/generated/prisma/client/postgres/client";
|
||||
import { Access } from "src/common/decorators/module-access.decorators";
|
||||
|
|
@ -29,21 +27,25 @@ export class SchedulePresetsController {
|
|||
|
||||
@Post('create')
|
||||
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||
async createPreset(@Body() dto: SchedulePresetsDto) {
|
||||
async createPreset(
|
||||
@Body() dto: SchedulePresetsDto
|
||||
) {
|
||||
return await this.createService.createPreset(dto);
|
||||
}
|
||||
|
||||
@Patch('update')
|
||||
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||
async updatePreset(
|
||||
@Body() dto: SchedulePresetsDto) {
|
||||
@Body() dto: SchedulePresetsDto
|
||||
) {
|
||||
return await this.updateService.updatePreset(dto);
|
||||
}
|
||||
|
||||
@Delete('delete/:id')
|
||||
@ModuleAccessAllowed(ModulesEnum.employee_management)
|
||||
async deletePreset(
|
||||
@Param('id') id: number) {
|
||||
@Param('id') id: number
|
||||
) {
|
||||
return await this.deleteService.deletePreset(id);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ export class SchedulePresetShiftsDto {
|
|||
@IsOptional() @IsBoolean() is_remote?: boolean;
|
||||
}
|
||||
|
||||
export const WEEKDAY_MAP: Record<Weekday, number> = {
|
||||
SUN: 0,
|
||||
MON: 1,
|
||||
TUE: 2,
|
||||
WED: 3,
|
||||
THU: 4,
|
||||
FRI: 5,
|
||||
SAT: 6,
|
||||
};
|
||||
export const WEEKDAY_MAP: Weekday[] = [
|
||||
'SUN',
|
||||
'MON',
|
||||
'TUE',
|
||||
'WED',
|
||||
'THU',
|
||||
'FRI',
|
||||
'SAT'
|
||||
]
|
||||
|
|
@ -18,7 +18,9 @@ import { PayPeriodEventService } from "../pay-period/services/pay-period-event.s
|
|||
|
||||
|
||||
@Module({
|
||||
controllers: [SchedulePresetsController],
|
||||
controllers: [
|
||||
SchedulePresetsController
|
||||
],
|
||||
providers: [
|
||||
SchedulePresetsGetService,
|
||||
SchedulePresetsCreateService,
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
|
||||
|
||||
import { sevenDaysFrom, toDateFromString, toStringFromDate, toStringFromHHmm } from "src/common/utils/date-utils";
|
||||
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
||||
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
|
||||
import { Result } from "src/common/errors/result-error.factory";
|
||||
|
||||
import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service";
|
||||
import { timesheet_select } from "src/time-and-attendance/utils/selects.utils";
|
||||
import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto";
|
||||
import { WEEKDAY_MAP } from "src/time-and-attendance/schedule-presets/schedule-presets.dto";
|
||||
import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service";
|
||||
import { $Enums, SchedulePresetShifts } from "prisma/postgres/generated/prisma/client/postgres/client";
|
||||
import { SchedulePresetShifts } from "prisma/postgres/generated/prisma/client/postgres/client";
|
||||
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -24,7 +22,11 @@ export class SchedulePresetsApplyService {
|
|||
private readonly payPeriodEventService: PayPeriodEventService,
|
||||
) { }
|
||||
|
||||
async applyPresetToTimesheet(email: string, timesheet_id: number, employee_email?: string): Promise<Result<boolean, string>> {
|
||||
async applyPresetToTimesheet(
|
||||
email: string,
|
||||
timesheet_id: number,
|
||||
employee_email?: string
|
||||
): Promise<Result<boolean, string>> {
|
||||
const user_email = employee_email ?? email;
|
||||
const employee_id = await this.emailResolver.findIdByEmail(user_email);
|
||||
if (!employee_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' };
|
||||
|
|
@ -63,15 +65,15 @@ export class SchedulePresetsApplyService {
|
|||
if (timesheet.is_approved) return { success: false, error: 'INVALID_TIMESHEET' };
|
||||
if (timesheet.shift.length > 0) return { success: false, error: 'INVALID_TIMESHEET' };
|
||||
|
||||
const dated_map = await sevenDaysFrom(timesheet.start_date);
|
||||
const dated_map = sevenDaysFrom(timesheet.start_date);
|
||||
|
||||
let created_shifts: ShiftDto[] = [];
|
||||
const created_shifts: ShiftDto[] = [];
|
||||
|
||||
for (const preset_shift of default_preset_shifts) {
|
||||
const date = dated_map.find(date => date.getUTCDay() === WEEKDAY_MAP[preset_shift.week_day])
|
||||
if (!date) return { success: false, error: 'INVALID_PRESET_DATE' };
|
||||
|
||||
const shift = await this.createShiftFromPreset(preset_shift, date!, timesheet.id)
|
||||
const shift = await this.createShiftFromPreset(preset_shift, date, timesheet.id)
|
||||
if (!shift.success) return { success: false, error: shift.error };
|
||||
|
||||
created_shifts.push(shift.data);
|
||||
|
|
@ -99,7 +101,7 @@ export class SchedulePresetsApplyService {
|
|||
const user_email = employee_email ?? email;
|
||||
const employee_id = await this.emailResolver.findIdByEmail(user_email);
|
||||
if (!employee_id.success) return { success: false, error: 'EMPLOYEE_NOT_FOUND' };
|
||||
const week_day = Object.keys(WEEKDAY_MAP)[week_day_index];
|
||||
const week_day = WEEKDAY_MAP[week_day_index];
|
||||
|
||||
const preset_shift = await this.prisma.employees.findFirst({
|
||||
where: { id: employee_id.data, },
|
||||
|
|
@ -108,7 +110,7 @@ export class SchedulePresetsApplyService {
|
|||
select: {
|
||||
id: true,
|
||||
shifts: {
|
||||
where: { week_day: $Enums.Weekday[week_day] },
|
||||
where: { week_day },
|
||||
select: {
|
||||
bank_code_id: true,
|
||||
start_time: true,
|
||||
|
|
@ -146,7 +148,11 @@ export class SchedulePresetsApplyService {
|
|||
return { success: true, data: true };
|
||||
}
|
||||
|
||||
private createShiftFromPreset = async (preset: Partial<SchedulePresetShifts>, date: Date, timesheet_id: number): Promise<Result<ShiftDto, string>> => {
|
||||
private createShiftFromPreset = async (
|
||||
preset: Partial<SchedulePresetShifts>,
|
||||
date: Date,
|
||||
timesheet_id: number
|
||||
): Promise<Result<ShiftDto, string>> => {
|
||||
const type = await this.typeResolver.findTypeByBankCodeId(preset.bank_code_id!);
|
||||
if (!type.success) return { success: false, error: 'INVALID_PRESET_SHIFT' };
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
|
||||
|
||||
import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto";
|
||||
|
||||
import { overlaps, toDateFromHHmm } from "src/common/utils/date-utils";
|
||||
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
||||
import { Result } from "src/common/errors/result-error.factory";
|
||||
|
|
@ -14,10 +11,10 @@ export class SchedulePresetsCreateService {
|
|||
private readonly prisma: PrismaPostgresService,
|
||||
private readonly typeResolver: BankCodesResolver,
|
||||
) { }
|
||||
//_________________________________________________________________
|
||||
// CREATE
|
||||
//_________________________________________________________________
|
||||
async createPreset(dto: SchedulePresetsDto): Promise<Result<boolean, string>> {
|
||||
|
||||
async createPreset(
|
||||
dto: SchedulePresetsDto
|
||||
): Promise<Result<boolean, string>> {
|
||||
try {
|
||||
//validate new unique name
|
||||
const existing = await this.prisma.schedulePresets.findFirst({
|
||||
|
|
@ -80,6 +77,7 @@ export class SchedulePresetsCreateService {
|
|||
});
|
||||
return { success: true, data: true }
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { success: false, error: 'INVALID_SCHEDULE_PRESET' }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@ import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
|
|||
export class SchedulePresetDeleteService {
|
||||
constructor(private readonly prisma: PrismaPostgresService) { }
|
||||
|
||||
//_________________________________________________________________
|
||||
// DELETE
|
||||
//_________________________________________________________________
|
||||
async deletePreset(preset_id: number): Promise<Result<boolean, string>> {
|
||||
async deletePreset(
|
||||
preset_id: number
|
||||
): Promise<Result<boolean, string>> {
|
||||
|
||||
const preset = await this.prisma.schedulePresets.findUnique({
|
||||
where: { id: preset_id },
|
||||
|
|
@ -17,7 +16,7 @@ export class SchedulePresetDeleteService {
|
|||
});
|
||||
if (!preset) return { success: false, error: `SCHEDULE_PRESET_NOT_FOUND` };
|
||||
|
||||
const updated_employees = await this.prisma.employees.updateMany({
|
||||
await this.prisma.employees.updateMany({
|
||||
where: { schedule_preset_id: preset_id },
|
||||
data: {
|
||||
schedule_preset_id: 0,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
|
||||
|
||||
import { SchedulePresetsDto, SchedulePresetShiftsDto } from "../schedule-presets.dto";
|
||||
|
||||
import { Result } from "src/common/errors/result-error.factory";
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -40,6 +37,7 @@ export class SchedulePresetsGetService {
|
|||
|
||||
return { success: true, data: response };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { success: false, error: `SCHEDULE_PRESET_NOT_FOUND` };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
|
||||
|
||||
import { SchedulePresetsDto } from "src/time-and-attendance/schedule-presets/schedule-presets.dto";
|
||||
|
||||
import { overlaps, toDateFromHHmm } from "src/common/utils/date-utils";
|
||||
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
||||
import { Result } from "src/common/errors/result-error.factory";
|
||||
|
|
@ -14,10 +12,9 @@ export class SchedulePresetUpdateService {
|
|||
private readonly typeResolver: BankCodesResolver,
|
||||
) { }
|
||||
|
||||
//_________________________________________________________________
|
||||
// UPDATE
|
||||
//_________________________________________________________________
|
||||
async updatePreset(dto: SchedulePresetsDto): Promise<Result<boolean, string>> {
|
||||
async updatePreset(
|
||||
dto: SchedulePresetsDto
|
||||
): Promise<Result<boolean, string>> {
|
||||
const existing = await this.prisma.schedulePresets.findFirst({
|
||||
where: { id: dto.id },
|
||||
select: {
|
||||
|
|
|
|||
|
|
@ -25,10 +25,11 @@ export class ShiftsCreateService {
|
|||
private readonly payPeriodEventService: PayPeriodEventService,
|
||||
) { }
|
||||
|
||||
//_________________________________________________________________
|
||||
// CREATE WRAPPER FUNCTION FOR ONE OR MANY INPUT
|
||||
//_________________________________________________________________
|
||||
async createOneOrManyShifts(email: string, shifts: ShiftDto[], is_from_timesheet: boolean = true): Promise<Result<boolean, string>> {
|
||||
async createOneOrManyShifts(
|
||||
email: string,
|
||||
shifts: ShiftDto[],
|
||||
is_from_timesheet: boolean = true
|
||||
): Promise<Result<boolean, string>> {
|
||||
try {
|
||||
//verify if array is empty or not
|
||||
if (!Array.isArray(shifts) || shifts.length === 0) return { success: false, error: 'NO_DATA_RECEIVED' };
|
||||
|
|
@ -71,13 +72,16 @@ export class ShiftsCreateService {
|
|||
// returns array of created shifts
|
||||
return { success: true, data: true }
|
||||
} catch (error) {
|
||||
return { success: false, error }
|
||||
return { success: false, error: `${error}` }
|
||||
}
|
||||
}
|
||||
//_________________________________________________________________
|
||||
// CREATE
|
||||
//_________________________________________________________________
|
||||
async createShift(employee_id: number, dto: ShiftDto): Promise<Result<ShiftDto, string>> {
|
||||
async createShift(
|
||||
employee_id: number,
|
||||
dto: ShiftDto
|
||||
): Promise<Result<ShiftDto, string>> {
|
||||
try {
|
||||
//transform string format to date and HHmm
|
||||
const normed_shift = await this.normalizeShiftDto(dto);
|
||||
|
|
@ -99,9 +103,9 @@ export class ShiftsCreateService {
|
|||
select: { id: true, date: true, start_time: true, end_time: true },
|
||||
});
|
||||
for (const existing of existing_shifts) {
|
||||
const existing_start = await toDateFromString(existing.start_time);
|
||||
const existing_end = await toDateFromString(existing.end_time);
|
||||
const existing_date = await toDateFromString(existing.date);
|
||||
const existing_start = toDateFromString(existing.start_time);
|
||||
const existing_end = toDateFromString(existing.end_time);
|
||||
const existing_date = toDateFromString(existing.date);
|
||||
|
||||
const has_overlap = overlaps(
|
||||
{ start: normed_shift.data.start_time, end: normed_shift.data.end_time, date: normed_shift.data.date },
|
||||
|
|
@ -183,13 +187,11 @@ export class ShiftsCreateService {
|
|||
}
|
||||
return { success: true, data: shift };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { success: false, error: `INVALID_SHIFT` };
|
||||
}
|
||||
}
|
||||
|
||||
//_________________________________________________________________
|
||||
// LOCAL HELPERS
|
||||
//_________________________________________________________________
|
||||
//converts all string hours and date to Date and HHmm formats
|
||||
private normalizeShiftDto = async (dto: ShiftDto): Promise<Result<Normalized, string>> => {
|
||||
const bank_code_id = await this.typeResolver.findBankCodeIDByType(dto.type);
|
||||
|
|
@ -200,6 +202,14 @@ export class ShiftsCreateService {
|
|||
const start_time = toDateFromHHmm(dto.start_time);
|
||||
const end_time = toDateFromHHmm(dto.end_time);
|
||||
|
||||
return { success: true, data: { date, start_time, end_time, bank_code_id: bank_code_id.data } };
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
date,
|
||||
start_time,
|
||||
end_time,
|
||||
bank_code_id: bank_code_id.data
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,12 @@ export class ShiftsDeleteService {
|
|||
private readonly emailResolver: EmailToIdResolver,
|
||||
private readonly payPeriodEventService: PayPeriodEventService,
|
||||
) { }
|
||||
//_________________________________________________________________
|
||||
// DELETE
|
||||
//_________________________________________________________________
|
||||
//finds shifts using shit_ids
|
||||
//ajust paid-time-off banks
|
||||
//blocs deletion if approved
|
||||
async deleteShift(shift_id: number, email: string, is_from_timesheet: boolean = true): Promise<Result<number, string>> {
|
||||
|
||||
async deleteShift(
|
||||
shift_id: number,
|
||||
email: string,
|
||||
is_from_timesheet: boolean = true
|
||||
): Promise<Result<number, string>> {
|
||||
try {
|
||||
|
||||
//verify if email is valid or not
|
||||
|
|
@ -80,6 +79,7 @@ export class ShiftsDeleteService {
|
|||
return { success: true, data: shift.id };
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { success: false, error: `SHIFT_NOT_FOUND` };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import { toDateFromString, toStringFromHHmm, toStringFromDate, toDateFromHHmm, overlaps, computeHours } from "src/common/utils/date-utils";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
|
||||
|
||||
import { EmployeeTimesheetResolver } from "src/common/mappers/timesheet.mapper";
|
||||
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
||||
import { Result } from "src/common/errors/result-error.factory";
|
||||
|
||||
import { shift_select } from "src/time-and-attendance/utils/selects.utils";
|
||||
import { Normalized } from "src/time-and-attendance/utils/type.utils";
|
||||
import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto";
|
||||
|
|
@ -25,14 +23,18 @@ export class ShiftsUpdateService {
|
|||
private readonly payPeriodEventService: PayPeriodEventService,
|
||||
) { }
|
||||
|
||||
async updateOneOrManyShifts(shifts: ShiftDto[], email: string, is_from_timesheet: boolean = true): Promise<Result<boolean, string>> {
|
||||
async updateOneOrManyShifts(
|
||||
shifts: ShiftDto[],
|
||||
email: string,
|
||||
is_from_timesheet: boolean = true
|
||||
): Promise<Result<boolean, string>> {
|
||||
try {
|
||||
//verify if array is empty or not
|
||||
if (!Array.isArray(shifts) || shifts.length === 0) return { success: false, error: 'No data received' };
|
||||
|
||||
//check for overlap inside dto objects
|
||||
const overlap_check = await this.overlapChecker(shifts);
|
||||
if (!overlap_check.success) return overlap_check;
|
||||
const overlap_check = this.overlapChecker(shifts);
|
||||
if (!overlap_check.success) return { success: false, error: `${overlap_check.error}` };
|
||||
|
||||
//calls the update functions and await the return of successfull result or not
|
||||
const results = await Promise.allSettled(shifts.map(shift => this.updateShift(shift, email)));
|
||||
|
|
@ -68,12 +70,10 @@ export class ShiftsUpdateService {
|
|||
// returns array of updated shifts
|
||||
return { success: true, data: true }
|
||||
} catch (error) {
|
||||
return { success: false, error }
|
||||
return { success: false, error: `${error}` }
|
||||
}
|
||||
}
|
||||
//_________________________________________________________________
|
||||
// UPDATE
|
||||
//_________________________________________________________________
|
||||
|
||||
async updateShift(dto: ShiftDto, email: string): Promise<Result<ShiftDto, string>> {
|
||||
try {
|
||||
const timesheet = await this.timesheetResolver.findTimesheetIdByEmail(email, toDateFromString(dto.date));
|
||||
|
|
@ -164,6 +164,7 @@ export class ShiftsUpdateService {
|
|||
return { success: true, data: shift };
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { success: false, error: `INVALID_SHIFT` };
|
||||
}
|
||||
}
|
||||
|
|
@ -185,7 +186,7 @@ export class ShiftsUpdateService {
|
|||
};
|
||||
}
|
||||
|
||||
private overlapChecker = async (shifts: ShiftDto[]): Promise<Result<void, string>> => {
|
||||
private overlapChecker = (shifts: ShiftDto[]) => {
|
||||
for (let i = 0; i < shifts.length; i++) {
|
||||
for (let j = i + 1; j < shifts.length; j++) {
|
||||
const shift_a = shifts[i];
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import { Body, Controller, Delete, Param, Patch, Post } from "@nestjs/common";
|
||||
import { Modules as ModulesEnum } from "prisma/postgres/generated/prisma/client/postgres/client";
|
||||
|
||||
import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto";
|
||||
import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service";
|
||||
import { ShiftsUpdateService } from "src/time-and-attendance/shifts/services/shifts-update.service";
|
||||
import { ShiftsDeleteService } from "src/time-and-attendance/shifts/services/shifts-delete.service";
|
||||
|
||||
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
|
||||
import { Result } from "src/common/errors/result-error.factory";
|
||||
import { Access } from "src/common/decorators/module-access.decorators";
|
||||
|
|
@ -20,37 +18,55 @@ export class ShiftController {
|
|||
|
||||
@Post('create')
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||
createBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<boolean, string>> {
|
||||
createBatch(
|
||||
@Access('email') email: string,
|
||||
@Body() dtos: ShiftDto[]
|
||||
): Promise<Result<boolean, string>> {
|
||||
return this.create_service.createOneOrManyShifts(email, dtos);
|
||||
}
|
||||
|
||||
@Post('create/:email')
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||
createBatchByTimesheetsApproval(@Param('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<boolean, string>> {
|
||||
createBatchByTimesheetsApproval(
|
||||
@Param('email') email: string,
|
||||
@Body() dtos: ShiftDto[]
|
||||
): Promise<Result<boolean, string>> {
|
||||
return this.create_service.createOneOrManyShifts(email, dtos, false);
|
||||
}
|
||||
|
||||
@Patch('update')
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||
updateBatch(@Access('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<boolean, string>> {
|
||||
updateBatch(
|
||||
@Access('email') email: string,
|
||||
@Body() dtos: ShiftDto[]
|
||||
): Promise<Result<boolean, string>> {
|
||||
return this.update_service.updateOneOrManyShifts(dtos, email);
|
||||
}
|
||||
|
||||
@Patch('update/:email')
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||
updateBatchByTimesheetApproval(@Param('email') email: string, @Body() dtos: ShiftDto[]): Promise<Result<boolean, string>> {
|
||||
updateBatchByTimesheetApproval(
|
||||
@Param('email') email: string,
|
||||
@Body() dtos: ShiftDto[]
|
||||
): Promise<Result<boolean, string>> {
|
||||
return this.update_service.updateOneOrManyShifts(dtos, email, false);
|
||||
}
|
||||
|
||||
@Delete(':shift_id')
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||
remove(@Access('email') email: string, @Param('shift_id') shift_id: number): Promise<Result<number, string>> {
|
||||
remove(
|
||||
@Access('email') email: string,
|
||||
@Param('shift_id') shift_id: number
|
||||
): Promise<Result<number, string>> {
|
||||
return this.delete_service.deleteShift(shift_id, email);
|
||||
}
|
||||
|
||||
@Delete(':shift_id/:email')
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets)
|
||||
removeByTimesheetApproval(@Param('shift_id') shift_id: number, @Param('email') email: string): Promise<Result<number, string>> {
|
||||
removeByTimesheetApproval(
|
||||
@Param('shift_id') shift_id: number,
|
||||
@Param('email') email: string
|
||||
): Promise<Result<number, string>> {
|
||||
return this.delete_service.deleteShift(shift_id, email, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validat
|
|||
|
||||
export class ShiftDto {
|
||||
@IsInt() @IsOptional() id?: number;
|
||||
@IsInt() timesheet_id!: number;
|
||||
@IsString() type!: string;
|
||||
@IsString() date!: string;
|
||||
@IsString() start_time!: string;
|
||||
@IsString() end_time!: string;
|
||||
@IsBoolean() is_approved!: boolean;
|
||||
@IsBoolean() is_remote!: boolean;
|
||||
@IsInt() timesheet_id: number;
|
||||
@IsString() type: string;
|
||||
@IsString() date: string;
|
||||
@IsString() start_time: string;
|
||||
@IsString() end_time: string;
|
||||
@IsBoolean() is_approved: boolean;
|
||||
@IsBoolean() is_remote: boolean;
|
||||
@IsOptional() @IsString() @MaxLength(280) comment?: string;
|
||||
}
|
||||
|
||||
export type BillableShiftType = 'REGULAR' | 'EVENING' | 'EMERGENCY' | 'VACATION' | 'HOLIDAY' | 'SICK' | 'OVERTIME';
|
||||
|
|
@ -1 +0,0 @@
|
|||
export type BillableShiftType = 'REGULAR' | 'EVENING' | 'EMERGENCY' | 'VACATION' | 'HOLIDAY' | 'SICK' | 'OVERTIME';
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { ShiftController } from 'src/time-and-attendance/shifts/shift.controller';
|
||||
import { ShiftsCreateService } from 'src/time-and-attendance/shifts/services/shifts-create.service';
|
||||
import { ShiftsDeleteService } from 'src/time-and-attendance/shifts/services/shifts-delete.service';
|
||||
|
|
@ -12,8 +11,12 @@ import { PaidTimeOffBankHoursService } from 'src/time-and-attendance/paid-time-o
|
|||
import { PayPeriodEventService } from 'src/time-and-attendance/pay-period/services/pay-period-event.service';
|
||||
|
||||
@Module({
|
||||
imports: [PaidTimeOffModule],
|
||||
controllers: [ShiftController],
|
||||
imports: [
|
||||
PaidTimeOffModule
|
||||
],
|
||||
controllers: [
|
||||
ShiftController
|
||||
],
|
||||
providers: [
|
||||
ShiftsCreateService,
|
||||
ShiftsUpdateService,
|
||||
|
|
|
|||
|
|
@ -5,38 +5,31 @@ import { BankedHoursService } from "src/time-and-attendance/domains/services/ban
|
|||
import { PaidTimeOffModule } from "src/time-and-attendance/paid-time-off/paid-time-off.module";
|
||||
import { PaidTimeOffController } from "src/time-and-attendance/paid-time-off/paid-time-off.controller";
|
||||
import { PaidTimeOffBankHoursService } from "src/time-and-attendance/paid-time-off/paid-time-off.service";
|
||||
|
||||
import { ExpenseController } from "src/time-and-attendance/expenses/expense.controller";
|
||||
import { ExpenseCreateService } from "src/time-and-attendance/expenses/services/expense-create.service";
|
||||
import { ExpenseUpdateService } from "src/time-and-attendance/expenses/services/expense-update.service";
|
||||
import { ExpenseDeleteService } from "src/time-and-attendance/expenses/services/expense-delete.service";
|
||||
import { ExpensesModule } from "src/time-and-attendance/expenses/expenses.module";
|
||||
|
||||
import { TimesheetController } from "src/time-and-attendance/timesheets/timesheet.controller";
|
||||
import { TimesheetApprovalService } from "src/time-and-attendance/timesheets/services/timesheet-approval.service";
|
||||
import { GetTimesheetsOverviewService } from "src/time-and-attendance/timesheets/services/timesheet-employee-overview.service";
|
||||
import { TimesheetsModule } from "src/time-and-attendance/timesheets/timesheets.module";
|
||||
|
||||
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
||||
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
|
||||
import { EmployeeTimesheetResolver } from "src/common/mappers/timesheet.mapper";
|
||||
|
||||
import { PayperiodsModule } from "src/time-and-attendance/pay-period/pay-periods.module";
|
||||
import { PayPeriodsController } from "src/time-and-attendance/pay-period/pay-periods.controller";
|
||||
import { GetOverviewService } from "src/time-and-attendance/pay-period/services/pay-periods-build-overview.service";
|
||||
import { PayPeriodsQueryService } from "src/time-and-attendance/pay-period/services/pay-periods-query.service";
|
||||
import { PayPeriodsCommandService } from "src/time-and-attendance/pay-period/services/pay-periods-command.service";
|
||||
|
||||
import { CsvExportModule } from "src/time-and-attendance/exports/csv-exports.module";
|
||||
import { CsvExportService } from "src/time-and-attendance/exports/services/csv-exports.service";
|
||||
import { CsvGeneratorService } from "src/time-and-attendance/exports/services/csv-builder.service";
|
||||
import { CsvExportController } from "src/time-and-attendance/exports/csv-exports.controller";
|
||||
|
||||
import { ShiftController } from "src/time-and-attendance/shifts/shift.controller";
|
||||
import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shifts-create.service";
|
||||
import { ShiftsUpdateService } from "src/time-and-attendance/shifts/services/shifts-update.service";
|
||||
import { ShiftsDeleteService } from "src/time-and-attendance/shifts/services/shifts-delete.service";
|
||||
|
||||
import { SchedulePresetsGetService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-get.service";
|
||||
import { SchedulePresetsController } from "src/time-and-attendance/schedule-presets/schedule-presets.controller";
|
||||
import { SchedulePresetsModule } from "src/time-and-attendance/schedule-presets/schedule-presets.module";
|
||||
|
|
@ -94,5 +87,7 @@ import { PayPeriodEventService } from "./pay-period/services/pay-period-event.se
|
|||
PaidTimeOffBankHoursService,
|
||||
PayPeriodEventService,
|
||||
],
|
||||
exports: [TimesheetApprovalService],
|
||||
exports: [
|
||||
TimesheetApprovalService
|
||||
],
|
||||
}) export class TimeAndAttendanceModule { };
|
||||
|
|
@ -1,36 +1,39 @@
|
|||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Prisma, Timesheets } from "prisma/postgres/generated/prisma/client/postgres/client";
|
||||
import { Timesheets } from "prisma/postgres/generated/prisma/client/postgres/client";
|
||||
import { PrismaPostgresService, TransactionClient } from "prisma/postgres/prisma-postgres.service";
|
||||
import { BaseApprovalService } from "src/common/shared/base-approval.service";
|
||||
import { timesheet_select } from "src/time-and-attendance/utils/selects.utils";
|
||||
|
||||
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class TimesheetApprovalService extends BaseApprovalService<Timesheets> {
|
||||
constructor(
|
||||
prisma: PrismaPostgresService,
|
||||
) { super(prisma) }
|
||||
|
||||
//_____________________________________________________________________________________________
|
||||
// APPROVAL AND DELEGATE METHODS
|
||||
//_____________________________________________________________________________________________
|
||||
protected get delegate() {
|
||||
return this.prisma.timesheets;
|
||||
}
|
||||
|
||||
protected delegateFor(tx: TransactionClient) {
|
||||
protected delegateFor(
|
||||
tx: TransactionClient
|
||||
) {
|
||||
return tx.timesheets;
|
||||
}
|
||||
|
||||
async updateApproval(id: number, is_approved: boolean): Promise<Timesheets> {
|
||||
async updateApproval(
|
||||
id: number,
|
||||
is_approved: boolean
|
||||
): Promise<Timesheets> {
|
||||
return this.prisma.$transaction((tx) =>
|
||||
this.updateApprovalWithTransaction(tx, id, is_approved),
|
||||
);
|
||||
}
|
||||
|
||||
async cascadeApprovalWithtx(tx: TransactionClient, timesheet_id: number, is_approved: boolean): Promise<Timesheets> {
|
||||
async cascadeApprovalWithtx(
|
||||
tx: TransactionClient,
|
||||
timesheet_id: number,
|
||||
is_approved: boolean
|
||||
): Promise<Timesheets> {
|
||||
const timesheet = await this.updateApprovalWithTransaction(tx, timesheet_id, is_approved);
|
||||
await tx.shifts.updateMany({
|
||||
where: { timesheet_id: timesheet_id },
|
||||
|
|
@ -43,7 +46,10 @@ import { timesheet_select } from "src/time-and-attendance/utils/selects.utils";
|
|||
return timesheet;
|
||||
}
|
||||
|
||||
async approveTimesheetById( timesheet_id: number, is_approved: boolean){
|
||||
async approveTimesheetById(
|
||||
timesheet_id: number,
|
||||
is_approved: boolean
|
||||
) {
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
const timesheet = await tx.timesheets.findUnique({
|
||||
where: { id: timesheet_id },
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ export class GetTimesheetsOverviewService {
|
|||
private readonly emailResolver: EmailToIdResolver,
|
||||
) { }
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
// GET TIMESHEETS FOR A SELECTED EMPLOYEE
|
||||
//-----------------------------------------------------------------------------------
|
||||
async getTimesheetsForEmployeeByPeriod(email: string, pay_year: number, pay_period_no: number, employee_email?: string): Promise<Result<Timesheets, string>> {
|
||||
async getTimesheetsForEmployeeByPeriod(
|
||||
email: string,
|
||||
pay_year: number,
|
||||
pay_period_no: number,
|
||||
employee_email?: string
|
||||
): Promise<Result<Timesheets, string>> {
|
||||
try {
|
||||
const account_email = employee_email ?? email;
|
||||
|
||||
|
|
@ -82,11 +84,11 @@ export class GetTimesheetsOverviewService {
|
|||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
// MAPPERS & HELPERS
|
||||
//-----------------------------------------------------------------------------------
|
||||
//fetch timesheet's infos
|
||||
private async loadTimesheets(employee_id: number, period_start: Date, period_end: Date) {
|
||||
private async loadTimesheets(
|
||||
employee_id: number,
|
||||
period_start: Date,
|
||||
period_end: Date
|
||||
) {
|
||||
return this.prisma.timesheets.findMany({
|
||||
where: { employee_id, start_date: { gte: period_start, lte: period_end } },
|
||||
include: {
|
||||
|
|
@ -98,7 +100,10 @@ export class GetTimesheetsOverviewService {
|
|||
});
|
||||
}
|
||||
|
||||
private ensureTimesheet = async (employee_id: number, start_date: Date | string) => {
|
||||
private ensureTimesheet = async (
|
||||
employee_id: number,
|
||||
start_date: Date | string
|
||||
) => {
|
||||
const start = toDateFromString(start_date);
|
||||
|
||||
let row = await this.prisma.timesheets.findFirst({
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
|
||||
import { Prisma } from "prisma/postgres/generated/prisma/client/postgres/client";
|
||||
import { toDateFromString, sevenDaysFrom, toStringFromDate, toHHmmFromDate } from "src/common/utils/date-utils";
|
||||
import { BankCodeDto } from "src/time-and-attendance/bank-codes/bank-codes.dto";
|
||||
import { Timesheet } from "src/time-and-attendance/timesheets/timesheet.dto";
|
||||
|
||||
export const mapOneTimesheet = async (timesheet: Prisma.TimesheetsGetPayload<{
|
||||
export const mapOneTimesheet = (
|
||||
timesheet: Prisma.TimesheetsGetPayload<{
|
||||
include: {
|
||||
employee: { include: { user } },
|
||||
shift: { include: { bank_code }, orderBy: { start_time: 'asc' } },
|
||||
expense: { include: { bank_code } },
|
||||
}
|
||||
}>): Promise<Timesheet> => {
|
||||
}>
|
||||
): Timesheet => {
|
||||
//converts string to UTC date format
|
||||
const start = toDateFromString(timesheet.start_date);
|
||||
const day_dates = sevenDaysFrom(start);
|
||||
|
|
@ -23,7 +26,7 @@ export const mapOneTimesheet = async (timesheet: Prisma.TimesheetsGetPayload<{
|
|||
shifts_by_date.set(date_string, arr);
|
||||
}
|
||||
//map of expenses by days
|
||||
const expenses_by_date = new Map<string, Prisma.ExpensesGetPayload<{ include: { bank_code: {} } }>[]>();
|
||||
const expenses_by_date = new Map<string, Prisma.ExpensesGetPayload<{ include: { bank_code: Prisma.BankCodesDefaultArgs } }>[]>();
|
||||
for (const expense of timesheet.expense) {
|
||||
const date_string = toStringFromDate(expense.date);
|
||||
const arr = expenses_by_date.get(date_string) ?? [];
|
||||
|
|
@ -150,7 +153,7 @@ const diffOfHours = (a: Date, b: Date): number => {
|
|||
const num = (value: any): number => { return value ? Number(value) : 0 };
|
||||
|
||||
// shift's subgroup types
|
||||
const hoursSubGroupFromBankCode = (bank_code: any): keyof TotalHours => {
|
||||
const hoursSubGroupFromBankCode = (bank_code: BankCodeDto): keyof TotalHours => {
|
||||
const type = bank_code.type;
|
||||
if (type.includes('EVENING')) return 'evening';
|
||||
if (type.includes('EMERGENCY')) return 'emergency';
|
||||
|
|
@ -164,7 +167,7 @@ const hoursSubGroupFromBankCode = (bank_code: any): keyof TotalHours => {
|
|||
}
|
||||
|
||||
// expense's subgroup types
|
||||
const expenseSubgroupFromBankCode = (bank_code: any): keyof TotalExpenses => {
|
||||
const expenseSubgroupFromBankCode = (bank_code: BankCodeDto): keyof TotalExpenses => {
|
||||
const type = bank_code.type;
|
||||
if (type.includes('MILEAGE')) return 'mileage';
|
||||
if (type.includes('PER_DIEM')) return 'per_diem';
|
||||
|
|
|
|||
|
|
@ -6,12 +6,16 @@ import { GetTimesheetsOverviewService } from 'src/time-and-attendance/timesheets
|
|||
import { EmailToIdResolver } from 'src/common/mappers/email-id.mapper';
|
||||
|
||||
@Module({
|
||||
controllers: [TimesheetController],
|
||||
controllers: [
|
||||
TimesheetController
|
||||
],
|
||||
providers: [
|
||||
GetTimesheetsOverviewService,
|
||||
EmailToIdResolver,
|
||||
TimesheetApprovalService,
|
||||
],
|
||||
exports: [TimesheetApprovalService],
|
||||
exports: [
|
||||
TimesheetApprovalService
|
||||
],
|
||||
})
|
||||
export class TimesheetsModule { }
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user