targo-backend/src/modules/pay-periods/controllers/pay-periods.controller.ts

113 lines
5.6 KiB
TypeScript

import { Controller, ForbiddenException, Get, Param, ParseBoolPipe, ParseIntPipe, Patch, Query } from "@nestjs/common";
import { ApiNotFoundResponse, ApiOperation, ApiParam, ApiQuery, ApiResponse, ApiTags } from "@nestjs/swagger";
import { PayPeriodDto } from "../dtos/pay-period.dto";
import { PayPeriodOverviewDto } from "../dtos/overview-pay-period.dto";
import { PayPeriodsQueryService } from "../services/pay-periods-query.service";
import { RolesAllowed } from "src/common/decorators/roles.decorators";
import { Roles as RoleEnum } from '.prisma/client';
import { Req } from '@nestjs/common';
import { Request } from 'express';
import { PayPeriodsCommandService } from "../services/pay-periods-command.service";
import { PayPeriodBundleDto } from "../dtos/bundle-pay-period.dto";
@ApiTags('pay-periods')
@Controller('pay-periods')
export class PayPeriodsController {
constructor(
private readonly queryService: PayPeriodsQueryService,
private readonly commandService: PayPeriodsCommandService,
) {}
@Get()
@ApiOperation({ summary: 'Find all pay period' })
@ApiResponse({status: 200,description: 'List of pay period found', type: PayPeriodDto, isArray: true })
async findAll(): Promise<PayPeriodDto[]> {
return this.queryService.findAll();
}
@Get('bundle/current-and-all')
@ApiOperation({summary: 'Return current pay period and the full list'})
@ApiQuery({name: 'date', required:false, example: '2025-08-11', description:'Override for resolving the current period'})
@ApiResponse({status: 200, description:'Find current and all pay periods', type: PayPeriodBundleDto})
async getCurrentAndAll(@Query('date') date?: string): Promise<PayPeriodBundleDto> {
const [current, periods] = await Promise.all([
this.queryService.findCurrent(date),
this.queryService.findAll(),
]);
return { current, periods };
}
@Get("date/:date")
@ApiOperation({ summary: "Resolve a period by a date within it" })
@ApiResponse({ status: 200, description: "Pay period found for the selected date", type: PayPeriodDto })
@ApiNotFoundResponse({ description: "Pay period not found for the selected date" })
async findByDate(@Param("date") date: string) {
return this.queryService.findByDate(date);
}
@Get(":year/:periodNumber")
@ApiOperation({ summary: "Find pay period by year and period number" })
@ApiParam({ name: "year", type: Number, example: 2024 })
@ApiParam({ name: "periodNumber", type: Number, example: 1, description: "1..26" })
@ApiResponse({ status: 200, description: "Pay period found", type: PayPeriodDto })
@ApiNotFoundResponse({ description: "Pay period not found" })
async findOneByYear(
@Param("year", ParseIntPipe) year: number,
@Param("periodNumber", ParseIntPipe) periodNumber: number,
) {
return this.queryService.findOneByYearPeriod(year, periodNumber);
}
@Patch(":year/:periodNumber/approval")
@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
@ApiOperation({ summary: "Approve all timesheets with activity in the period" })
@ApiParam({ name: "year", type: Number, example: 2024 })
@ApiParam({ name: "periodNumber", type: Number, example: 1, description: "1..26" })
@ApiResponse({ status: 200, description: "Pay period approved" })
async approve(
@Param("year", ParseIntPipe) year: number,
@Param("periodNumber", ParseIntPipe) periodNumber: number,
) {
await this.commandService.approvalPayPeriod(year, periodNumber);
return { message: `Pay-period ${year}-${periodNumber} approved` };
}
@Get(':year/:periodNumber/crew-overview')
@RolesAllowed(RoleEnum.SUPERVISOR)
@ApiOperation({ summary: 'Supervisor crew overview for a given pay period' })
@ApiParam({ name: 'year', type: Number, example: 2024 })
@ApiParam({ name: 'periodNumber', type: Number, example: 1, description: '1..26' })
@ApiQuery({ name: 'includeSubtree', required: false, type: Boolean, example: false, description: 'Include indirect reports' })
@ApiResponse({ status: 200, description: 'Crew overview', type: PayPeriodOverviewDto })
@ApiNotFoundResponse({ description: 'Pay period not found' })
async getCrewOverview(
@Param('year', ParseIntPipe) year: number,
@Param('periodNumber', ParseIntPipe) periodNumber: number,
@Query('includeSubtree', new ParseBoolPipe({ optional: true })) includeSubtree = false,
@Req() req: Request,
): Promise<PayPeriodOverviewDto> {
const rawUser = (req as any).user ?? {};
const userId: string | undefined = rawUser.id ?? rawUser.sub ?? rawUser.userId; //needs ajusting according to passport logic
if (!userId) {
throw new ForbiddenException('Authenticated user not found on request');
}
return this.queryService.getCrewOverview(year, periodNumber, userId, includeSubtree);
}
@Get(':year/:periodNumber/overview')
@ApiOperation({ summary: 'Detailed view of a pay period by year + number' })
@ApiParam({ name: 'year', type: Number, example: 2024 })
@ApiParam({ name: 'periodNumber', type: Number, example: 1, description: '1..26' })
@ApiResponse({ status: 200, description: 'Pay period overview found', type: PayPeriodOverviewDto })
@ApiNotFoundResponse({ description: 'Pay period not found' })
async getOverviewByYear(
@Param('year', ParseIntPipe) year: number,
@Param('periodNumber', ParseIntPipe) periodNumber: number,
): Promise<PayPeriodOverviewDto> {
return this.queryService.getOverviewByYearPeriod(year, periodNumber);
}
}