251124:1702 Ready to Phase 7
This commit is contained in:
@@ -1,9 +1,22 @@
|
||||
// File: src/modules/master/master.controller.ts
|
||||
|
||||
import { Controller, Get, Post, Body, UseGuards } from '@nestjs/common';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
Query,
|
||||
UseGuards,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import { MasterService } from './master.service';
|
||||
import { CreateTagDto } from './dto/create-tag.dto';
|
||||
import { UpdateTagDto } from './dto/update-tag.dto';
|
||||
import { SearchTagDto } from './dto/search-tag.dto';
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator';
|
||||
|
||||
@@ -13,6 +26,10 @@ import { RequirePermission } from '../../common/decorators/require-permission.de
|
||||
export class MasterController {
|
||||
constructor(private readonly masterService: MasterService) {}
|
||||
|
||||
// =================================================================
|
||||
// 📦 Dropdowns Endpoints (Read-Only for Frontend)
|
||||
// =================================================================
|
||||
|
||||
@Get('correspondence-types')
|
||||
@ApiOperation({ summary: 'Get all active correspondence types' })
|
||||
getCorrespondenceTypes() {
|
||||
@@ -49,16 +66,40 @@ export class MasterController {
|
||||
return this.masterService.findAllCirculationStatuses();
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 🏷️ Tag Management Endpoints
|
||||
// =================================================================
|
||||
|
||||
@Get('tags')
|
||||
@ApiOperation({ summary: 'Get all tags' })
|
||||
getTags() {
|
||||
return this.masterService.findAllTags();
|
||||
@ApiOperation({ summary: 'Get all tags (supports search & pagination)' })
|
||||
getTags(@Query() query: SearchTagDto) {
|
||||
return this.masterService.findAllTags(query);
|
||||
}
|
||||
|
||||
@Get('tags/:id')
|
||||
@ApiOperation({ summary: 'Get a tag by ID' })
|
||||
getTagById(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.masterService.findOneTag(id);
|
||||
}
|
||||
|
||||
@Post('tags')
|
||||
@RequirePermission('master_data.tag.manage') // ต้องมีสิทธิ์จัดการ Tag
|
||||
@ApiOperation({ summary: 'Create a new tag (Admin only)' })
|
||||
@RequirePermission('master_data.tag.manage') // ต้องมีสิทธิ์ (Admin/Doc Control)
|
||||
@ApiOperation({ summary: 'Create a new tag' })
|
||||
createTag(@Body() dto: CreateTagDto) {
|
||||
return this.masterService.createTag(dto);
|
||||
}
|
||||
|
||||
@Patch('tags/:id')
|
||||
@RequirePermission('master_data.tag.manage') // ต้องมีสิทธิ์
|
||||
@ApiOperation({ summary: 'Update a tag' })
|
||||
updateTag(@Param('id', ParseIntPipe) id: number, @Body() dto: UpdateTagDto) {
|
||||
return this.masterService.updateTag(id, dto);
|
||||
}
|
||||
|
||||
@Delete('tags/:id')
|
||||
@RequirePermission('master_data.tag.manage') // ต้องมีสิทธิ์
|
||||
@ApiOperation({ summary: 'Delete a tag' })
|
||||
deleteTag(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.masterService.deleteTag(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
// File: src/modules/master/master.service.ts
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
// Import Entities จาก Module อื่นๆ (ตามโครงสร้างที่มีอยู่แล้ว)
|
||||
// Import Entities
|
||||
import { CorrespondenceType } from '../correspondence/entities/correspondence-type.entity';
|
||||
import { CorrespondenceStatus } from '../correspondence/entities/correspondence-status.entity';
|
||||
import { RfaType } from '../rfa/entities/rfa-type.entity';
|
||||
import { RfaStatusCode } from '../rfa/entities/rfa-status-code.entity';
|
||||
import { RfaApproveCode } from '../rfa/entities/rfa-approve-code.entity';
|
||||
import { CirculationStatusCode } from '../circulation/entities/circulation-status-code.entity';
|
||||
import { Tag } from './entities/tag.entity'; // Entity ของ Module นี้เอง
|
||||
import { Tag } from './entities/tag.entity';
|
||||
|
||||
// Import DTOs
|
||||
import { CreateTagDto } from './dto/create-tag.dto';
|
||||
import { UpdateTagDto } from './dto/update-tag.dto';
|
||||
import { SearchTagDto } from './dto/search-tag.dto';
|
||||
|
||||
@Injectable()
|
||||
export class MasterService {
|
||||
@@ -40,58 +43,123 @@ export class MasterService {
|
||||
private readonly tagRepo: Repository<Tag>,
|
||||
) {}
|
||||
|
||||
// --- Correspondence ---
|
||||
findAllCorrespondenceTypes() {
|
||||
// =================================================================
|
||||
// ✉️ Correspondence Master Data
|
||||
// =================================================================
|
||||
|
||||
async findAllCorrespondenceTypes() {
|
||||
return this.corrTypeRepo.find({
|
||||
where: { is_active: true },
|
||||
order: { sort_order: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
findAllCorrespondenceStatuses() {
|
||||
async findAllCorrespondenceStatuses() {
|
||||
return this.corrStatusRepo.find({
|
||||
where: { is_active: true },
|
||||
order: { sort_order: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
// --- RFA ---
|
||||
findAllRfaTypes() {
|
||||
// =================================================================
|
||||
// 📐 RFA Master Data
|
||||
// =================================================================
|
||||
|
||||
async findAllRfaTypes() {
|
||||
return this.rfaTypeRepo.find({
|
||||
where: { is_active: true },
|
||||
order: { sort_order: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
findAllRfaStatuses() {
|
||||
async findAllRfaStatuses() {
|
||||
return this.rfaStatusRepo.find({
|
||||
where: { is_active: true },
|
||||
order: { sort_order: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
findAllRfaApproveCodes() {
|
||||
async findAllRfaApproveCodes() {
|
||||
return this.rfaApproveRepo.find({
|
||||
where: { is_active: true },
|
||||
order: { sort_order: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
// --- Circulation ---
|
||||
findAllCirculationStatuses() {
|
||||
// =================================================================
|
||||
// 🔄 Circulation Master Data
|
||||
// =================================================================
|
||||
|
||||
async findAllCirculationStatuses() {
|
||||
return this.circulationStatusRepo.find({
|
||||
where: { is_active: true },
|
||||
order: { sort_order: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
// --- Tags ---
|
||||
findAllTags() {
|
||||
return this.tagRepo.find({ order: { tag_name: 'ASC' } });
|
||||
// =================================================================
|
||||
// 🏷️ Tag Management (CRUD)
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* ค้นหา Tag ทั้งหมด พร้อมรองรับการ Search และ Pagination
|
||||
*/
|
||||
async findAllTags(query?: SearchTagDto) {
|
||||
const qb = this.tagRepo.createQueryBuilder('tag');
|
||||
|
||||
if (query?.search) {
|
||||
qb.where('tag.tag_name LIKE :search OR tag.description LIKE :search', {
|
||||
search: `%${query.search}%`,
|
||||
});
|
||||
}
|
||||
|
||||
qb.orderBy('tag.tag_name', 'ASC');
|
||||
|
||||
// Pagination Logic
|
||||
if (query?.page && query?.limit) {
|
||||
const page = query.page;
|
||||
const limit = query.limit;
|
||||
qb.skip((page - 1) * limit).take(limit);
|
||||
}
|
||||
|
||||
// ถ้ามีการแบ่งหน้า ให้ส่งคืนทั้งข้อมูลและจำนวนทั้งหมด (count)
|
||||
if (query?.page && query?.limit) {
|
||||
const [items, total] = await qb.getManyAndCount();
|
||||
return {
|
||||
data: items,
|
||||
meta: {
|
||||
total,
|
||||
page: query.page,
|
||||
limit: query.limit,
|
||||
totalPages: Math.ceil(total / query.limit),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return qb.getMany();
|
||||
}
|
||||
|
||||
async findOneTag(id: number) {
|
||||
const tag = await this.tagRepo.findOne({ where: { id } });
|
||||
if (!tag) {
|
||||
throw new NotFoundException(`Tag with ID "${id}" not found`);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
async createTag(dto: CreateTagDto) {
|
||||
const tag = this.tagRepo.create(dto);
|
||||
return this.tagRepo.save(tag);
|
||||
}
|
||||
|
||||
async updateTag(id: number, dto: UpdateTagDto) {
|
||||
const tag = await this.findOneTag(id); // Reuse findOne for check
|
||||
Object.assign(tag, dto);
|
||||
return this.tagRepo.save(tag);
|
||||
}
|
||||
|
||||
async deleteTag(id: number) {
|
||||
const tag = await this.findOneTag(id);
|
||||
return this.tagRepo.remove(tag);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user