128 lines
5.4 KiB
TypeScript
128 lines
5.4 KiB
TypeScript
import { Body, Controller, Delete, Get, Header, Param, ParseBoolPipe, ParseIntPipe, Patch, Post, Put, Query, UseGuards, UsePipes, ValidationPipe } from "@nestjs/common";
|
|
import { Shifts } from "@prisma/client";
|
|
import { CreateShiftDto } from "../dtos/create-shift.dto";
|
|
import { UpdateShiftsDto } from "../dtos/update-shift.dto";
|
|
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
|
import { Roles as RoleEnum } from '.prisma/client';
|
|
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
|
import { ShiftsCommandService } from "../services/shifts-command.service";
|
|
import { SearchShiftsDto } from "../dtos/search-shift.dto";
|
|
import { OverviewRow, ShiftsQueryService } from "../services/shifts-query.service";
|
|
import { GetShiftsOverviewDto } from "../dtos/get-shift-overview.dto";
|
|
import { UpsertShiftDto } from "../dtos/upsert-shift.dto";
|
|
|
|
@ApiTags('Shifts')
|
|
@ApiBearerAuth('access-token')
|
|
// @UseGuards()
|
|
@Controller('shifts')
|
|
export class ShiftsController {
|
|
constructor(
|
|
private readonly shiftsService: ShiftsQueryService,
|
|
private readonly shiftsCommandService: ShiftsCommandService,
|
|
private readonly shiftsValidationService: ShiftsQueryService,
|
|
){}
|
|
|
|
@Put('upsert/:email/:date')
|
|
async upsert_by_date(
|
|
@Param('email') email_param: string,
|
|
@Param('date') date_param: string,
|
|
@Body() payload: UpsertShiftDto,
|
|
) {
|
|
return this.shiftsCommandService.upsertShfitsByDate(email_param, date_param, payload);
|
|
}
|
|
|
|
@Post()
|
|
//@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
@ApiOperation({ summary: 'Create shift' })
|
|
@ApiResponse({ status: 201, description: 'Shift created',type: CreateShiftDto })
|
|
@ApiResponse({ status: 400, description: 'Incomplete task or invalid data' })
|
|
create(@Body() dto: CreateShiftDto): Promise<Shifts> {
|
|
return this.shiftsService.create(dto);
|
|
}
|
|
|
|
@Get()
|
|
//@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
@ApiOperation({ summary: 'Find all shifts' })
|
|
@ApiResponse({ status: 201, description: 'List of shifts found',type: CreateShiftDto, isArray: true })
|
|
@ApiResponse({ status: 400, description: 'List of shifts not found' })
|
|
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
|
|
findAll(@Query() filters: SearchShiftsDto) {
|
|
return this.shiftsService.findAll(filters);
|
|
}
|
|
|
|
@Get(':id')
|
|
//@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
@ApiOperation({ summary: 'Find shift' })
|
|
@ApiResponse({ status: 201, description: 'Shift found',type: CreateShiftDto })
|
|
@ApiResponse({ status: 400, description: 'Shift not found' })
|
|
findOne(@Param('id', ParseIntPipe) id: number): Promise<Shifts> {
|
|
return this.shiftsService.findOne(id);
|
|
}
|
|
|
|
@Patch(':id')
|
|
//@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
@ApiOperation({ summary: 'Update shift' })
|
|
@ApiResponse({ status: 201, description: 'Shift updated',type: CreateShiftDto })
|
|
@ApiResponse({ status: 400, description: 'Shift not found' })
|
|
update(@Param('id', ParseIntPipe) id: number,@Body() dto: UpdateShiftsDto): Promise<Shifts> {
|
|
return this.shiftsService.update(id, dto);
|
|
}
|
|
|
|
@Delete(':id')
|
|
//@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
@ApiOperation({ summary: 'Delete shift' })
|
|
@ApiResponse({ status: 201, description: 'Shift deleted',type: CreateShiftDto })
|
|
@ApiResponse({ status: 400, description: 'Shift not found' })
|
|
remove(@Param('id', ParseIntPipe) id: number): Promise<Shifts> {
|
|
return this.shiftsService.remove(id);
|
|
}
|
|
|
|
@Patch('approval/:id')
|
|
//@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
async approve(@Param('id', ParseIntPipe) id: number, @Body('is_approved', ParseBoolPipe) isApproved: boolean) {
|
|
return this.shiftsCommandService.updateApproval(id, isApproved);
|
|
}
|
|
|
|
@Get('summary')
|
|
async getSummary( @Query() query: GetShiftsOverviewDto): Promise<OverviewRow[]> {
|
|
return this.shiftsValidationService.getSummary(query.period_id);
|
|
}
|
|
|
|
@Get('export.csv')
|
|
@Header('Content-Type', 'text/csv; charset=utf-8')
|
|
@Header('Content-Disposition', 'attachment; filename="shifts-validation.csv"')
|
|
async exportCsv(@Query() query: GetShiftsOverviewDto): Promise<Buffer>{
|
|
const rows = await this.shiftsValidationService.getSummary(query.period_id);
|
|
|
|
//CSV Headers
|
|
const header = [
|
|
'full_name',
|
|
'supervisor',
|
|
'total_regular_hrs',
|
|
'total_evening_hrs',
|
|
'total_overtime_hrs',
|
|
'total_expenses',
|
|
'total_mileage',
|
|
'is_validated'
|
|
].join(',') + '\n';
|
|
|
|
//CSV rows
|
|
const body = rows.map(r => {
|
|
const esc = (str: string) => `"${str.replace(/"/g, '""')}"`;
|
|
|
|
return [
|
|
esc(r.full_name),
|
|
esc(r.supervisor),
|
|
r.total_regular_hrs.toFixed(2),
|
|
r.total_evening_hrs.toFixed(2),
|
|
r.total_overtime_hrs.toFixed(2),
|
|
r.total_expenses.toFixed(2),
|
|
r.total_mileage.toFixed(2),
|
|
r.is_approved,
|
|
].join(',');
|
|
}).join('\n');
|
|
|
|
return Buffer.from('\uFEFF' + header + body, 'utf8');
|
|
}
|
|
|
|
} |