260326:0842 Fixing Naming convention missunderstand #0
This commit is contained in:
@@ -63,10 +63,7 @@ export class VirtualColumnService {
|
|||||||
tableName: string,
|
tableName: string,
|
||||||
config: VirtualColumnConfig
|
config: VirtualColumnConfig
|
||||||
) {
|
) {
|
||||||
const hasColumn = await queryRunner.hasColumn(
|
const hasColumn = await queryRunner.hasColumn(tableName, config.columnName);
|
||||||
tableName,
|
|
||||||
config.column_name
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!hasColumn) {
|
if (!hasColumn) {
|
||||||
const sql = this.generateAddColumnSql(tableName, config);
|
const sql = this.generateAddColumnSql(tableName, config);
|
||||||
@@ -75,7 +72,7 @@ export class VirtualColumnService {
|
|||||||
} else {
|
} else {
|
||||||
// TODO: (Advance) ถ้ามี Column แล้ว แต่ Definition เปลี่ยน อาจต้อง ALTER MODIFY
|
// TODO: (Advance) ถ้ามี Column แล้ว แต่ Definition เปลี่ยน อาจต้อง ALTER MODIFY
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Column '${config.column_name}' already exists in '${tableName}'.`
|
`Column '${config.columnName}' already exists in '${tableName}'.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +85,7 @@ export class VirtualColumnService {
|
|||||||
tableName: string,
|
tableName: string,
|
||||||
config: VirtualColumnConfig
|
config: VirtualColumnConfig
|
||||||
) {
|
) {
|
||||||
const indexName = `idx_${tableName}_${config.column_name}`;
|
const indexName = `idx_${tableName}_${config.columnName}`;
|
||||||
|
|
||||||
// ตรวจสอบว่า Index มีอยู่จริงไหม (Query จาก information_schema เพื่อความชัวร์)
|
// ตรวจสอบว่า Index มีอยู่จริงไหม (Query จาก information_schema เพื่อความชัวร์)
|
||||||
const checkIndexSql = `
|
const checkIndexSql = `
|
||||||
@@ -104,7 +101,7 @@ export class VirtualColumnService {
|
|||||||
])) as { count: number }[];
|
])) as { count: number }[];
|
||||||
|
|
||||||
if (result[0]?.count === 0) {
|
if (result[0]?.count === 0) {
|
||||||
const sql = `CREATE ${config.index_type === 'UNIQUE' ? 'UNIQUE' : ''} INDEX ${indexName} ON ${tableName} (${config.column_name})`;
|
const sql = `CREATE ${config.indexType === 'UNIQUE' ? 'UNIQUE' : ''} INDEX ${indexName} ON ${tableName} (${config.columnName})`;
|
||||||
this.logger.log(`Creating Index: ${sql}`);
|
this.logger.log(`Creating Index: ${sql}`);
|
||||||
await queryRunner.query(sql);
|
await queryRunner.query(sql);
|
||||||
}
|
}
|
||||||
@@ -118,16 +115,16 @@ export class VirtualColumnService {
|
|||||||
tableName: string,
|
tableName: string,
|
||||||
config: VirtualColumnConfig
|
config: VirtualColumnConfig
|
||||||
): string {
|
): string {
|
||||||
const dbType = this.mapDataTypeToSql(config.data_type);
|
const dbType = this.mapDataTypeToSql(config.dataType);
|
||||||
// JSON_UNQUOTE(JSON_EXTRACT(details, '$.path'))
|
// JSON_UNQUOTE(JSON_EXTRACT(details, '$.path'))
|
||||||
// ใช้ 'details' เป็นชื่อ column JSON หลัก (ต้องตรงกับ Database Schema ที่ออกแบบไว้)
|
// ใช้ 'details' เป็นชื่อ column JSON หลัก (ต้องตรงกับ Database Schema ที่ออกแบบไว้)
|
||||||
const expression = `JSON_UNQUOTE(JSON_EXTRACT(details, '${config.json_path}'))`;
|
const expression = `JSON_UNQUOTE(JSON_EXTRACT(details, '${config.jsonPath}'))`;
|
||||||
|
|
||||||
// Handle Type Casting inside expression if needed,
|
// Handle Type Casting inside expression if needed,
|
||||||
// but usually MariaDB handles string return from JSON_EXTRACT.
|
// but usually MariaDB handles string return from JSON_EXTRACT.
|
||||||
// For INT/DATE, virtual column type definition enforces it.
|
// For INT/DATE, virtual column type definition enforces it.
|
||||||
|
|
||||||
return `ALTER TABLE ${tableName} ADD COLUMN ${config.column_name} ${dbType} GENERATED ALWAYS AS (${expression}) VIRTUAL`;
|
return `ALTER TABLE ${tableName} ADD COLUMN ${config.columnName} ${dbType} GENERATED ALWAYS AS (${expression}) VIRTUAL`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapDataTypeToSql(type: string): string {
|
private mapDataTypeToSql(type: string): string {
|
||||||
|
|||||||
@@ -136,11 +136,11 @@ export class MigrationService {
|
|||||||
|
|
||||||
// We now use project_id from n8n (instead of hardcoding LCBP3)
|
// We now use project_id from n8n (instead of hardcoding LCBP3)
|
||||||
const project = await this.projectRepo.findOne({
|
const project = await this.projectRepo.findOne({
|
||||||
where: { id: dto.project_id },
|
where: { id: dto.projectId },
|
||||||
});
|
});
|
||||||
if (!project) {
|
if (!project) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
`Project ID ${dto.project_id} not found in database`
|
`Project ID ${dto.projectId} not found in database`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,18 +154,18 @@ export class MigrationService {
|
|||||||
// 3. Find or Create Correspondence
|
// 3. Find or Create Correspondence
|
||||||
let correspondence = await queryRunner.manager.findOne(Correspondence, {
|
let correspondence = await queryRunner.manager.findOne(Correspondence, {
|
||||||
where: {
|
where: {
|
||||||
correspondenceNumber: dto.document_number,
|
correspondenceNumber: dto.documentNumber,
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!correspondence) {
|
if (!correspondence) {
|
||||||
correspondence = queryRunner.manager.create(Correspondence, {
|
correspondence = queryRunner.manager.create(Correspondence, {
|
||||||
correspondenceNumber: dto.document_number,
|
correspondenceNumber: dto.documentNumber,
|
||||||
correspondenceTypeId: typeId,
|
correspondenceTypeId: typeId,
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
disciplineId: dto.discipline_id || undefined,
|
disciplineId: dto.disciplineId || undefined,
|
||||||
originatorId: dto.sender_id || undefined, // Set explicitly from DTO
|
originatorId: dto.senderId || undefined, // Set explicitly from DTO
|
||||||
isInternal: false,
|
isInternal: false,
|
||||||
createdBy: userId,
|
createdBy: userId,
|
||||||
});
|
});
|
||||||
@@ -187,12 +187,12 @@ export class MigrationService {
|
|||||||
} else {
|
} else {
|
||||||
// Update values if missing
|
// Update values if missing
|
||||||
let hasChanges = false;
|
let hasChanges = false;
|
||||||
if (dto.discipline_id && !correspondence.disciplineId) {
|
if (dto.disciplineId && !correspondence.disciplineId) {
|
||||||
correspondence.disciplineId = dto.discipline_id;
|
correspondence.disciplineId = dto.disciplineId;
|
||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
}
|
}
|
||||||
if (dto.sender_id && !correspondence.originatorId) {
|
if (dto.senderId && !correspondence.originatorId) {
|
||||||
correspondence.originatorId = dto.sender_id;
|
correspondence.originatorId = dto.senderId;
|
||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
}
|
}
|
||||||
if (hasChanges) {
|
if (hasChanges) {
|
||||||
@@ -202,8 +202,8 @@ export class MigrationService {
|
|||||||
|
|
||||||
// 4. File Handling
|
// 4. File Handling
|
||||||
let attachmentId: number | null = null;
|
let attachmentId: number | null = null;
|
||||||
if (dto.temp_attachment_id) {
|
if (dto.tempAttachmentId) {
|
||||||
attachmentId = dto.temp_attachment_id;
|
attachmentId = dto.tempAttachmentId;
|
||||||
try {
|
try {
|
||||||
// Mark attachment as permanent
|
// Mark attachment as permanent
|
||||||
await queryRunner.manager.update(
|
await queryRunner.manager.update(
|
||||||
@@ -218,10 +218,10 @@ export class MigrationService {
|
|||||||
`Failed to update temp_file [id:${attachmentId}]: ${errMsg}`
|
`Failed to update temp_file [id:${attachmentId}]: ${errMsg}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (dto.source_file_path) {
|
} else if (dto.sourceFilePath) {
|
||||||
try {
|
try {
|
||||||
const attachment = await this.fileStorageService.importStagingFile(
|
const attachment = await this.fileStorageService.importStagingFile(
|
||||||
dto.source_file_path,
|
dto.sourceFilePath,
|
||||||
userId,
|
userId,
|
||||||
{ documentType: dto.category }
|
{ documentType: dto.category }
|
||||||
);
|
);
|
||||||
@@ -231,7 +231,7 @@ export class MigrationService {
|
|||||||
fileError instanceof Error ? fileError.message : String(fileError);
|
fileError instanceof Error ? fileError.message : String(fileError);
|
||||||
|
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`Failed to import file for [${dto.document_number}], continuing without attachment: ${errMsg}`
|
`Failed to import file for [${dto.documentNumber}], continuing without attachment: ${errMsg}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,14 +268,14 @@ export class MigrationService {
|
|||||||
subject: dto.subject,
|
subject: dto.subject,
|
||||||
description: 'Migrated from legacy system via Auto Ingest',
|
description: 'Migrated from legacy system via Auto Ingest',
|
||||||
body: dto.body || undefined,
|
body: dto.body || undefined,
|
||||||
documentDate: parseDateStr(dto.document_date || dto.issued_date),
|
documentDate: parseDateStr(dto.documentDate || dto.issuedDate),
|
||||||
issuedDate: parseDateStr(dto.issued_date),
|
issuedDate: parseDateStr(dto.issuedDate),
|
||||||
receivedDate: parseDateStr(dto.received_date),
|
receivedDate: parseDateStr(dto.receivedDate),
|
||||||
details: {
|
details: {
|
||||||
...dto.details,
|
...dto.details,
|
||||||
ai_confidence: dto.ai_confidence,
|
ai_confidence: dto.aiConfidence,
|
||||||
ai_issues: dto.ai_issues as unknown,
|
ai_issues: dto.aiIssues as unknown,
|
||||||
source_file_path: dto.source_file_path,
|
source_file_path: dto.sourceFilePath,
|
||||||
attachment_id: attachmentId,
|
attachment_id: attachmentId,
|
||||||
},
|
},
|
||||||
schemaVersion: 1,
|
schemaVersion: 1,
|
||||||
@@ -323,9 +323,9 @@ export class MigrationService {
|
|||||||
if (typeof tagItem === 'string') {
|
if (typeof tagItem === 'string') {
|
||||||
tagName = tagItem;
|
tagName = tagItem;
|
||||||
} else if (tagItem && typeof tagItem === 'object') {
|
} else if (tagItem && typeof tagItem === 'object') {
|
||||||
const tObj = tagItem as { tag_name?: unknown };
|
const tObj = tagItem as { tagName?: unknown };
|
||||||
if (typeof tObj.tag_name === 'string') {
|
if (typeof tObj.tagName === 'string') {
|
||||||
tagName = tObj.tag_name;
|
tagName = tObj.tagName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,8 +360,8 @@ export class MigrationService {
|
|||||||
// 6. Track Transaction
|
// 6. Track Transaction
|
||||||
const transaction = queryRunner.manager.create(ImportTransaction, {
|
const transaction = queryRunner.manager.create(ImportTransaction, {
|
||||||
idempotencyKey,
|
idempotencyKey,
|
||||||
documentNumber: dto.document_number,
|
documentNumber: dto.documentNumber,
|
||||||
batchId: dto.batch_id,
|
batchId: dto.batchId,
|
||||||
statusCode: 201,
|
statusCode: 201,
|
||||||
});
|
});
|
||||||
await queryRunner.manager.save(transaction);
|
await queryRunner.manager.save(transaction);
|
||||||
@@ -369,7 +369,7 @@ export class MigrationService {
|
|||||||
await queryRunner.commitTransaction();
|
await queryRunner.commitTransaction();
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`Ingested document [${dto.document_number}] successfully (Batch: ${dto.batch_id})`
|
`Ingested document [${dto.documentNumber}] successfully (Batch: ${dto.batchId})`
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -385,14 +385,14 @@ export class MigrationService {
|
|||||||
const errorStack = error instanceof Error ? error.stack : undefined;
|
const errorStack = error instanceof Error ? error.stack : undefined;
|
||||||
|
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
`Import failed for document [${dto.document_number}]: ${errorMessage}`,
|
`Import failed for document [${dto.documentNumber}]: ${errorMessage}`,
|
||||||
errorStack
|
errorStack
|
||||||
);
|
);
|
||||||
|
|
||||||
const failedTransaction = this.importTransactionRepo.create({
|
const failedTransaction = this.importTransactionRepo.create({
|
||||||
idempotencyKey,
|
idempotencyKey,
|
||||||
documentNumber: dto.document_number,
|
documentNumber: dto.documentNumber,
|
||||||
batchId: dto.batch_id,
|
batchId: dto.batchId,
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
});
|
});
|
||||||
await this.importTransactionRepo.save(failedTransaction).catch(() => {});
|
await this.importTransactionRepo.save(failedTransaction).catch(() => {});
|
||||||
@@ -406,14 +406,14 @@ export class MigrationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async enqueueRecord(dto: EnqueueMigrationDto) {
|
async enqueueRecord(dto: EnqueueMigrationDto) {
|
||||||
if (!dto.document_number) {
|
if (!dto.documentNumber) {
|
||||||
throw new BadRequestException('document_number is required');
|
throw new BadRequestException('documentNumber is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine status based on confidence policy in ADR-017
|
// Determine status based on confidence policy in ADR-017
|
||||||
let autoStatus = MigrationReviewStatus.PENDING;
|
let autoStatus = MigrationReviewStatus.PENDING;
|
||||||
if (
|
if (
|
||||||
dto.is_valid === false ||
|
dto.isValid === false ||
|
||||||
(dto.confidence != null && dto.confidence < 0.6)
|
(dto.confidence != null && dto.confidence < 0.6)
|
||||||
) {
|
) {
|
||||||
autoStatus = MigrationReviewStatus.REJECTED;
|
autoStatus = MigrationReviewStatus.REJECTED;
|
||||||
@@ -421,43 +421,42 @@ export class MigrationService {
|
|||||||
|
|
||||||
// Upsert or create new queue item
|
// Upsert or create new queue item
|
||||||
let queueItem = await this.reviewQueueRepo.findOne({
|
let queueItem = await this.reviewQueueRepo.findOne({
|
||||||
where: { documentNumber: dto.document_number },
|
where: { documentNumber: dto.documentNumber },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!queueItem) {
|
if (!queueItem) {
|
||||||
queueItem = this.reviewQueueRepo.create({
|
queueItem = this.reviewQueueRepo.create({
|
||||||
documentNumber: dto.document_number,
|
documentNumber: dto.documentNumber,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
queueItem.subject = dto.subject;
|
queueItem.subject = dto.subject;
|
||||||
queueItem.originalSubject = dto.original_subject;
|
queueItem.originalSubject = dto.originalSubject;
|
||||||
queueItem.body = dto.body;
|
queueItem.body = dto.body;
|
||||||
queueItem.aiSuggestedCategory = dto.category;
|
queueItem.aiSuggestedCategory = dto.category;
|
||||||
queueItem.aiConfidence = dto.confidence;
|
queueItem.aiIssues = dto.aiIssues;
|
||||||
queueItem.aiIssues = dto.ai_issues;
|
queueItem.projectId = dto.projectId;
|
||||||
queueItem.projectId = dto.project_id;
|
queueItem.senderOrganizationId = dto.senderOrgId;
|
||||||
queueItem.senderOrganizationId = dto.sender_org_id;
|
queueItem.receiverOrganizationId = dto.receiverOrgId;
|
||||||
queueItem.receiverOrganizationId = dto.receiver_org_id;
|
|
||||||
queueItem.remarks = dto.remarks;
|
queueItem.remarks = dto.remarks;
|
||||||
queueItem.aiSummary = dto.ai_summary;
|
queueItem.aiSummary = dto.aiSummary;
|
||||||
queueItem.extractedTags = dto.extracted_tags;
|
queueItem.extractedTags = dto.extractedTags;
|
||||||
queueItem.tempAttachmentId = dto.temp_attachment_id;
|
queueItem.tempAttachmentId = dto.tempAttachmentId;
|
||||||
queueItem.status = autoStatus;
|
queueItem.status = autoStatus;
|
||||||
|
|
||||||
if (dto.issued_date) {
|
if (dto.issuedDate) {
|
||||||
const parsed = new Date(dto.issued_date);
|
const parsed = new Date(dto.issuedDate);
|
||||||
if (!isNaN(parsed.getTime())) queueItem.issuedDate = parsed;
|
if (!isNaN(parsed.getTime())) queueItem.issuedDate = parsed;
|
||||||
}
|
}
|
||||||
if (dto.received_date) {
|
if (dto.receivedDate) {
|
||||||
const parsed = new Date(dto.received_date);
|
const parsed = new Date(dto.receivedDate);
|
||||||
if (!isNaN(parsed.getTime())) queueItem.receivedDate = parsed;
|
if (!isNaN(parsed.getTime())) queueItem.receivedDate = parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.reviewQueueRepo.save(queueItem);
|
await this.reviewQueueRepo.save(queueItem);
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`Enqueued document [${dto.document_number}] to staging queue with status [${autoStatus}]`
|
`Enqueued document [${dto.documentNumber}] to staging queue with status [${autoStatus}]`
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -500,15 +499,15 @@ export class MigrationService {
|
|||||||
|
|
||||||
async createError(dto: CreateMigrationErrorDto) {
|
async createError(dto: CreateMigrationErrorDto) {
|
||||||
const error = this.errorRepo.create({
|
const error = this.errorRepo.create({
|
||||||
batchId: dto.batch_id,
|
batchId: dto.batchId,
|
||||||
documentNumber: dto.document_number,
|
documentNumber: dto.documentNumber,
|
||||||
errorType: dto.error_type,
|
errorType: dto.errorType,
|
||||||
errorMessage: dto.error_message,
|
errorMessage: dto.errorMessage,
|
||||||
rawAiResponse: dto.raw_ai_response,
|
rawAiResponse: dto.rawAiResponse,
|
||||||
});
|
});
|
||||||
const saved = await this.errorRepo.save(error);
|
const saved = await this.errorRepo.save(error);
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`Migration error logged [${dto.error_type}] for doc [${dto.document_number}] batch [${dto.batch_id}]`
|
`Migration error logged [${dto.errorType}] for doc [${dto.documentNumber}] batch [${dto.batchId}]`
|
||||||
);
|
);
|
||||||
return { message: 'Error logged', id: saved.id };
|
return { message: 'Error logged', id: saved.id };
|
||||||
}
|
}
|
||||||
@@ -581,7 +580,7 @@ export class MigrationService {
|
|||||||
const subKey = `${idempotencyKey}_${item.queueId}`;
|
const subKey = `${idempotencyKey}_${item.queueId}`;
|
||||||
|
|
||||||
// Force batchId on the item dto
|
// Force batchId on the item dto
|
||||||
item.dto.batch_id = dto.batchId;
|
item.dto.batchId = dto.batchId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await this.approveQueueItem(
|
const result = await this.approveQueueItem(
|
||||||
|
|||||||
Reference in New Issue
Block a user