124 lines
4.0 KiB
TypeScript
124 lines
4.0 KiB
TypeScript
// File: src/modules/review-team/review-task.controller.ts
|
|
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Patch,
|
|
Body,
|
|
Param,
|
|
Query,
|
|
UseGuards,
|
|
ParseUUIDPipe,
|
|
} from '@nestjs/common';
|
|
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
|
import { PermissionsGuard } from '../../common/auth/guards/permissions.guard';
|
|
import { RequirePermission } from '../../common/decorators/require-permission.decorator';
|
|
import { Audit } from '../../common/decorators/audit.decorator';
|
|
import { ReviewTaskService } from './review-task.service';
|
|
|
|
import { ConsensusService } from './services/consensus.service';
|
|
import { VetoOverrideService } from './services/veto-override.service';
|
|
import type { VetoOverrideDto } from './services/veto-override.service';
|
|
import {
|
|
CompleteReviewTaskDto,
|
|
SearchReviewTaskDto,
|
|
} from './dto/shared/review-team.dto';
|
|
import { CurrentUser } from '../../common/decorators/current-user.decorator';
|
|
import { User } from '../user/entities/user.entity';
|
|
|
|
@Controller('review-tasks')
|
|
@UseGuards(JwtAuthGuard, PermissionsGuard)
|
|
export class ReviewTaskController {
|
|
constructor(
|
|
private readonly reviewTaskService: ReviewTaskService,
|
|
private readonly consensusService: ConsensusService,
|
|
private readonly vetoOverrideService: VetoOverrideService
|
|
) {}
|
|
|
|
@Get()
|
|
@RequirePermission('document.view')
|
|
findAll(@Query() dto: SearchReviewTaskDto) {
|
|
return this.reviewTaskService.findAll(dto);
|
|
}
|
|
|
|
@Get(':publicId')
|
|
@RequirePermission('document.view')
|
|
findOne(@Param('publicId', ParseUUIDPipe) publicId: string) {
|
|
return this.reviewTaskService.findByPublicId(publicId);
|
|
}
|
|
|
|
@Patch(':publicId/start')
|
|
@RequirePermission('workflow.action_review')
|
|
@Audit('review_task.start', 'review_task')
|
|
startReview(@Param('publicId', ParseUUIDPipe) publicId: string) {
|
|
return this.reviewTaskService.startReview(publicId);
|
|
}
|
|
|
|
@Patch(':publicId/complete')
|
|
@RequirePermission('workflow.action_review')
|
|
@Audit('review_task.complete', 'review_task')
|
|
async completeReview(
|
|
@Param('publicId', ParseUUIDPipe) publicId: string,
|
|
@Body() dto: CompleteReviewTaskDto,
|
|
@CurrentUser() _user: User
|
|
) {
|
|
const task = await this.reviewTaskService.completeReview(publicId, dto);
|
|
|
|
// Evaluate consensus after completion (FR-010)
|
|
try {
|
|
const fullTask =
|
|
await this.reviewTaskService.findFullTaskContext(publicId);
|
|
|
|
// Cast to access dynamic properties from innerJoinAndMapOne safely without 'any'
|
|
const context = fullTask as unknown as {
|
|
rfaRevisionId: number;
|
|
rfaRevision?: {
|
|
correspondenceRevision?: {
|
|
publicId: string;
|
|
correspondence?: {
|
|
publicId: string;
|
|
projectId: number;
|
|
type?: {
|
|
id: number;
|
|
typeCode: string;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
const rfaRevision = context.rfaRevision;
|
|
const corrRevision = rfaRevision?.correspondenceRevision;
|
|
const correspondence = corrRevision?.correspondence;
|
|
|
|
if (rfaRevision && corrRevision && correspondence) {
|
|
await this.consensusService.evaluateAfterTaskComplete(
|
|
context.rfaRevisionId,
|
|
{
|
|
rfaPublicId: correspondence.publicId,
|
|
rfaRevisionPublicId: corrRevision.publicId,
|
|
projectId: correspondence.projectId,
|
|
documentTypeId: correspondence.type?.id,
|
|
documentTypeCode: correspondence.type?.typeCode ?? 'RFA',
|
|
}
|
|
);
|
|
}
|
|
} catch (_error: unknown) {
|
|
// Log error but don't fail the task completion response
|
|
// (error as any).logger?.error(`Consensus evaluation failed: ${(error as Error).message}`);
|
|
}
|
|
|
|
return task;
|
|
}
|
|
|
|
@Post('veto-override')
|
|
@RequirePermission('document.admin_edit')
|
|
@Audit('review_task.veto_override', 'review_task')
|
|
async overrideVeto(@Body() dto: VetoOverrideDto, @CurrentUser() user: User) {
|
|
return this.vetoOverrideService.executeOverride({
|
|
...dto,
|
|
overriddenByUserId: user.user_id,
|
|
});
|
|
}
|
|
}
|