complete script move draf to current

This commit is contained in:
Warunee Tamkoo 2026-02-10 16:23:52 +07:00
parent 1cab2b3afc
commit 3b97e52bd6

View file

@ -7865,7 +7865,6 @@ export class OrganizationController extends Controller {
]); ]);
if (!orgRootDraft) return new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้างร่าง"); if (!orgRootDraft) return new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้างร่าง");
// Part 1: Differential sync of organization structure (bottom-up) // Part 1: Differential sync of organization structure (bottom-up)
// Build mapping incrementally as we process each level // Build mapping incrementally as we process each level
const allMappings: AllOrgMappings = { const allMappings: AllOrgMappings = {
@ -7876,60 +7875,80 @@ export class OrganizationController extends Controller {
orgChild4: { byAncestorDNA: new Map(), byDraftId: new Map() }, orgChild4: { byAncestorDNA: new Map(), byDraftId: new Map() },
}; };
// Process from bottom (Child4) to top (Root) to handle foreign key constraints // Track sync statistics for organization nodes
// Child4 (leaf nodes - no children depending on them) const orgSyncStats: Record<string, { deleted: number; updated: number; inserted: number }> =
allMappings.orgChild4 = await this.syncOrgLevel( {};
queryRunner,
OrgChild4,
this.child4Repository,
drafRevisionId,
currentRevisionId,
rootDnaId,
allMappings,
);
// Child3 // Process from top (Root) to bottom (Child4) to handle foreign key constraints
allMappings.orgChild3 = await this.syncOrgLevel( // OrgRoot (sync first - no parent dependencies)
queryRunner, const orgRootResult = await this.syncOrgLevel(
OrgChild3,
this.child3Repository,
drafRevisionId,
currentRevisionId,
rootDnaId,
allMappings,
);
// Child2
allMappings.orgChild2 = await this.syncOrgLevel(
queryRunner,
OrgChild2,
this.child2Repository,
drafRevisionId,
currentRevisionId,
rootDnaId,
allMappings,
);
// Child1
allMappings.orgChild1 = await this.syncOrgLevel(
queryRunner,
OrgChild1,
this.child1Repository,
drafRevisionId,
currentRevisionId,
rootDnaId,
allMappings,
);
// OrgRoot (root level - no parent mapping needed)
allMappings.orgRoot = await this.syncOrgLevel(
queryRunner, queryRunner,
OrgRoot, OrgRoot,
this.orgRootRepository, this.orgRootRepository,
drafRevisionId, drafRevisionId,
currentRevisionId, currentRevisionId,
rootDnaId, allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
); );
allMappings.orgRoot = orgRootResult.mapping;
orgSyncStats.orgRoot = orgRootResult.counts;
// Child1 (parent OrgRoot already synced)
const child1Result = await this.syncOrgLevel(
queryRunner,
OrgChild1,
this.child1Repository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
allMappings.orgChild1 = child1Result.mapping;
orgSyncStats.orgChild1 = child1Result.counts;
// Child2 (parents OrgRoot and Child1 already synced)
const child2Result = await this.syncOrgLevel(
queryRunner,
OrgChild2,
this.child2Repository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
allMappings.orgChild2 = child2Result.mapping;
orgSyncStats.orgChild2 = child2Result.counts;
// Child3 (parents OrgRoot, Child1, Child2 already synced)
const child3Result = await this.syncOrgLevel(
queryRunner,
OrgChild3,
this.child3Repository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
allMappings.orgChild3 = child3Result.mapping;
orgSyncStats.orgChild3 = child3Result.counts;
// Child4 (parents OrgRoot, Child1, Child2, Child3 already synced)
const child4Result = await this.syncOrgLevel(
queryRunner,
OrgChild4,
this.child4Repository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
allMappings.orgChild4 = child4Result.mapping;
orgSyncStats.orgChild4 = child4Result.counts;
// Part 2: Sync position data using new org IDs from Part 1 // Part 2: Sync position data using new org IDs from Part 1
// 2.1 Clear current_holderId for affected positions (keep existing logic) // 2.1 Clear current_holderId for affected positions (keep existing logic)
@ -8097,17 +8116,44 @@ export class OrganizationController extends Controller {
} }
// 2.5 Sync positions table for all affected posMasters // 2.5 Sync positions table for all affected posMasters
const positionSyncStats: { deleted: number; updated: number; inserted: number } = {
deleted: 0,
updated: 0,
inserted: 0,
};
for (const [draftPosMasterId, currentPosMasterId] of posMasterMapping) { for (const [draftPosMasterId, currentPosMasterId] of posMasterMapping) {
await this.syncPositionsForPosMaster( const stats = await this.syncPositionsForPosMaster(
queryRunner, queryRunner,
draftPosMasterId, draftPosMasterId,
currentPosMasterId, currentPosMasterId,
drafRevisionId, drafRevisionId,
currentRevisionId, currentRevisionId,
); );
positionSyncStats.deleted += stats.deleted;
positionSyncStats.updated += stats.updated;
positionSyncStats.inserted += stats.inserted;
} }
// Build comprehensive summary
const summary = {
message: "ย้ายโครงสร้างสำเร็จ",
organization: {
orgRoot: orgSyncStats.orgRoot,
orgChild1: orgSyncStats.orgChild1,
orgChild2: orgSyncStats.orgChild2,
orgChild3: orgSyncStats.orgChild3,
orgChild4: orgSyncStats.orgChild4,
},
positionMaster: {
deleted: toDelete.length,
updated: toUpdate.length,
inserted: toInsert.length,
},
position: positionSyncStats,
};
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();
return new HttpSuccess(summary);
} catch (error) { } catch (error) {
console.error("Error moving draft to current:", error); console.error("Error moving draft to current:", error);
await queryRunner.rollbackTransaction(); await queryRunner.rollbackTransaction();
@ -8161,23 +8207,49 @@ export class OrganizationController extends Controller {
repository: any, repository: any,
draftRevisionId: string, draftRevisionId: string,
currentRevisionId: string, currentRevisionId: string,
rootDnaId: string,
parentMappings?: AllOrgMappings, parentMappings?: AllOrgMappings,
): Promise<OrgIdMapping> { draftOrgRootId?: string,
currentOrgRootId?: string,
): Promise<{
mapping: OrgIdMapping;
counts: { deleted: number; updated: number; inserted: number };
}> {
// 1. Fetch draft and current nodes under the given rootDnaId // 1. Fetch draft and current nodes under the given rootDnaId
// Build WHERE condition for draft nodes
const draftWhere: any = {
orgRevisionId: draftRevisionId,
};
if (
draftOrgRootId &&
(entityClass === OrgChild1 ||
entityClass === OrgChild2 ||
entityClass === OrgChild3 ||
entityClass === OrgChild4)
) {
draftWhere.orgRootId = draftOrgRootId;
} else if (entityClass === OrgRoot) {
draftWhere.id = draftOrgRootId;
}
// Build WHERE condition for current nodes
const currentWhere: any = {
orgRevisionId: currentRevisionId,
};
if (
currentOrgRootId &&
(entityClass === OrgChild1 ||
entityClass === OrgChild2 ||
entityClass === OrgChild3 ||
entityClass === OrgChild4)
) {
currentWhere.orgRootId = currentOrgRootId;
} else if (entityClass === OrgRoot) {
currentWhere.id = currentOrgRootId;
}
const [draftNodes, currentNodes] = await Promise.all([ const [draftNodes, currentNodes] = await Promise.all([
repository.find({ repository.find({ where: draftWhere }),
where: { repository.find({ where: currentWhere }),
orgRevisionId: draftRevisionId,
ancestorDNA: Like(`${rootDnaId}%`),
},
}),
repository.find({
where: {
orgRevisionId: currentRevisionId,
ancestorDNA: Like(`${rootDnaId}%`),
},
}),
]); ]);
// 2. Build lookup maps for efficient matching by ancestorDNA // 2. Build lookup maps for efficient matching by ancestorDNA
@ -8270,37 +8342,71 @@ export class OrganizationController extends Controller {
}); });
// Map parent IDs based on entity level // Map parent IDs based on entity level
if (entityClass === OrgChild1 && draft.orgRootId && parentMappings) { if (entityClass === OrgChild1 && draft.orgRootId) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId); if (draft.orgRootId === draftOrgRootId) {
} else if (entityClass === OrgChild2) { newNode.orgRootId = currentOrgRootId;
if (draft.orgRootId && parentMappings) { } else if (parentMappings) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId); newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId);
} }
} else if (entityClass === OrgChild2) {
if (draft.orgRootId) {
if (draft.orgRootId === draftOrgRootId) {
newNode.orgRootId = currentOrgRootId;
} else if (parentMappings) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId);
}
}
if (draft.orgChild1Id && parentMappings) { if (draft.orgChild1Id && parentMappings) {
newNode.orgChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id); const mappedChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id);
if (mappedChild1Id) {
newNode.orgChild1Id = mappedChild1Id;
}
} }
} else if (entityClass === OrgChild3) { } else if (entityClass === OrgChild3) {
if (draft.orgRootId && parentMappings) { if (draft.orgRootId) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId); if (draft.orgRootId === draftOrgRootId) {
newNode.orgRootId = currentOrgRootId;
} else if (parentMappings) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId);
}
} }
if (draft.orgChild1Id && parentMappings) { if (draft.orgChild1Id && parentMappings) {
newNode.orgChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id); const mappedChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id);
if (mappedChild1Id) {
newNode.orgChild1Id = mappedChild1Id;
}
} }
if (draft.orgChild2Id && parentMappings) { if (draft.orgChild2Id && parentMappings) {
newNode.orgChild2Id = parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id); const mappedChild2Id = parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id);
if (mappedChild2Id) {
newNode.orgChild2Id = mappedChild2Id;
}
} }
} else if (entityClass === OrgChild4) { } else if (entityClass === OrgChild4) {
if (draft.orgRootId && parentMappings) { if (draft.orgRootId) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId); if (draft.orgRootId === draftOrgRootId) {
newNode.orgRootId = currentOrgRootId;
} else if (parentMappings) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId);
}
} }
if (draft.orgChild1Id && parentMappings) { if (draft.orgChild1Id && parentMappings) {
newNode.orgChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id); const mappedChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id);
if (mappedChild1Id) {
newNode.orgChild1Id = mappedChild1Id;
}
} }
if (draft.orgChild2Id && parentMappings) { if (draft.orgChild2Id && parentMappings) {
newNode.orgChild2Id = parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id); const mappedChild2Id = parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id);
if (mappedChild2Id) {
newNode.orgChild2Id = mappedChild2Id;
}
} }
if (draft.orgChild3Id && parentMappings) { if (draft.orgChild3Id && parentMappings) {
newNode.orgChild3Id = parentMappings.orgChild3.byDraftId.get(draft.orgChild3Id); const mappedChild3Id = parentMappings.orgChild3.byDraftId.get(draft.orgChild3Id);
if (mappedChild3Id) {
newNode.orgChild3Id = mappedChild3Id;
}
} }
} }
@ -8310,7 +8416,14 @@ export class OrganizationController extends Controller {
mapping.byDraftId.set(draft.id, saved.id); mapping.byDraftId.set(draft.id, saved.id);
} }
return mapping; return {
mapping,
counts: {
deleted: toDelete.length,
updated: toUpdate.length,
inserted: toInsert.length,
},
};
} }
/** /**
@ -8323,7 +8436,7 @@ export class OrganizationController extends Controller {
currentPosMasterId: string, currentPosMasterId: string,
draftRevisionId: string, draftRevisionId: string,
currentRevisionId: string, currentRevisionId: string,
): Promise<void> { ): Promise<{ deleted: number; updated: number; inserted: number }> {
// Fetch draft and current positions for this posMaster // Fetch draft and current positions for this posMaster
const [draftPositions, currentPositions] = await Promise.all([ const [draftPositions, currentPositions] = await Promise.all([
queryRunner.manager.find(Position, { queryRunner.manager.find(Position, {
@ -8347,7 +8460,7 @@ export class OrganizationController extends Controller {
currentPositions.map((p: any) => p.id), currentPositions.map((p: any) => p.id),
); );
} }
return; return { deleted: currentPositions.length, updated: 0, inserted: 0 };
} }
// Build maps for tracking // Build maps for tracking
@ -8365,6 +8478,8 @@ export class OrganizationController extends Controller {
} }
// UPDATE and INSERT // UPDATE and INSERT
let updatedCount = 0;
let insertedCount = 0;
for (const draftPos of draftPositions) { for (const draftPos of draftPositions) {
const current: any = currentByOrderNo.get(draftPos.orderNo); const current: any = currentByOrderNo.get(draftPos.orderNo);
@ -8380,6 +8495,7 @@ export class OrganizationController extends Controller {
positionArea: draftPos.positionArea, positionArea: draftPos.positionArea,
isSpecial: draftPos.isSpecial, isSpecial: draftPos.isSpecial,
}); });
updatedCount++;
} else { } else {
// INSERT new position // INSERT new position
const newPosition = queryRunner.manager.create(Position, { const newPosition = queryRunner.manager.create(Position, {
@ -8388,7 +8504,10 @@ export class OrganizationController extends Controller {
posMasterId: currentPosMasterId, posMasterId: currentPosMasterId,
}); });
await queryRunner.manager.save(newPosition); await queryRunner.manager.save(newPosition);
insertedCount++;
} }
} }
return { deleted: toDelete.length, updated: updatedCount, inserted: insertedCount };
} }
} }