From bda80475d15f2f99103aaf2a7cf18f5366e179f2 Mon Sep 17 00:00:00 2001 From: waruneeauy Date: Tue, 22 Jul 2025 10:29:07 +0700 Subject: [PATCH] tuning api org chart --- src/controllers/OrganizationController.ts | 1051 +++++++++------------ 1 file changed, 463 insertions(+), 588 deletions(-) diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index a4c67c32..97839425 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -3340,325 +3340,258 @@ export class OrganizationController extends Controller { let posMasterChild3: any; let posMasterChild4: any; if (data.orgRevisionIsCurrent == true && data.orgRevisionIsDraft == false) { - posMasterRoot = await this.posMasterRepository.find({ + // ใช้ query เดียวแทน 5 queries แยก เพื่อความเร็วในการทำงาน + const allPosMasters = await this.posMasterRepository.find({ where: { orgRevisionId: data.id, - orgChild1Id: IsNull(), - // current_holderId: Not(IsNull()), }, - relations: ["current_holder", "orgRoot"], + relations: [ + "current_holder", + "orgRoot", + "orgChild1", + "orgChild2", + "orgChild3", + "orgChild4", + ], order: { posMasterOrder: "ASC" }, }); - posMasterChild1 = await this.posMasterRepository.find({ - where: { - orgRevisionId: data.id, - orgChild2Id: IsNull(), - orgChild1Id: Not(IsNull()), - // current_holderId: Not(IsNull()), - }, - relations: ["current_holder", "orgChild1"], - order: { posMasterOrder: "ASC" }, + + // แยกข้อมูลด้วย JavaScript แทนการใช้ database queries หลาย ๆ ครั้ง + posMasterRoot = allPosMasters.filter((item) => item.orgChild1Id === null); + posMasterChild1 = allPosMasters.filter( + (item) => item.orgChild2Id === null && item.orgChild1Id !== null, + ); + posMasterChild2 = allPosMasters.filter( + (item) => item.orgChild3Id === null && item.orgChild2Id !== null, + ); + posMasterChild3 = allPosMasters.filter( + (item) => item.orgChild4Id === null && item.orgChild3Id !== null, + ); + posMasterChild4 = allPosMasters.filter((item) => item.orgChild4Id !== null); + + // สร้าง Maps เพื่อ lookup ที่เร็วขึ้น แทนการใช้ filter หลายรอบ + const rootByOrgRootId = new Map(); + const child1ByOrgRootId = new Map(); + const child1ByOrgChild1Id = new Map(); + const child2ByOrgChild1Id = new Map(); + const child2ByOrgChild2Id = new Map(); + const child3ByOrgChild2Id = new Map(); + const child3ByOrgChild3Id = new Map(); + const child4ByOrgChild3Id = new Map(); + + // Pre-compute all lookups เพื่อหลีกเลี่ยงการ filter ซ้ำๆ + posMasterRoot.forEach((item: PosMaster) => { + if (item.current_holderId) { + if (item.isDirector) { + // Root directors will be processed in main loop + } else { + // Group root non-directors by orgRootId + const key = item.orgRootId || ""; + if (!rootByOrgRootId.has(key)) rootByOrgRootId.set(key, []); + rootByOrgRootId.get(key)!.push(item); + } + } }); - posMasterChild2 = await this.posMasterRepository.find({ - where: { - orgRevisionId: data.id, - orgChild3Id: IsNull(), - orgChild2Id: Not(IsNull()), - // current_holderId: Not(IsNull()), - }, - relations: ["current_holder", "orgChild2"], - order: { posMasterOrder: "ASC" }, + + posMasterChild1.forEach((item: PosMaster) => { + if (item.isDirector) { + // Group child1 directors by orgRootId + const key = item.orgRootId || ""; + if (!child1ByOrgRootId.has(key)) child1ByOrgRootId.set(key, []); + child1ByOrgRootId.get(key)!.push(item); + } else if (item.current_holderId) { + // Group child1 non-directors by orgChild1Id + const key = item.orgChild1Id || ""; + if (!child1ByOrgChild1Id.has(key)) child1ByOrgChild1Id.set(key, []); + child1ByOrgChild1Id.get(key)!.push(item); + } }); - posMasterChild3 = await this.posMasterRepository.find({ - where: { - orgRevisionId: data.id, - orgChild4Id: IsNull(), - orgChild3Id: Not(IsNull()), - // current_holderId: Not(IsNull()), - }, - relations: ["current_holder", "orgChild3"], - order: { posMasterOrder: "ASC" }, + + posMasterChild2.forEach((item: PosMaster) => { + if (item.isDirector) { + // Group child2 directors by orgChild1Id + const key = item.orgChild1Id || ""; + if (!child2ByOrgChild1Id.has(key)) child2ByOrgChild1Id.set(key, []); + child2ByOrgChild1Id.get(key)!.push(item); + } else if (item.current_holderId) { + // Group child2 non-directors by orgChild2Id + const key = item.orgChild2Id || ""; + if (!child2ByOrgChild2Id.has(key)) child2ByOrgChild2Id.set(key, []); + child2ByOrgChild2Id.get(key)!.push(item); + } }); - posMasterChild4 = await this.posMasterRepository.find({ - where: { - orgRevisionId: data.id, - orgChild4Id: Not(IsNull()), - // current_holderId: Not(IsNull()), - }, - relations: ["current_holder", "orgChild4"], - order: { posMasterOrder: "ASC" }, + + posMasterChild3.forEach((item: PosMaster) => { + if (item.isDirector) { + // Group child3 directors by orgChild2Id + const key = item.orgChild2Id || ""; + if (!child3ByOrgChild2Id.has(key)) child3ByOrgChild2Id.set(key, []); + child3ByOrgChild2Id.get(key)!.push(item); + } else if (item.current_holderId) { + // Group child3 non-directors by orgChild3Id + const key = item.orgChild3Id || ""; + if (!child3ByOrgChild3Id.has(key)) child3ByOrgChild3Id.set(key, []); + child3ByOrgChild3Id.get(key)!.push(item); + } + }); + + posMasterChild4.forEach((item: PosMaster) => { + if (item.isDirector) { + // Group child4 directors by orgChild3Id + const key = item.orgChild3Id || ""; + if (!child4ByOrgChild3Id.has(key)) child4ByOrgChild3Id.set(key, []); + child4ByOrgChild3Id.get(key)!.push(item); + } + }); + + // Helper function เพื่อสร้าง node object + const createNode = (item: PosMaster, level: number, holder: any, orgInfo: any) => ({ + level, + personID: holder?.id ?? "", + name: holder ? `${holder.firstName} ${holder.lastName}` : "ว่าง", + avatar: + holder?.avatar && holder?.avatarName ? `${holder.avatar}/${holder.avatarName}` : null, + positionName: holder?.position ?? "", + positionNum: `${orgInfo.shortName} ${item.posMasterNo}`, + positionNumInt: item.posMasterNo, + departmentName: orgInfo.name, + organizationId: orgInfo.id, + children: [] as any[], }); let formattedData = posMasterRoot .filter((x: any) => x.current_holderId != null && x.isDirector) .map((x0: PosMaster) => { - // Level 2 - const childLevel1 = [ - // Level 2: Root not director - ...posMasterRoot - .filter( - (x: any) => - x.orgRootId == x0.orgRootId && x.current_holderId != null && !x.isDirector, - ) - .map((x00: PosMaster) => ({ - level: 2, - personID: x00.current_holder ? x00.current_holder.id : "", - name: x00.current_holder - ? `${x00.current_holder.firstName} ${x00.current_holder.lastName}` - : "ว่าง", - avatar: - x00.current_holder && - x00.current_holder.avatar != null && - x00.current_holder.avatarName != null - ? `${x00.current_holder.avatar}/${x00.current_holder.avatarName}` - : null, - positionName: x00.current_holder ? x00.current_holder.position : "", - positionNum: `${x00.orgRoot.orgRootShortName} ${x00.posMasterNo}`, - positionNumInt: x00.posMasterNo, - departmentName: x00.orgRoot.orgRootName, - organizationId: x00.orgRoot.id, - children: [], - })), - // Level 2: Child 1 director - ...posMasterChild1 - .filter((x: any) => x.isDirector && x.orgRootId == x0.orgRootId) - .map((x1: PosMaster) => { - // Level 3 - const childLevel2 = [ - // Level 3: Child 1 not director - ...posMasterChild1 - .filter( - (x: any) => - x.orgChild1Id == x1.orgChild1Id && - !x.isDirector && - x.current_holderId != null, - ) - .map((x11: PosMaster) => { - return { - level: 3, - personID: x11.current_holder ? x11.current_holder.id : "", - name: x11.current_holder - ? `${x11.current_holder.firstName} ${x11.current_holder.lastName}` - : "ว่าง", - avatar: - x11.current_holder && - x11.current_holder.avatar != null && - x11.current_holder.avatarName != null - ? `${x11.current_holder.avatar}/${x11.current_holder.avatarName}` - : null, - positionName: x11.current_holder ? x11.current_holder.position : "", - positionNum: `${x11.orgChild1.orgChild1ShortName} ${x11.posMasterNo}`, - positionNumInt: x11.posMasterNo, - departmentName: x11.orgChild1.orgChild1Name, - organizationId: x11.orgChild1.id, - children: [], - }; - }), - // Level 3: Child 2 director - ...posMasterChild2 - .filter((x: any) => x.isDirector && x.orgChild1Id == x1.orgChild1Id) - .map((x2: PosMaster) => { - const childLevel3 = [ - // Level 4: Child 2 not director - ...posMasterChild2 - .filter( - (x: any) => - !x.isDirector && - x.current_holderId != null && - x.orgChild1Id == x2.orgChild1Id, - ) - .map((x22: PosMaster) => ({ - level: 4, - personID: x22.current_holder ? x22.current_holder.id : "", - name: x22.current_holder - ? `${x22.current_holder.firstName} ${x22.current_holder.lastName}` - : "ว่าง", - avatar: - x22.current_holder && - x22.current_holder.avatar != null && - x22.current_holder.avatarName != null - ? `${x22.current_holder.avatar}/${x22.current_holder.avatarName}` - : null, - positionName: x22.current_holder ? x22.current_holder.position : "", - positionNum: `${x22.orgChild2.orgChild2ShortName} ${x22.posMasterNo}`, - positionNumInt: x22.posMasterNo, - departmentName: x22.orgChild2.orgChild2Name, - organizationId: x22.orgChild2.id, - children: [], - })), - // Level 4: Child 3 director - ...posMasterChild3 - .filter((x: any) => x.isDirector && x.orgChild2Id == x2.orgChild2Id) - .map((x3: PosMaster) => { - const childLevel4 = [ - ...posMasterChild3 - .filter( - (x: any) => - !x.isDirector && - x.current_holderId != null && - x.orgChild2Id == x3.orgChild2Id, - ) - .map((x33: PosMaster) => ({ - level: 5, - personID: x33.current_holder ? x33.current_holder.id : "", - name: x33.current_holder - ? `${x33.current_holder.firstName} ${x33.current_holder.lastName}` - : "ว่าง", - avatar: - x33.current_holder && - x33.current_holder.avatar != null && - x33.current_holder.avatarName != null - ? `${x33.current_holder.avatar}/${x33.current_holder.avatarName}` - : null, - positionName: x33.current_holder - ? x33.current_holder.position - : "", - positionNum: `${x33.orgChild3.orgChild3ShortName} ${x33.posMasterNo}`, - positionNumInt: x33.posMasterNo, - departmentName: x33.orgChild3.orgChild3Name, - organizationId: x33.orgChild3.id, - children: [], - })), - ...posMasterChild4 - .filter((x: any) => x.isDirector && x.orgChild3Id == x3.orgChild3Id) - .map((x4: PosMaster) => { - const childLevel5 = posMasterChild4 - .filter( - (x: any) => - !x.isDirector && - x.current_holderId != null && - x.orgChild3Id == x4.orgChild3Id, - ) - .map((x44: PosMaster) => ({ - level: 5, - personID: x44.current_holder ? x44.current_holder.id : "", - name: x44.current_holder - ? `${x44.current_holder.firstName} ${x44.current_holder.lastName}` - : "ว่าง", - avatar: - x44.current_holder && - x44.current_holder.avatar != null && - x44.current_holder.avatarName != null - ? `${x44.current_holder.avatar}/${x44.current_holder.avatarName}` - : null, - positionName: x44.current_holder - ? x44.current_holder.position - : "", - positionNum: `${x44.orgChild4.orgChild4ShortName} ${x44.posMasterNo}`, - positionNumInt: x44.posMasterNo, - departmentName: x44.orgChild4.orgChild4Name, - organizationId: x44.orgChild4.id, - children: [], - })); + const childLevel1: any[] = []; - return { - level: 4, - personID: x4.current_holder ? x4.current_holder.id : "", - name: x4.current_holder - ? `${x4.current_holder.firstName} ${x4.current_holder.lastName}` - : "ว่าง", - avatar: - x4.current_holder && - x4.current_holder.avatar != null && - x4.current_holder.avatarName != null - ? `${x4.current_holder.avatar}/${x4.current_holder.avatarName}` - : null, - positionName: x4.current_holder - ? x4.current_holder.position - : "", - positionNum: `${x4.orgChild4.orgChild4ShortName} ${x4.posMasterNo}`, - positionNumInt: x4.posMasterNo, - departmentName: x4.orgChild4.orgChild4Name, - organizationId: x4.orgChild4.id, - children: childLevel5, - }; - }), - ]; - - return { - level: 4, - personID: x3.current_holder ? x3.current_holder.id : "", - name: x3.current_holder - ? `${x3.current_holder.firstName} ${x3.current_holder.lastName}` - : "ว่าง", - avatar: - x3.current_holder && - x3.current_holder.avatar != null && - x3.current_holder.avatarName != null - ? `${x3.current_holder.avatar}/${x3.current_holder.avatarName}` - : null, - positionName: x3.current_holder ? x3.current_holder.position : "", - positionNum: `${x3.orgChild3.orgChild3ShortName} ${x3.posMasterNo}`, - positionNumInt: x3.posMasterNo, - departmentName: x3.orgChild3.orgChild3Name, - organizationId: x3.orgChild3.id, - children: childLevel4, - }; - }), - ]; - - return { - level: 3, - personID: x2.current_holder ? x2.current_holder.id : "", - name: x2.current_holder - ? `${x2.current_holder.firstName} ${x2.current_holder.lastName}` - : "ว่าง", - avatar: - x2.current_holder && - x2.current_holder.avatar != null && - x2.current_holder.avatarName != null - ? `${x2.current_holder.avatar}/${x2.current_holder.avatarName}` - : null, - positionName: x2.current_holder ? x2.current_holder.position : "", - positionNum: `${x2.orgChild2.orgChild2ShortName} ${x2.posMasterNo}`, - positionNumInt: x2.posMasterNo, - departmentName: x2.orgChild2.orgChild2Name, - organizationId: x2.orgChild2.id, - children: childLevel3, - }; - }), - ]; - - return { - level: 2, - personID: x1.current_holder ? x1.current_holder.id : "", - name: x1.current_holder - ? `${x1.current_holder.firstName} ${x1.current_holder.lastName}` - : "ว่าง", - avatar: - x1.current_holder && - x1.current_holder.avatar != null && - x1.current_holder.avatarName != null - ? `${x1.current_holder.avatar}/${x1.current_holder.avatarName}` - : null, - positionName: x1.current_holder ? x1.current_holder.position : "", - positionNum: `${x1.orgChild1.orgChild1ShortName} ${x1.posMasterNo}`, - positionNumInt: x1.posMasterNo, - departmentName: x1.orgChild1.orgChild1Name, - organizationId: x1.orgChild1.id, - children: childLevel2, - }; + // Add root non-directors (Level 2) + const rootNonDirectors = rootByOrgRootId.get(x0.orgRootId || "") || []; + rootNonDirectors.forEach((x00: PosMaster) => { + childLevel1.push( + createNode(x00, 2, x00.current_holder, { + shortName: x00.orgRoot.orgRootShortName, + name: x00.orgRoot.orgRootName, + id: x00.orgRoot.id, }), - ]; + ); + }); + + // Add child1 directors (Level 2) + const child1Directors = child1ByOrgRootId.get(x0.orgRootId || "") || []; + child1Directors.forEach((x1: PosMaster) => { + const childLevel2: any[] = []; + + // Add child1 non-directors (Level 3) + const child1NonDirectors = child1ByOrgChild1Id.get(x1.orgChild1Id || "") || []; + child1NonDirectors.forEach((x11: PosMaster) => { + childLevel2.push( + createNode(x11, 3, x11.current_holder, { + shortName: x11.orgChild1.orgChild1ShortName, + name: x11.orgChild1.orgChild1Name, + id: x11.orgChild1.id, + }), + ); + }); + + // Add child2 directors (Level 3) + const child2Directors = child2ByOrgChild1Id.get(x1.orgChild1Id || "") || []; + child2Directors.forEach((x2: PosMaster) => { + const childLevel3: any[] = []; + + // Add child2 non-directors (Level 4) + const child2NonDirectors = child2ByOrgChild2Id.get(x2.orgChild2Id || "") || []; + child2NonDirectors.forEach((x22: PosMaster) => { + childLevel3.push( + createNode(x22, 4, x22.current_holder, { + shortName: x22.orgChild2.orgChild2ShortName, + name: x22.orgChild2.orgChild2Name, + id: x22.orgChild2.id, + }), + ); + }); + + // Add child3 directors (Level 4) + const child3Directors = child3ByOrgChild2Id.get(x2.orgChild2Id || "") || []; + child3Directors.forEach((x3: PosMaster) => { + const childLevel4: any[] = []; + + // Add child3 non-directors (Level 5) + const child3NonDirectors = child3ByOrgChild3Id.get(x3.orgChild3Id || "") || []; + child3NonDirectors.forEach((x33: PosMaster) => { + childLevel4.push( + createNode(x33, 5, x33.current_holder, { + shortName: x33.orgChild3.orgChild3ShortName, + name: x33.orgChild3.orgChild3Name, + id: x33.orgChild3.id, + }), + ); + }); + + // Add child4 directors (Level 5) + const child4Directors = child4ByOrgChild3Id.get(x3.orgChild3Id || "") || []; + child4Directors.forEach((x4: PosMaster) => { + const childLevel5: any[] = []; + + // Add child4 non-directors (Level 5) + posMasterChild4 + .filter( + (x: PosMaster) => + !x.isDirector && x.current_holderId && x.orgChild3Id === x4.orgChild3Id, + ) + .forEach((x44: PosMaster) => { + childLevel5.push( + createNode(x44, 5, x44.current_holder, { + shortName: x44.orgChild4.orgChild4ShortName, + name: x44.orgChild4.orgChild4Name, + id: x44.orgChild4.id, + }), + ); + }); + + const child4Node = createNode(x4, 4, x4.current_holder, { + shortName: x4.orgChild4.orgChild4ShortName, + name: x4.orgChild4.orgChild4Name, + id: x4.orgChild4.id, + }); + child4Node.children = childLevel5; + childLevel4.push(child4Node); + }); + + const child3Node = createNode(x3, 4, x3.current_holder, { + shortName: x3.orgChild3.orgChild3ShortName, + name: x3.orgChild3.orgChild3Name, + id: x3.orgChild3.id, + }); + child3Node.children = childLevel4; + childLevel3.push(child3Node); + }); + + const child2Node = createNode(x2, 3, x2.current_holder, { + shortName: x2.orgChild2.orgChild2ShortName, + name: x2.orgChild2.orgChild2Name, + id: x2.orgChild2.id, + }); + child2Node.children = childLevel3; + childLevel2.push(child2Node); + }); + + const child1Node = createNode(x1, 2, x1.current_holder, { + shortName: x1.orgChild1.orgChild1ShortName, + name: x1.orgChild1.orgChild1Name, + id: x1.orgChild1.id, + }); + child1Node.children = childLevel2; + childLevel1.push(child1Node); + }); // Root Level 1 - return { - level: 1, - personID: x0.current_holder.id, - name: `${x0.current_holder.firstName} ${x0.current_holder.lastName}`, - avatar: - x0.current_holder && - x0.current_holder.avatar != null && - x0.current_holder.avatarName != null - ? `${x0.current_holder.avatar}/${x0.current_holder.avatarName}` - : null, - positionName: x0.current_holder.position, - positionNum: `${x0.orgRoot.orgRootShortName} ${x0.posMasterNo}`, - positionNumInt: x0.posMasterNo, - departmentName: x0.orgRoot.orgRootName, - organizationId: x0.orgRoot.id, - children: childLevel1, - }; + const rootNode = createNode(x0, 1, x0.current_holder, { + shortName: x0.orgRoot.orgRootShortName, + name: x0.orgRoot.orgRootName, + id: x0.orgRoot.id, + }); + rootNode.children = childLevel1; + return rootNode; }); const formattedData_ = { @@ -3674,309 +3607,251 @@ export class OrganizationController extends Controller { }; return new HttpSuccess([formattedData_]); } else if (data.orgRevisionIsCurrent == false && data.orgRevisionIsDraft == true) { - posMasterRoot = await this.posMasterRepository.find({ + // ใช้ query เดียวแทน 5 queries แยก เพื่อความเร็วในการทำงาน + const allPosMasters = await this.posMasterRepository.find({ where: { orgRevisionId: data.id, - orgChild1Id: IsNull(), // next_holderId: Not(IsNull()), }, - relations: ["next_holder", "orgRoot"], + relations: ["next_holder", "orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"], }); - posMasterChild1 = await this.posMasterRepository.find({ - where: { - orgRevisionId: data.id, - orgChild2Id: IsNull(), - orgChild1Id: Not(IsNull()), - // next_holderId: Not(IsNull()), - }, - relations: ["next_holder", "orgChild1"], + + // แยกข้อมูลด้วย JavaScript แทนการใช้ database queries หลาย ๆ ครั้ง + posMasterRoot = allPosMasters.filter((item) => item.orgChild1Id === null); + posMasterChild1 = allPosMasters.filter( + (item) => item.orgChild2Id === null && item.orgChild1Id !== null, + ); + posMasterChild2 = allPosMasters.filter( + (item) => item.orgChild3Id === null && item.orgChild2Id !== null, + ); + posMasterChild3 = allPosMasters.filter( + (item) => item.orgChild4Id === null && item.orgChild3Id !== null, + ); + posMasterChild4 = allPosMasters.filter((item) => item.orgChild4Id !== null); + + // สร้าง Maps เพื่อ lookup ที่เร็วขึ้น แทนการใช้ filter หลายรอบ สำหรับ draft version + const rootByOrgRootIdDraft = new Map(); + const child1ByOrgRootIdDraft = new Map(); + const child1ByOrgChild1IdDraft = new Map(); + const child2ByOrgChild1IdDraft = new Map(); + const child2ByOrgChild2IdDraft = new Map(); + const child3ByOrgChild2IdDraft = new Map(); + const child3ByOrgChild3IdDraft = new Map(); + const child4ByOrgChild3IdDraft = new Map(); + + // Pre-compute all lookups เพื่อหลีกเลี่ยงการ filter ซ้ำๆ สำหรับ draft version + posMasterRoot.forEach((item: PosMaster) => { + if (item.next_holderId) { + if (item.isDirector) { + // Root directors will be processed in main loop + } else { + // Group root non-directors by orgRootId + const key = item.orgRootId || ""; + if (!rootByOrgRootIdDraft.has(key)) rootByOrgRootIdDraft.set(key, []); + rootByOrgRootIdDraft.get(key)!.push(item); + } + } }); - posMasterChild2 = await this.posMasterRepository.find({ - where: { - orgRevisionId: data.id, - orgChild3Id: IsNull(), - orgChild2Id: Not(IsNull()), - // next_holderId: Not(IsNull()), - }, - relations: ["next_holder", "orgChild2"], + + posMasterChild1.forEach((item: PosMaster) => { + if (item.isDirector) { + // Group child1 directors by orgRootId + const key = item.orgRootId || ""; + if (!child1ByOrgRootIdDraft.has(key)) child1ByOrgRootIdDraft.set(key, []); + child1ByOrgRootIdDraft.get(key)!.push(item); + } else if (item.next_holderId) { + // Group child1 non-directors by orgChild1Id + const key = item.orgChild1Id || ""; + if (!child1ByOrgChild1IdDraft.has(key)) child1ByOrgChild1IdDraft.set(key, []); + child1ByOrgChild1IdDraft.get(key)!.push(item); + } }); - posMasterChild3 = await this.posMasterRepository.find({ - where: { - orgRevisionId: data.id, - orgChild4Id: IsNull(), - orgChild3Id: Not(IsNull()), - // next_holderId: Not(IsNull()), - }, - relations: ["next_holder", "orgChild3"], + + posMasterChild2.forEach((item: PosMaster) => { + if (item.isDirector) { + // Group child2 directors by orgChild1Id + const key = item.orgChild1Id || ""; + if (!child2ByOrgChild1IdDraft.has(key)) child2ByOrgChild1IdDraft.set(key, []); + child2ByOrgChild1IdDraft.get(key)!.push(item); + } else if (item.next_holderId) { + // Group child2 non-directors by orgChild2Id + const key = item.orgChild2Id || ""; + if (!child2ByOrgChild2IdDraft.has(key)) child2ByOrgChild2IdDraft.set(key, []); + child2ByOrgChild2IdDraft.get(key)!.push(item); + } }); - posMasterChild4 = await this.posMasterRepository.find({ - where: { - orgRevisionId: data.id, - orgChild4Id: Not(IsNull()), - // next_holderId: Not(IsNull()), - }, - relations: ["next_holder", "orgChild4"], + + posMasterChild3.forEach((item: PosMaster) => { + if (item.isDirector) { + // Group child3 directors by orgChild2Id + const key = item.orgChild2Id || ""; + if (!child3ByOrgChild2IdDraft.has(key)) child3ByOrgChild2IdDraft.set(key, []); + child3ByOrgChild2IdDraft.get(key)!.push(item); + } else if (item.next_holderId) { + // Group child3 non-directors by orgChild3Id + const key = item.orgChild3Id || ""; + if (!child3ByOrgChild3IdDraft.has(key)) child3ByOrgChild3IdDraft.set(key, []); + child3ByOrgChild3IdDraft.get(key)!.push(item); + } + }); + + posMasterChild4.forEach((item: PosMaster) => { + if (item.isDirector) { + // Group child4 directors by orgChild3Id + const key = item.orgChild3Id || ""; + if (!child4ByOrgChild3IdDraft.has(key)) child4ByOrgChild3IdDraft.set(key, []); + child4ByOrgChild3IdDraft.get(key)!.push(item); + } + }); + + // Helper function เพื่อสร้าง node object สำหรับ draft version + const createNodeDraft = (item: PosMaster, level: number, holder: any, orgInfo: any) => ({ + level, + personID: holder?.id ?? "", + name: holder ? `${holder.firstName} ${holder.lastName}` : "ว่าง", + avatar: + holder?.avatar && holder?.avatarName ? `${holder.avatar}/${holder.avatarName}` : null, + positionName: holder?.position ?? "", + positionNum: `${orgInfo.shortName} ${item.posMasterNo}`, + positionNumInt: item.posMasterNo, + departmentName: orgInfo.name, + organizationId: orgInfo.id, + children: [] as any[], }); let formattedData = posMasterRoot .filter((x: any) => x.next_holderId != null && x.isDirector) .map((x0: PosMaster) => { - // Level 2 - const childLevel1 = [ - // Level 2: Root not director - ...posMasterRoot - .filter( - (x: any) => x.orgRootId == x0.orgRootId && x.next_holderId != null && !x.isDirector, - ) - .map((x00: PosMaster) => ({ - level: 2, - personID: x00.next_holder ? x00.next_holder.id : "", - name: x00.next_holder - ? `${x00.next_holder.firstName} ${x00.next_holder.lastName}` - : "ว่าง", - avatar: - x00.next_holder && - x00.next_holder.avatar != null && - x00.next_holder.avatarName != null - ? `${x00.next_holder.avatar}/${x00.next_holder.avatarName}` - : null, - positionName: x00.next_holder ? x00.next_holder.position : "", - positionNum: `${x00.orgRoot.orgRootShortName} ${x00.posMasterNo}`, - positionNumInt: x00.posMasterNo, - departmentName: x00.orgRoot.orgRootName, - organizationId: x00.orgRoot.id, - children: [], - })), - // Level 2: Child 1 director - ...posMasterChild1 - .filter((x: any) => x.isDirector && x.orgRootId == x0.orgRootId) - .map((x1: PosMaster) => { - // Level 3 - const childLevel2 = [ - // Level 3: Child 1 not director - ...posMasterChild1 - .filter( - (x: any) => - x.orgChild1Id == x1.orgChild1Id && !x.isDirector && x.next_holderId != null, - ) - .map((x11: PosMaster) => { - return { - level: 3, - personID: x11.next_holder ? x11.next_holder.id : "", - name: x11.next_holder - ? `${x11.next_holder.firstName} ${x11.next_holder.lastName}` - : "ว่าง", - avatar: - x11.next_holder && - x11.next_holder.avatar != null && - x11.next_holder.avatarName != null - ? `${x11.next_holder.avatar}/${x11.next_holder.avatarName}` - : null, - positionName: x11.next_holder ? x11.next_holder.position : "", - positionNum: `${x11.orgChild1.orgChild1ShortName} ${x11.posMasterNo}`, - positionNumInt: x11.posMasterNo, - departmentName: x11.orgChild1.orgChild1Name, - organizationId: x11.orgChild1.id, - children: [], - }; - }), - // Level 3: Child 2 director - ...posMasterChild2 - .filter((x: any) => x.isDirector && x.orgChild1Id == x1.orgChild1Id) - .map((x2: PosMaster) => { - const childLevel3 = [ - // Level 4: Child 2 not director - ...posMasterChild2 - .filter( - (x: any) => - !x.isDirector && - x.next_holderId != null && - x.orgChild1Id == x2.orgChild1Id, - ) - .map((x22: PosMaster) => ({ - level: 4, - personID: x22.next_holder ? x22.next_holder.id : "", - name: x22.next_holder - ? `${x22.next_holder.firstName} ${x22.next_holder.lastName}` - : "ว่าง", - avatar: - x22.next_holder && - x22.next_holder.avatar != null && - x22.next_holder.avatarName != null - ? `${x22.next_holder.avatar}/${x22.next_holder.avatarName}` - : null, - positionName: x22.next_holder ? x22.next_holder.position : "", - positionNum: `${x22.orgChild2.orgChild2ShortName} ${x22.posMasterNo}`, - positionNumInt: x22.posMasterNo, - departmentName: x22.orgChild2.orgChild2Name, - organizationId: x22.orgChild2.id, - children: [], - })), - // Level 4: Child 3 director - ...posMasterChild3 - .filter((x: any) => x.isDirector && x.orgChild2Id == x2.orgChild2Id) - .map((x3: PosMaster) => { - const childLevel4 = [ - ...posMasterChild3 - .filter( - (x: any) => - !x.isDirector && - x.next_holderId != null && - x.orgChild2Id == x3.orgChild2Id, - ) - .map((x33: PosMaster) => ({ - level: 5, - personID: x33.next_holder ? x33.next_holder.id : "", - name: x33.next_holder - ? `${x33.next_holder.firstName} ${x33.next_holder.lastName}` - : "ว่าง", - avatar: - x33.next_holder && - x33.next_holder.avatar != null && - x33.next_holder.avatarName != null - ? `${x33.next_holder.avatar}/${x33.next_holder.avatarName}` - : null, - positionName: x33.next_holder ? x33.next_holder.position : "", - positionNum: `${x33.orgChild3.orgChild3ShortName} ${x33.posMasterNo}`, - positionNumInt: x33.posMasterNo, - departmentName: x33.orgChild3.orgChild3Name, - organizationId: x33.orgChild3.id, - children: [], - })), - ...posMasterChild4 - .filter((x: any) => x.isDirector && x.orgChild3Id == x3.orgChild3Id) - .map((x4: PosMaster) => { - const childLevel5 = posMasterChild4 - .filter( - (x: any) => - !x.isDirector && - x.next_holderId != null && - x.orgChild3Id == x4.orgChild3Id, - ) - .map((x44: PosMaster) => ({ - level: 5, - personID: x44.next_holder ? x44.next_holder.id : "", - name: x44.next_holder - ? `${x44.next_holder.firstName} ${x44.next_holder.lastName}` - : "ว่าง", - avatar: - x44.next_holder && - x44.next_holder.avatar != null && - x44.next_holder.avatarName != null - ? `${x44.next_holder.avatar}/${x44.next_holder.avatarName}` - : null, - positionName: x44.next_holder ? x44.next_holder.position : "", - positionNum: `${x44.orgChild4.orgChild4ShortName} ${x44.posMasterNo}`, - positionNumInt: x44.posMasterNo, - departmentName: x44.orgChild4.orgChild4Name, - organizationId: x44.orgChild4.id, - children: [], - })); + const childLevel1: any[] = []; - return { - level: 4, - personID: x4.next_holder ? x4.next_holder.id : "", - name: x4.next_holder - ? `${x4.next_holder.firstName} ${x4.next_holder.lastName}` - : "ว่าง", - avatar: - x4.next_holder && - x4.next_holder.avatar != null && - x4.next_holder.avatarName != null - ? `${x4.next_holder.avatar}/${x4.next_holder.avatarName}` - : null, - positionName: x4.next_holder ? x4.next_holder.position : "", - positionNum: `${x4.orgChild4.orgChild4ShortName} ${x4.posMasterNo}`, - positionNumInt: x4.posMasterNo, - departmentName: x4.orgChild4.orgChild4Name, - organizationId: x4.orgChild4.id, - children: childLevel5, - }; - }), - ]; - - return { - level: 4, - personID: x3.next_holder ? x3.next_holder.id : "", - name: x3.next_holder - ? `${x3.next_holder.firstName} ${x3.next_holder.lastName}` - : "ว่าง", - avatar: - x3.next_holder && - x3.next_holder.avatar != null && - x3.next_holder.avatarName != null - ? `${x3.next_holder.avatar}/${x3.next_holder.avatarName}` - : null, - positionName: x3.next_holder ? x3.next_holder.position : "", - positionNum: `${x3.orgChild3.orgChild3ShortName} ${x3.posMasterNo}`, - positionNumInt: x3.posMasterNo, - departmentName: x3.orgChild3.orgChild3Name, - organizationId: x3.orgChild3.id, - children: childLevel4, - }; - }), - ]; - - return { - level: 3, - personID: x2.next_holder ? x2.next_holder.id : "", - name: x2.next_holder - ? `${x2.next_holder.firstName} ${x2.next_holder.lastName}` - : "ว่าง", - avatar: - x2.next_holder && - x2.next_holder.avatar != null && - x2.next_holder.avatarName != null - ? `${x2.next_holder.avatar}/${x2.next_holder.avatarName}` - : null, - positionName: x2.next_holder ? x2.next_holder.position : "", - positionNum: `${x2.orgChild2.orgChild2ShortName} ${x2.posMasterNo}`, - positionNumInt: x2.posMasterNo, - departmentName: x2.orgChild2.orgChild2Name, - organizationId: x2.orgChild2.id, - children: childLevel3, - }; - }), - ]; - - return { - level: 2, - personID: x1.next_holder ? x1.next_holder.id : "", - name: x1.next_holder - ? `${x1.next_holder.firstName} ${x1.next_holder.lastName}` - : "ว่าง", - avatar: - x1.next_holder && - x1.next_holder.avatar != null && - x1.next_holder.avatarName != null - ? `${x1.next_holder.avatar}/${x1.next_holder.avatarName}` - : null, - positionName: x1.next_holder ? x1.next_holder.position : "", - positionNum: `${x1.orgChild1.orgChild1ShortName} ${x1.posMasterNo}`, - positionNumInt: x1.posMasterNo, - departmentName: x1.orgChild1.orgChild1Name, - organizationId: x1.orgChild1.id, - children: childLevel2, - }; + // Add root non-directors (Level 2) + const rootNonDirectors = rootByOrgRootIdDraft.get(x0.orgRootId || "") || []; + rootNonDirectors.forEach((x00: PosMaster) => { + childLevel1.push( + createNodeDraft(x00, 2, x00.next_holder, { + shortName: x00.orgRoot.orgRootShortName, + name: x00.orgRoot.orgRootName, + id: x00.orgRoot.id, }), - ]; + ); + }); + + // Add child1 directors (Level 2) + const child1Directors = child1ByOrgRootIdDraft.get(x0.orgRootId || "") || []; + child1Directors.forEach((x1: PosMaster) => { + const childLevel2: any[] = []; + + // Add child1 non-directors (Level 3) + const child1NonDirectors = child1ByOrgChild1IdDraft.get(x1.orgChild1Id || "") || []; + child1NonDirectors.forEach((x11: PosMaster) => { + childLevel2.push( + createNodeDraft(x11, 3, x11.next_holder, { + shortName: x11.orgChild1.orgChild1ShortName, + name: x11.orgChild1.orgChild1Name, + id: x11.orgChild1.id, + }), + ); + }); + + // Add child2 directors (Level 3) + const child2Directors = child2ByOrgChild1IdDraft.get(x1.orgChild1Id || "") || []; + child2Directors.forEach((x2: PosMaster) => { + const childLevel3: any[] = []; + + // Add child2 non-directors (Level 4) + const child2NonDirectors = child2ByOrgChild2IdDraft.get(x2.orgChild2Id || "") || []; + child2NonDirectors.forEach((x22: PosMaster) => { + childLevel3.push( + createNodeDraft(x22, 4, x22.next_holder, { + shortName: x22.orgChild2.orgChild2ShortName, + name: x22.orgChild2.orgChild2Name, + id: x22.orgChild2.id, + }), + ); + }); + + // Add child3 directors (Level 4) + const child3Directors = child3ByOrgChild2IdDraft.get(x2.orgChild2Id || "") || []; + child3Directors.forEach((x3: PosMaster) => { + const childLevel4: any[] = []; + + // Add child3 non-directors (Level 5) + const child3NonDirectors = child3ByOrgChild3IdDraft.get(x3.orgChild3Id || "") || []; + child3NonDirectors.forEach((x33: PosMaster) => { + childLevel4.push( + createNodeDraft(x33, 5, x33.next_holder, { + shortName: x33.orgChild3.orgChild3ShortName, + name: x33.orgChild3.orgChild3Name, + id: x33.orgChild3.id, + }), + ); + }); + + // Add child4 directors (Level 5) + const child4Directors = child4ByOrgChild3IdDraft.get(x3.orgChild3Id || "") || []; + child4Directors.forEach((x4: PosMaster) => { + const childLevel5: any[] = []; + + // Add child4 non-directors (Level 5) + posMasterChild4 + .filter( + (x: PosMaster) => + !x.isDirector && x.next_holderId && x.orgChild3Id === x4.orgChild3Id, + ) + .forEach((x44: PosMaster) => { + childLevel5.push( + createNodeDraft(x44, 5, x44.next_holder, { + shortName: x44.orgChild4.orgChild4ShortName, + name: x44.orgChild4.orgChild4Name, + id: x44.orgChild4.id, + }), + ); + }); + + const child4Node = createNodeDraft(x4, 4, x4.next_holder, { + shortName: x4.orgChild4.orgChild4ShortName, + name: x4.orgChild4.orgChild4Name, + id: x4.orgChild4.id, + }); + child4Node.children = childLevel5; + childLevel4.push(child4Node); + }); + + const child3Node = createNodeDraft(x3, 4, x3.next_holder, { + shortName: x3.orgChild3.orgChild3ShortName, + name: x3.orgChild3.orgChild3Name, + id: x3.orgChild3.id, + }); + child3Node.children = childLevel4; + childLevel3.push(child3Node); + }); + + const child2Node = createNodeDraft(x2, 3, x2.next_holder, { + shortName: x2.orgChild2.orgChild2ShortName, + name: x2.orgChild2.orgChild2Name, + id: x2.orgChild2.id, + }); + child2Node.children = childLevel3; + childLevel2.push(child2Node); + }); + + const child1Node = createNodeDraft(x1, 2, x1.next_holder, { + shortName: x1.orgChild1.orgChild1ShortName, + name: x1.orgChild1.orgChild1Name, + id: x1.orgChild1.id, + }); + child1Node.children = childLevel2; + childLevel1.push(child1Node); + }); // Root Level 1 - return { - level: 1, - personID: x0.next_holder.id, - name: `${x0.next_holder.firstName} ${x0.next_holder.lastName}`, - avatar: - x0.next_holder && x0.next_holder.avatar != null && x0.next_holder.avatarName != null - ? `${x0.next_holder.avatar}/${x0.next_holder.avatarName}` - : null, - positionName: x0.next_holder.position, - positionNum: `${x0.orgRoot.orgRootShortName} ${x0.posMasterNo}`, - positionNumInt: x0.posMasterNo, - departmentName: x0.orgRoot.orgRootName, - organizationId: x0.orgRoot.id, - children: childLevel1, - }; + const rootNode = createNodeDraft(x0, 1, x0.next_holder, { + shortName: x0.orgRoot.orgRootShortName, + name: x0.orgRoot.orgRootName, + id: x0.orgRoot.id, + }); + rootNode.children = childLevel1; + return rootNode; }); const formattedData_ = {