import { Controller, Get, Post, Put, Delete, Body, Param, Query, Req, Res, UseGuards } from '@nestjs/common'; import { Response } from 'express'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { AllowViewer } from '../../common/decorators/allow-viewer.decorator'; import { BoardPlanningService } from './board-planning.service'; import { BoardPlanningProjectionService } from './board-planning-projection.service'; import { BudgetPlanningService } from './budget-planning.service'; @ApiTags('board-planning') @Controller('board-planning') @ApiBearerAuth() @UseGuards(JwtAuthGuard) export class BoardPlanningController { constructor( private service: BoardPlanningService, private projection: BoardPlanningProjectionService, private budgetPlanning: BudgetPlanningService, ) {} // ── Scenarios ── @Get('scenarios') @AllowViewer() listScenarios(@Query('type') type?: string) { return this.service.listScenarios(type); } @Get('scenarios/:id') @AllowViewer() getScenario(@Param('id') id: string) { return this.service.getScenario(id); } @Post('scenarios') createScenario(@Body() dto: any, @Req() req: any) { return this.service.createScenario(dto, req.user.sub); } @Put('scenarios/:id') updateScenario(@Param('id') id: string, @Body() dto: any) { return this.service.updateScenario(id, dto); } @Delete('scenarios/:id') deleteScenario(@Param('id') id: string) { return this.service.deleteScenario(id); } // ── Scenario Investments ── @Get('scenarios/:scenarioId/investments') @AllowViewer() listInvestments(@Param('scenarioId') scenarioId: string) { return this.service.listInvestments(scenarioId); } @Post('scenarios/:scenarioId/investments') addInvestment(@Param('scenarioId') scenarioId: string, @Body() dto: any) { return this.service.addInvestment(scenarioId, dto); } @Post('scenarios/:scenarioId/investments/from-recommendation') addFromRecommendation(@Param('scenarioId') scenarioId: string, @Body() dto: any) { return this.service.addInvestmentFromRecommendation(scenarioId, dto); } @Put('investments/:id') updateInvestment(@Param('id') id: string, @Body() dto: any) { return this.service.updateInvestment(id, dto); } @Delete('investments/:id') removeInvestment(@Param('id') id: string) { return this.service.removeInvestment(id); } // ── Scenario Assessments ── @Get('scenarios/:scenarioId/assessments') @AllowViewer() listAssessments(@Param('scenarioId') scenarioId: string) { return this.service.listAssessments(scenarioId); } @Post('scenarios/:scenarioId/assessments') addAssessment(@Param('scenarioId') scenarioId: string, @Body() dto: any) { return this.service.addAssessment(scenarioId, dto); } @Put('assessments/:id') updateAssessment(@Param('id') id: string, @Body() dto: any) { return this.service.updateAssessment(id, dto); } @Delete('assessments/:id') removeAssessment(@Param('id') id: string) { return this.service.removeAssessment(id); } // ── Projections ── @Get('scenarios/:id/projection') @AllowViewer() getProjection(@Param('id') id: string) { return this.projection.getProjection(id); } @Post('scenarios/:id/projection/refresh') refreshProjection(@Param('id') id: string) { return this.projection.computeProjection(id); } // ── Comparison ── @Get('compare') @AllowViewer() compareScenarios(@Query('ids') ids: string) { const scenarioIds = ids.split(',').map((s) => s.trim()).filter(Boolean); return this.projection.compareScenarios(scenarioIds); } // ── Execute Investment ── @Post('investments/:id/execute') executeInvestment( @Param('id') id: string, @Body() dto: { executionDate: string }, @Req() req: any, ) { return this.service.executeInvestment(id, dto.executionDate, req.user.sub); } // ── Budget Planning ── @Get('budget-plans') @AllowViewer() listBudgetPlans() { return this.budgetPlanning.listPlans(); } @Get('budget-plans/available-years') @AllowViewer() getAvailableYears() { return this.budgetPlanning.getAvailableYears(); } @Get('budget-plans/:year') @AllowViewer() getBudgetPlan(@Param('year') year: string) { return this.budgetPlanning.getPlan(parseInt(year, 10)); } @Post('budget-plans') createBudgetPlan(@Body() dto: { fiscalYear: number; baseYear: number; inflationRate?: number }, @Req() req: any) { return this.budgetPlanning.createPlan(dto.fiscalYear, dto.baseYear, dto.inflationRate ?? 2.5, req.user.sub); } @Put('budget-plans/:year/lines') updateBudgetPlanLines(@Param('year') year: string, @Body() dto: { planId: string; lines: any[] }) { return this.budgetPlanning.updateLines(dto.planId, dto.lines); } @Put('budget-plans/:year/inflation') updateBudgetPlanInflation(@Param('year') year: string, @Body() dto: { inflationRate: number }) { return this.budgetPlanning.updateInflation(parseInt(year, 10), dto.inflationRate); } @Put('budget-plans/:year/status') advanceBudgetPlanStatus(@Param('year') year: string, @Body() dto: { status: string }, @Req() req: any) { return this.budgetPlanning.advanceStatus(parseInt(year, 10), dto.status, req.user.sub); } @Post('budget-plans/:year/import') importBudgetPlanLines( @Param('year') year: string, @Body() lines: any[], @Req() req: any, ) { return this.budgetPlanning.importLines(parseInt(year, 10), lines, req.user.sub); } @Get('budget-plans/:year/template') async getBudgetPlanTemplate( @Param('year') year: string, @Res() res: Response, ) { const csv = await this.budgetPlanning.getTemplate(parseInt(year, 10)); res.set({ 'Content-Type': 'text/csv', 'Content-Disposition': `attachment; filename="budget_template_${year}.csv"`, }); res.send(csv); } @Delete('budget-plans/:year') deleteBudgetPlan(@Param('year') year: string) { return this.budgetPlanning.deletePlan(parseInt(year, 10)); } }