This commit is contained in:
@@ -14,6 +14,8 @@ import { CreateCirculationDto } from './dto/create-circulation.dto';
|
||||
import { UpdateCirculationRoutingDto } from './dto/update-circulation-routing.dto';
|
||||
import { SearchCirculationDto } from './dto/search-circulation.dto';
|
||||
import { DocumentNumberingService } from '../document-numbering/services/document-numbering.service';
|
||||
import { Project } from '../project/entities/project.entity';
|
||||
import { Correspondence } from '../correspondence/entities/correspondence.entity';
|
||||
|
||||
@Injectable()
|
||||
export class CirculationService {
|
||||
@@ -26,6 +28,58 @@ export class CirculationService {
|
||||
private dataSource: DataSource
|
||||
) {}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve projectId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private 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.dataSource.manager.findOne(Project, {
|
||||
where: { uuid: projectId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!project)
|
||||
throw new NotFoundException(`Project with UUID ${projectId} not found`);
|
||||
return project.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve correspondenceId (INT or UUID string) to internal INT ID
|
||||
*/
|
||||
private async resolveCorrespondenceId(
|
||||
corrId: number | string
|
||||
): Promise<number> {
|
||||
if (typeof corrId === 'number') return corrId;
|
||||
const num = Number(corrId);
|
||||
if (!isNaN(num)) return num;
|
||||
const corr = await this.dataSource.manager.findOne(Correspondence, {
|
||||
where: { uuid: corrId },
|
||||
select: ['id'],
|
||||
});
|
||||
if (!corr)
|
||||
throw new NotFoundException(
|
||||
`Correspondence with UUID ${corrId} not found`
|
||||
);
|
||||
return corr.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADR-019: Resolve userId (INT or UUID string) to internal user_id
|
||||
*/
|
||||
private async resolveUserId(userId: number | string): Promise<number> {
|
||||
if (typeof userId === 'number') return userId;
|
||||
const num = Number(userId);
|
||||
if (!isNaN(num)) return num;
|
||||
const user = await this.dataSource.manager.findOne(User, {
|
||||
where: { uuid: userId },
|
||||
select: ['user_id'],
|
||||
});
|
||||
if (!user)
|
||||
throw new NotFoundException(`User with UUID ${userId} not found`);
|
||||
return user.user_id;
|
||||
}
|
||||
|
||||
async create(createDto: CreateCirculationDto, user: User) {
|
||||
if (!user.primaryOrganizationId) {
|
||||
throw new BadRequestException('User must belong to an organization');
|
||||
@@ -36,9 +90,20 @@ export class CirculationService {
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
try {
|
||||
// ADR-019: Resolve UUID references to internal INT IDs
|
||||
const resolvedProjectId = createDto.projectId
|
||||
? await this.resolveProjectId(createDto.projectId)
|
||||
: 0;
|
||||
const resolvedCorrId = await this.resolveCorrespondenceId(
|
||||
createDto.correspondenceId
|
||||
);
|
||||
const resolvedAssigneeIds = await Promise.all(
|
||||
createDto.assigneeIds.map((id) => this.resolveUserId(id))
|
||||
);
|
||||
|
||||
// Generate No. using DocumentNumberingService (Type 900 - Circulation)
|
||||
const result = await this.numberingService.generateNextNumber({
|
||||
projectId: createDto.projectId || 0, // Use projectId from DTO or 0
|
||||
projectId: resolvedProjectId,
|
||||
originatorOrganizationId: user.primaryOrganizationId,
|
||||
typeId: 900, // Fixed Type ID for Circulation
|
||||
year: new Date().getFullYear(),
|
||||
@@ -50,7 +115,7 @@ export class CirculationService {
|
||||
|
||||
const circulation = queryRunner.manager.create(Circulation, {
|
||||
organizationId: user.primaryOrganizationId,
|
||||
correspondenceId: createDto.correspondenceId,
|
||||
correspondenceId: resolvedCorrId,
|
||||
circulationNo: result.number,
|
||||
subject: createDto.subject,
|
||||
statusCode: 'OPEN',
|
||||
@@ -58,13 +123,13 @@ export class CirculationService {
|
||||
});
|
||||
const savedCirculation = await queryRunner.manager.save(circulation);
|
||||
|
||||
if (createDto.assigneeIds && createDto.assigneeIds.length > 0) {
|
||||
const routings = createDto.assigneeIds.map((userId, index) =>
|
||||
if (resolvedAssigneeIds.length > 0) {
|
||||
const routings = resolvedAssigneeIds.map((assigneeId, index) =>
|
||||
queryRunner.manager.create(CirculationRouting, {
|
||||
circulationId: savedCirculation.id,
|
||||
stepNumber: index + 1,
|
||||
organizationId: user.primaryOrganizationId,
|
||||
assignedTo: userId,
|
||||
assignedTo: assigneeId,
|
||||
status: 'PENDING',
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
import {
|
||||
IsInt,
|
||||
IsString,
|
||||
IsNotEmpty,
|
||||
IsArray,
|
||||
IsOptional,
|
||||
ArrayMinSize, // ✅ เพิ่ม
|
||||
ArrayMinSize,
|
||||
} from 'class-validator';
|
||||
|
||||
export class CreateCirculationDto {
|
||||
@IsInt()
|
||||
@IsNotEmpty()
|
||||
correspondenceId!: number; // เอกสารต้นเรื่องที่จะเวียน
|
||||
correspondenceId!: number | string; // เอกสารต้นเรื่องที่จะเวียน (INT or UUID)
|
||||
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
projectId?: number; // Project ID for Numbering
|
||||
projectId?: number | string; // Project ID or UUID for Numbering
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
subject!: string; // หัวข้อเรื่อง (Subject)
|
||||
|
||||
@IsArray()
|
||||
@IsInt({ each: true })
|
||||
@ArrayMinSize(1) // ✅ ต้องมีผู้รับอย่างน้อย 1 คน
|
||||
assigneeIds!: number[]; // รายชื่อ User ID ที่ต้องการส่งให้ (ผู้รับผิดชอบ)
|
||||
assigneeIds!: (number | string)[]; // รายชื่อ User ID or UUID ที่ต้องการส่งให้ (ADR-019)
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
|
||||
Reference in New Issue
Block a user