From 13fa8cbf2402e9523a146ee7c1429f9da83d37e2 Mon Sep 17 00:00:00 2001 From: waruneeauy Date: Thu, 12 Feb 2026 11:53:24 +0700 Subject: [PATCH 1/2] fix: script case nextholder id null --- src/controllers/OrganizationController.ts | 121 +++------------------- 1 file changed, 13 insertions(+), 108 deletions(-) diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index 813e268c..b0a007f5 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -8167,6 +8167,10 @@ export class OrganizationController extends Controller { }); toUpdate.push(current); + if (draftPos.next_holderId === null) { + await SavePosMasterHistoryOfficer(queryRunner, draftPos.ancestorDNA, null, null); + } + // Track mapping for position sync posMasterMapping.set(draftPos.id, [current.id, draftPos.next_holderId]); } else { @@ -8512,107 +8516,6 @@ export class OrganizationController extends Controller { }; } - /** - * Helper function: Sync positions for a PosMaster - * Handles DELETE/UPDATE/INSERT for positions associated with a posMaster - * - * @deprecated Kept as fallback - use syncAllPositionsBatch for better performance - */ - private async syncPositionsForPosMaster( - queryRunner: any, - draftPosMasterId: string, - currentPosMasterId: string, - _draftRevisionId: string, - _currentRevisionId: string, - nextHolderId: string | null | undefined, - ): Promise<{ deleted: number; updated: number; inserted: number }> { - // Fetch draft and current positions for this posMaster - const [draftPositions, currentPositions] = await Promise.all([ - queryRunner.manager.find(Position, { - where: { - posMasterId: draftPosMasterId, - }, - order: { orderNo: "ASC" }, - }), - queryRunner.manager.find(Position, { - where: { - posMasterId: currentPosMasterId, - }, - }), - ]); - - // If no draft positions, delete all current positions - if (draftPositions.length === 0) { - if (currentPositions.length > 0) { - await queryRunner.manager.delete( - Position, - currentPositions.map((p: any) => p.id), - ); - } - return { deleted: currentPositions.length, updated: 0, inserted: 0 }; - } - - // Build maps for tracking - const currentByOrderNo = new Map(currentPositions.map((p: any) => [p.orderNo, p])); - - // DELETE: Current positions not in draft (by orderNo) - const draftOrderNos = new Set(draftPositions.map((p: any) => p.orderNo)); - const toDelete = currentPositions.filter((p: any) => !draftOrderNos.has(p.orderNo)); - - if (toDelete.length > 0) { - await queryRunner.manager.delete( - Position, - toDelete.map((p: any) => p.id), - ); - } - - // UPDATE and INSERT - let updatedCount = 0; - let insertedCount = 0; - for (const draftPos of draftPositions) { - const current: any = currentByOrderNo.get(draftPos.orderNo); - - if (current) { - // UPDATE existing position - await queryRunner.manager.update(Position, current.id, { - positionName: draftPos.positionName, - positionField: draftPos.positionField, - posTypeId: draftPos.posTypeId, - posLevelId: draftPos.posLevelId, - posExecutiveId: draftPos.posExecutiveId, - positionExecutiveField: draftPos.positionExecutiveField, - positionArea: draftPos.positionArea, - isSpecial: draftPos.isSpecial, - orderNo: draftPos.orderNo, - positionIsSelected: draftPos.positionIsSelected, - lastUpdateFullName: draftPos.lastUpdateFullName, - lastUpdatedAt: new Date(), - }); - updatedCount++; - } else { - // INSERT new position - const newPosition = queryRunner.manager.create(Position, { - ...draftPos, - id: undefined, - posMasterId: currentPosMasterId, - }); - await queryRunner.manager.save(newPosition); - insertedCount++; - } - - // update profile - if (nextHolderId != null && draftPos.positionIsSelected) { - await queryRunner.manager.update(Profile, nextHolderId, { - position: draftPos.positionName, - posTypeId: draftPos.posTypeId, - posLevelId: draftPos.posLevelId, - }); - } - } - - return { deleted: toDelete.length, updated: updatedCount, inserted: insertedCount }; - } - /** * Batch version: Sync positions for ALL posMasters in a single operation * This significantly reduces database round trips for large organizations @@ -8674,6 +8577,7 @@ export class OrganizationController extends Controller { // Collect all operations const allToDelete: string[] = []; + const allToDeleteHistory: string[] = []; const allToUpdate: Array<{ id: string; data: any }> = []; const allToInsert: Array = []; const profileUpdates: Map = new Map(); @@ -8696,6 +8600,7 @@ export class OrganizationController extends Controller { // If no draft positions, mark all current positions for deletion if (draftPositions.length === 0) { allToDelete.push(...currentPositions.map((p: any) => p.id)); + allToDeleteHistory.push(...currentPositions.map((p: any) => p.ancestorDNA)); continue; } @@ -8707,6 +8612,7 @@ export class OrganizationController extends Controller { for (const currentPos of currentPositions) { if (!draftOrderNos.has(currentPos.orderNo)) { allToDelete.push(currentPos.id); + allToDeleteHistory.push(currentPos.ancestorDNA); } } @@ -8742,10 +8648,6 @@ export class OrganizationController extends Controller { }); } - if (nextHolderId === null) { - await SavePosMasterHistoryOfficer(queryRunner, draftPos.ancestorDNA, null, null); - } - // Collect profile update for the selected position if (nextHolderId != null && draftPos.positionIsSelected) { profileUpdates.set(nextHolderId, { @@ -8753,10 +8655,8 @@ export class OrganizationController extends Controller { posTypeId: draftPos.posTypeId, posLevelId: draftPos.posLevelId, }); - } - // Collect history data for the selected position - if (nextHolderId != null && draftPos.positionIsSelected) { + // Collect history data for the selected position const draftPosMaster = draftPosMasterMap.get(draftPosMasterId) as any; if (draftPosMaster && draftPosMaster.ancestorDNA) { // Find the selected position from draft positions @@ -8805,6 +8705,11 @@ export class OrganizationController extends Controller { // Bulk DELETE if (allToDelete.length > 0) { await queryRunner.manager.delete(Position, allToDelete); + await Promise.all( + allToDeleteHistory.map(async (ancestorDNA) => { + await SavePosMasterHistoryOfficer(queryRunner, ancestorDNA, null, null); + }), + ); deletedCount = allToDelete.length; } From 64aca4f5fa82b211c1a583a24f3fc963b2df599b Mon Sep 17 00:00:00 2001 From: harid Date: Thu, 12 Feb 2026 12:10:14 +0700 Subject: [PATCH 2/2] Migrate move isDeleted in profileSalary --- src/entities/ProfileSalary.ts | 7 ------- src/entities/ProfileSalaryBackup.ts | 7 ------- src/entities/ProfileSalaryHistory.ts | 7 ------- ...ields_isDeleted_in_tables_profileSalary.ts | 19 +++++++++++++++++++ 4 files changed, 19 insertions(+), 21 deletions(-) create mode 100644 src/migration/1770872734016-move_fields_isDeleted_in_tables_profileSalary.ts diff --git a/src/entities/ProfileSalary.ts b/src/entities/ProfileSalary.ts index 1ab7acab..ddbe184b 100644 --- a/src/entities/ProfileSalary.ts +++ b/src/entities/ProfileSalary.ts @@ -287,13 +287,6 @@ export class ProfileSalary extends EntityBase { }) positionArea: string; - @Column({ - nullable: false, - comment: "สถานะลบข้อมูล", - default: false, - }) - isDeleted: boolean; - @ManyToOne(() => Command, (command) => command.profileSalarys) @JoinColumn({ name: "commandId" }) command: Command; diff --git a/src/entities/ProfileSalaryBackup.ts b/src/entities/ProfileSalaryBackup.ts index 1274e319..29cdd325 100644 --- a/src/entities/ProfileSalaryBackup.ts +++ b/src/entities/ProfileSalaryBackup.ts @@ -292,11 +292,4 @@ export class ProfileSalaryBackup extends EntityBase { }) positionArea: string; - @Column({ - nullable: false, - comment: "สถานะลบข้อมูล", - default: false, - }) - isDeleted: boolean; - } \ No newline at end of file diff --git a/src/entities/ProfileSalaryHistory.ts b/src/entities/ProfileSalaryHistory.ts index b5482c29..ea6af033 100644 --- a/src/entities/ProfileSalaryHistory.ts +++ b/src/entities/ProfileSalaryHistory.ts @@ -228,13 +228,6 @@ export class ProfileSalaryHistory extends EntityBase { }) posNumCodeSitAbb: string; - @Column({ - nullable: false, - comment: "สถานะลบข้อมูล", - default: false, - }) - isDeleted: boolean; - @ManyToOne(() => Command, (command) => command.profileSalaryHistorys) @JoinColumn({ name: "commandId" }) command: Command; diff --git a/src/migration/1770872734016-move_fields_isDeleted_in_tables_profileSalary.ts b/src/migration/1770872734016-move_fields_isDeleted_in_tables_profileSalary.ts new file mode 100644 index 00000000..31d4a79c --- /dev/null +++ b/src/migration/1770872734016-move_fields_isDeleted_in_tables_profileSalary.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class MoveFieldsIsDeletedInTablesProfileSalary1770872734016 implements MigrationInterface { + name = 'MoveFieldsIsDeletedInTablesProfileSalary1770872734016' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`profileSalaryHistory\` DROP COLUMN \`isDeleted\``); + await queryRunner.query(`ALTER TABLE \`profileSalary\` DROP COLUMN \`isDeleted\``); + await queryRunner.query(`ALTER TABLE \`profileSalaryBackup\` DROP COLUMN \`isDeleted\``); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`profileSalaryBackup\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูล' DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE \`profileSalary\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูล' DEFAULT '0'`); + await queryRunner.query(`ALTER TABLE \`profileSalaryHistory\` ADD \`isDeleted\` tinyint NOT NULL COMMENT 'สถานะลบข้อมูล' DEFAULT '0'`); + + } + +}