Merge branch 'develop' into develop-Bright
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m19s

This commit is contained in:
harid 2026-02-12 12:12:25 +07:00
commit 3e684df6c5

View file

@ -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<any> = [];
const profileUpdates: Map<string, any> = 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;
}