add test, and fix script
This commit is contained in:
parent
638362df1c
commit
f9d626a499
6 changed files with 653 additions and 73 deletions
|
|
@ -7813,7 +7813,7 @@ export class OrganizationController extends Controller {
|
|||
*
|
||||
*/
|
||||
@Post("move-draft-to-current/{rootDnaId}")
|
||||
async moveDraftToCurrent(@Request() request: RequestWithUser) {
|
||||
async moveDraftToCurrent(@Path() rootDnaId: string, @Request() request: RequestWithUser) {
|
||||
const queryRunner = AppDataSource.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
|
@ -7850,14 +7850,14 @@ export class OrganizationController extends Controller {
|
|||
const [orgRootDraft, orgRootCurrent] = await Promise.all([
|
||||
this.orgRootRepository.findOne({
|
||||
where: {
|
||||
ancestorDNA: request.params.rootDnaId,
|
||||
ancestorDNA: rootDnaId,
|
||||
orgRevisionId: drafRevisionId,
|
||||
},
|
||||
select: ["id"],
|
||||
}),
|
||||
this.orgRootRepository.findOne({
|
||||
where: {
|
||||
ancestorDNA: request.params.rootDnaId,
|
||||
ancestorDNA: rootDnaId,
|
||||
orgRevisionId: currentRevisionId,
|
||||
},
|
||||
select: ["id"],
|
||||
|
|
@ -7873,43 +7873,62 @@ export class OrganizationController extends Controller {
|
|||
orgChild1: { byAncestorDNA: new Map(), byDraftId: new Map() },
|
||||
orgChild2: { byAncestorDNA: new Map(), byDraftId: new Map() },
|
||||
orgChild3: { byAncestorDNA: new Map(), byDraftId: new Map() },
|
||||
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
|
||||
// Child4 (leaf nodes - no children depending on them)
|
||||
allMappings.orgChild4 = await this.syncOrgLevel(
|
||||
queryRunner, OrgChild4, this.child4Repository,
|
||||
drafRevisionId, currentRevisionId,
|
||||
request.params.rootDnaId, allMappings
|
||||
queryRunner,
|
||||
OrgChild4,
|
||||
this.child4Repository,
|
||||
drafRevisionId,
|
||||
currentRevisionId,
|
||||
rootDnaId,
|
||||
allMappings,
|
||||
);
|
||||
|
||||
// Child3
|
||||
allMappings.orgChild3 = await this.syncOrgLevel(
|
||||
queryRunner, OrgChild3, this.child3Repository,
|
||||
drafRevisionId, currentRevisionId,
|
||||
request.params.rootDnaId, allMappings
|
||||
queryRunner,
|
||||
OrgChild3,
|
||||
this.child3Repository,
|
||||
drafRevisionId,
|
||||
currentRevisionId,
|
||||
rootDnaId,
|
||||
allMappings,
|
||||
);
|
||||
|
||||
// Child2
|
||||
allMappings.orgChild2 = await this.syncOrgLevel(
|
||||
queryRunner, OrgChild2, this.child2Repository,
|
||||
drafRevisionId, currentRevisionId,
|
||||
request.params.rootDnaId, allMappings
|
||||
queryRunner,
|
||||
OrgChild2,
|
||||
this.child2Repository,
|
||||
drafRevisionId,
|
||||
currentRevisionId,
|
||||
rootDnaId,
|
||||
allMappings,
|
||||
);
|
||||
|
||||
// Child1
|
||||
allMappings.orgChild1 = await this.syncOrgLevel(
|
||||
queryRunner, OrgChild1, this.child1Repository,
|
||||
drafRevisionId, currentRevisionId,
|
||||
request.params.rootDnaId, allMappings
|
||||
queryRunner,
|
||||
OrgChild1,
|
||||
this.child1Repository,
|
||||
drafRevisionId,
|
||||
currentRevisionId,
|
||||
rootDnaId,
|
||||
allMappings,
|
||||
);
|
||||
|
||||
// OrgRoot (root level - no parent mapping needed)
|
||||
allMappings.orgRoot = await this.syncOrgLevel(
|
||||
queryRunner, OrgRoot, this.orgRootRepository,
|
||||
drafRevisionId, currentRevisionId,
|
||||
request.params.rootDnaId
|
||||
queryRunner,
|
||||
OrgRoot,
|
||||
this.orgRootRepository,
|
||||
drafRevisionId,
|
||||
currentRevisionId,
|
||||
rootDnaId,
|
||||
);
|
||||
|
||||
// Part 2: Sync position data using new org IDs from Part 1
|
||||
|
|
@ -7939,17 +7958,17 @@ export class OrganizationController extends Controller {
|
|||
|
||||
// Clear current_holderId for positions that will have new holders
|
||||
const nextHolderIds = posMasterDraft
|
||||
.filter(x => x.next_holderId != null)
|
||||
.map(x => x.next_holderId);
|
||||
.filter((x) => x.next_holderId != null)
|
||||
.map((x) => x.next_holderId);
|
||||
|
||||
if (nextHolderIds.length > 0) {
|
||||
await queryRunner.manager.update(
|
||||
PosMaster,
|
||||
{
|
||||
orgRevisionId: currentRevisionId,
|
||||
current_holderId: In(nextHolderIds)
|
||||
current_holderId: In(nextHolderIds),
|
||||
},
|
||||
{ current_holderId: null, isSit: false }
|
||||
{ current_holderId: null, isSit: false },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -7974,29 +7993,21 @@ export class OrganizationController extends Controller {
|
|||
});
|
||||
|
||||
// Build lookup map
|
||||
const currentByDNA = new Map(
|
||||
posMasterCurrent.map(p => [p.ancestorDNA, p])
|
||||
);
|
||||
const currentByDNA = new Map(posMasterCurrent.map((p) => [p.ancestorDNA, p]));
|
||||
|
||||
// 2.3 Batch DELETE: positions in current but not in draft
|
||||
const toDelete = posMasterCurrent.filter(
|
||||
curr => !posMasterDraft.some(d => d.ancestorDNA === curr.ancestorDNA)
|
||||
(curr) => !posMasterDraft.some((d) => d.ancestorDNA === curr.ancestorDNA),
|
||||
);
|
||||
|
||||
if (toDelete.length > 0) {
|
||||
const toDeleteIds = toDelete.map(p => p.id);
|
||||
const toDeleteIds = toDelete.map((p) => p.id);
|
||||
|
||||
// Cascade delete positions first
|
||||
await queryRunner.manager.delete(
|
||||
Position,
|
||||
{ posMasterId: In(toDeleteIds) }
|
||||
);
|
||||
await queryRunner.manager.delete(Position, { posMasterId: In(toDeleteIds) });
|
||||
|
||||
// Then delete posMaster records
|
||||
await queryRunner.manager.delete(
|
||||
PosMaster,
|
||||
toDeleteIds
|
||||
);
|
||||
await queryRunner.manager.delete(PosMaster, toDeleteIds);
|
||||
}
|
||||
|
||||
// 2.4 Process draft positions (UPDATE or INSERT)
|
||||
|
|
@ -8077,7 +8088,7 @@ export class OrganizationController extends Controller {
|
|||
// saved is an array, map each to its draft ID
|
||||
if (Array.isArray(saved)) {
|
||||
for (let i = 0; i < saved.length; i++) {
|
||||
const draftPos = posMasterDraft.filter(d => !currentByDNA.has(d.ancestorDNA))[i];
|
||||
const draftPos = posMasterDraft.filter((d) => !currentByDNA.has(d.ancestorDNA))[i];
|
||||
if (draftPos && saved[i]) {
|
||||
posMasterMapping.set(draftPos.id, saved[i].id);
|
||||
}
|
||||
|
|
@ -8092,7 +8103,7 @@ export class OrganizationController extends Controller {
|
|||
draftPosMasterId,
|
||||
currentPosMasterId,
|
||||
drafRevisionId,
|
||||
currentRevisionId
|
||||
currentRevisionId,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -8107,10 +8118,7 @@ export class OrganizationController extends Controller {
|
|||
/**
|
||||
* Helper function: Map draft ID to current ID using the mapping
|
||||
*/
|
||||
private resolveOrgId(
|
||||
draftId: string | null,
|
||||
mapping: OrgIdMapping
|
||||
): string | null {
|
||||
private resolveOrgId(draftId: string | null, mapping: OrgIdMapping): string | null {
|
||||
if (!draftId) return null;
|
||||
return mapping.byDraftId.get(draftId) ?? null;
|
||||
}
|
||||
|
|
@ -8121,10 +8129,10 @@ export class OrganizationController extends Controller {
|
|||
private async cascadeDeletePositions(
|
||||
queryRunner: any,
|
||||
node: any,
|
||||
entityClass: any
|
||||
entityClass: any,
|
||||
): Promise<void> {
|
||||
const whereClause: any = {
|
||||
orgRevisionId: node.orgRevisionId
|
||||
orgRevisionId: node.orgRevisionId,
|
||||
};
|
||||
|
||||
// Determine which FK field to use based on entity type
|
||||
|
|
@ -8154,22 +8162,22 @@ export class OrganizationController extends Controller {
|
|||
draftRevisionId: string,
|
||||
currentRevisionId: string,
|
||||
rootDnaId: string,
|
||||
parentMappings?: AllOrgMappings
|
||||
parentMappings?: AllOrgMappings,
|
||||
): Promise<OrgIdMapping> {
|
||||
// 1. Fetch draft and current nodes under the given rootDnaId
|
||||
const [draftNodes, currentNodes] = await Promise.all([
|
||||
repository.find({
|
||||
where: {
|
||||
orgRevisionId: draftRevisionId,
|
||||
ancestorDNA: Like(`${rootDnaId}%`)
|
||||
}
|
||||
ancestorDNA: Like(`${rootDnaId}%`),
|
||||
},
|
||||
}),
|
||||
repository.find({
|
||||
where: {
|
||||
orgRevisionId: currentRevisionId,
|
||||
ancestorDNA: Like(`${rootDnaId}%`)
|
||||
}
|
||||
})
|
||||
ancestorDNA: Like(`${rootDnaId}%`),
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
// 2. Build lookup maps for efficient matching by ancestorDNA
|
||||
|
|
@ -8178,7 +8186,7 @@ export class OrganizationController extends Controller {
|
|||
|
||||
const mapping: OrgIdMapping = {
|
||||
byAncestorDNA: new Map(),
|
||||
byDraftId: new Map()
|
||||
byDraftId: new Map(),
|
||||
};
|
||||
|
||||
// 3. DELETE: Current nodes not in draft (cascade delete positions first)
|
||||
|
|
@ -8203,36 +8211,46 @@ export class OrganizationController extends Controller {
|
|||
|
||||
// Map parent IDs based on entity level
|
||||
if (entityClass === OrgChild1 && draft.orgRootId && parentMappings) {
|
||||
updateData.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
|
||||
updateData.orgRootId =
|
||||
parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
|
||||
} else if (entityClass === OrgChild2) {
|
||||
if (draft.orgRootId && parentMappings) {
|
||||
updateData.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
|
||||
updateData.orgRootId =
|
||||
parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
|
||||
}
|
||||
if (draft.orgChild1Id && parentMappings) {
|
||||
updateData.orgChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
|
||||
updateData.orgChild1Id =
|
||||
parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
|
||||
}
|
||||
} else if (entityClass === OrgChild3) {
|
||||
if (draft.orgRootId && parentMappings) {
|
||||
updateData.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
|
||||
updateData.orgRootId =
|
||||
parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
|
||||
}
|
||||
if (draft.orgChild1Id && parentMappings) {
|
||||
updateData.orgChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
|
||||
updateData.orgChild1Id =
|
||||
parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
|
||||
}
|
||||
if (draft.orgChild2Id && parentMappings) {
|
||||
updateData.orgChild2Id = parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id) ?? draft.orgChild2Id;
|
||||
updateData.orgChild2Id =
|
||||
parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id) ?? draft.orgChild2Id;
|
||||
}
|
||||
} else if (entityClass === OrgChild4) {
|
||||
if (draft.orgRootId && parentMappings) {
|
||||
updateData.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
|
||||
updateData.orgRootId =
|
||||
parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
|
||||
}
|
||||
if (draft.orgChild1Id && parentMappings) {
|
||||
updateData.orgChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
|
||||
updateData.orgChild1Id =
|
||||
parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
|
||||
}
|
||||
if (draft.orgChild2Id && parentMappings) {
|
||||
updateData.orgChild2Id = parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id) ?? draft.orgChild2Id;
|
||||
updateData.orgChild2Id =
|
||||
parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id) ?? draft.orgChild2Id;
|
||||
}
|
||||
if (draft.orgChild3Id && parentMappings) {
|
||||
updateData.orgChild3Id = parentMappings.orgChild3.byDraftId.get(draft.orgChild3Id) ?? draft.orgChild3Id;
|
||||
updateData.orgChild3Id =
|
||||
parentMappings.orgChild3.byDraftId.get(draft.orgChild3Id) ?? draft.orgChild3Id;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8304,21 +8322,21 @@ export class OrganizationController extends Controller {
|
|||
draftPosMasterId: string,
|
||||
currentPosMasterId: string,
|
||||
draftRevisionId: string,
|
||||
currentRevisionId: string
|
||||
currentRevisionId: string,
|
||||
): Promise<void> {
|
||||
// Fetch draft and current positions for this posMaster
|
||||
const [draftPositions, currentPositions] = await Promise.all([
|
||||
queryRunner.manager.find(Position, {
|
||||
where: {
|
||||
posMasterId: draftPosMasterId
|
||||
posMasterId: draftPosMasterId,
|
||||
},
|
||||
order: { orderNo: 'ASC' }
|
||||
order: { orderNo: "ASC" },
|
||||
}),
|
||||
queryRunner.manager.find(Position, {
|
||||
where: {
|
||||
posMasterId: currentPosMasterId
|
||||
}
|
||||
})
|
||||
posMasterId: currentPosMasterId,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
// If no draft positions, delete all current positions
|
||||
|
|
@ -8326,16 +8344,14 @@ export class OrganizationController extends Controller {
|
|||
if (currentPositions.length > 0) {
|
||||
await queryRunner.manager.delete(
|
||||
Position,
|
||||
currentPositions.map((p: any) => p.id)
|
||||
currentPositions.map((p: any) => p.id),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Build maps for tracking
|
||||
const currentByOrderNo = new Map(
|
||||
currentPositions.map((p: any) => [p.orderNo, p])
|
||||
);
|
||||
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));
|
||||
|
|
@ -8344,7 +8360,7 @@ export class OrganizationController extends Controller {
|
|||
if (toDelete.length > 0) {
|
||||
await queryRunner.manager.delete(
|
||||
Position,
|
||||
toDelete.map((p: any) => p.id)
|
||||
toDelete.map((p: any) => p.id),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue