260318:1237 Fix UUID #4
Build and Deploy / deploy (push) Successful in 11m17s

This commit is contained in:
admin
2026-03-18 12:37:29 +07:00
parent 5d89079c2a
commit ba642e7e42
71 changed files with 533 additions and 319 deletions
@@ -88,14 +88,31 @@ export class DocumentNumberingController {
})
@RequirePermission('correspondence.read')
async previewNumber(@Body() dto: PreviewNumberDto) {
// ADR-019: Resolve UUID→INT for project and organization IDs
const resolvedProjectId = await this.numberingService.resolveIdForPreview(
'project',
dto.projectId
);
const resolvedOriginatorId =
await this.numberingService.resolveIdForPreview(
'organization',
dto.originatorOrganizationId
);
const resolvedRecipientId = dto.recipientOrganizationId
? await this.numberingService.resolveIdForPreview(
'organization',
dto.recipientOrganizationId
)
: undefined;
return this.numberingService.previewNumber({
projectId: dto.projectId,
originatorOrganizationId: dto.originatorOrganizationId,
projectId: resolvedProjectId,
originatorOrganizationId: resolvedOriginatorId,
typeId: dto.correspondenceTypeId,
subTypeId: dto.subTypeId,
rfaTypeId: dto.rfaTypeId,
disciplineId: dto.disciplineId,
recipientOrganizationId: dto.recipientOrganizationId,
recipientOrganizationId: resolvedRecipientId,
year: dto.year,
customTokens: dto.customTokens,
});
@@ -1,18 +1,16 @@
// File: src/modules/document-numbering/dto/preview-number.dto.ts
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsInt, IsOptional, IsObject } from 'class-validator';
import { IsInt, IsNotEmpty, IsOptional, IsObject } from 'class-validator';
import { Type } from 'class-transformer';
export class PreviewNumberDto {
@ApiProperty({ description: 'Project ID' })
@IsInt()
@Type(() => Number)
projectId!: number;
@ApiProperty({ description: 'Project ID or UUID' })
@IsNotEmpty()
projectId!: number | string;
@ApiProperty({ description: 'Originator organization ID' })
@IsInt()
@Type(() => Number)
originatorOrganizationId!: number;
@ApiProperty({ description: 'Originator organization ID or UUID' })
@IsNotEmpty()
originatorOrganizationId!: number | string;
@ApiProperty({ description: 'Correspondence type ID' })
@IsInt()
@@ -43,11 +41,9 @@ export class PreviewNumberDto {
@Type(() => Number)
year?: number;
@ApiPropertyOptional({ description: 'Recipient organization ID' })
@ApiPropertyOptional({ description: 'Recipient organization ID or UUID' })
@IsOptional()
@IsInt()
@Type(() => Number)
recipientOrganizationId?: number;
recipientOrganizationId?: number | string;
@ApiPropertyOptional({ description: 'Custom tokens' })
@IsOptional()
@@ -26,6 +26,7 @@ import { GenerateNumberContext } from '../interfaces/document-numbering.interfac
import { ReserveNumberDto } from '../dto/reserve-number.dto';
import { ConfirmReservationDto } from '../dto/confirm-reservation.dto';
import { Project } from '../../project/entities/project.entity';
import { Organization } from '../../organization/entities/organization.entity';
@Injectable()
export class DocumentNumberingService {
@@ -66,6 +67,33 @@ export class DocumentNumberingService {
return project.id;
}
/**
* ADR-019: Public facade for controllers to resolve project/organization IDs
*/
async resolveIdForPreview(
type: 'project' | 'organization',
id: number | string
): Promise<number> {
if (type === 'project') return this.resolveProjectId(id);
return this.resolveOrganizationId(id);
}
/**
* ADR-019: Resolve organizationId (INT or UUID string) to internal INT ID
*/
private async resolveOrganizationId(orgId: number | string): Promise<number> {
if (typeof orgId === 'number') return orgId;
const num = Number(orgId);
if (!isNaN(num)) return num;
const org = await this.entityManager.findOne(Organization, {
where: { uuid: orgId },
select: ['id'],
});
if (!org)
throw new NotFoundException(`Organization with UUID ${orgId} not found`);
return org.id;
}
async generateNextNumber(
ctx: GenerateNumberContext
): Promise<{ number: string; auditId: number }> {