260321:1700 Correct Coresspondence / Doing RFA
This commit is contained in:
+7
-7
@@ -32,7 +32,7 @@ export class DocumentNumberingAdminController {
|
||||
|
||||
@Get('templates')
|
||||
@ApiOperation({ summary: 'Get all document numbering templates' })
|
||||
@RequirePermission('system.manage_settings')
|
||||
@RequirePermission('numbering.view_formats')
|
||||
async getTemplates(@Query('projectId') projectId?: number) {
|
||||
if (projectId) {
|
||||
return this.service.getTemplatesByProject(projectId);
|
||||
@@ -42,7 +42,7 @@ export class DocumentNumberingAdminController {
|
||||
|
||||
@Post('templates')
|
||||
@ApiOperation({ summary: 'Create or Update a numbering template' })
|
||||
@RequirePermission('system.manage_settings')
|
||||
@RequirePermission('numbering.manage_formats')
|
||||
async saveTemplate(
|
||||
@Body() dto: Partial<DocumentNumberFormat> & { projectId?: number | string }
|
||||
) {
|
||||
@@ -51,7 +51,7 @@ export class DocumentNumberingAdminController {
|
||||
|
||||
@Delete('templates/:id')
|
||||
@ApiOperation({ summary: 'Delete a numbering template' })
|
||||
@RequirePermission('system.manage_settings')
|
||||
@RequirePermission('numbering.manage_formats')
|
||||
async deleteTemplate(@Param('id', ParseIntPipe) id: number) {
|
||||
await this.service.deleteTemplate(id);
|
||||
return { success: true };
|
||||
@@ -78,7 +78,7 @@ export class DocumentNumberingAdminController {
|
||||
@ApiOperation({
|
||||
summary: 'Manually override or set a document number counter',
|
||||
})
|
||||
@RequirePermission('system.manage_settings')
|
||||
@RequirePermission('numbering.manage_formats')
|
||||
async manualOverride(
|
||||
@Body() dto: ManualOverrideDto,
|
||||
@CurrentUser() user: User
|
||||
@@ -88,7 +88,7 @@ export class DocumentNumberingAdminController {
|
||||
|
||||
@Post('void-and-replace')
|
||||
@ApiOperation({ summary: 'Void a number and replace with a new generation' })
|
||||
@RequirePermission('system.manage_settings')
|
||||
@RequirePermission('numbering.manage_formats')
|
||||
async voidAndReplace(
|
||||
@Body()
|
||||
dto: {
|
||||
@@ -104,7 +104,7 @@ export class DocumentNumberingAdminController {
|
||||
|
||||
@Post('cancel')
|
||||
@ApiOperation({ summary: 'Cancel/Skip a specific document number' })
|
||||
@RequirePermission('system.manage_settings')
|
||||
@RequirePermission('numbering.manage_formats')
|
||||
async cancelNumber(
|
||||
@Body()
|
||||
dto: {
|
||||
@@ -119,7 +119,7 @@ export class DocumentNumberingAdminController {
|
||||
|
||||
@Post('bulk-import')
|
||||
@ApiOperation({ summary: 'Bulk import/set document number counters' })
|
||||
@RequirePermission('system.manage_settings')
|
||||
@RequirePermission('numbering.manage_formats')
|
||||
async bulkImport(@Body() items: ManualOverrideDto[]) {
|
||||
return this.service.bulkImport(items);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export class DocumentNumberingController {
|
||||
|
||||
@Patch('counters/:id')
|
||||
@ApiOperation({ summary: 'Update counter sequence value (Admin only)' })
|
||||
@RequirePermission('system.manage_settings')
|
||||
@RequirePermission('numbering.manage_formats')
|
||||
async updateCounter(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body('sequence') sequence: number
|
||||
@@ -105,7 +105,7 @@ export class DocumentNumberingController {
|
||||
)
|
||||
: undefined;
|
||||
|
||||
return this.numberingService.previewNumber({
|
||||
const result = await this.numberingService.previewNumber({
|
||||
projectId: resolvedProjectId,
|
||||
originatorOrganizationId: resolvedOriginatorId,
|
||||
typeId: dto.correspondenceTypeId,
|
||||
@@ -116,5 +116,7 @@ export class DocumentNumberingController {
|
||||
year: dto.year,
|
||||
customTokens: dto.customTokens,
|
||||
});
|
||||
console.log('[DocumentNumberingController] Preview result:', JSON.stringify(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Project } from '../../project/entities/project.entity';
|
||||
import { CorrespondenceType } from '../../correspondence/entities/correspondence-type.entity';
|
||||
|
||||
@Entity('document_number_formats')
|
||||
@Unique(['projectId', 'correspondenceTypeId'])
|
||||
@Unique(['projectId', 'correspondenceTypeId', 'disciplineId'])
|
||||
export class DocumentNumberFormat {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number;
|
||||
@@ -25,6 +25,9 @@ export class DocumentNumberFormat {
|
||||
@Column({ name: 'correspondence_type_id', nullable: true })
|
||||
correspondenceTypeId?: number;
|
||||
|
||||
@Column({ name: 'discipline_id', default: 0 })
|
||||
disciplineId!: number;
|
||||
|
||||
@Column({ name: 'format_string', length: 100 })
|
||||
formatTemplate!: string;
|
||||
|
||||
@@ -35,6 +38,9 @@ export class DocumentNumberFormat {
|
||||
@Column({ name: 'reset_annually', default: true })
|
||||
resetSequenceYearly!: boolean;
|
||||
|
||||
@Column({ name: 'is_active', default: 1 })
|
||||
isActive!: number;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
|
||||
@@ -5,7 +5,13 @@ import {
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository, InjectEntityManager } from '@nestjs/typeorm';
|
||||
import { Repository, EntityManager } from 'typeorm';
|
||||
import {
|
||||
Repository,
|
||||
EntityManager,
|
||||
In,
|
||||
IsNull,
|
||||
Equal,
|
||||
} from 'typeorm';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import { DocumentNumberFormat } from '../entities/document-number-format.entity';
|
||||
@@ -121,7 +127,7 @@ export class DocumentNumberingService {
|
||||
const sequence = await this.counterService.incrementCounter(key);
|
||||
|
||||
// 4. Format Number
|
||||
const documentNumber = await this.formatService.format({
|
||||
const { previewNumber: documentNumber } = await this.formatService.format({
|
||||
projectId: ctx.projectId,
|
||||
correspondenceTypeId: ctx.typeId,
|
||||
subTypeId: ctx.subTypeId,
|
||||
@@ -193,7 +199,7 @@ export class DocumentNumberingService {
|
||||
|
||||
async previewNumber(
|
||||
ctx: GenerateNumberContext
|
||||
): Promise<{ previewNumber: string; nextSequence: number }> {
|
||||
): Promise<{ previewNumber: string; nextSequence: number; isDefault: boolean }> {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const resetScope = `YEAR_${currentYear}`;
|
||||
|
||||
@@ -211,7 +217,7 @@ export class DocumentNumberingService {
|
||||
const currentSeq = await this.counterService.getCurrentCounter(key);
|
||||
const nextSequence = currentSeq + 1;
|
||||
|
||||
const previewNumber = await this.formatService.format({
|
||||
const { previewNumber, isDefault } = await this.formatService.format({
|
||||
projectId: ctx.projectId,
|
||||
correspondenceTypeId: ctx.typeId,
|
||||
subTypeId: ctx.subTypeId,
|
||||
@@ -224,7 +230,7 @@ export class DocumentNumberingService {
|
||||
recipientOrganizationId: ctx.recipientOrganizationId,
|
||||
});
|
||||
|
||||
return { previewNumber, nextSequence };
|
||||
return { previewNumber, nextSequence, isDefault };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,10 +264,36 @@ export class DocumentNumberingService {
|
||||
async saveTemplate(
|
||||
dto: Partial<DocumentNumberFormat> & { projectId?: number | string }
|
||||
) {
|
||||
if (dto.projectId) {
|
||||
dto.projectId = await this.uuidResolver.resolveProjectId(dto.projectId);
|
||||
try {
|
||||
this.logger.log(`Saving numbering template: ${JSON.stringify(dto)}`);
|
||||
|
||||
// Resolve project ID if it's a UUID/String
|
||||
if (dto.projectId && typeof dto.projectId === 'string') {
|
||||
dto.projectId = await this.uuidResolver.resolveProjectId(dto.projectId);
|
||||
}
|
||||
|
||||
// Upsert logic: If no ID provided, check for existing template with same business key
|
||||
if (!dto.id) {
|
||||
const existing = await this.formatRepo.findOne({
|
||||
where: {
|
||||
projectId: Number(dto.projectId),
|
||||
correspondenceTypeId: dto.correspondenceTypeId ? Equal(dto.correspondenceTypeId) : IsNull(),
|
||||
disciplineId: dto.disciplineId || 0,
|
||||
},
|
||||
});
|
||||
if (existing) {
|
||||
this.logger.log(`Found existing template ID: ${existing.id} for business key, updating instead of creating.`);
|
||||
dto.id = existing.id;
|
||||
}
|
||||
}
|
||||
|
||||
const result = await this.formatRepo.save(dto);
|
||||
this.logger.log(`Successfully saved template ID: ${result.id}`);
|
||||
return result;
|
||||
} catch (e: any) {
|
||||
this.logger.error(`Failed to save numbering template: ${e.message}`, e.stack);
|
||||
throw e;
|
||||
}
|
||||
return this.formatRepo.save(dto);
|
||||
}
|
||||
|
||||
async deleteTemplate(id: number) {
|
||||
|
||||
@@ -39,12 +39,14 @@ export class FormatService {
|
||||
private disciplineRepo: Repository<Discipline>
|
||||
) {}
|
||||
|
||||
async format(options: FormatOptions): Promise<string> {
|
||||
const { template } = await this.resolveFormatAndScope(options);
|
||||
async format(options: FormatOptions): Promise<{ previewNumber: string; isDefault: boolean }> {
|
||||
const { template, isDefault } = await this.resolveFormatAndScope(options);
|
||||
const currentYear = options.year || new Date().getFullYear();
|
||||
const tokens = await this.resolveTokens(options, currentYear);
|
||||
|
||||
return this.replaceTokens(template, tokens, options.sequence);
|
||||
const previewNumber = this.replaceTokens(template, tokens, options.sequence);
|
||||
console.log(`[FormatService] Generated: "${previewNumber}" | Template: "${template}" | isDefault: ${isDefault}`);
|
||||
return { previewNumber, isDefault };
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
@@ -52,6 +54,7 @@ export class FormatService {
|
||||
private async resolveFormatAndScope(options: FormatOptions): Promise<{
|
||||
template: string;
|
||||
resetSequenceYearly: boolean;
|
||||
isDefault: boolean;
|
||||
}> {
|
||||
// 1. Specific Format
|
||||
const specificFormat = await this.formatRepo.findOne({
|
||||
@@ -64,6 +67,7 @@ export class FormatService {
|
||||
return {
|
||||
template: specificFormat.formatTemplate,
|
||||
resetSequenceYearly: specificFormat.resetSequenceYearly,
|
||||
isDefault: false,
|
||||
};
|
||||
|
||||
// 2. Default Format
|
||||
@@ -74,12 +78,14 @@ export class FormatService {
|
||||
return {
|
||||
template: defaultFormat.formatTemplate,
|
||||
resetSequenceYearly: defaultFormat.resetSequenceYearly,
|
||||
isDefault: true,
|
||||
};
|
||||
|
||||
// 3. Fallback
|
||||
return {
|
||||
template: '{ORG}-{RECIPIENT}-{SEQ:4}-{YEAR:BE}',
|
||||
resetSequenceYearly: true,
|
||||
isDefault: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ export class ReservationService {
|
||||
const sequence = await this.counterService.incrementCounter(counterKey);
|
||||
|
||||
// Format document number
|
||||
const documentNumber = await this.formatService.format({
|
||||
const { previewNumber: documentNumber } = await this.formatService.format({
|
||||
...dto,
|
||||
sequence,
|
||||
resetScope: counterKey.resetScope,
|
||||
|
||||
Reference in New Issue
Block a user