From 5a1eeca7f33c52863b9443ca0caba9cd9ab1283f Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 18 Mar 2026 16:35:00 +0700 Subject: [PATCH] 260318:1635 Fix UUID #10 --- .../document-numbering.service.spec.ts | 4 +-- .../entities/document-number-audit.entity.ts | 6 ++-- .../services/document-numbering.service.ts | 16 +++++----- .../services/manual-override.service.spec.ts | 2 +- .../services/manual-override.service.ts | 2 +- backend/src/modules/search/search.module.ts | 6 ++-- backend/src/modules/search/search.service.ts | 30 ++++++++++++++++++- 7 files changed, 46 insertions(+), 20 deletions(-) diff --git a/backend/src/modules/document-numbering/document-numbering.service.spec.ts b/backend/src/modules/document-numbering/document-numbering.service.spec.ts index 68da5c9..1e1f8f3 100644 --- a/backend/src/modules/document-numbering/document-numbering.service.spec.ts +++ b/backend/src/modules/document-numbering/document-numbering.service.spec.ts @@ -144,7 +144,7 @@ describe('DocumentNumberingService', () => { it('voidAndReplace should verify audit log exists', async () => { const auditRepo = module.get(getRepositoryToken(DocumentNumberAudit)); (auditRepo.findOne as jest.Mock).mockResolvedValue({ - generatedNumber: 'DOC-001', + documentNumber: 'DOC-001', counterKey: JSON.stringify({ projectId: 1, correspondenceTypeId: 1 }), templateUsed: 'test', }); @@ -162,7 +162,7 @@ describe('DocumentNumberingService', () => { it('cancelNumber should log cancellation', async () => { const auditRepo = module.get(getRepositoryToken(DocumentNumberAudit)); (auditRepo.findOne as jest.Mock).mockResolvedValue({ - generatedNumber: 'DOC-002', + documentNumber: 'DOC-002', counterKey: {}, }); (auditRepo.save as jest.Mock).mockResolvedValue({ id: 3 }); diff --git a/backend/src/modules/document-numbering/entities/document-number-audit.entity.ts b/backend/src/modules/document-numbering/entities/document-number-audit.entity.ts index 648dbb6..b427cce 100644 --- a/backend/src/modules/document-numbering/entities/document-number-audit.entity.ts +++ b/backend/src/modules/document-numbering/entities/document-number-audit.entity.ts @@ -12,7 +12,7 @@ import { @Index(['documentId']) @Index(['status']) @Index(['operation']) -@Index(['generatedNumber']) +@Index(['documentNumber']) @Index(['reservationToken']) export class DocumentNumberAudit { @PrimaryGeneratedColumn() @@ -21,8 +21,8 @@ export class DocumentNumberAudit { @Column({ name: 'document_id', nullable: true }) documentId?: number; - @Column({ name: 'generated_number', length: 100 }) - generatedNumber!: string; + @Column({ name: 'document_number', length: 100 }) + documentNumber!: string; @Column({ name: 'counter_key', type: 'json' }) counterKey!: any; diff --git a/backend/src/modules/document-numbering/services/document-numbering.service.ts b/backend/src/modules/document-numbering/services/document-numbering.service.ts index e03ef01..568aca9 100644 --- a/backend/src/modules/document-numbering/services/document-numbering.service.ts +++ b/backend/src/modules/document-numbering/services/document-numbering.service.ts @@ -146,7 +146,7 @@ export class DocumentNumberingService { const sequence = await this.counterService.incrementCounter(key); // 4. Format Number - const generatedNumber = await this.formatService.format({ + const documentNumber = await this.formatService.format({ projectId: ctx.projectId, correspondenceTypeId: ctx.typeId, subTypeId: ctx.subTypeId, @@ -161,7 +161,7 @@ export class DocumentNumberingService { // 5. Audit Log const audit = await this.logAudit({ - generatedNumber, + documentNumber, counterKey: JSON.stringify(key), templateUsed: 'DELEGATED_TO_FORMAT_SERVICE', context: ctx, @@ -175,7 +175,7 @@ export class DocumentNumberingService { type_id: String(ctx.typeId), }); - return { number: generatedNumber, auditId: audit.id }; + return { number: documentNumber, auditId: audit.id }; } catch (error: any) { await this.logError(error, ctx, 'GENERATE'); throw error; @@ -322,7 +322,7 @@ export class DocumentNumberingService { }) { // 1. Find the audit log for this number to get context const lastAudit = await this.auditRepo.findOne({ - where: { generatedNumber: dto.documentNumber }, + where: { documentNumber: dto.documentNumber }, order: { createdAt: 'DESC' }, }); @@ -334,7 +334,7 @@ export class DocumentNumberingService { ); // Create a void audit anyway if possible? await this.logAudit({ - generatedNumber: dto.documentNumber, + documentNumber: dto.documentNumber, counterKey: {}, // Unknown templateUsed: 'VOID_UNKNOWN', context: { userId: 0, ipAddress: '0.0.0.0' }, // System @@ -349,7 +349,7 @@ export class DocumentNumberingService { // 2. Log VOID await this.logAudit({ - generatedNumber: dto.documentNumber, + documentNumber: dto.documentNumber, counterKey: lastAudit.counterKey, templateUsed: lastAudit.templateUsed, context: { userId: 0, ipAddress: '0.0.0.0' }, // TODO: Pass userId from controller @@ -409,14 +409,14 @@ export class DocumentNumberingService { }) { // Similar to VOID but status CANCELLED const lastAudit = await this.auditRepo.findOne({ - where: { generatedNumber: dto.documentNumber }, + where: { documentNumber: dto.documentNumber }, order: { createdAt: 'DESC' }, }); const contextKey = lastAudit?.counterKey; await this.logAudit({ - generatedNumber: dto.documentNumber, + documentNumber: dto.documentNumber, counterKey: contextKey || {}, templateUsed: lastAudit?.templateUsed || 'CANCEL', context: { diff --git a/backend/src/modules/document-numbering/services/manual-override.service.spec.ts b/backend/src/modules/document-numbering/services/manual-override.service.spec.ts index 279f9a9..d5319a7 100644 --- a/backend/src/modules/document-numbering/services/manual-override.service.spec.ts +++ b/backend/src/modules/document-numbering/services/manual-override.service.spec.ts @@ -56,7 +56,7 @@ describe('ManualOverrideService', () => { expect(counterService.forceUpdateCounter).toHaveBeenCalledWith(dto, 999); expect(auditService.log).toHaveBeenCalledWith( expect.objectContaining({ - generatedNumber: 'OVERRIDE-TO-999', + documentNumber: 'OVERRIDE-TO-999', operation: 'MANUAL_OVERRIDE', status: 'MANUAL', userId: userId, diff --git a/backend/src/modules/document-numbering/services/manual-override.service.ts b/backend/src/modules/document-numbering/services/manual-override.service.ts index 8c3ef33..4b2b40f 100644 --- a/backend/src/modules/document-numbering/services/manual-override.service.ts +++ b/backend/src/modules/document-numbering/services/manual-override.service.ts @@ -23,7 +23,7 @@ export class ManualOverrideService { // 2. Log Audit await this.auditService.log({ documentId: undefined, // No specific document - generatedNumber: `OVERRIDE-TO-${dto.newLastNumber}`, + documentNumber: `OVERRIDE-TO-${dto.newLastNumber}`, operation: 'MANUAL_OVERRIDE', status: 'MANUAL', counterKey: dto, // CounterKeyDto part of ManualOverrideDto diff --git a/backend/src/modules/search/search.module.ts b/backend/src/modules/search/search.module.ts index 4458173..682c32d 100644 --- a/backend/src/modules/search/search.module.ts +++ b/backend/src/modules/search/search.module.ts @@ -13,10 +13,8 @@ import { UserModule } from '../user/user.module'; // ✅ 1. Import UserModule ElasticsearchModule.registerAsync({ imports: [ConfigModule], - useFactory: async (configService: ConfigService) => ({ - node: - configService.get('ELASTICSEARCH_NODE') || - 'http://localhost:9200', + useFactory: (configService: ConfigService) => ({ + node: `http://${configService.get('ELASTICSEARCH_HOST', 'localhost')}:${configService.get('ELASTICSEARCH_PORT', '9200')}`, auth: { username: configService.get('ELASTICSEARCH_USERNAME') || '', password: configService.get('ELASTICSEARCH_PASSWORD') || '', diff --git a/backend/src/modules/search/search.service.ts b/backend/src/modules/search/search.service.ts index 343bbcb..d6f68f4 100644 --- a/backend/src/modules/search/search.service.ts +++ b/backend/src/modules/search/search.service.ts @@ -7,6 +7,7 @@ import { SearchQueryDto } from './dto/search-query.dto'; export class SearchService implements OnModuleInit { private readonly logger = new Logger(SearchService.name); private readonly indexName = 'dms_documents'; + private isElasticsearchAvailable = false; constructor( private readonly esService: ElasticsearchService, @@ -14,6 +15,20 @@ export class SearchService implements OnModuleInit { ) {} async onModuleInit() { + // Test Elasticsearch connection first + try { + await this.esService.ping(); + this.logger.log('Elasticsearch connection successful'); + this.isElasticsearchAvailable = true; + } catch (error) { + this.logger.error( + `Elasticsearch connection failed: ${(error as Error).message}`, + (error as Error).stack + ); + this.isElasticsearchAvailable = false; + return; // Don't try to create index if connection fails + } + await this.createIndexIfNotExists(); } @@ -94,6 +109,12 @@ export class SearchService implements OnModuleInit { const { q, type, projectId, page = 1, limit = 20 } = queryDto; const from = (page - 1) * limit; + // Early fallback if Elasticsearch is not available + if (!this.isElasticsearchAvailable) { + this.logger.warn('Search unavailable - Elasticsearch not connected'); + return { data: [], meta: { total: 0, page, limit, took: 0 } }; + } + const mustQueries: any[] = []; // 1. Full-text search logic @@ -146,7 +167,14 @@ export class SearchService implements OnModuleInit { }, }; } catch (error) { - this.logger.error(`Search failed: ${(error as Error).message}`); + const err = error as Error; + this.logger.error(`Search failed: ${err.message}`, err.stack); + this.logger.debug( + `Search query context: ${JSON.stringify({ + query: queryDto, + esNode: this.configService.get('ELASTICSEARCH_NODE'), + })}` + ); return { data: [], meta: { total: 0, page, limit, took: 0 } }; } }