251209:0000 Backend Test stagenot finish & Frontend add Task 013-015
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { CorrespondenceController } from './correspondence.controller';
|
||||
import { CorrespondenceService } from './correspondence.service';
|
||||
|
||||
describe('CorrespondenceController', () => {
|
||||
let controller: CorrespondenceController;
|
||||
@@ -7,6 +8,20 @@ describe('CorrespondenceController', () => {
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [CorrespondenceController],
|
||||
providers: [
|
||||
{
|
||||
provide: CorrespondenceService,
|
||||
useValue: {
|
||||
create: jest.fn(),
|
||||
findAll: jest.fn(),
|
||||
submit: jest.fn(),
|
||||
processAction: jest.fn(),
|
||||
getReferences: jest.fn(),
|
||||
addReference: jest.fn(),
|
||||
removeReference: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<CorrespondenceController>(CorrespondenceController);
|
||||
|
||||
@@ -5,91 +5,118 @@ import {
|
||||
Body,
|
||||
UseGuards,
|
||||
Request,
|
||||
Param, // <--- ✅ 1. เพิ่ม Param
|
||||
ParseIntPipe, // <--- ✅ 2. เพิ่ม ParseIntPipe
|
||||
Param,
|
||||
ParseIntPipe,
|
||||
Query,
|
||||
Delete,
|
||||
} from '@nestjs/common';
|
||||
import { CorrespondenceService } from './correspondence.service.js';
|
||||
import { CreateCorrespondenceDto } from './dto/create-correspondence.dto.js';
|
||||
import { SubmitCorrespondenceDto } from './dto/submit-correspondence.dto.js'; // <--- ✅ 3. เพิ่ม Import DTO นี้
|
||||
import {
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
ApiResponse,
|
||||
ApiBearerAuth,
|
||||
} from '@nestjs/swagger';
|
||||
import { CorrespondenceService } from './correspondence.service';
|
||||
import { CreateCorrespondenceDto } from './dto/create-correspondence.dto';
|
||||
import { SubmitCorrespondenceDto } from './dto/submit-correspondence.dto';
|
||||
import { WorkflowActionDto } from './dto/workflow-action.dto';
|
||||
import { AddReferenceDto } from './dto/add-reference.dto';
|
||||
import { SearchCorrespondenceDto } from './dto/search-correspondence.dto';
|
||||
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard.js';
|
||||
import { RbacGuard } from '../../common/guards/rbac.guard.js';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator.js';
|
||||
|
||||
import { WorkflowActionDto } from './dto/workflow-action.dto.js';
|
||||
// ... imports ...
|
||||
import { AddReferenceDto } from './dto/add-reference.dto.js';
|
||||
import { SearchCorrespondenceDto } from './dto/search-correspondence.dto.js';
|
||||
import { Query, Delete } from '@nestjs/common'; // เพิ่ม Query, Delete
|
||||
import { Audit } from '../../common/decorators/audit.decorator'; // Import
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
||||
import { RbacGuard } from '../../common/guards/rbac.guard';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator';
|
||||
import { Audit } from '../../common/decorators/audit.decorator';
|
||||
|
||||
@ApiTags('Correspondences')
|
||||
@Controller('correspondences')
|
||||
@UseGuards(JwtAuthGuard, RbacGuard)
|
||||
@ApiBearerAuth()
|
||||
export class CorrespondenceController {
|
||||
constructor(private readonly correspondenceService: CorrespondenceService) {}
|
||||
|
||||
@Post(':id/workflow/action')
|
||||
@RequirePermission('workflow.action_review') // สิทธิ์ในการกดอนุมัติ/ตรวจสอบ
|
||||
@ApiOperation({ summary: 'Process workflow action (Approve/Reject/Review)' })
|
||||
@ApiResponse({ status: 201, description: 'Action processed successfully.' })
|
||||
@RequirePermission('workflow.action_review')
|
||||
processAction(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() actionDto: WorkflowActionDto,
|
||||
@Request() req: any,
|
||||
@Request() req: any
|
||||
) {
|
||||
return this.correspondenceService.processAction(id, actionDto, req.user);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@RequirePermission('correspondence.create') // 🔒 ต้องมีสิทธิ์สร้าง
|
||||
@Audit('correspondence.create', 'correspondence') // ✅ แปะตรงนี้
|
||||
@ApiOperation({ summary: 'Create new correspondence' })
|
||||
@ApiResponse({
|
||||
status: 201,
|
||||
description: 'Correspondence created successfully.',
|
||||
type: CreateCorrespondenceDto,
|
||||
})
|
||||
@RequirePermission('correspondence.create')
|
||||
@Audit('correspondence.create', 'correspondence')
|
||||
create(@Body() createDto: CreateCorrespondenceDto, @Request() req: any) {
|
||||
return this.correspondenceService.create(createDto, req.user);
|
||||
}
|
||||
|
||||
// ✅ ปรับปรุง findAll ให้รับ Query Params
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Search correspondences' })
|
||||
@ApiResponse({ status: 200, description: 'Return list of correspondences.' })
|
||||
@RequirePermission('document.view')
|
||||
findAll(@Query() searchDto: SearchCorrespondenceDto) {
|
||||
return this.correspondenceService.findAll(searchDto);
|
||||
}
|
||||
|
||||
// ✅ เพิ่ม Endpoint นี้ครับ
|
||||
@Post(':id/submit')
|
||||
@RequirePermission('correspondence.create') // หรือจะสร้าง Permission ใหม่ 'workflow.submit' ก็ได้
|
||||
@Audit('correspondence.create', 'correspondence') // ✅ แปะตรงนี้
|
||||
@ApiOperation({ summary: 'Submit correspondence to workflow' })
|
||||
@ApiResponse({
|
||||
status: 201,
|
||||
description: 'Correspondence submitted successfully.',
|
||||
})
|
||||
@RequirePermission('correspondence.create')
|
||||
@Audit('correspondence.create', 'correspondence')
|
||||
submit(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() submitDto: SubmitCorrespondenceDto,
|
||||
@Request() req: any,
|
||||
@Request() req: any
|
||||
) {
|
||||
return this.correspondenceService.submit(
|
||||
id,
|
||||
submitDto.templateId,
|
||||
req.user,
|
||||
req.user
|
||||
);
|
||||
}
|
||||
|
||||
// --- REFERENCES ---
|
||||
|
||||
@Get(':id/references')
|
||||
@ApiOperation({ summary: 'Get referenced documents' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Return list of referenced documents.',
|
||||
})
|
||||
@RequirePermission('document.view')
|
||||
getReferences(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.correspondenceService.getReferences(id);
|
||||
}
|
||||
|
||||
@Post(':id/references')
|
||||
@RequirePermission('document.edit') // ต้องมีสิทธิ์แก้ไขถึงจะเพิ่ม Ref ได้
|
||||
@ApiOperation({ summary: 'Add reference to another document' })
|
||||
@ApiResponse({ status: 201, description: 'Reference added successfully.' })
|
||||
@RequirePermission('document.edit')
|
||||
addReference(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: AddReferenceDto,
|
||||
@Body() dto: AddReferenceDto
|
||||
) {
|
||||
return this.correspondenceService.addReference(id, dto);
|
||||
}
|
||||
|
||||
@Delete(':id/references/:targetId')
|
||||
@ApiOperation({ summary: 'Remove reference' })
|
||||
@ApiResponse({ status: 200, description: 'Reference removed successfully.' })
|
||||
@RequirePermission('document.edit')
|
||||
removeReference(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Param('targetId', ParseIntPipe) targetId: number,
|
||||
@Param('targetId', ParseIntPipe) targetId: number
|
||||
) {
|
||||
return this.correspondenceService.removeReference(id, targetId);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { IsInt, IsNotEmpty } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class AddReferenceDto {
|
||||
@ApiProperty({
|
||||
description: 'Target Correspondence ID to reference',
|
||||
example: 20,
|
||||
})
|
||||
@IsInt()
|
||||
@IsNotEmpty()
|
||||
targetId!: number;
|
||||
|
||||
@@ -1,33 +1,43 @@
|
||||
import { IsOptional, IsString, IsInt } from 'class-validator';
|
||||
import { Type } from 'class-transformer'; // <--- ✅ Import จาก class-transformer
|
||||
import { Type } from 'class-transformer';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class SearchCorrespondenceDto {
|
||||
@ApiPropertyOptional({
|
||||
description: 'Search term (Title or Document Number)',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
search?: string; // ค้นหาจาก Title หรือ Number
|
||||
search?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Filter by Document Type ID' })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
typeId?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Filter by Project ID' })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
projectId?: number;
|
||||
|
||||
// status อาจจะซับซ้อนหน่อยเพราะอยู่ที่ Revision แต่ใส่ไว้ก่อน
|
||||
@ApiPropertyOptional({ description: 'Filter by Status ID' })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
statusId?: number;
|
||||
|
||||
// Pagination
|
||||
@ApiPropertyOptional({ description: 'Page number (default 1)', default: 1 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
page?: number;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Items per page (default 10)',
|
||||
default: 10,
|
||||
})
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { IsInt, IsNotEmpty } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class SubmitCorrespondenceDto {
|
||||
@ApiProperty({
|
||||
description: 'ID of the Workflow Template to start',
|
||||
example: 1,
|
||||
})
|
||||
@IsInt()
|
||||
@IsNotEmpty()
|
||||
templateId!: number;
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
import { IsEnum, IsString, IsOptional, IsInt } from 'class-validator';
|
||||
import { WorkflowAction } from '../../workflow-engine/interfaces/workflow.interface.js';
|
||||
import { WorkflowAction } from '../../workflow-engine/interfaces/workflow.interface';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class WorkflowActionDto {
|
||||
@ApiProperty({
|
||||
description: 'Workflow Action',
|
||||
enum: ['APPROVE', 'REJECT', 'RETURN', 'CANCEL', 'ACKNOWLEDGE'],
|
||||
})
|
||||
@IsEnum(WorkflowAction)
|
||||
action!: WorkflowAction; // APPROVE, REJECT, RETURN, ACKNOWLEDGE
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Review comments',
|
||||
example: 'Approved with note...',
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
comments?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Sequence to return to (only for RETURN action)',
|
||||
example: 1,
|
||||
})
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
returnToSequence?: number; // ใช้กรณี action = RETURN
|
||||
|
||||
Reference in New Issue
Block a user