refactor(shifts): modified return and switched bank_code_id for types
This commit is contained in:
parent
bdbec4f68c
commit
6adb614931
|
|
@ -279,6 +279,20 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/timesheets/timesheet-approval": {
|
||||
"patch": {
|
||||
"operationId": "TimesheetController_approveTimesheet",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Timesheet"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/preferences": {
|
||||
"patch": {
|
||||
"operationId": "PreferencesController_updatePreferences",
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ export abstract class BaseApprovalService<T> {
|
|||
//returns the corresponding Prisma delegate
|
||||
protected abstract get delegate(): UpdatableDelegate<T>;
|
||||
|
||||
protected abstract delegateFor(transaction: Prisma.TransactionClient): UpdatableDelegate<T>;
|
||||
protected abstract delegateFor(tx: Prisma.TransactionClient): UpdatableDelegate<T>;
|
||||
|
||||
//standard update Aproval
|
||||
async updateApproval(id: number, isApproved: boolean): Promise<T> {
|
||||
async updateApproval(id: number, is_approved: boolean): Promise<T> {
|
||||
try{
|
||||
return await this.delegate.update({
|
||||
where: { id },
|
||||
data: { is_approved: isApproved },
|
||||
data: { is_approved: is_approved },
|
||||
});
|
||||
}catch (error: any) {
|
||||
if (error instanceof PrismaClientKnownRequestError && error.code === "P2025") {
|
||||
|
|
@ -36,11 +36,11 @@ export abstract class BaseApprovalService<T> {
|
|||
}
|
||||
|
||||
//approval with transaction to avoid many requests
|
||||
async updateApprovalWithTransaction(transaction: Prisma.TransactionClient, id: number, isApproved: boolean): Promise<T> {
|
||||
async updateApprovalWithTransaction(tx: Prisma.TransactionClient, id: number, is_approved: boolean): Promise<T> {
|
||||
try {
|
||||
return await this.delegateFor(transaction).update({
|
||||
return await this.delegateFor(tx).update({
|
||||
where: { id },
|
||||
data: { is_approved: isApproved },
|
||||
data: { is_approved: is_approved },
|
||||
});
|
||||
} catch (error: any ){
|
||||
if(error instanceof PrismaClientKnownRequestError && error.code === 'P2025') {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export class HolidayLeaveRequestsService {
|
|||
async create(dto: UpsertLeaveRequestDto): Promise<UpsertResult> {
|
||||
const email = dto.email.trim();
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
const bank_code = await this.typeResolver.findByType(LeaveTypes.HOLIDAY);
|
||||
const bank_code = await this.typeResolver.findIdAndModifierByType(LeaveTypes.HOLIDAY);
|
||||
const dates = normalizeDates(dto.dates);
|
||||
if (!bank_code) throw new NotFoundException(`bank_code not found`);
|
||||
if (!dates.length) throw new BadRequestException('Dates array must not be empty');
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export class LeaveRequestsService {
|
|||
async update(dto: UpsertLeaveRequestDto, type: LeaveTypes): Promise<UpsertResult> {
|
||||
const email = dto.email.trim();
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
const bank_code = await this.typeResolver.findByType(type);
|
||||
const bank_code = await this.typeResolver.findIdAndModifierByType(type);
|
||||
if(!bank_code) throw new NotFoundException(`bank_code not found`);
|
||||
const modifier = Number(bank_code.modifier ?? 1);
|
||||
const dates = normalizeDates(dto.dates);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export class SickLeaveRequestsService {
|
|||
async create(dto: UpsertLeaveRequestDto): Promise<UpsertResult> {
|
||||
const email = dto.email.trim();
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
const bank_code = await this.typeResolver.findByType(LeaveTypes.SICK);
|
||||
const bank_code = await this.typeResolver.findIdAndModifierByType(LeaveTypes.SICK);
|
||||
if(!bank_code) throw new NotFoundException(`bank_code not found`);
|
||||
|
||||
const modifier = bank_code.modifier ?? 1;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export class VacationLeaveRequestsService {
|
|||
async create(dto: UpsertLeaveRequestDto): Promise<UpsertResult> {
|
||||
const email = dto.email.trim();
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
const bank_code = await this.typeResolver.findByType(LeaveTypes.VACATION);
|
||||
const bank_code = await this.typeResolver.findIdAndModifierByType(LeaveTypes.VACATION);
|
||||
if(!bank_code) throw new NotFoundException(`bank_code not found`);
|
||||
|
||||
const modifier = bank_code.modifier ?? 1;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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 { TimesheetApprovalService } from "src/time-and-attendance/time-tracker/timesheets/services/timesheet-approval.service";
|
||||
|
||||
@Module({
|
||||
imports:[TimesheetsModule],
|
||||
|
|
@ -13,8 +12,7 @@ import { TimesheetApprovalService } from "src/time-and-attendance/time-tracker/t
|
|||
PayPeriodsQueryService,
|
||||
PayPeriodsCommandService,
|
||||
EmailToIdResolver,
|
||||
TimesheetApprovalService,
|
||||
],
|
||||
})
|
||||
|
||||
export class PayperiodsModule {}
|
||||
export class PayperiodsModule {}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { TimesheetApprovalService } from "src/time-and-attendance/time-tracker/t
|
|||
export class PayPeriodsCommandService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly timesheets_approval: TimesheetApprovalService,
|
||||
private readonly timesheetsApproval: TimesheetApprovalService,
|
||||
private readonly query: PayPeriodsQueryService,
|
||||
) {}
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ export class PayPeriodsCommandService {
|
|||
for(const item of items) {
|
||||
const { period_start, period_end } = await getPeriod(item.pay_year, item.period_no);
|
||||
|
||||
const t_sheets = await transaction.timesheets.findMany({
|
||||
const timesheets = await transaction.timesheets.findMany({
|
||||
where: {
|
||||
employee: { user: { email: item.employee_email } },
|
||||
OR: [
|
||||
|
|
@ -60,8 +60,8 @@ export class PayPeriodsCommandService {
|
|||
select: { id: true },
|
||||
});
|
||||
|
||||
for(const { id } of t_sheets) {
|
||||
await this.timesheets_approval.cascadeApprovalWithtx(transaction, id, item.approve);
|
||||
for(const { id } of timesheets) {
|
||||
await this.timesheetsApproval.cascadeApprovalWithtx(transaction, id, item.approve);
|
||||
updated++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ import { ShiftController } from "src/time-and-attendance/time-tracker/shifts/con
|
|||
import { ShiftsGetService } from "src/time-and-attendance/time-tracker/shifts/services/shifts-get.service";
|
||||
import { ShiftsUpsertService } from "src/time-and-attendance/time-tracker/shifts/services/shifts-upsert.service";
|
||||
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 { 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";
|
||||
|
||||
|
|
@ -20,6 +22,7 @@ import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-i
|
|||
imports: [
|
||||
BusinessLogicsModule,
|
||||
PayperiodsModule,
|
||||
TimesheetsModule,
|
||||
],
|
||||
controllers: [
|
||||
TimesheetController,
|
||||
|
|
@ -37,6 +40,7 @@ import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-i
|
|||
SchedulePresetsApplyService,
|
||||
EmailToIdResolver,
|
||||
BankCodesResolver,
|
||||
TimesheetApprovalService,
|
||||
],
|
||||
exports: [],
|
||||
exports: [TimesheetApprovalService ],
|
||||
}) export class TimeAndAttendanceModule { };
|
||||
|
|
@ -171,7 +171,7 @@ export class SchedulePresetsUpsertService {
|
|||
const bank_code_set = new Map<string, number>();
|
||||
|
||||
for (const type of types) {
|
||||
const { id } = await this.typeResolver.findByType(type);
|
||||
const { id } = await this.typeResolver.findIdAndModifierByType(type);
|
||||
bank_code_set.set(type, id)
|
||||
}
|
||||
const toTime = (hhmm: string) => new Date(`1970-01-01T${hhmm}:00.000Z`);
|
||||
|
|
|
|||
|
|
@ -5,10 +5,14 @@ import { ShiftsUpsertService } from "src/time-and-attendance/time-tracker/shifts
|
|||
import { CreateShiftResult, UpdateShiftResult } from "src/time-and-attendance/utils/type.utils";
|
||||
import { Roles as RoleEnum } from '.prisma/client';
|
||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||
import { BankCodesResolver } from "src/time-and-attendance/utils/resolve-bank-type-id.utils";
|
||||
|
||||
@Controller('shift')
|
||||
export class ShiftController {
|
||||
constructor( private readonly upsert_service: ShiftsUpsertService ){}
|
||||
constructor(
|
||||
private readonly upsert_service: ShiftsUpsertService,
|
||||
private readonly typeResolver: BankCodesResolver,
|
||||
){}
|
||||
|
||||
@Post('create')
|
||||
@RolesAllowed(RoleEnum.EMPLOYEE, RoleEnum.ACCOUNTING, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ADMIN)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validat
|
|||
export class ShiftDto {
|
||||
@IsInt() @IsOptional() id: number;
|
||||
@IsInt() timesheet_id!: number;
|
||||
@IsInt() bank_code_id!: number;
|
||||
@IsString() type!: string;
|
||||
|
||||
@IsString() date!: string;
|
||||
@IsString() start_time!: string;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
export class GetShiftDto {
|
||||
timesheet_id: number;
|
||||
bank_code_id: number;
|
||||
date: string;
|
||||
type: string;
|
||||
date: string;
|
||||
start_time: string;
|
||||
end_time: string;
|
||||
is_remote: boolean;
|
||||
end_time: string;
|
||||
is_remote: boolean;
|
||||
is_approved: boolean;
|
||||
comment?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export class ShiftsGetService {
|
|||
const shift = row_by_id.get(id)!;
|
||||
return {
|
||||
timesheet_id: shift.timesheet_id,
|
||||
bank_code_id: shift.bank_code_id,
|
||||
type: shift.bank_code.type,
|
||||
date: toStringFromDate(shift.date),
|
||||
start_time: toStringFromHHmm(shift.start_time),
|
||||
end_time: toStringFromHHmm(shift.end_time),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import { EmailToIdResolver } from "src/time-and-attendance/utils/resolve-email-i
|
|||
import { ShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-create.dto";
|
||||
import { GetShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-get.dto";
|
||||
import { UpdateShiftDto } from "src/time-and-attendance/time-tracker/shifts/dtos/shift-update.dto";
|
||||
import { shift_select } from "src/time-and-attendance/utils/selects.utils";
|
||||
import { shift_select, timesheet_select } from "src/time-and-attendance/utils/selects.utils";
|
||||
import { BankCodesResolver } from "src/time-and-attendance/utils/resolve-bank-type-id.utils";
|
||||
|
||||
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ export class ShiftsUpsertService {
|
|||
private readonly prisma: PrismaService,
|
||||
private readonly overtime: OvertimeService,
|
||||
private readonly emailResolver: EmailToIdResolver,
|
||||
private readonly typeResolver: BankCodesResolver,
|
||||
) { }
|
||||
|
||||
//_________________________________________________________________
|
||||
|
|
@ -35,7 +37,7 @@ export class ShiftsUpsertService {
|
|||
const normed_shifts = await Promise.all(
|
||||
dtos.map(async (dto, index) => {
|
||||
try {
|
||||
const normed = this.normalizeShiftDto(dto);
|
||||
const normed = await this.normalizeShiftDto(dto);
|
||||
if (normed.end_time <= normed.start_time) {
|
||||
return {
|
||||
index,
|
||||
|
|
@ -45,18 +47,12 @@ export class ShiftsUpsertService {
|
|||
};
|
||||
}
|
||||
|
||||
const start_date = weekStartSunday(normed.date);
|
||||
|
||||
const timesheet = await this.prisma.timesheets.findFirst({
|
||||
where: { start_date, employee_id },
|
||||
select: { id: true },
|
||||
const timesheet = await this.prisma.timesheets.findUnique({
|
||||
where: { id: dto.timesheet_id, employee_id },
|
||||
select: timesheet_select,
|
||||
});
|
||||
if (!timesheet) {
|
||||
return {
|
||||
index,
|
||||
error: new NotFoundException(`Timesheet not found`),
|
||||
};
|
||||
|
||||
return { index, error: new NotFoundException(`Timesheet not found`)};
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -181,7 +177,7 @@ export class ShiftsUpsertService {
|
|||
const row = await tx.shifts.create({
|
||||
data: {
|
||||
timesheet_id: timesheet_id,
|
||||
bank_code_id: dto.bank_code_id,
|
||||
bank_code_id: normed.id,
|
||||
date: normed.date,
|
||||
start_time: normed.start_time,
|
||||
end_time: normed.end_time,
|
||||
|
|
@ -194,10 +190,12 @@ export class ShiftsUpsertService {
|
|||
existing.push({ start_time: row.start_time, end_time: row.end_time });
|
||||
existing_map.set(map_key, existing);
|
||||
|
||||
const {type: bank_type} = await this.typeResolver.findTypeByBankCodeId(row.bank_code_id);
|
||||
const summary = await this.overtime.getWeekOvertimeSummary(timesheet_id, normed.date, tx);
|
||||
|
||||
const shift: GetShiftDto = {
|
||||
timesheet_id: timesheet_id,
|
||||
bank_code_id: row.bank_code_id,
|
||||
type: bank_type,
|
||||
date: toStringFromDate(row.date),
|
||||
start_time: toStringFromHHmm(row.start_time),
|
||||
end_time: toStringFromHHmm(row.end_time),
|
||||
|
|
@ -227,7 +225,7 @@ export class ShiftsUpsertService {
|
|||
async updateShifts(dtos: UpdateShiftDto[]): Promise<UpdateShiftResult[]> {
|
||||
if (!Array.isArray(dtos) || dtos.length === 0) return [];
|
||||
|
||||
const updates: UpdateShiftPayload[] = dtos.map((item) => {
|
||||
const updates: UpdateShiftPayload[] = await Promise.all(dtos.map((item) => {
|
||||
const { id, ...rest } = item;
|
||||
if (!Number.isInteger(id)) {
|
||||
throw new BadRequestException('Update shift payload is missing a valid id');
|
||||
|
|
@ -237,12 +235,12 @@ export class ShiftsUpsertService {
|
|||
if (rest.date !== undefined) changes.date = rest.date;
|
||||
if (rest.start_time !== undefined) changes.start_time = rest.start_time;
|
||||
if (rest.end_time !== undefined) changes.end_time = rest.end_time;
|
||||
if (rest.bank_code_id !== undefined) changes.bank_code_id = rest.bank_code_id;
|
||||
if (rest.type !== undefined) changes.type = rest.type;
|
||||
if (rest.is_remote !== undefined) changes.is_remote = rest.is_remote;
|
||||
if (rest.comment !== undefined) changes.comment = rest.comment;
|
||||
|
||||
return { id, dto: changes };
|
||||
});
|
||||
}));
|
||||
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
const shift_ids = updates.map(update_shift => update_shift.id);
|
||||
|
|
@ -266,7 +264,7 @@ export class ShiftsUpsertService {
|
|||
}
|
||||
}
|
||||
|
||||
const planned_updates = updates.map(update => {
|
||||
const planned_updates = updates.map( update => {
|
||||
const exist_shift = regroup_id.get(update.id)!;
|
||||
const date_string = update.dto.date ?? toStringFromDate(exist_shift.date);
|
||||
const start_string = update.dto.start_time ?? toStringFromHHmm(exist_shift.start_time);
|
||||
|
|
@ -275,6 +273,7 @@ export class ShiftsUpsertService {
|
|||
date: toDateFromString(date_string),
|
||||
start_time: toHHmmFromString(start_string),
|
||||
end_time: toHHmmFromString(end_string),
|
||||
id: exist_shift.id,
|
||||
};
|
||||
return { update, exist_shift, normed };
|
||||
});
|
||||
|
|
@ -342,12 +341,12 @@ export class ShiftsUpsertService {
|
|||
for (const planned of planned_updates) {
|
||||
const data: any = {};
|
||||
const { dto } = planned.update;
|
||||
if (dto.date !== undefined) data.date = planned.normed.date;
|
||||
if (dto.date !== undefined) data.date = planned.normed.date;
|
||||
if (dto.start_time !== undefined) data.start_time = planned.normed.start_time;
|
||||
if (dto.end_time !== undefined) data.end_time = planned.normed.end_time;
|
||||
if (dto.bank_code_id !== undefined) data.bank_code_id = dto.bank_code_id;
|
||||
if (dto.is_remote !== undefined) data.is_remote = dto.is_remote;
|
||||
if (dto.comment !== undefined) data.comment = dto.comment ?? null;
|
||||
if (dto.end_time !== undefined) data.end_time = planned.normed.end_time;
|
||||
if (dto.type !== undefined) data.type = dto.type;
|
||||
if (dto.is_remote !== undefined) data.is_remote = dto.is_remote;
|
||||
if (dto.comment !== undefined) data.comment = dto.comment ?? null;
|
||||
|
||||
const row = await tx.shifts.update({
|
||||
where: { id: planned.exist_shift.id },
|
||||
|
|
@ -362,7 +361,7 @@ export class ShiftsUpsertService {
|
|||
|
||||
const shift: GetShiftDto = {
|
||||
timesheet_id: row.timesheet_id,
|
||||
bank_code_id: row.bank_code_id,
|
||||
type: data.type,
|
||||
date: toStringFromDate(row.date),
|
||||
start_time: toStringFromHHmm(row.start_time),
|
||||
end_time: toStringFromHHmm(row.end_time),
|
||||
|
|
@ -406,10 +405,11 @@ export class ShiftsUpsertService {
|
|||
// LOCAL HELPERS
|
||||
//_________________________________________________________________
|
||||
//converts all string hours and date to Date and HHmm formats
|
||||
private normalizeShiftDto = (dto: ShiftDto): Normalized => {
|
||||
private normalizeShiftDto = async (dto: ShiftDto): Promise<Normalized> => {
|
||||
const { id: bank_code_id} = await this.typeResolver.findBankCodeIDByType(dto.type);
|
||||
const date = toDateFromString(dto.date);
|
||||
const start_time = toHHmmFromString(dto.start_time);
|
||||
const end_time = toHHmmFromString(dto.end_time);
|
||||
return { date, start_time, end_time };
|
||||
return { date, start_time, end_time, id: bank_code_id };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,33 @@
|
|||
import { Controller, Get, ParseIntPipe, Query, Req, UnauthorizedException} from "@nestjs/common";
|
||||
import { Body, Controller, Get, ParseBoolPipe, ParseIntPipe, Patch, Query, Req, UnauthorizedException} from "@nestjs/common";
|
||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||
import { GetTimesheetsOverviewService } from "src/time-and-attendance/time-tracker/timesheets/services/timesheet-get-overview.service";
|
||||
import { Roles as RoleEnum } from '.prisma/client';
|
||||
import { TimesheetApprovalService } from "src/time-and-attendance/time-tracker/timesheets/services/timesheet-approval.service";
|
||||
|
||||
|
||||
@Controller('timesheets')
|
||||
export class TimesheetController {
|
||||
constructor( private readonly timesheetOverview: GetTimesheetsOverviewService ){}
|
||||
constructor(
|
||||
private readonly timesheetOverview: GetTimesheetsOverviewService,
|
||||
private readonly approvalService: TimesheetApprovalService,
|
||||
){}
|
||||
|
||||
@Get()
|
||||
@RolesAllowed(RoleEnum.SUPERVISOR, RoleEnum.HR, RoleEnum.ACCOUNTING, RoleEnum.ADMIN)
|
||||
async getTimesheetByIds(
|
||||
@Req() req, @Query('year', ParseIntPipe) year:number, @Query('period_number', ParseIntPipe) period_number: number) {
|
||||
const email = req.user?.email;
|
||||
if(!email) throw new UnauthorizedException('Unauthorized User');
|
||||
if(!email) throw new UnauthorizedException('Unauthorized User');
|
||||
return this.timesheetOverview.getTimesheetsForEmployeeByPeriod(email, year, period_number);
|
||||
}
|
||||
|
||||
@Patch('timesheet-approval')
|
||||
@RolesAllowed(RoleEnum.SUPERVISOR, RoleEnum.HR, RoleEnum.ACCOUNTING, RoleEnum.ADMIN)
|
||||
async approveTimesheet(
|
||||
@Body('timesheet_id', ParseIntPipe) timesheet_id: number,
|
||||
@Body('is_approved' , ParseBoolPipe) is_approved: boolean,
|
||||
) {
|
||||
return this.approvalService.approveTimesheetById(timesheet_id, is_approved);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
import { BaseApprovalService } from "src/common/shared/base-approval.service";
|
||||
import { Prisma, Timesheets } from "@prisma/client";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { timesheet_select } from "src/time-and-attendance/utils/selects.utils";
|
||||
|
||||
@Injectable()
|
||||
export class TimesheetApprovalService extends BaseApprovalService<Timesheets>{
|
||||
constructor(prisma: PrismaService){super(prisma)}
|
||||
constructor(
|
||||
prisma: PrismaService,
|
||||
){super(prisma)}
|
||||
|
||||
//_____________________________________________________________________________________________
|
||||
// APPROVAL AND DELEGATE METHODS
|
||||
//_____________________________________________________________________________________________
|
||||
|
|
@ -13,26 +17,43 @@ import { Injectable } from "@nestjs/common";
|
|||
return this.prisma.timesheets;
|
||||
}
|
||||
|
||||
protected delegateFor(transaction: Prisma.TransactionClient) {
|
||||
return transaction.timesheets;
|
||||
protected delegateFor(tx: Prisma.TransactionClient) {
|
||||
return tx.timesheets;
|
||||
}
|
||||
|
||||
async updateApproval(id: number, isApproved: boolean): Promise<Timesheets> {
|
||||
return this.prisma.$transaction((transaction) =>
|
||||
this.updateApprovalWithTransaction(transaction, id, isApproved),
|
||||
async updateApproval(id: number, is_approved: boolean): Promise<Timesheets> {
|
||||
return this.prisma.$transaction((tx) =>
|
||||
this.updateApprovalWithTransaction(tx, id, is_approved),
|
||||
);
|
||||
}
|
||||
|
||||
async cascadeApprovalWithtx(transaction: Prisma.TransactionClient, timesheetId: number, isApproved: boolean): Promise<Timesheets> {
|
||||
const timesheet = await this.updateApprovalWithTransaction(transaction, timesheetId, isApproved);
|
||||
await transaction.shifts.updateMany({
|
||||
where: { timesheet_id: timesheetId },
|
||||
data: { is_approved: isApproved },
|
||||
async cascadeApprovalWithtx(tx: Prisma.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 },
|
||||
data: { is_approved: is_approved },
|
||||
});
|
||||
await transaction.expenses.updateManyAndReturn({
|
||||
where: { timesheet_id: timesheetId },
|
||||
data: { is_approved: isApproved },
|
||||
await tx.expenses.updateManyAndReturn({
|
||||
where: { timesheet_id: timesheet_id },
|
||||
data: { is_approved: is_approved },
|
||||
});
|
||||
return timesheet;
|
||||
}
|
||||
|
||||
async approveTimesheetById( timesheet_id: number, is_approved: boolean){
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
const timesheet = await tx.timesheets.findUnique({
|
||||
where: { id: timesheet_id },
|
||||
select: { id: true },
|
||||
});
|
||||
if(!timesheet) throw new NotFoundException(`Timesheet with id: ${timesheet_id} not found`);
|
||||
|
||||
await this.cascadeApprovalWithtx(tx, timesheet_id, is_approved);
|
||||
|
||||
return tx.timesheets.findUnique({
|
||||
where: { id: timesheet_id },
|
||||
select: timesheet_select,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +1,49 @@
|
|||
import { TimesheetsArchive } from "@prisma/client";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
// import { TimesheetsArchive } from "@prisma/client";
|
||||
// import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
export class TimesheetArchiveService {
|
||||
constructor(private readonly prisma: PrismaService){}
|
||||
// export class TimesheetArchiveService {
|
||||
// constructor(private readonly prisma: PrismaService){}
|
||||
|
||||
async archiveOld(): Promise<void> {
|
||||
//calcul du cutoff pour archivation
|
||||
const cutoff = new Date();
|
||||
cutoff.setMonth(cutoff.getMonth() - 6)
|
||||
// async archiveOld(): Promise<void> {
|
||||
// //calcul du cutoff pour archivation
|
||||
// const cutoff = new Date();
|
||||
// cutoff.setMonth(cutoff.getMonth() - 6)
|
||||
|
||||
await this.prisma.$transaction(async transaction => {
|
||||
//fetches all timesheets to cutoff
|
||||
const oldSheets = await transaction.timesheets.findMany({
|
||||
where: { shift: { some: { date: { lt: cutoff } } },
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
employee_id: true,
|
||||
is_approved: true,
|
||||
},
|
||||
});
|
||||
if( oldSheets.length === 0) return;
|
||||
// await this.prisma.$transaction(async transaction => {
|
||||
// //fetches all timesheets to cutoff
|
||||
// const oldSheets = await transaction.timesheets.findMany({
|
||||
// where: { shift: { some: { date: { lt: cutoff } } },
|
||||
// },
|
||||
// select: {
|
||||
// id: true,
|
||||
// employee_id: true,
|
||||
// is_approved: true,
|
||||
// },
|
||||
// });
|
||||
// if( oldSheets.length === 0) return;
|
||||
|
||||
//preping data for archivation
|
||||
const archiveDate = oldSheets.map(sheet => ({
|
||||
timesheet_id: sheet.id,
|
||||
employee_id: sheet.employee_id,
|
||||
is_approved: sheet.is_approved,
|
||||
}));
|
||||
// //preping data for archivation
|
||||
// const archiveDate = oldSheets.map(sheet => ({
|
||||
// timesheet_id: sheet.id,
|
||||
// employee_id: sheet.employee_id,
|
||||
// is_approved: sheet.is_approved,
|
||||
// }));
|
||||
|
||||
//copying data from timesheets table to archive table
|
||||
await transaction.timesheetsArchive.createMany({ data: archiveDate });
|
||||
// //copying data from timesheets table to archive table
|
||||
// await transaction.timesheetsArchive.createMany({ data: archiveDate });
|
||||
|
||||
//removing data from timesheets table
|
||||
await transaction.timesheets.deleteMany({ where: { id: { in: oldSheets.map(s => s.id) } } });
|
||||
});
|
||||
}
|
||||
// //removing data from timesheets table
|
||||
// await transaction.timesheets.deleteMany({ where: { id: { in: oldSheets.map(s => s.id) } } });
|
||||
// });
|
||||
// }
|
||||
|
||||
//fetches all archived timesheets
|
||||
async findAllArchived(): Promise<TimesheetsArchive[]> {
|
||||
return this.prisma.timesheetsArchive.findMany();
|
||||
}
|
||||
// //fetches all archived timesheets
|
||||
// async findAllArchived(): Promise<TimesheetsArchive[]> {
|
||||
// return this.prisma.timesheetsArchive.findMany();
|
||||
// }
|
||||
|
||||
//fetches an archived timesheet
|
||||
async findOneArchived(id: number): Promise<TimesheetsArchive> {
|
||||
return this.prisma.timesheetsArchive.findUniqueOrThrow({ where: { id } });
|
||||
}
|
||||
}
|
||||
// //fetches an archived timesheet
|
||||
// async findOneArchived(id: number): Promise<TimesheetsArchive> {
|
||||
// return this.prisma.timesheetsArchive.findUniqueOrThrow({ where: { id } });
|
||||
// }
|
||||
// }
|
||||
|
|
@ -2,19 +2,16 @@
|
|||
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 { TimesheetArchiveService } from 'src/time-and-attendance/time-tracker/timesheets/services/timesheet-archive.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';
|
||||
|
||||
@Module({
|
||||
|
||||
controllers: [TimesheetController],
|
||||
providers: [
|
||||
TimesheetArchiveService,
|
||||
GetTimesheetsOverviewService,
|
||||
TimesheetApprovalService,
|
||||
EmailToIdResolver,
|
||||
TimesheetApprovalService,
|
||||
],
|
||||
exports: [],
|
||||
exports: [TimesheetApprovalService],
|
||||
})
|
||||
export class TimesheetsModule {}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export class BankCodesResolver {
|
|||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
//find id and modifier by type
|
||||
readonly findByType = async ( type: string, client?: Tx
|
||||
readonly findIdAndModifierByType = async ( type: string, client?: Tx
|
||||
): Promise<{id:number; modifier: number }> => {
|
||||
const db = client ?? this.prisma;
|
||||
const bank = await db.bankCodes.findFirst({
|
||||
|
|
@ -20,4 +20,25 @@ export class BankCodesResolver {
|
|||
if(!bank) throw new NotFoundException(`Unknown bank code type: ${type}`);
|
||||
return { id: bank.id, modifier: bank.modifier };
|
||||
};
|
||||
|
||||
//finds only id by type
|
||||
readonly findBankCodeIDByType = async (type: string, client?: Tx) => {
|
||||
const db = client ?? this.prisma;
|
||||
const bank_code_id = await db.bankCodes.findFirst({
|
||||
where: { type },
|
||||
select: {id: true},
|
||||
});
|
||||
if(!bank_code_id) throw new NotFoundException(`Unkown bank type: ${type}`);
|
||||
return bank_code_id;
|
||||
}
|
||||
|
||||
readonly findTypeByBankCodeId = async (bank_code_id: number, client?: Tx) => {
|
||||
const db = client ?? this.prisma;
|
||||
const type = await db.bankCodes.findFirst({
|
||||
where: { id: bank_code_id },
|
||||
select: { type: true },
|
||||
});
|
||||
if(!type) throw new NotFoundException(`Type with id : ${bank_code_id} not found`);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
import { dmmfToRuntimeDataModel } from "@prisma/client/runtime/library";
|
||||
|
||||
export const expense_select = {
|
||||
id: true,
|
||||
|
|
@ -17,6 +18,9 @@ export const shift_select = {
|
|||
id: true,
|
||||
timesheet_id: true,
|
||||
bank_code_id: true,
|
||||
bank_code: {
|
||||
select: { type: true },
|
||||
},
|
||||
date: true,
|
||||
start_time: true,
|
||||
end_time: true,
|
||||
|
|
@ -78,3 +82,11 @@ export const SHIFT_SELECT = {
|
|||
|
||||
export const SHIFT_ASC_ORDER = [{date: 'asc' as const}, {start_time: 'asc' as const}];
|
||||
|
||||
export const timesheet_select = {
|
||||
id: true,
|
||||
employee_id: true,
|
||||
shift: true,
|
||||
expense: true,
|
||||
start_date: true,
|
||||
is_approved: true,
|
||||
} satisfies Prisma.TimesheetsSelect;
|
||||
|
|
@ -25,7 +25,7 @@ export type TotalExpenses = {
|
|||
mileage: number;
|
||||
};
|
||||
|
||||
export type Normalized = { date: Date; start_time: Date; end_time: Date; };
|
||||
export type Normalized = { date: Date; start_time: Date; end_time: Date; id: number};
|
||||
|
||||
export type ShiftWithOvertimeDto = {
|
||||
shift: GetShiftDto;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user