From 0052f5cb9b995782286e136bf45801585d09ffc3 Mon Sep 17 00:00:00 2001 From: Adisak Date: Wed, 6 May 2026 11:59:40 +0700 Subject: [PATCH] =?UTF-8?q?#235=20=E0=B9=80=E0=B8=9E=E0=B8=B4=E0=B9=88?= =?UTF-8?q?=E0=B8=A1=E0=B8=9A=E0=B8=B1=E0=B8=99=E0=B8=97=E0=B8=B6=E0=B8=81?= =?UTF-8?q?=E0=B8=9F=E0=B8=B4=E0=B8=A7=E0=B9=80=E0=B8=A1=E0=B8=B7=E0=B9=88?= =?UTF-8?q?=E0=B8=AD=E0=B8=A5=E0=B8=9A=E0=B8=84=E0=B8=99=E0=B8=84=E0=B8=A3?= =?UTF-8?q?=E0=B8=AD=E0=B8=87=E0=B9=81=E0=B8=A5=E0=B8=B0=E0=B9=80=E0=B8=9C?= =?UTF-8?q?=E0=B8=A2=E0=B9=81=E0=B8=9E=E0=B8=A3=E0=B9=88=E0=B8=A2=E0=B9=88?= =?UTF-8?q?=E0=B8=AD=E0=B8=A2=20(=E0=B9=81=E0=B8=9A=E0=B8=9A=E0=B8=A3?= =?UTF-8?q?=E0=B9=88=E0=B8=B2=E0=B8=87>>=E0=B9=82=E0=B8=84=E0=B8=A3?= =?UTF-8?q?=E0=B8=87=E0=B8=AA=E0=B8=A3=E0=B9=89=E0=B8=B2=E0=B8=87=E0=B8=9B?= =?UTF-8?q?=E0=B8=B1=E0=B8=88=E0=B8=88=E0=B8=B8=E0=B8=9A=E0=B8=B1=E0=B8=99?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/OrganizationController.ts | 56 ++++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index 98077f8f..766ab0b4 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -61,7 +61,6 @@ import { BatchSavePosMasterHistoryOfficer, CreatePosMasterHistoryEmployee, CreatePosMasterHistoryOfficer, - SavePosMasterHistoryOfficer, } from "../services/PositionService"; import { orgStructureCache } from "../utils/OrgStructureCache"; import { OrgIdMapping, AllOrgMappings, SavePosMasterHistory } from "../interfaces/OrgMapping"; @@ -8420,6 +8419,9 @@ export class OrganizationController extends Controller { // Type: Map const posMasterMapping: Map = new Map(); + // Collect positions where next_holderId is null for batch history saving + const nullHolderPosIds: string[] = []; + for (const draftPos of posMasterDraft) { const current = currentByDNA.get(draftPos.ancestorDNA); @@ -8461,7 +8463,7 @@ export class OrganizationController extends Controller { toUpdate.push(current); if (draftPos.next_holderId === null) { - await SavePosMasterHistoryOfficer(queryRunner, draftPos.ancestorDNA, null, null); + nullHolderPosIds.push(draftPos.id); } // Track mapping for position sync @@ -8504,6 +8506,56 @@ export class OrganizationController extends Controller { } } + // 2.4.1 Save PosMasterHistory for positions where next_holderId was cleared (null) + // These need org relations to populate shortName, rootDnaId, child*DnaId fields + if (nullHolderPosIds.length > 0) { + const nullHolderPosMasters = await queryRunner.manager.find(PosMaster, { + where: { id: In(nullHolderPosIds) }, + relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"], + }); + const nullHolderMap = new Map(nullHolderPosMasters.map((pm) => [pm.id, pm as any])); + + const nullHolderHistoryOps = posMasterDraft + .filter((d) => nullHolderPosIds.includes(d.id)) + .map((draftPos) => { + const pmWithRelations = nullHolderMap.get(draftPos.id); + return { + posMasterDnaId: draftPos.ancestorDNA, + profileId: null as string | null, + pm: { + prefix: null, + firstName: null, + lastName: null, + position: null, + posType: null, + posLevel: null, + posExecutive: null, + profileId: null, + shortName: pmWithRelations + ? [ + pmWithRelations.orgChild4?.orgChild4ShortName, + pmWithRelations.orgChild3?.orgChild3ShortName, + pmWithRelations.orgChild2?.orgChild2ShortName, + pmWithRelations.orgChild1?.orgChild1ShortName, + pmWithRelations.orgRoot?.orgRootShortName, + ].find((s: string | undefined) => typeof s === "string" && s.trim().length > 0) ?? + null + : null, + posMasterNoPrefix: draftPos.posMasterNoPrefix ?? null, + posMasterNo: draftPos.posMasterNo != null ? String(draftPos.posMasterNo) : null, + posMasterNoSuffix: draftPos.posMasterNoSuffix ?? null, + rootDnaId: pmWithRelations?.orgRoot?.ancestorDNA ?? null, + child1DnaId: pmWithRelations?.orgChild1?.ancestorDNA ?? null, + child2DnaId: pmWithRelations?.orgChild2?.ancestorDNA ?? null, + child3DnaId: pmWithRelations?.orgChild3?.ancestorDNA ?? null, + child4DnaId: pmWithRelations?.orgChild4?.ancestorDNA ?? null, + } as SavePosMasterHistory, + }; + }); + + await BatchSavePosMasterHistoryOfficer(queryRunner, nullHolderHistoryOps); + } + // 2.5 Sync positions table for all affected posMasters (BATCH operation for performance) const positionSyncStats = await this.syncAllPositionsBatch( queryRunner,