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,