This commit is contained in:
@@ -3,20 +3,45 @@ import {
|
||||
NotFoundException,
|
||||
ConflictException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, Like } from 'typeorm';
|
||||
import { InjectRepository, InjectEntityManager } from '@nestjs/typeorm';
|
||||
import { Repository, Like, EntityManager } from 'typeorm';
|
||||
import { Contract } from './entities/contract.entity';
|
||||
import { CreateContractDto } from './dto/create-contract.dto.js';
|
||||
import { UpdateContractDto } from './dto/update-contract.dto.js';
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
|
||||
@Injectable()
|
||||
export class ContractService {
|
||||
constructor(
|
||||
@InjectRepository(Contract)
|
||||
private readonly contractRepo: Repository<Contract>
|
||||
private readonly contractRepo: Repository<Contract>,
|
||||
@InjectEntityManager()
|
||||
private readonly entityManager: EntityManager
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Helper to resolve projectId (ID or UUID) to internal INT ID
|
||||
*/
|
||||
async resolveProjectId(projectId: number | string): Promise<number> {
|
||||
if (typeof projectId === 'number') return projectId;
|
||||
const num = Number(projectId);
|
||||
if (!isNaN(num)) return num;
|
||||
|
||||
const project = await this.entityManager.findOne(Project, {
|
||||
where: { uuid: projectId as string },
|
||||
select: ['id'],
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
}
|
||||
|
||||
return project.id;
|
||||
}
|
||||
|
||||
async create(dto: CreateContractDto) {
|
||||
const internalProjectId = await this.resolveProjectId(dto.projectId);
|
||||
|
||||
const existing = await this.contractRepo.findOne({
|
||||
where: { contractCode: dto.contractCode },
|
||||
});
|
||||
@@ -25,7 +50,7 @@ export class ContractService {
|
||||
`Contract Code "${dto.contractCode}" already exists`
|
||||
);
|
||||
}
|
||||
const contract = this.contractRepo.create(dto);
|
||||
const contract = this.contractRepo.create({ ...dto, projectId: internalProjectId });
|
||||
return this.contractRepo.save(contract);
|
||||
}
|
||||
|
||||
@@ -33,6 +58,11 @@ export class ContractService {
|
||||
const { search, projectId, page = 1, limit = 100 } = params || {};
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
let internalProjectId = undefined;
|
||||
if (projectId) {
|
||||
internalProjectId = await this.resolveProjectId(projectId);
|
||||
}
|
||||
|
||||
const findOptions: any = {
|
||||
relations: ['project'],
|
||||
order: { contractCode: 'ASC' },
|
||||
@@ -47,21 +77,20 @@ export class ContractService {
|
||||
searchConditions.push({ contractName: Like(`%${search}%`) });
|
||||
}
|
||||
|
||||
if (projectId) {
|
||||
// Combine project filter with search if exists
|
||||
if (internalProjectId) {
|
||||
if (searchConditions.length > 0) {
|
||||
findOptions.where = searchConditions.map((cond) => ({
|
||||
...cond,
|
||||
projectId,
|
||||
projectId: internalProjectId,
|
||||
}));
|
||||
} else {
|
||||
findOptions.where = { projectId };
|
||||
findOptions.where = { projectId: internalProjectId };
|
||||
}
|
||||
} else {
|
||||
if (searchConditions.length > 0) {
|
||||
findOptions.where = searchConditions;
|
||||
} else {
|
||||
delete findOptions.where; // No filters
|
||||
delete findOptions.where;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +128,9 @@ export class ContractService {
|
||||
|
||||
async update(uuid: string, dto: UpdateContractDto) {
|
||||
const contract = await this.findOneByUuid(uuid);
|
||||
if (dto.projectId) {
|
||||
dto.projectId = await this.resolveProjectId(dto.projectId);
|
||||
}
|
||||
Object.assign(contract, dto);
|
||||
return this.contractRepo.save(contract);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
BeforeInsert,
|
||||
} from 'typeorm';
|
||||
import { v7 as uuidv7 } from 'uuid';
|
||||
import { Exclude } from 'class-transformer';
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||
import { Project } from '../../project/entities/project.entity';
|
||||
|
||||
@@ -17,6 +17,7 @@ export class Contract extends BaseEntity {
|
||||
@Exclude()
|
||||
id!: number;
|
||||
|
||||
@Expose({ name: 'id' })
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
unique: true,
|
||||
|
||||
@@ -38,28 +38,16 @@ export class DrawingMasterDataController {
|
||||
|
||||
@Get('contract/volumes')
|
||||
@ApiOperation({ summary: 'List Contract Drawing Volumes' })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: String })
|
||||
@RequirePermission('document.view')
|
||||
getVolumes(@Query('projectId', ParseIntPipe) projectId: number) {
|
||||
this.logger.log(`Fetching Contract Volumes for Project ID: ${projectId}`);
|
||||
getVolumes(@Query('projectId') projectId: string | number) {
|
||||
return this.masterDataService.findAllVolumes(projectId);
|
||||
}
|
||||
|
||||
// ... (Create/Update/Delete methods remain unchanged) ...
|
||||
|
||||
@Post('contract/volumes')
|
||||
@ApiOperation({ summary: 'Create Volume' })
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
createVolume(
|
||||
@Body()
|
||||
body: {
|
||||
projectId: number;
|
||||
volumeCode: string;
|
||||
volumeName: string;
|
||||
description?: string;
|
||||
sortOrder: number;
|
||||
}
|
||||
) {
|
||||
createVolume(@Body() body: any) {
|
||||
return this.masterDataService.createVolume(body);
|
||||
}
|
||||
|
||||
@@ -68,13 +56,7 @@ export class DrawingMasterDataController {
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
updateVolume(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body()
|
||||
body: {
|
||||
volumeCode?: string;
|
||||
volumeName?: string;
|
||||
description?: string;
|
||||
sortOrder?: number;
|
||||
}
|
||||
@Body() body: any
|
||||
) {
|
||||
return this.masterDataService.updateVolume(id, body);
|
||||
}
|
||||
@@ -92,30 +74,16 @@ export class DrawingMasterDataController {
|
||||
|
||||
@Get('contract/categories')
|
||||
@ApiOperation({ summary: 'List Contract Drawing Categories' })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: String })
|
||||
@RequirePermission('document.view')
|
||||
getCategories(@Query('projectId', ParseIntPipe) projectId: number) {
|
||||
this.logger.log(
|
||||
`Fetching Contract Categories for Project ID: ${projectId}`
|
||||
);
|
||||
getCategories(@Query('projectId') projectId: string | number) {
|
||||
return this.masterDataService.findAllCategories(projectId);
|
||||
}
|
||||
|
||||
// ... (Create/Update/Delete methods remain unchanged) ...
|
||||
|
||||
@Post('contract/categories')
|
||||
@ApiOperation({ summary: 'Create Category' })
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
createCategory(
|
||||
@Body()
|
||||
body: {
|
||||
projectId: number;
|
||||
catCode: string;
|
||||
catName: string;
|
||||
description?: string;
|
||||
sortOrder: number;
|
||||
}
|
||||
) {
|
||||
createCategory(@Body() body: any) {
|
||||
return this.masterDataService.createCategory(body);
|
||||
}
|
||||
|
||||
@@ -124,13 +92,7 @@ export class DrawingMasterDataController {
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
updateCategory(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body()
|
||||
body: {
|
||||
catCode?: string;
|
||||
catName?: string;
|
||||
description?: string;
|
||||
sortOrder?: number;
|
||||
}
|
||||
@Body() body: any
|
||||
) {
|
||||
return this.masterDataService.updateCategory(id, body);
|
||||
}
|
||||
@@ -148,30 +110,16 @@ export class DrawingMasterDataController {
|
||||
|
||||
@Get('contract/sub-categories')
|
||||
@ApiOperation({ summary: 'List Contract Drawing Sub-Categories' })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: String })
|
||||
@RequirePermission('document.view')
|
||||
getContractSubCats(@Query('projectId', ParseIntPipe) projectId: number) {
|
||||
this.logger.log(
|
||||
`Fetching Contract Sub-Categories for Project ID: ${projectId}`
|
||||
);
|
||||
getContractSubCats(@Query('projectId') projectId: string | number) {
|
||||
return this.masterDataService.findAllContractSubCats(projectId);
|
||||
}
|
||||
|
||||
// ... (Create/Update/Delete methods remain unchanged) ...
|
||||
|
||||
@Post('contract/sub-categories')
|
||||
@ApiOperation({ summary: 'Create Contract Sub-Category' })
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
createContractSubCat(
|
||||
@Body()
|
||||
body: {
|
||||
projectId: number;
|
||||
subCatCode: string;
|
||||
subCatName: string;
|
||||
description?: string;
|
||||
sortOrder: number;
|
||||
}
|
||||
) {
|
||||
createContractSubCat(@Body() body: any) {
|
||||
return this.masterDataService.createContractSubCat(body);
|
||||
}
|
||||
|
||||
@@ -180,18 +128,15 @@ export class DrawingMasterDataController {
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
updateContractSubCat(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body()
|
||||
body: {
|
||||
subCatCode?: string;
|
||||
subCatName?: string;
|
||||
description?: string;
|
||||
sortOrder?: number;
|
||||
}
|
||||
@Body() body: any
|
||||
) {
|
||||
return this.masterDataService.updateContractSubCat(id, body);
|
||||
}
|
||||
|
||||
async deleteContractSubCat(@Param('id', ParseIntPipe) id: number) {
|
||||
@Delete('contract/sub-categories/:id')
|
||||
@ApiOperation({ summary: 'Delete Contract Sub-Category' })
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
deleteContractSubCat(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.masterDataService.deleteContractSubCat(id);
|
||||
}
|
||||
|
||||
@@ -201,11 +146,11 @@ export class DrawingMasterDataController {
|
||||
|
||||
@Get('contract/mappings')
|
||||
@ApiOperation({ summary: 'List Contract Drawing Mappings' })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: String })
|
||||
@ApiQuery({ name: 'categoryId', required: false, type: Number })
|
||||
@RequirePermission('document.view')
|
||||
getContractMappings(
|
||||
@Query('projectId', ParseIntPipe) projectId: number,
|
||||
@Query('projectId') projectId: string | number,
|
||||
@Query('categoryId') categoryId?: number
|
||||
) {
|
||||
return this.masterDataService.findContractMappings(
|
||||
@@ -217,14 +162,7 @@ export class DrawingMasterDataController {
|
||||
@Post('contract/mappings')
|
||||
@ApiOperation({ summary: 'Create Contract Drawing Mapping' })
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
createContractMapping(
|
||||
@Body()
|
||||
body: {
|
||||
projectId: number;
|
||||
categoryId: number;
|
||||
subCategoryId: number;
|
||||
}
|
||||
) {
|
||||
createContractMapping(@Body() body: any) {
|
||||
return this.masterDataService.createContractMapping(body);
|
||||
}
|
||||
|
||||
@@ -241,31 +179,16 @@ export class DrawingMasterDataController {
|
||||
|
||||
@Get('shop/main-categories')
|
||||
@ApiOperation({ summary: 'List Shop Drawing Main Categories' })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: String })
|
||||
@RequirePermission('document.view')
|
||||
getShopMainCats(@Query('projectId', ParseIntPipe) projectId: number) {
|
||||
this.logger.log(
|
||||
`Fetching Shop Main Categories for Project ID: ${projectId}`
|
||||
);
|
||||
getShopMainCats(@Query('projectId') projectId: string | number) {
|
||||
return this.masterDataService.findAllShopMainCats(projectId);
|
||||
}
|
||||
|
||||
// ... (Create/Update/Delete methods remain unchanged) ...
|
||||
|
||||
@Post('shop/main-categories')
|
||||
@ApiOperation({ summary: 'Create Shop Main Category' })
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
createShopMainCat(
|
||||
@Body()
|
||||
body: {
|
||||
projectId: number;
|
||||
mainCategoryCode: string;
|
||||
mainCategoryName: string;
|
||||
description?: string;
|
||||
isActive?: boolean;
|
||||
sortOrder: number;
|
||||
}
|
||||
) {
|
||||
createShopMainCat(@Body() body: any) {
|
||||
return this.masterDataService.createShopMainCat(body);
|
||||
}
|
||||
|
||||
@@ -274,14 +197,7 @@ export class DrawingMasterDataController {
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
updateShopMainCat(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body()
|
||||
body: {
|
||||
mainCategoryCode?: string;
|
||||
mainCategoryName?: string;
|
||||
description?: string;
|
||||
isActive?: boolean;
|
||||
sortOrder?: number;
|
||||
}
|
||||
@Body() body: any
|
||||
) {
|
||||
return this.masterDataService.updateShopMainCat(id, body);
|
||||
}
|
||||
@@ -299,16 +215,13 @@ export class DrawingMasterDataController {
|
||||
|
||||
@Get('shop/sub-categories')
|
||||
@ApiOperation({ summary: 'List Shop Drawing Sub-Categories' })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||
@ApiQuery({ name: 'projectId', required: true, type: String })
|
||||
@ApiQuery({ name: 'mainCategoryId', required: false, type: Number })
|
||||
@RequirePermission('document.view')
|
||||
getShopSubCats(
|
||||
@Query('projectId', ParseIntPipe) projectId: number,
|
||||
@Query('projectId') projectId: string | number,
|
||||
@Query('mainCategoryId') mainCategoryId?: number
|
||||
) {
|
||||
this.logger.log(
|
||||
`Fetching Shop Sub-Categories for Project ID: ${projectId}, MainCategory: ${mainCategoryId}`
|
||||
);
|
||||
return this.masterDataService.findAllShopSubCats(
|
||||
projectId,
|
||||
mainCategoryId ? Number(mainCategoryId) : undefined
|
||||
@@ -318,17 +231,7 @@ export class DrawingMasterDataController {
|
||||
@Post('shop/sub-categories')
|
||||
@ApiOperation({ summary: 'Create Shop Sub-Category' })
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
createShopSubCat(
|
||||
@Body()
|
||||
body: {
|
||||
projectId: number;
|
||||
subCategoryCode: string;
|
||||
subCategoryName: string;
|
||||
description?: string;
|
||||
isActive?: boolean;
|
||||
sortOrder: number;
|
||||
}
|
||||
) {
|
||||
createShopSubCat(@Body() body: any) {
|
||||
return this.masterDataService.createShopSubCat(body);
|
||||
}
|
||||
|
||||
@@ -337,14 +240,7 @@ export class DrawingMasterDataController {
|
||||
@RequirePermission('master_data.drawing_category.manage')
|
||||
updateShopSubCat(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body()
|
||||
body: {
|
||||
subCategoryCode?: string;
|
||||
subCategoryName?: string;
|
||||
description?: string;
|
||||
isActive?: boolean;
|
||||
sortOrder?: number;
|
||||
}
|
||||
@Body() body: any
|
||||
) {
|
||||
return this.masterDataService.updateShopSubCat(id, body);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, FindOptionsWhere } from 'typeorm';
|
||||
import { InjectRepository, InjectEntityManager } from '@nestjs/typeorm';
|
||||
import { Repository, FindOptionsWhere, EntityManager } from 'typeorm';
|
||||
|
||||
// Entities
|
||||
import { ContractDrawingVolume } from './entities/contract-drawing-volume.entity';
|
||||
@@ -9,6 +9,7 @@ import { ContractDrawingSubCategory } from './entities/contract-drawing-sub-cate
|
||||
import { ShopDrawingMainCategory } from './entities/shop-drawing-main-category.entity';
|
||||
import { ShopDrawingSubCategory } from './entities/shop-drawing-sub-category.entity';
|
||||
import { ContractDrawingSubcatCatMap } from './entities/contract-drawing-subcat-cat-map.entity';
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
|
||||
@Injectable()
|
||||
export class DrawingMasterDataService {
|
||||
@@ -24,22 +25,47 @@ export class DrawingMasterDataService {
|
||||
@InjectRepository(ShopDrawingSubCategory)
|
||||
private sdSubCatRepo: Repository<ShopDrawingSubCategory>,
|
||||
@InjectRepository(ContractDrawingSubcatCatMap)
|
||||
private cdMapRepo: Repository<ContractDrawingSubcatCatMap>
|
||||
private cdMapRepo: Repository<ContractDrawingSubcatCatMap>,
|
||||
@InjectEntityManager()
|
||||
private entityManager: EntityManager
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Helper to resolve projectId (ID or UUID) to internal INT ID
|
||||
*/
|
||||
async resolveProjectId(projectId: number | string): Promise<number> {
|
||||
if (typeof projectId === 'number') return projectId;
|
||||
const num = Number(projectId);
|
||||
if (!isNaN(num)) return num;
|
||||
|
||||
// If it's a string and not a number, it's a UUID (ADR-019)
|
||||
const project = await this.entityManager.findOne(Project, {
|
||||
where: { uuid: projectId as string },
|
||||
select: ['id'],
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
}
|
||||
|
||||
return project.id;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// Contract Drawing Volumes
|
||||
// =====================================================
|
||||
|
||||
async findAllVolumes(projectId: number) {
|
||||
async findAllVolumes(projectId: number | string) {
|
||||
const internalId = await this.resolveProjectId(projectId);
|
||||
return this.cdVolumeRepo.find({
|
||||
where: { projectId },
|
||||
where: { projectId: internalId },
|
||||
order: { sortOrder: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
async createVolume(data: Partial<ContractDrawingVolume>) {
|
||||
const volume = this.cdVolumeRepo.create(data);
|
||||
async createVolume(data: any) {
|
||||
const internalId = await this.resolveProjectId(data.projectId);
|
||||
const volume = this.cdVolumeRepo.create({ ...data, projectId: internalId });
|
||||
return this.cdVolumeRepo.save(volume);
|
||||
}
|
||||
|
||||
@@ -61,15 +87,17 @@ export class DrawingMasterDataService {
|
||||
// Contract Drawing Categories
|
||||
// =====================================================
|
||||
|
||||
async findAllCategories(projectId: number) {
|
||||
async findAllCategories(projectId: number | string) {
|
||||
const internalId = await this.resolveProjectId(projectId);
|
||||
return this.cdCatRepo.find({
|
||||
where: { projectId },
|
||||
where: { projectId: internalId },
|
||||
order: { sortOrder: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
async createCategory(data: Partial<ContractDrawingCategory>) {
|
||||
const cat = this.cdCatRepo.create(data);
|
||||
async createCategory(data: any) {
|
||||
const internalId = await this.resolveProjectId(data.projectId);
|
||||
const cat = this.cdCatRepo.create({ ...data, projectId: internalId });
|
||||
return this.cdCatRepo.save(cat);
|
||||
}
|
||||
|
||||
@@ -91,15 +119,17 @@ export class DrawingMasterDataService {
|
||||
// Contract Drawing Sub-Categories
|
||||
// =====================================================
|
||||
|
||||
async findAllContractSubCats(projectId: number) {
|
||||
async findAllContractSubCats(projectId: number | string) {
|
||||
const internalId = await this.resolveProjectId(projectId);
|
||||
return this.cdSubCatRepo.find({
|
||||
where: { projectId },
|
||||
where: { projectId: internalId },
|
||||
order: { sortOrder: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
async createContractSubCat(data: Partial<ContractDrawingSubCategory>) {
|
||||
const subCat = this.cdSubCatRepo.create(data);
|
||||
async createContractSubCat(data: any) {
|
||||
const internalId = await this.resolveProjectId(data.projectId);
|
||||
const subCat = this.cdSubCatRepo.create({ ...data, projectId: internalId });
|
||||
return this.cdSubCatRepo.save(subCat);
|
||||
}
|
||||
|
||||
@@ -124,8 +154,9 @@ export class DrawingMasterDataService {
|
||||
// Contract Drawing Mappings (Category <-> Sub-Category)
|
||||
// =====================================================
|
||||
|
||||
async findContractMappings(projectId: number, categoryId?: number) {
|
||||
const where: FindOptionsWhere<ContractDrawingSubcatCatMap> = { projectId };
|
||||
async findContractMappings(projectId: number | string, categoryId?: number) {
|
||||
const internalId = await this.resolveProjectId(projectId);
|
||||
const where: FindOptionsWhere<ContractDrawingSubcatCatMap> = { projectId: internalId };
|
||||
if (categoryId) {
|
||||
where.categoryId = categoryId;
|
||||
}
|
||||
@@ -136,15 +167,12 @@ export class DrawingMasterDataService {
|
||||
});
|
||||
}
|
||||
|
||||
async createContractMapping(data: {
|
||||
projectId: number;
|
||||
categoryId: number;
|
||||
subCategoryId: number;
|
||||
}) {
|
||||
async createContractMapping(data: any) {
|
||||
const internalId = await this.resolveProjectId(data.projectId);
|
||||
// Check if mapping already exists to prevent duplicates (though DB has UNIQUE constraint)
|
||||
const existing = await this.cdMapRepo.findOne({
|
||||
where: {
|
||||
projectId: data.projectId,
|
||||
projectId: internalId,
|
||||
categoryId: data.categoryId,
|
||||
subCategoryId: data.subCategoryId,
|
||||
},
|
||||
@@ -152,7 +180,7 @@ export class DrawingMasterDataService {
|
||||
|
||||
if (existing) return existing;
|
||||
|
||||
const map = this.cdMapRepo.create(data);
|
||||
const map = this.cdMapRepo.create({ ...data, projectId: internalId });
|
||||
return this.cdMapRepo.save(map);
|
||||
}
|
||||
|
||||
@@ -167,15 +195,17 @@ export class DrawingMasterDataService {
|
||||
// Shop Drawing Main Categories
|
||||
// =====================================================
|
||||
|
||||
async findAllShopMainCats(projectId: number) {
|
||||
async findAllShopMainCats(projectId: number | string) {
|
||||
const internalId = await this.resolveProjectId(projectId);
|
||||
return this.sdMainCatRepo.find({
|
||||
where: { projectId },
|
||||
where: { projectId: internalId },
|
||||
order: { sortOrder: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
async createShopMainCat(data: Partial<ShopDrawingMainCategory>) {
|
||||
const cat = this.sdMainCatRepo.create(data);
|
||||
async createShopMainCat(data: any) {
|
||||
const internalId = await this.resolveProjectId(data.projectId);
|
||||
const cat = this.sdMainCatRepo.create({ ...data, projectId: internalId });
|
||||
return this.sdMainCatRepo.save(cat);
|
||||
}
|
||||
|
||||
@@ -197,9 +227,10 @@ export class DrawingMasterDataService {
|
||||
// Shop Drawing Sub-Categories
|
||||
// =====================================================
|
||||
|
||||
async findAllShopSubCats(projectId: number, mainCategoryId?: number) {
|
||||
async findAllShopSubCats(projectId: number | string, mainCategoryId?: number) {
|
||||
const internalId = await this.resolveProjectId(projectId);
|
||||
const where: FindOptionsWhere<ShopDrawingSubCategory> = {
|
||||
projectId,
|
||||
projectId: internalId,
|
||||
...(mainCategoryId ? { mainCategoryId } : {}),
|
||||
};
|
||||
|
||||
@@ -209,8 +240,9 @@ export class DrawingMasterDataService {
|
||||
});
|
||||
}
|
||||
|
||||
async createShopSubCat(data: Partial<ShopDrawingSubCategory>) {
|
||||
const subCat = this.sdSubCatRepo.create(data);
|
||||
async createShopSubCat(data: any) {
|
||||
const internalId = await this.resolveProjectId(data.projectId);
|
||||
const subCat = this.sdSubCatRepo.create({ ...data, projectId: internalId });
|
||||
return this.sdSubCatRepo.save(subCat);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,151 +13,78 @@ import {
|
||||
UseGuards,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiQuery } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth, ApiQuery } from '@nestjs/swagger';
|
||||
import { MasterService } from './master.service';
|
||||
|
||||
// DTOs (สมมติว่ามีการสร้างไฟล์เหล่านี้แล้วตามแผนงาน)
|
||||
import { CreateTagDto } from './dto/create-tag.dto';
|
||||
import { UpdateTagDto } from './dto/update-tag.dto';
|
||||
import { SearchTagDto } from './dto/search-tag.dto';
|
||||
import { CreateDisciplineDto } from './dto/create-discipline.dto'; // [New]
|
||||
import { CreateSubTypeDto } from './dto/create-sub-type.dto'; // [New]
|
||||
import { SaveNumberFormatDto } from './dto/save-number-format.dto'; // [New]
|
||||
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
||||
import { RbacGuard } from '../../common/guards/rbac.guard';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator';
|
||||
import { CurrentUser } from '../../common/decorators/current-user.decorator';
|
||||
|
||||
// Import DTOs
|
||||
import { CreateTagDto } from './dto/create-tag.dto';
|
||||
import { UpdateTagDto } from './dto/update-tag.dto';
|
||||
import { SearchTagDto } from './dto/search-tag.dto';
|
||||
|
||||
@ApiTags('Master Data')
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, RbacGuard)
|
||||
@Controller('master')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class MasterController {
|
||||
constructor(private readonly masterService: MasterService) {}
|
||||
|
||||
// =================================================================
|
||||
// 📦 Common Dropdowns (Read-Only)
|
||||
// =================================================================
|
||||
|
||||
// --- Correspondence Types ---
|
||||
@Get('correspondence-types')
|
||||
@ApiOperation({ summary: 'Get all active correspondence types' })
|
||||
getCorrespondenceTypes() {
|
||||
@ApiOperation({ summary: 'Get all correspondence types' })
|
||||
findAllCorrespondenceTypes() {
|
||||
return this.masterService.findAllCorrespondenceTypes();
|
||||
}
|
||||
|
||||
@Post('correspondence-types')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Create Correspondence Type' })
|
||||
createCorrespondenceType(@Body() dto: any) {
|
||||
return this.masterService.createCorrespondenceType(dto);
|
||||
}
|
||||
|
||||
@Patch('correspondence-types/:id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Update Correspondence Type' })
|
||||
updateCorrespondenceType(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: any
|
||||
) {
|
||||
return this.masterService.updateCorrespondenceType(id, dto);
|
||||
}
|
||||
|
||||
@Delete('correspondence-types/:id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Delete Correspondence Type' })
|
||||
deleteCorrespondenceType(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.masterService.deleteCorrespondenceType(id);
|
||||
}
|
||||
|
||||
@Get('correspondence-statuses')
|
||||
@ApiOperation({ summary: 'Get all active correspondence statuses' })
|
||||
getCorrespondenceStatuses() {
|
||||
return this.masterService.findAllCorrespondenceStatuses();
|
||||
}
|
||||
|
||||
// --- RFA Types ---
|
||||
@Get('rfa-types')
|
||||
@ApiOperation({ summary: 'Get all active RFA types' })
|
||||
@ApiQuery({ name: 'contractId', required: false, type: Number })
|
||||
getRfaTypes(@Query('contractId') contractId?: number) {
|
||||
@ApiOperation({ summary: 'Get all RFA types' })
|
||||
@ApiQuery({ name: 'contractId', required: false, type: String })
|
||||
findAllRfaTypes(@Query('contractId') contractId?: string | number) {
|
||||
return this.masterService.findAllRfaTypes(contractId);
|
||||
}
|
||||
|
||||
@Post('rfa-types')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Create RFA Type' })
|
||||
createRfaType(@Body() dto: any) {
|
||||
// Note: Should use proper DTO. Delegating to service.
|
||||
// Need to add createRfaType to MasterService or RfaService?
|
||||
// Given the context, MasterService seems appropriate for "Reference Data".
|
||||
return this.masterService.createRfaType(dto);
|
||||
}
|
||||
|
||||
@Patch('rfa-types/:id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Update RFA Type' })
|
||||
updateRfaType(@Param('id', ParseIntPipe) id: number, @Body() dto: any) {
|
||||
return this.masterService.updateRfaType(id, dto);
|
||||
}
|
||||
|
||||
@Delete('rfa-types/:id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Delete RFA Type' })
|
||||
deleteRfaType(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.masterService.deleteRfaType(id);
|
||||
}
|
||||
|
||||
@Get('rfa-statuses')
|
||||
@ApiOperation({ summary: 'Get all active RFA status codes' })
|
||||
getRfaStatuses() {
|
||||
return this.masterService.findAllRfaStatuses();
|
||||
}
|
||||
|
||||
@Get('rfa-approve-codes')
|
||||
@ApiOperation({ summary: 'Get all active RFA approve codes' })
|
||||
getRfaApproveCodes() {
|
||||
return this.masterService.findAllRfaApproveCodes();
|
||||
}
|
||||
|
||||
@Get('circulation-statuses')
|
||||
@ApiOperation({ summary: 'Get all active circulation statuses' })
|
||||
getCirculationStatuses() {
|
||||
return this.masterService.findAllCirculationStatuses();
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 🏗️ Disciplines Management (Req 6B)
|
||||
// =================================================================
|
||||
|
||||
// --- Disciplines ---
|
||||
@Get('disciplines')
|
||||
@ApiOperation({ summary: 'Get disciplines (filter by contract optional)' })
|
||||
@ApiQuery({ name: 'contractId', required: false, type: Number })
|
||||
getDisciplines(@Query('contractId') contractId?: number) {
|
||||
@ApiOperation({ summary: 'Get all disciplines' })
|
||||
@ApiQuery({ name: 'contractId', required: false, type: String })
|
||||
findAllDisciplines(@Query('contractId') contractId?: string | number) {
|
||||
return this.masterService.findAllDisciplines(contractId);
|
||||
}
|
||||
|
||||
@Post('disciplines')
|
||||
@RequirePermission('master_data.manage') // สิทธิ์ Admin
|
||||
@ApiOperation({ summary: 'Create a new discipline' })
|
||||
createDiscipline(@Body() dto: CreateDisciplineDto) {
|
||||
@RequirePermission('master_data.manage')
|
||||
createDiscipline(@Body() dto: any) {
|
||||
return this.masterService.createDiscipline(dto);
|
||||
}
|
||||
|
||||
@Delete('disciplines/:id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Delete a discipline' })
|
||||
deleteDiscipline(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.masterService.deleteDiscipline(id);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 📑 Correspondence Sub-Types (Req 6B)
|
||||
// =================================================================
|
||||
|
||||
// --- Sub Types ---
|
||||
@Get('sub-types')
|
||||
@ApiOperation({ summary: 'Get sub-types (filter by contract/type optional)' })
|
||||
@ApiQuery({ name: 'contractId', required: false, type: Number })
|
||||
@ApiQuery({ name: 'typeId', required: false, type: Number })
|
||||
getSubTypes(
|
||||
@Query('contractId') contractId?: number,
|
||||
@ApiOperation({ summary: 'Get all sub-types' })
|
||||
@ApiQuery({ name: 'contractId', required: false, type: String })
|
||||
findAllSubTypes(
|
||||
@Query('contractId') contractId?: string | number,
|
||||
@Query('typeId') typeId?: number
|
||||
) {
|
||||
return this.masterService.findAllSubTypes(contractId, typeId);
|
||||
@@ -165,62 +92,43 @@ export class MasterController {
|
||||
|
||||
@Post('sub-types')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Create/Map a new sub-type' })
|
||||
createSubType(@Body() dto: CreateSubTypeDto) {
|
||||
createSubType(@Body() dto: any) {
|
||||
return this.masterService.createSubType(dto);
|
||||
}
|
||||
|
||||
@Delete('sub-types/:id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Delete a sub-type' })
|
||||
deleteSubType(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.masterService.deleteSubType(id);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 🔢 Numbering Formats (Admin Config)
|
||||
// =================================================================
|
||||
|
||||
// --- Numbering Formats ---
|
||||
@Get('numbering-formats')
|
||||
@RequirePermission('master_data.manage') // ข้อมูล config ควรสงวนสิทธิ์
|
||||
@ApiOperation({ summary: 'Get numbering format for specific project/type' })
|
||||
getNumberFormat(
|
||||
@Query('projectId', ParseIntPipe) projectId: number,
|
||||
@ApiOperation({ summary: 'Get numbering format for project/type' })
|
||||
findNumberFormat(
|
||||
@Query('projectId') projectId: string | number,
|
||||
@Query('typeId', ParseIntPipe) typeId: number
|
||||
) {
|
||||
return this.masterService.findNumberFormat(projectId, typeId);
|
||||
}
|
||||
|
||||
@Post('numbering-formats')
|
||||
@RequirePermission('system.manage_all') // เฉพาะ Superadmin/System Admin
|
||||
@ApiOperation({ summary: 'Save or Update numbering format template' })
|
||||
saveNumberFormat(@Body() dto: SaveNumberFormatDto) {
|
||||
@RequirePermission('master_data.manage')
|
||||
saveNumberFormat(@Body() dto: any) {
|
||||
return this.masterService.saveNumberFormat(dto);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 🏷️ Tag Management
|
||||
// =================================================================
|
||||
|
||||
// --- Tags ---
|
||||
@Get('tags')
|
||||
@ApiOperation({ summary: 'Get all tags (supports search & pagination)' })
|
||||
getTags(@Query() query: SearchTagDto) {
|
||||
@ApiOperation({ summary: 'Get all tags' })
|
||||
findAllTags(@Query() query: SearchTagDto) {
|
||||
return this.masterService.findAllTags(query);
|
||||
}
|
||||
|
||||
@Get('tags/:id')
|
||||
@ApiOperation({ summary: 'Get a tag by ID' })
|
||||
getTagById(@Param('id', ParseIntPipe) id: number) {
|
||||
findOneTag(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.masterService.findOneTag(id);
|
||||
}
|
||||
|
||||
@Post('tags')
|
||||
@RequirePermission('master_data.tag.manage')
|
||||
@ApiOperation({ summary: 'Create a new tag' })
|
||||
createTag(
|
||||
@CurrentUser() user: { userId: number },
|
||||
@Body() dto: CreateTagDto
|
||||
) {
|
||||
createTag(@Body() dto: CreateTagDto, @CurrentUser() user: any) {
|
||||
return this.masterService.createTag(dto, user.userId);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
NotFoundException,
|
||||
ConflictException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { InjectRepository, InjectEntityManager } from '@nestjs/typeorm';
|
||||
import { Repository, EntityManager } from 'typeorm';
|
||||
|
||||
// Import Entities
|
||||
import { CorrespondenceType } from '../correspondence/entities/correspondence-type.entity';
|
||||
@@ -21,6 +21,8 @@ import { Tag } from './entities/tag.entity';
|
||||
import { Discipline } from './entities/discipline.entity';
|
||||
import { CorrespondenceSubType } from '../correspondence/entities/correspondence-sub-type.entity';
|
||||
import { DocumentNumberFormat } from '../document-numbering/entities/document-number-format.entity';
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
import { Contract } from '../contract/entities/contract.entity';
|
||||
|
||||
// Import DTOs
|
||||
import { CreateTagDto } from './dto/create-tag.dto';
|
||||
@@ -54,12 +56,41 @@ export class MasterService {
|
||||
@InjectRepository(CorrespondenceSubType)
|
||||
private readonly subTypeRepo: Repository<CorrespondenceSubType>,
|
||||
@InjectRepository(DocumentNumberFormat)
|
||||
private readonly formatRepo: Repository<DocumentNumberFormat>
|
||||
private readonly formatRepo: Repository<DocumentNumberFormat>,
|
||||
|
||||
@InjectEntityManager()
|
||||
private readonly entityManager: EntityManager
|
||||
) {}
|
||||
|
||||
// ... (Method เดิม: findAllCorrespondenceTypes, findAllCorrespondenceStatuses, ฯลฯ เก็บไว้เหมือนเดิม) ...
|
||||
// หมายเหตุ: ตรวจสอบว่า Entity ใช้ชื่อ property ว่า isActive หรือ is_active (ใน SQL เป็น is_active แต่ใน Entity มักเป็น isActive)
|
||||
// โค้ดเดิมใช้ `where: { isActive: true }` ซึ่งถูกต้องถ้า Entity map column name แล้ว
|
||||
/**
|
||||
* Helper to resolve projectId (ID or UUID) to internal INT ID
|
||||
*/
|
||||
async resolveProjectId(projectId: number | string): Promise<number> {
|
||||
if (typeof projectId === 'number') return projectId;
|
||||
const num = Number(projectId);
|
||||
if (!isNaN(num)) return num;
|
||||
const project = await this.entityManager.findOne(Project, {
|
||||
where: { uuid: projectId as string },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!project) throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
return project.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to resolve contractId (ID or UUID) to internal INT ID
|
||||
*/
|
||||
async resolveContractId(contractId: number | string): Promise<number> {
|
||||
if (typeof contractId === 'number') return contractId;
|
||||
const num = Number(contractId);
|
||||
if (!isNaN(num)) return num;
|
||||
const contract = await this.entityManager.findOne(Contract, {
|
||||
where: { uuid: contractId as string },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!contract) throw new NotFoundException(`Contract with UUID ${contractId} not found`);
|
||||
return contract.id;
|
||||
}
|
||||
|
||||
async findAllCorrespondenceTypes() {
|
||||
return this.corrTypeRepo.find({
|
||||
@@ -92,27 +123,29 @@ export class MasterService {
|
||||
order: { sortOrder: 'ASC' },
|
||||
});
|
||||
}
|
||||
async findAllRfaTypes(contractId?: number) {
|
||||
async findAllRfaTypes(contractId?: number | string) {
|
||||
const where: any = { isActive: true };
|
||||
if (contractId) {
|
||||
where.contractId = contractId;
|
||||
where.contractId = await this.resolveContractId(contractId);
|
||||
}
|
||||
return this.rfaTypeRepo.find({
|
||||
where,
|
||||
order: { typeCode: 'ASC' },
|
||||
relations: contractId ? [] : [], // Add relations if needed later
|
||||
});
|
||||
}
|
||||
|
||||
async createRfaType(dto: any) {
|
||||
// Validate unique code if needed
|
||||
const rfaType = this.rfaTypeRepo.create(dto);
|
||||
const internalContractId = await this.resolveContractId(dto.contractId);
|
||||
const rfaType = this.rfaTypeRepo.create({ ...dto, contractId: internalContractId });
|
||||
return this.rfaTypeRepo.save(rfaType);
|
||||
}
|
||||
|
||||
async updateRfaType(id: number, dto: any) {
|
||||
const rfaType = await this.rfaTypeRepo.findOne({ where: { id } });
|
||||
if (!rfaType) throw new NotFoundException('RFA Type not found');
|
||||
if (dto.contractId) {
|
||||
dto.contractId = await this.resolveContractId(dto.contractId);
|
||||
}
|
||||
Object.assign(rfaType, dto);
|
||||
return this.rfaTypeRepo.save(rfaType);
|
||||
}
|
||||
@@ -146,31 +179,32 @@ export class MasterService {
|
||||
// 🏗️ Disciplines Logic
|
||||
// =================================================================
|
||||
|
||||
async findAllDisciplines(contractId?: number) {
|
||||
async findAllDisciplines(contractId?: number | string) {
|
||||
const query = this.disciplineRepo
|
||||
.createQueryBuilder('d')
|
||||
.leftJoinAndSelect('d.contract', 'c')
|
||||
.orderBy('d.disciplineCode', 'ASC');
|
||||
|
||||
if (contractId) {
|
||||
query.where('d.contractId = :contractId', { contractId });
|
||||
const internalId = await this.resolveContractId(contractId);
|
||||
query.where('d.contractId = :contractId', { contractId: internalId });
|
||||
}
|
||||
// เพิ่มเงื่อนไข Active หากต้องการ
|
||||
query.andWhere('d.isActive = :isActive', { isActive: true });
|
||||
|
||||
return query.getMany();
|
||||
}
|
||||
|
||||
async createDiscipline(dto: CreateDisciplineDto) {
|
||||
async createDiscipline(dto: any) {
|
||||
const internalContractId = await this.resolveContractId(dto.contractId);
|
||||
const exists = await this.disciplineRepo.findOne({
|
||||
where: { contractId: dto.contractId, disciplineCode: dto.disciplineCode },
|
||||
where: { contractId: internalContractId, disciplineCode: dto.disciplineCode },
|
||||
});
|
||||
if (exists)
|
||||
throw new ConflictException(
|
||||
'Discipline code already exists in this contract'
|
||||
);
|
||||
|
||||
const discipline = this.disciplineRepo.create(dto);
|
||||
const discipline = this.disciplineRepo.create({ ...dto, contractId: internalContractId });
|
||||
return this.disciplineRepo.save(discipline);
|
||||
}
|
||||
|
||||
@@ -185,23 +219,25 @@ export class MasterService {
|
||||
// 📑 Sub-Types Logic
|
||||
// =================================================================
|
||||
|
||||
async findAllSubTypes(contractId?: number, typeId?: number) {
|
||||
async findAllSubTypes(contractId?: number | string, typeId?: number) {
|
||||
const query = this.subTypeRepo
|
||||
.createQueryBuilder('st')
|
||||
.leftJoinAndSelect('st.contract', 'c')
|
||||
.leftJoinAndSelect('st.correspondenceType', 'ct')
|
||||
.orderBy('st.subTypeCode', 'ASC');
|
||||
|
||||
if (contractId)
|
||||
query.andWhere('st.contractId = :contractId', { contractId });
|
||||
if (contractId) {
|
||||
const internalId = await this.resolveContractId(contractId);
|
||||
query.andWhere('st.contractId = :contractId', { contractId: internalId });
|
||||
}
|
||||
if (typeId) query.andWhere('st.correspondenceTypeId = :typeId', { typeId });
|
||||
|
||||
return query.getMany();
|
||||
}
|
||||
|
||||
async createSubType(dto: CreateSubTypeDto) {
|
||||
// อาจจะเช็ค Duplicate code ด้วย logic คล้าย discipline
|
||||
const subType = this.subTypeRepo.create(dto);
|
||||
async createSubType(dto: any) {
|
||||
const internalContractId = await this.resolveContractId(dto.contractId);
|
||||
const subType = this.subTypeRepo.create({ ...dto, contractId: internalContractId });
|
||||
return this.subTypeRepo.save(subType);
|
||||
}
|
||||
|
||||
@@ -216,47 +252,43 @@ export class MasterService {
|
||||
// 🔢 Numbering Formats Logic
|
||||
// =================================================================
|
||||
|
||||
async findNumberFormat(projectId: number, typeId: number) {
|
||||
async findNumberFormat(projectId: number | string, typeId: number) {
|
||||
const internalId = await this.resolveProjectId(projectId);
|
||||
const format = await this.formatRepo.findOne({
|
||||
where: { projectId, correspondenceTypeId: typeId },
|
||||
where: { projectId: internalId, correspondenceTypeId: typeId },
|
||||
});
|
||||
if (!format) {
|
||||
// Optional: Return default format structure or null
|
||||
return null;
|
||||
}
|
||||
return format;
|
||||
return format || null;
|
||||
}
|
||||
|
||||
async saveNumberFormat(dto: SaveNumberFormatDto) {
|
||||
// Check if exists (Upsert)
|
||||
async saveNumberFormat(dto: any) {
|
||||
const internalProjectId = await this.resolveProjectId(dto.projectId);
|
||||
let format = await this.formatRepo.findOne({
|
||||
where: {
|
||||
projectId: dto.projectId,
|
||||
projectId: internalProjectId,
|
||||
correspondenceTypeId: dto.correspondenceTypeId,
|
||||
},
|
||||
});
|
||||
|
||||
if (format) {
|
||||
format.formatTemplate = dto.formatTemplate;
|
||||
// format.updatedBy = ... (ถ้ามี)
|
||||
} else {
|
||||
format = this.formatRepo.create({
|
||||
projectId: dto.projectId,
|
||||
correspondenceTypeId: dto.correspondenceTypeId,
|
||||
formatTemplate: dto.formatTemplate,
|
||||
...dto,
|
||||
projectId: internalProjectId,
|
||||
});
|
||||
}
|
||||
|
||||
return this.formatRepo.save(format);
|
||||
}
|
||||
|
||||
// ... (Tag Logic เดิม คงไว้ตามปกติ) ...
|
||||
async findAllTags(query?: SearchTagDto) {
|
||||
const qb = this.tagRepo.createQueryBuilder('tag');
|
||||
|
||||
if (query?.project_id) {
|
||||
// In Tags, we use project_id (INT) directly or resolve if UUID passed via query
|
||||
const internalId = await this.resolveProjectId(query.project_id);
|
||||
qb.andWhere('tag.project_id = :projectId', {
|
||||
projectId: query.project_id,
|
||||
projectId: internalId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -288,16 +320,21 @@ export class MasterService {
|
||||
return tag;
|
||||
}
|
||||
|
||||
async createTag(dto: CreateTagDto, userId: number) {
|
||||
async createTag(dto: any, userId: number) {
|
||||
const internalProjectId = dto.project_id ? await this.resolveProjectId(dto.project_id) : null;
|
||||
const tag = this.tagRepo.create({
|
||||
...dto,
|
||||
project_id: internalProjectId,
|
||||
created_by: userId,
|
||||
});
|
||||
return this.tagRepo.save(tag);
|
||||
}
|
||||
|
||||
async updateTag(id: number, dto: UpdateTagDto) {
|
||||
async updateTag(id: number, dto: any) {
|
||||
const tag = await this.findOneTag(id);
|
||||
if (dto.project_id) {
|
||||
dto.project_id = await this.resolveProjectId(dto.project_id);
|
||||
}
|
||||
Object.assign(tag, dto);
|
||||
return this.tagRepo.save(tag);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
BeforeInsert,
|
||||
} from 'typeorm';
|
||||
import { v7 as uuidv7 } from 'uuid';
|
||||
import { Exclude } from 'class-transformer';
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||
import { Contract } from '../../contract/entities/contract.entity';
|
||||
|
||||
@@ -16,6 +16,7 @@ export class Project extends BaseEntity {
|
||||
@Exclude()
|
||||
id!: number;
|
||||
|
||||
@Expose({ name: 'id' })
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
unique: true,
|
||||
|
||||
Reference in New Issue
Block a user