feat(approval): clean up Approval services. creation of a "shared" folder
This commit is contained in:
parent
ef5af80471
commit
c23da925e7
26
src/common/shared/base-approval.service.ts
Normal file
26
src/common/shared/base-approval.service.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { NotFoundException } from "@nestjs/common";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
//abstract class for approving or rejecting a shift, expense, timesheet or pay-period
|
||||
export abstract class BaseApprovalService<T> {
|
||||
protected constructor(protected readonly prisma: PrismaService) {}
|
||||
|
||||
//returns the corresponding Prisma delegate
|
||||
protected abstract get delegate(): {
|
||||
update(args: {where: {id: number };
|
||||
data: { is_approved: boolean }
|
||||
}): Promise<T>;
|
||||
};
|
||||
|
||||
//standard update Aproval
|
||||
async updateApproval(id: number, isApproved: boolean): Promise<T> {
|
||||
const entity = await this.delegate.update({
|
||||
where: { id },
|
||||
data: { is_approved: isApproved },
|
||||
});
|
||||
|
||||
if(!entity) throw new NotFoundException(`Entity #${id} not found`);
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, UseGuards } from "@nestjs/common";
|
||||
import { Body, Controller, Delete, Get, Param, ParseBoolPipe, ParseIntPipe, Patch, Post, UseGuards } from "@nestjs/common";
|
||||
import { ExpensesService } from "../services/expenses.service";
|
||||
import { CreateExpenseDto } from "../dtos/create-expense";
|
||||
import { Expenses } from "@prisma/client";
|
||||
|
|
@ -8,13 +8,17 @@ import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagg
|
|||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||
import { JwtAuthGuard } from "src/modules/authentication/guards/jwt-auth.guard";
|
||||
import { ExpenseEntity } from "../dtos/swagger-entities/expenses.entity";
|
||||
import { ExpensesApprovalService } from "../services/expenses-approval.service";
|
||||
|
||||
@ApiTags('Expenses')
|
||||
@ApiBearerAuth('access-token')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('Expenses')
|
||||
export class ExpensesController {
|
||||
constructor(private readonly expensesService: ExpensesService) {}
|
||||
constructor(
|
||||
private readonly expensesService: ExpensesService,
|
||||
private readonly expensesApprovalService: ExpensesApprovalService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||
|
|
@ -61,4 +65,10 @@ export class ExpensesController {
|
|||
return this.expensesService.remove(id);
|
||||
}
|
||||
|
||||
@Patch(':id/approval')
|
||||
@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||
async approve(@Param('id', ParseIntPipe) id: number, @Body('is_approved', ParseBoolPipe) isApproved: boolean) {
|
||||
return this.expensesApprovalService.updateApproval(id, isApproved);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
import { Expenses } from "@prisma/client";
|
||||
import { BaseApprovalService } from "src/common/shared/base-approval.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
export class ExpensesApprovalService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async updateApproval(expenseId: number, isApproved: boolean) {
|
||||
export class ExpensesApprovalService extends BaseApprovalService<Expenses> {
|
||||
constructor(prisma: PrismaService) { super(prisma); }
|
||||
|
||||
protected get delegate() {
|
||||
return this.prisma.expenses;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,40 @@
|
|||
import { NotFoundException } from "@nestjs/common";
|
||||
import { TimesheetsApprovalService } from "src/modules/timesheets/services/timesheets-approval.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
export class PayPeriodsApprovalService {
|
||||
constructor(private readonly timesheetsApproval: TimesheetsApprovalService) {}
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly timesheetsApproval: TimesheetsApprovalService,
|
||||
) {}
|
||||
|
||||
async approvaPayperdiod(periodNumber: number): Promise<void> {
|
||||
const period = await this.prisma.payPeriods.findUnique({
|
||||
where: { period_number: periodNumber },
|
||||
});
|
||||
if (!period) throw new NotFoundException(`PayPeriod #${periodNumber} not found`);
|
||||
|
||||
//fetches timesheet of selected period if the timesheet as atleast 1 shift or 1 expense
|
||||
const timesheetList = await this.prisma.timesheets.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ shift: {some: { date: { gte: period.start_date,
|
||||
lte: period.end_date,
|
||||
},
|
||||
}},
|
||||
},
|
||||
{ expense: { some: { date: { gte: period.start_date,
|
||||
lte: period.end_date,
|
||||
},
|
||||
}},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
//approval of both timesheet (cascading to the approval of related shifts and expenses)
|
||||
for(const timesheet of timesheetList) {
|
||||
await this.timesheetsApproval.updateApproval(timesheet.id, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,15 @@
|
|||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Injectable, NotFoundException, Param, ParseIntPipe, Patch } from "@nestjs/common";
|
||||
import { PayPeriods } from "@prisma/client";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { PayPeriodsApprovalService } from "./pay-periods-approval.service";
|
||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||
import { Roles as RoleEnum } from '.prisma/client';
|
||||
|
||||
@Injectable()
|
||||
export class PayPeriodsService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
constructor(private readonly prisma: PrismaService,
|
||||
private readonly payperiodsApprovalService: PayPeriodsApprovalService
|
||||
) {}
|
||||
|
||||
async findAll(): Promise<PayPeriods[]> {
|
||||
return this.prisma.payPeriods.findMany({
|
||||
|
|
@ -32,4 +37,13 @@ export class PayPeriodsService {
|
|||
}
|
||||
return period;
|
||||
}
|
||||
|
||||
@Patch(':periodNumber/approval')
|
||||
@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||
async approve(@Param('periodNumber', ParseIntPipe) periodNumber: number): Promise<{message:string}> {
|
||||
await this.payperiodsApprovalService.approvaPayperdiod(periodNumber);
|
||||
return {message: `Pay-period #${periodNumber} approved`};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,21 +1,13 @@
|
|||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Shifts } from "@prisma/client";
|
||||
import { BaseApprovalService } from "src/common/shared/base-approval.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
export class ShiftsApprovalService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
export class ShiftsApprovalService extends BaseApprovalService<Shifts> {
|
||||
constructor(prisma: PrismaService) { super(prisma); }
|
||||
|
||||
async updateApproval(shiftId: number, isApproved: boolean): Promise<Shifts> {
|
||||
const shift = await this.prisma.shifts.update({
|
||||
where: { id: shiftId },
|
||||
data: { is_approved: isApproved },
|
||||
});
|
||||
|
||||
if(!shift) {
|
||||
throw new NotFoundException(`Shift # ${shiftId} not found`);
|
||||
}
|
||||
|
||||
return shift;
|
||||
protected get delegate() {
|
||||
return this.prisma.shifts;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ export interface OverviewRow {
|
|||
export class ShiftsOverviewService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async getSummary(periodId: number): Promise<ValidationRow[]> {
|
||||
async getSummary(periodId: number): Promise<OverviewRow[]> {
|
||||
//fetch pay-period to display
|
||||
const period = await this.prisma.payPeriods.findUnique({
|
||||
where: { period_number: periodId },
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, UseGuards } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, ParseBoolPipe, ParseIntPipe, Patch, Post, UseGuards } from '@nestjs/common';
|
||||
import { TimesheetsService } from '../services/timesheets.service';
|
||||
import { CreateTimesheetDto } from '../dtos/create-timesheet.dto';
|
||||
import { Timesheets } from '@prisma/client';
|
||||
|
|
@ -8,13 +8,17 @@ import { Roles as RoleEnum } from '.prisma/client';
|
|||
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from 'src/modules/authentication/guards/jwt-auth.guard';
|
||||
import { TimesheetEntity } from '../dtos/swagger-entities/timesheet.entity';
|
||||
import { TimesheetsApprovalService } from '../services/timesheets-approval.service';
|
||||
|
||||
@ApiTags('Timesheets')
|
||||
@ApiBearerAuth('access-token')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('timesheets')
|
||||
export class TimesheetsController {
|
||||
constructor(private readonly timesheetsService: TimesheetsService) {}
|
||||
constructor(
|
||||
private readonly timesheetsService: TimesheetsService,
|
||||
private readonly timesheetsApprovalService: TimesheetsApprovalService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||
|
|
@ -63,4 +67,10 @@ export class TimesheetsController {
|
|||
remove(@Param('id', ParseIntPipe) id: number): Promise<Timesheets> {
|
||||
return this.timesheetsService.remove(id);
|
||||
}
|
||||
|
||||
@Patch(':id/approval')
|
||||
@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||
async approve(@Param('id', ParseIntPipe) id: number, @Body('is_approved', ParseBoolPipe) isApproved: boolean) {
|
||||
return this.timesheetsApprovalService.updateApproval(id, isApproved);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,37 @@
|
|||
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Timesheets } from "@prisma/client";
|
||||
import { BaseApprovalService } from "src/common/shared/base-approval.service";
|
||||
import { ExpensesApprovalService } from "src/modules/expenses/services/expenses-approval.service";
|
||||
import { ShiftsApprovalService } from "src/modules/shifts/services/shifts-approval.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
export class TimesheetsApprovalService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
export class TimesheetsApprovalService extends BaseApprovalService<Timesheets>{
|
||||
constructor(
|
||||
prisma: PrismaService,
|
||||
private readonly shiftsApproval: ShiftsApprovalService,
|
||||
private readonly expensesApproval: ExpensesApprovalService,
|
||||
) {super(prisma);}
|
||||
|
||||
protected get delegate() {
|
||||
return this.prisma.timesheets;
|
||||
}
|
||||
|
||||
async updateApproval(timesheetId: number, isApproved: boolean): Promise<Timesheets> {
|
||||
const timesheet = await this.prisma.timesheets.update({
|
||||
where: { id: timesheetId },
|
||||
const timesheet = await super.updateApproval(timesheetId, isApproved);
|
||||
|
||||
await this.prisma.shifts.updateMany({
|
||||
where: { timesheet_id: timesheetId },
|
||||
data: { is_approved: isApproved },
|
||||
});
|
||||
|
||||
await this.prisma.expenses.updateMany({
|
||||
where: { timesheet_id: timesheetId },
|
||||
data: { is_approved: isApproved },
|
||||
});
|
||||
if (!timesheet) throw new NotFoundException(`Timesheet # ${timesheetId} not found`);
|
||||
|
||||
return timesheet;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user