diff --git a/src/controllers/ReportController.ts b/src/controllers/ReportController.ts index 13d3e8a2..f78ba007 100644 --- a/src/controllers/ReportController.ts +++ b/src/controllers/ReportController.ts @@ -8808,168 +8808,924 @@ export class ReportController extends Controller { default: throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล"); } + // Step 1: ดึงข้อมูล OrgRoot พื้นฐาน + const orgRootData = await this.orgRootRepository + .createQueryBuilder("orgRoot") + .select([ + "orgRoot.id", + "orgRoot.orgRootName", + "orgRoot.orgRootShortName", + "orgRoot.orgRootOrder", + ]) + .where("orgRoot.id = :nodeId", { nodeId }) + .orderBy("orgRoot.orgRootOrder", "ASC") + .getMany(); + + if (!orgRootData || orgRootData.length === 0) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลองค์กร"); + } + + // Step 2: ดึงข้อมูล PosMasters ที่เกี่ยวข้องเท่านั้น + const posMastersData = await this.posMasterRepository + .createQueryBuilder("posMaster") + .select([ + "posMaster.id", + "posMaster.posMasterOrder", + "posMaster.isSit", + "posMaster.posMasterNo", + "posMaster.ancestorDNA", + "posMaster.reason", + "posMaster.orgRootId", + "posMaster.orgChild1Id", + "posMaster.current_holderId", + "posMaster.next_holderId", + ]) + .where("posMaster.orgRootId = :nodeId", { nodeId }) + .andWhere("posMaster.orgChild1Id IS NULL") // เฉพาะ root level + .orderBy("posMaster.posMasterOrder", "ASC") + .getMany(); + + // Step 3: ดึงข้อมูล Profiles ที่ใช้จริงเท่านั้น + const profileIds = [ + ...new Set([ + ...posMastersData.map((pm: any) => pm.current_holderId).filter(Boolean), + ...posMastersData.map((pm: any) => pm.next_holderId).filter(Boolean), + ]), + ]; + + let profilesData: any[] = []; + if (profileIds.length > 0) { + profilesData = await this.profileRepository + .createQueryBuilder("profile") + .select([ + "profile.id", + "profile.prefix", + "profile.firstName", + "profile.lastName", + "profile.position", + ]) + .where("profile.id IN (:...profileIds)", { profileIds }) + .getMany(); + } + + // Step 4: ดึงข้อมูล Education ล่าสุดของแต่ละ Profile + let educationsData: any[] = []; + if (profileIds.length > 0) { + educationsData = await this.profileEducationRepository + .createQueryBuilder("pe") + .select(["pe.profileId", "pe.finishDate", "pe.degree", "pe.level"]) + .where("pe.profileId IN (:...profileIds)", { profileIds }) + .andWhere( + `(pe.profileId, COALESCE(pe.finishDate, '1900-01-01'), pe.level) IN ( + SELECT pe2.profileId, + COALESCE(MAX(pe2.finishDate), '1900-01-01'), + CASE + WHEN MAX(pe2.finishDate) IS NOT NULL THEN + (SELECT pe3.level FROM profileEducation pe3 + WHERE pe3.profileId = pe2.profileId + AND pe3.finishDate = MAX(pe2.finishDate) LIMIT 1) + ELSE MIN(pe2.level) + END + FROM profileEducation pe2 + WHERE pe2.profileId IN (:...profileIds) + GROUP BY pe2.profileId + )`, + { profileIds }, + ) + .getMany(); + } + + // Step 5: ดึงข้อมูล Salary ล่าสุดของแต่ละ Profile + let salariesData: any[] = []; + if (profileIds.length > 0) { + salariesData = await this.profileSalaryRepository + .createQueryBuilder("ps") + .select([ + "ps.profileId", + "ps.commandDateAffect", + "ps.amount", + "ps.positionSalaryAmount", + "ps.mouthSalaryAmount", + ]) + .where("ps.profileId IN (:...profileIds)", { profileIds }) + .andWhere( + `(ps.profileId, ps.commandDateAffect) IN ( + SELECT ps2.profileId, MAX(ps2.commandDateAffect) + FROM profileSalary ps2 + WHERE ps2.profileId IN (:...profileIds) + GROUP BY ps2.profileId + )`, + { profileIds }, + ) + .getMany(); + } + + // Step 6: ดึงข้อมูล Positions ที่เกี่ยวข้อง + const posMasterIds = posMastersData.map((pm: any) => pm.id); + let positionsData: any[] = []; + if (posMasterIds.length > 0) { + positionsData = await this.positionRepository + .createQueryBuilder("position") + .leftJoinAndSelect("position.posType", "posType") + .leftJoinAndSelect("position.posLevel", "posLevel") + .leftJoinAndSelect("position.posExecutive", "posExecutive") + .select([ + "position.id", + "position.positionName", + "position.positionIsSelected", + "position.posMasterId", + "posType.id", + "posType.posTypeName", + "posLevel.id", + "posLevel.posLevelName", + "posExecutive.id", + "posExecutive.posExecutiveName", + ]) + .where("position.posMasterId IN (:...posMasterIds)", { posMasterIds }) + .getMany(); + } + + // Step 7: Combine ข้อมูลกลับเหมือนเดิม + for (let orgRoot of orgRootData) { + orgRoot.posMasters = posMastersData.filter((pm: any) => pm.orgRootId === orgRoot.id); + + for (let posMaster of orgRoot.posMasters) { + // Attach current_holder + if (posMaster.current_holderId) { + posMaster.current_holder = profilesData.find( + (p: any) => p.id === posMaster.current_holderId, + ); + if (posMaster.current_holder) { + posMaster.current_holder.profileEducations = educationsData.filter( + (ed: any) => ed.profileId === posMaster.current_holderId, + ); + posMaster.current_holder.profileSalary = salariesData.filter( + (sal: any) => sal.profileId === posMaster.current_holderId, + ); + } + } + + // Attach next_holder + if (posMaster.next_holderId) { + posMaster.next_holder = profilesData.find((p: any) => p.id === posMaster.next_holderId); + if (posMaster.next_holder) { + posMaster.next_holder.profileEducations = educationsData.filter( + (ed: any) => ed.profileId === posMaster.next_holderId, + ); + posMaster.next_holder.profileSalary = salariesData.filter( + (sal: any) => sal.profileId === posMaster.next_holderId, + ); + } + } + + // Attach positions + posMaster.positions = positionsData.filter((pos: any) => pos.posMasterId === posMaster.id); + } + } + + if (!orgRootData || orgRootData.length === 0) { + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลองค์กร"); + } - const orgRootData = await this.orgRootRepository.find({ - where: { - id: nodeId, - // orgRevisionId: orgRevision.id, - }, - order: { orgRootOrder: "ASC" }, - relations: [ - "posMasters", - "posMasters.orgRoot", - "posMasters.orgChild1", - "posMasters.orgChild2", - "posMasters.orgChild3", - "posMasters.orgChild4", - "posMasters.next_holder", - "posMasters.next_holder", - "posMasters.next_holder", - "posMasters.next_holder.posLevel", - "posMasters.next_holder.posType", - "posMasters.next_holder.profileSalary", - "posMasters.next_holder.profileEducations", - "posMasters.next_holder.current_holders", - "posMasters.next_holder.current_holders.positions", - "posMasters.next_holder.current_holders.orgRoot", - "posMasters.next_holder.current_holders.orgChild1", - "posMasters.next_holder.current_holders.orgChild2", - "posMasters.next_holder.current_holders.orgChild3", - "posMasters.next_holder.current_holders.orgChild4", - "posMasters.positions", - "posMasters.positions.posLevel", - "posMasters.positions.posType", - "posMasters.positions.posExecutive", - ], - }); const orgName = orgRootData[0].orgRootName ?? ""; const orgRootIds = orgRootData.map((orgRoot) => orgRoot.id) || null; - const orgChild1Data = await this.child1Repository.find({ - where: { - orgRootId: In(orgRootIds), - }, - order: { orgChild1Order: "ASC" }, - relations: [ - "posMasters", - "posMasters.orgRoot", - "posMasters.orgChild1", - "posMasters.orgChild2", - "posMasters.orgChild3", - "posMasters.orgChild4", - "posMasters.next_holder", - "posMasters.next_holder.posLevel", - "posMasters.next_holder.posType", - "posMasters.next_holder.profileSalary", - "posMasters.next_holder.profileEducations", - "posMasters.next_holder.current_holders", - "posMasters.next_holder.current_holders.positions", - "posMasters.next_holder.current_holders.orgRoot", - "posMasters.next_holder.current_holders.orgChild1", - "posMasters.next_holder.current_holders.orgChild2", - "posMasters.next_holder.current_holders.orgChild3", - "posMasters.next_holder.current_holders.orgChild4", - "posMasters.positions", - "posMasters.positions.posLevel", - "posMasters.positions.posType", - "posMasters.positions.posExecutive", - ], - }); - const orgChild1Ids = orgChild1Data.map((orgChild1) => orgChild1.id) || null; - const orgChild2Data = await this.child2Repository.find({ - where: { - orgChild1: In(orgChild1Ids), - }, - order: { orgChild2Order: "ASC" }, - relations: [ - "posMasters", - "posMasters.orgRoot", - "posMasters.orgChild1", - "posMasters.orgChild2", - "posMasters.orgChild3", - "posMasters.orgChild4", - "posMasters.next_holder", - "posMasters.next_holder.posLevel", - "posMasters.next_holder.posType", - "posMasters.next_holder.profileSalary", - "posMasters.next_holder.profileEducations", - "posMasters.next_holder.current_holders", - "posMasters.next_holder.current_holders.positions", - "posMasters.next_holder.current_holders.orgRoot", - "posMasters.next_holder.current_holders.orgChild1", - "posMasters.next_holder.current_holders.orgChild2", - "posMasters.next_holder.current_holders.orgChild3", - "posMasters.next_holder.current_holders.orgChild4", - "posMasters.positions", - "posMasters.positions.posLevel", - "posMasters.positions.posType", - "posMasters.positions.posExecutive", - ], - }); + // Step 8: ปรับปรุง orgChild1Data - ใช้ optimized approach + const orgChild1Data = await this.child1Repository + .createQueryBuilder("orgChild1") + .select([ + "orgChild1.id", + "orgChild1.orgRootId", + "orgChild1.orgChild1Name", + "orgChild1.orgChild1ShortName", + "orgChild1.orgChild1Order", + ]) + .where("orgChild1.orgRootId IN (:...orgRootIds)", { orgRootIds }) + .orderBy("orgChild1.orgChild1Order", "ASC") + .getMany(); - const orgChild2Ids = orgChild2Data.map((orgChild2) => orgChild2.id) || null; - const orgChild3Data = await this.child3Repository.find({ - where: { - orgChild2: In(orgChild2Ids), - }, - order: { orgChild3Order: "ASC" }, - relations: [ - "posMasters", - "posMasters.orgRoot", - "posMasters.orgChild1", - "posMasters.orgChild2", - "posMasters.orgChild3", - "posMasters.orgChild4", - "posMasters.next_holder", - "posMasters.next_holder.posLevel", - "posMasters.next_holder.posType", - "posMasters.next_holder.profileSalary", - "posMasters.next_holder.profileEducations", - "posMasters.next_holder.current_holders", - "posMasters.next_holder.current_holders.positions", - "posMasters.next_holder.current_holders.orgRoot", - "posMasters.next_holder.current_holders.orgChild1", - "posMasters.next_holder.current_holders.orgChild2", - "posMasters.next_holder.current_holders.orgChild3", - "posMasters.next_holder.current_holders.orgChild4", - "posMasters.positions", - "posMasters.positions.posLevel", - "posMasters.positions.posType", - "posMasters.positions.posExecutive", - ], - }); + // ดึงข้อมูล PosMasters สำหรับ orgChild1 + const orgChild1Ids = orgChild1Data.map((orgChild1) => orgChild1.id); + let child1PosMasters: any[] = []; + if (orgChild1Ids.length > 0) { + child1PosMasters = await this.posMasterRepository + .createQueryBuilder("posMaster") + .select([ + "posMaster.id", + "posMaster.posMasterOrder", + "posMaster.isSit", + "posMaster.posMasterNo", + "posMaster.ancestorDNA", + "posMaster.reason", + "posMaster.orgChild1Id", + "posMaster.orgChild2Id", + "posMaster.current_holderId", + "posMaster.next_holderId", + ]) + .where("posMaster.orgChild1Id IN (:...orgChild1Ids)", { orgChild1Ids }) + .andWhere("posMaster.orgChild2Id IS NULL") // เฉพาะ child1 level + .orderBy("posMaster.posMasterOrder", "ASC") + .getMany(); + } - const orgChild3Ids = orgChild3Data.map((orgChild3) => orgChild3.id) || null; - const orgChild4Data = await this.child4Repository.find({ - where: { - orgChild3: In(orgChild3Ids), - }, - order: { orgChild4Order: "ASC" }, - relations: [ - "posMasters", - "posMasters.orgRoot", - "posMasters.orgChild1", - "posMasters.orgChild2", - "posMasters.orgChild3", - "posMasters.orgChild4", - "posMasters.next_holder", - "posMasters.next_holder.posLevel", - "posMasters.next_holder.posType", - "posMasters.next_holder.profileSalary", - "posMasters.next_holder.profileEducations", - "posMasters.next_holder.current_holders", - "posMasters.next_holder.current_holders.positions", - "posMasters.next_holder.current_holders.orgRoot", - "posMasters.next_holder.current_holders.orgChild1", - "posMasters.next_holder.current_holders.orgChild2", - "posMasters.next_holder.current_holders.orgChild3", - "posMasters.next_holder.current_holders.orgChild4", - "posMasters.positions", - "posMasters.positions.posLevel", - "posMasters.positions.posType", - "posMasters.positions.posExecutive", - ], - }); + // รวบรวม Profile IDs สำหรับ child1 + const child1ProfileIds = + child1PosMasters.length > 0 + ? [ + ...new Set([ + ...child1PosMasters.map((pm: any) => pm.current_holderId).filter(Boolean), + ...child1PosMasters.map((pm: any) => pm.next_holderId).filter(Boolean), + ]), + ] + : []; + + // ดึงข้อมูล Profiles, Education, Salary, Positions สำหรับ child1 + let child1Profiles: any[] = []; + let child1Educations: any[] = []; + let child1Salaries: any[] = []; + let child1Positions: any[] = []; + + if (child1ProfileIds.length > 0) { + [child1Profiles, child1Educations, child1Salaries] = await Promise.all([ + this.profileRepository + .createQueryBuilder("profile") + .select([ + "profile.id", + "profile.prefix", + "profile.firstName", + "profile.lastName", + "profile.position", + "profile.posTypeId", + "profile.posLevelId", + ]) + .where("profile.id IN (:...child1ProfileIds)", { child1ProfileIds }) + .getMany(), + + this.profileEducationRepository + .createQueryBuilder("pe") + .select(["pe.profileId", "pe.finishDate", "pe.degree", "pe.level"]) + .where("pe.profileId IN (:...child1ProfileIds)", { child1ProfileIds }) + .andWhere( + `(pe.profileId, COALESCE(pe.finishDate, '1900-01-01'), pe.level) IN ( + SELECT pe2.profileId, + COALESCE(MAX(pe2.finishDate), '1900-01-01'), + CASE + WHEN MAX(pe2.finishDate) IS NOT NULL THEN + (SELECT pe3.level FROM profileEducation pe3 + WHERE pe3.profileId = pe2.profileId + AND pe3.finishDate = MAX(pe2.finishDate) LIMIT 1) + ELSE MIN(pe2.level) + END + FROM profileEducation pe2 + WHERE pe2.profileId IN (:...child1ProfileIds) + GROUP BY pe2.profileId + )`, + { child1ProfileIds }, + ) + .getMany(), + + this.profileSalaryRepository + .createQueryBuilder("ps") + .select([ + "ps.profileId", + "ps.commandDateAffect", + "ps.amount", + "ps.positionSalaryAmount", + "ps.mouthSalaryAmount", + ]) + .where("ps.profileId IN (:...child1ProfileIds)", { child1ProfileIds }) + .andWhere( + `(ps.profileId, ps.commandDateAffect) IN ( + SELECT ps2.profileId, MAX(ps2.commandDateAffect) + FROM profileSalary ps2 + WHERE ps2.profileId IN (:...child1ProfileIds) + GROUP BY ps2.profileId + )`, + { child1ProfileIds }, + ) + .getMany(), + ]); + } + + if (child1PosMasters.length > 0) { + const child1PosMasterIds = child1PosMasters.map((pm: any) => pm.id); + child1Positions = await this.positionRepository + .createQueryBuilder("position") + .leftJoinAndSelect("position.posType", "posType") + .leftJoinAndSelect("position.posLevel", "posLevel") + .leftJoinAndSelect("position.posExecutive", "posExecutive") + .select([ + "position.id", + "position.positionName", + "position.positionIsSelected", + "position.posMasterId", + "posType.id", + "posType.posTypeName", + "posLevel.id", + "posLevel.posLevelName", + "posExecutive.id", + "posExecutive.posExecutiveName", + ]) + .where("position.posMasterId IN (:...child1PosMasterIds)", { child1PosMasterIds }) + .getMany(); + } + + // Combine ข้อมูล orgChild1 + for (let orgChild1 of orgChild1Data) { + orgChild1.posMasters = child1PosMasters.filter((pm: any) => pm.orgChild1Id === orgChild1.id); + + for (let posMaster of orgChild1.posMasters) { + if (posMaster.current_holderId) { + posMaster.current_holder = child1Profiles.find( + (p: any) => p.id === posMaster.current_holderId, + ); + if (posMaster.current_holder) { + posMaster.current_holder.profileEducations = child1Educations.filter( + (ed: any) => ed.profileId === posMaster.current_holderId, + ); + posMaster.current_holder.profileSalary = child1Salaries.filter( + (sal: any) => sal.profileId === posMaster.current_holderId, + ); + } + } + + if (posMaster.next_holderId) { + posMaster.next_holder = child1Profiles.find((p: any) => p.id === posMaster.next_holderId); + if (posMaster.next_holder) { + posMaster.next_holder.profileEducations = child1Educations.filter( + (ed: any) => ed.profileId === posMaster.next_holderId, + ); + posMaster.next_holder.profileSalary = child1Salaries.filter( + (sal: any) => sal.profileId === posMaster.next_holderId, + ); + } + } + + posMaster.positions = child1Positions.filter( + (pos: any) => pos.posMasterId === posMaster.id, + ); + } + } + + // Step 9: ปรับปรุง orgChild2Data + const originalOrgChild1Ids = + orgChild1Data.length > 0 ? orgChild1Data.map((orgChild1) => orgChild1.id) : []; + const orgChild2Data = await this.child2Repository + .createQueryBuilder("orgChild2") + .select([ + "orgChild2.id", + "orgChild2.orgChild1Id", + "orgChild2.orgChild2Name", + "orgChild2.orgChild2ShortName", + "orgChild2.orgChild2Order", + ]) + .where( + originalOrgChild1Ids.length > 0 + ? "orgChild2.orgChild1Id IN (:...originalOrgChild1Ids)" + : "1=0", + { + originalOrgChild1Ids, + }, + ) + .orderBy("orgChild2.orgChild2Order", "ASC") + .getMany(); + + // ดึงข้อมูล PosMasters สำหรับ orgChild2 + const orgChild2Ids = orgChild2Data.map((orgChild2) => orgChild2.id); + let child2PosMasters: any[] = []; + if (orgChild2Ids.length > 0) { + child2PosMasters = await this.posMasterRepository + .createQueryBuilder("posMaster") + .select([ + "posMaster.id", + "posMaster.posMasterOrder", + "posMaster.isSit", + "posMaster.posMasterNo", + "posMaster.ancestorDNA", + "posMaster.reason", + "posMaster.orgChild2Id", + "posMaster.orgChild3Id", + "posMaster.current_holderId", + "posMaster.next_holderId", + ]) + .where("posMaster.orgChild2Id IN (:...orgChild2Ids)", { orgChild2Ids }) + .andWhere("posMaster.orgChild3Id IS NULL") // เฉพาะ child2 level + .orderBy("posMaster.posMasterOrder", "ASC") + .getMany(); + } + + // รวบรวม Profile IDs สำหรับ child2 + const child2ProfileIds = + child2PosMasters.length > 0 + ? [ + ...new Set([ + ...child2PosMasters.map((pm: any) => pm.current_holderId).filter(Boolean), + ...child2PosMasters.map((pm: any) => pm.next_holderId).filter(Boolean), + ]), + ] + : []; + + // ดึงข้อมูล Profiles, Education, Salary, Positions สำหรับ child2 + let child2Profiles: any[] = []; + let child2Educations: any[] = []; + let child2Salaries: any[] = []; + let child2Positions: any[] = []; + + console.log("4"); + if (child2ProfileIds.length > 0) { + [child2Profiles, child2Educations, child2Salaries] = await Promise.all([ + this.profileRepository + .createQueryBuilder("profile") + .select([ + "profile.id", + "profile.prefix", + "profile.firstName", + "profile.lastName", + "profile.position", + "profile.posTypeId", + "profile.posLevelId", + ]) + .where("profile.id IN (:...child2ProfileIds)", { child2ProfileIds }) + .getMany(), + + this.profileEducationRepository + .createQueryBuilder("pe") + .select(["pe.profileId", "pe.finishDate", "pe.degree", "pe.level"]) + .where("pe.profileId IN (:...child2ProfileIds)", { child2ProfileIds }) + .andWhere( + `(pe.profileId, COALESCE(pe.finishDate, '1900-01-01'), pe.level) IN ( + SELECT pe2.profileId, + COALESCE(MAX(pe2.finishDate), '1900-01-01'), + CASE + WHEN MAX(pe2.finishDate) IS NOT NULL THEN + (SELECT pe3.level FROM profileEducation pe3 + WHERE pe3.profileId = pe2.profileId + AND pe3.finishDate = MAX(pe2.finishDate) LIMIT 1) + ELSE MIN(pe2.level) + END + FROM profileEducation pe2 + WHERE pe2.profileId IN (:...child2ProfileIds) + GROUP BY pe2.profileId + )`, + { child2ProfileIds }, + ) + .getMany(), + + this.profileSalaryRepository + .createQueryBuilder("ps") + .select([ + "ps.profileId", + "ps.commandDateAffect", + "ps.amount", + "ps.positionSalaryAmount", + "ps.mouthSalaryAmount", + ]) + .where("ps.profileId IN (:...child2ProfileIds)", { child2ProfileIds }) + .andWhere( + `(ps.profileId, ps.commandDateAffect) IN ( + SELECT ps2.profileId, MAX(ps2.commandDateAffect) + FROM profileSalary ps2 + WHERE ps2.profileId IN (:...child2ProfileIds) + GROUP BY ps2.profileId + )`, + { child2ProfileIds }, + ) + .getMany(), + ]); + } + + if (child2PosMasters.length > 0) { + const child2PosMasterIds = child2PosMasters.map((pm: any) => pm.id); + child2Positions = await this.positionRepository + .createQueryBuilder("position") + .leftJoinAndSelect("position.posType", "posType") + .leftJoinAndSelect("position.posLevel", "posLevel") + .leftJoinAndSelect("position.posExecutive", "posExecutive") + .select([ + "position.id", + "position.positionName", + "position.positionIsSelected", + "position.posMasterId", + "posType.id", + "posType.posTypeName", + "posLevel.id", + "posLevel.posLevelName", + "posExecutive.id", + "posExecutive.posExecutiveName", + ]) + .where("position.posMasterId IN (:...child2PosMasterIds)", { child2PosMasterIds }) + .getMany(); + } + + // Combine ข้อมูล orgChild2 + for (let orgChild2 of orgChild2Data) { + orgChild2.posMasters = child2PosMasters.filter((pm: any) => pm.orgChild2Id === orgChild2.id); + + for (let posMaster of orgChild2.posMasters) { + if (posMaster.current_holderId) { + posMaster.current_holder = child2Profiles.find( + (p: any) => p.id === posMaster.current_holderId, + ); + if (posMaster.current_holder) { + posMaster.current_holder.profileEducations = child2Educations.filter( + (ed: any) => ed.profileId === posMaster.current_holderId, + ); + posMaster.current_holder.profileSalary = child2Salaries.filter( + (sal: any) => sal.profileId === posMaster.current_holderId, + ); + } + } + + if (posMaster.next_holderId) { + posMaster.next_holder = child2Profiles.find((p: any) => p.id === posMaster.next_holderId); + if (posMaster.next_holder) { + posMaster.next_holder.profileEducations = child2Educations.filter( + (ed: any) => ed.profileId === posMaster.next_holderId, + ); + posMaster.next_holder.profileSalary = child2Salaries.filter( + (sal: any) => sal.profileId === posMaster.next_holderId, + ); + } + } + + posMaster.positions = child2Positions.filter( + (pos: any) => pos.posMasterId === posMaster.id, + ); + } + } + + // Step 10: ปรับปรุง orgChild3Data + const originalOrgChild2Ids = + orgChild2Data.length > 0 ? orgChild2Data.map((orgChild2) => orgChild2.id) : []; + const orgChild3Data = await this.child3Repository + .createQueryBuilder("orgChild3") + .select([ + "orgChild3.id", + "orgChild3.orgChild2Id", + "orgChild3.orgChild3Name", + "orgChild3.orgChild3ShortName", + "orgChild3.orgChild3Order", + ]) + .where( + originalOrgChild2Ids.length > 0 + ? "orgChild3.orgChild2Id IN (:...originalOrgChild2Ids)" + : "1=0", + { + originalOrgChild2Ids, + }, + ) + .orderBy("orgChild3.orgChild3Order", "ASC") + .getMany(); + + // ดึงข้อมูล PosMasters สำหรับ orgChild3 + const orgChild3Ids = orgChild3Data.map((orgChild3) => orgChild3.id); + let child3PosMasters: any[] = []; + if (orgChild3Ids.length > 0) { + child3PosMasters = await this.posMasterRepository + .createQueryBuilder("posMaster") + .select([ + "posMaster.id", + "posMaster.posMasterOrder", + "posMaster.isSit", + "posMaster.posMasterNo", + "posMaster.ancestorDNA", + "posMaster.reason", + "posMaster.orgChild2Id", + "posMaster.orgChild3Id", + "posMaster.orgChild4Id", + "posMaster.current_holderId", + "posMaster.next_holderId", + ]) + .where("posMaster.orgChild3Id IN (:...orgChild3Ids)", { orgChild3Ids }) + .andWhere("posMaster.orgChild4Id IS NULL") // เฉพาะ child3 level + .orderBy("posMaster.posMasterOrder", "ASC") + .getMany(); + } + + // รวบรวม Profile IDs สำหรับ child3 + const child3ProfileIds = + child3PosMasters.length > 0 + ? [ + ...new Set([ + ...child3PosMasters.map((pm: any) => pm.current_holderId).filter(Boolean), + ...child3PosMasters.map((pm: any) => pm.next_holderId).filter(Boolean), + ]), + ] + : []; + + // ดึงข้อมูล Profiles, Education, Salary, Positions สำหรับ child3 + let child3Profiles: any[] = []; + let child3Educations: any[] = []; + let child3Salaries: any[] = []; + let child3Positions: any[] = []; + + if (child3ProfileIds.length > 0) { + [child3Profiles, child3Educations, child3Salaries] = await Promise.all([ + this.profileRepository + .createQueryBuilder("profile") + .select([ + "profile.id", + "profile.prefix", + "profile.firstName", + "profile.lastName", + "profile.position", + "profile.posTypeId", + "profile.posLevelId", + ]) + .where("profile.id IN (:...child3ProfileIds)", { child3ProfileIds }) + .getMany(), + + this.profileEducationRepository + .createQueryBuilder("pe") + .select(["pe.profileId", "pe.finishDate", "pe.degree", "pe.level"]) + .where("pe.profileId IN (:...child3ProfileIds)", { child3ProfileIds }) + .andWhere( + `(pe.profileId, COALESCE(pe.finishDate, '1900-01-01'), pe.level) IN ( + SELECT pe2.profileId, + COALESCE(MAX(pe2.finishDate), '1900-01-01'), + CASE + WHEN MAX(pe2.finishDate) IS NOT NULL THEN + (SELECT pe3.level FROM profileEducation pe3 + WHERE pe3.profileId = pe2.profileId + AND pe3.finishDate = MAX(pe2.finishDate) LIMIT 1) + ELSE MIN(pe2.level) + END + FROM profileEducation pe2 + WHERE pe2.profileId IN (:...child3ProfileIds) + GROUP BY pe2.profileId + )`, + { child3ProfileIds }, + ) + .getMany(), + + this.profileSalaryRepository + .createQueryBuilder("ps") + .select([ + "ps.profileId", + "ps.commandDateAffect", + "ps.amount", + "ps.positionSalaryAmount", + "ps.mouthSalaryAmount", + ]) + .where("ps.profileId IN (:...child3ProfileIds)", { child3ProfileIds }) + .andWhere( + `(ps.profileId, ps.commandDateAffect) IN ( + SELECT ps2.profileId, MAX(ps2.commandDateAffect) + FROM profileSalary ps2 + WHERE ps2.profileId IN (:...child3ProfileIds) + GROUP BY ps2.profileId + )`, + { child3ProfileIds }, + ) + .getMany(), + ]); + } + console.log("2"); + + if (child3PosMasters.length > 0) { + const child3PosMasterIds = child3PosMasters.map((pm: any) => pm.id); + child3Positions = await this.positionRepository + .createQueryBuilder("position") + .leftJoinAndSelect("position.posType", "posType") + .leftJoinAndSelect("position.posLevel", "posLevel") + .leftJoinAndSelect("position.posExecutive", "posExecutive") + .select([ + "position.id", + "position.positionName", + "position.positionIsSelected", + "position.posMasterId", + "posType.id", + "posType.posTypeName", + "posLevel.id", + "posLevel.posLevelName", + "posExecutive.id", + "posExecutive.posExecutiveName", + ]) + .where("position.posMasterId IN (:...child3PosMasterIds)", { child3PosMasterIds }) + .getMany(); + } + + // Combine ข้อมูล orgChild3 + for (let orgChild3 of orgChild3Data) { + orgChild3.posMasters = child3PosMasters.filter((pm: any) => pm.orgChild3Id === orgChild3.id); + + for (let posMaster of orgChild3.posMasters) { + if (posMaster.current_holderId) { + posMaster.current_holder = child3Profiles.find( + (p: any) => p.id === posMaster.current_holderId, + ); + if (posMaster.current_holder) { + posMaster.current_holder.profileEducations = child3Educations.filter( + (ed: any) => ed.profileId === posMaster.current_holderId, + ); + posMaster.current_holder.profileSalary = child3Salaries.filter( + (sal: any) => sal.profileId === posMaster.current_holderId, + ); + } + } + + if (posMaster.next_holderId) { + posMaster.next_holder = child3Profiles.find((p: any) => p.id === posMaster.next_holderId); + if (posMaster.next_holder) { + posMaster.next_holder.profileEducations = child3Educations.filter( + (ed: any) => ed.profileId === posMaster.next_holderId, + ); + posMaster.next_holder.profileSalary = child3Salaries.filter( + (sal: any) => sal.profileId === posMaster.next_holderId, + ); + } + } + + posMaster.positions = child3Positions.filter( + (pos: any) => pos.posMasterId === posMaster.id, + ); + } + } + + // Step 11: ปรับปรุง orgChild4Data + const originalOrgChild3Ids = + orgChild3Data.length > 0 ? orgChild3Data.map((orgChild3) => orgChild3.id) : []; + const orgChild4Data = await this.child4Repository + .createQueryBuilder("orgChild4") + .select([ + "orgChild4.id", + "orgChild4.orgChild3Id", + "orgChild4.orgChild4Name", + "orgChild4.orgChild4ShortName", + "orgChild4.orgChild4Order", + ]) + .where( + originalOrgChild3Ids.length > 0 + ? "orgChild4.orgChild3Id IN (:...originalOrgChild3Ids)" + : "1=0", + { + originalOrgChild3Ids, + }, + ) + .orderBy("orgChild4.orgChild4Order", "ASC") + .getMany(); + + // ดึงข้อมูล PosMasters สำหรับ orgChild4 + const orgChild4Ids = orgChild4Data.map((orgChild4) => orgChild4.id); + let child4PosMasters: any[] = []; + if (orgChild4Ids.length > 0) { + child4PosMasters = await this.posMasterRepository + .createQueryBuilder("posMaster") + .select([ + "posMaster.id", + "posMaster.posMasterOrder", + "posMaster.isSit", + "posMaster.posMasterNo", + "posMaster.ancestorDNA", + "posMaster.reason", + "posMaster.orgChild3Id", + "posMaster.orgChild4Id", + "posMaster.current_holderId", + "posMaster.next_holderId", + ]) + .where("posMaster.orgChild4Id IN (:...orgChild4Ids)", { orgChild4Ids }) + .orderBy("posMaster.posMasterOrder", "ASC") + .getMany(); + } + + // รวบรวม Profile IDs สำหรับ child4 + const child4ProfileIds = + child4PosMasters.length > 0 + ? [ + ...new Set([ + ...child4PosMasters.map((pm: any) => pm.current_holderId).filter(Boolean), + ...child4PosMasters.map((pm: any) => pm.next_holderId).filter(Boolean), + ]), + ] + : []; + + // ดึงข้อมูล Profiles, Education, Salary, Positions สำหรับ child4 + let child4Profiles: any[] = []; + let child4Educations: any[] = []; + let child4Salaries: any[] = []; + let child4Positions: any[] = []; + + if (child4ProfileIds.length > 0) { + [child4Profiles, child4Educations, child4Salaries] = await Promise.all([ + this.profileRepository + .createQueryBuilder("profile") + .select([ + "profile.id", + "profile.prefix", + "profile.firstName", + "profile.lastName", + "profile.position", + "profile.posTypeId", + "profile.posLevelId", + ]) + .where("profile.id IN (:...child4ProfileIds)", { child4ProfileIds }) + .getMany(), + + this.profileEducationRepository + .createQueryBuilder("pe") + .select(["pe.profileId", "pe.finishDate", "pe.degree", "pe.level"]) + .where("pe.profileId IN (:...child4ProfileIds)", { child4ProfileIds }) + .andWhere( + `(pe.profileId, COALESCE(pe.finishDate, '1900-01-01'), pe.level) IN ( + SELECT pe2.profileId, + COALESCE(MAX(pe2.finishDate), '1900-01-01'), + CASE + WHEN MAX(pe2.finishDate) IS NOT NULL THEN + (SELECT pe3.level FROM profileEducation pe3 + WHERE pe3.profileId = pe2.profileId + AND pe3.finishDate = MAX(pe2.finishDate) LIMIT 1) + ELSE MIN(pe2.level) + END + FROM profileEducation pe2 + WHERE pe2.profileId IN (:...child4ProfileIds) + GROUP BY pe2.profileId + )`, + { child4ProfileIds }, + ) + .getMany(), + + this.profileSalaryRepository + .createQueryBuilder("ps") + .select([ + "ps.profileId", + "ps.commandDateAffect", + "ps.amount", + "ps.positionSalaryAmount", + "ps.mouthSalaryAmount", + ]) + .where("ps.profileId IN (:...child4ProfileIds)", { child4ProfileIds }) + .andWhere( + `(ps.profileId, ps.commandDateAffect) IN ( + SELECT ps2.profileId, MAX(ps2.commandDateAffect) + FROM profileSalary ps2 + WHERE ps2.profileId IN (:...child4ProfileIds) + GROUP BY ps2.profileId + )`, + { child4ProfileIds }, + ) + .getMany(), + ]); + } + + if (child4PosMasters.length > 0) { + const child4PosMasterIds = child4PosMasters.map((pm: any) => pm.id); + child4Positions = await this.positionRepository + .createQueryBuilder("position") + .leftJoinAndSelect("position.posType", "posType") + .leftJoinAndSelect("position.posLevel", "posLevel") + .leftJoinAndSelect("position.posExecutive", "posExecutive") + .select([ + "position.id", + "position.positionName", + "position.positionIsSelected", + "position.posMasterId", + "posType.id", + "posType.posTypeName", + "posLevel.id", + "posLevel.posLevelName", + "posExecutive.id", + "posExecutive.posExecutiveName", + ]) + .where("position.posMasterId IN (:...child4PosMasterIds)", { child4PosMasterIds }) + .getMany(); + } + + // Combine ข้อมูล orgChild4 + for (let orgChild4 of orgChild4Data) { + orgChild4.posMasters = child4PosMasters.filter((pm: any) => pm.orgChild4Id === orgChild4.id); + + for (let posMaster of orgChild4.posMasters) { + if (posMaster.current_holderId) { + posMaster.current_holder = child4Profiles.find( + (p: any) => p.id === posMaster.current_holderId, + ); + if (posMaster.current_holder) { + posMaster.current_holder.profileEducations = child4Educations.filter( + (ed: any) => ed.profileId === posMaster.current_holderId, + ); + posMaster.current_holder.profileSalary = child4Salaries.filter( + (sal: any) => sal.profileId === posMaster.current_holderId, + ); + } + } + + if (posMaster.next_holderId) { + posMaster.next_holder = child4Profiles.find((p: any) => p.id === posMaster.next_holderId); + if (posMaster.next_holder) { + posMaster.next_holder.profileEducations = child4Educations.filter( + (ed: any) => ed.profileId === posMaster.next_holderId, + ); + posMaster.next_holder.profileSalary = child4Salaries.filter( + (sal: any) => sal.profileId === posMaster.next_holderId, + ); + } + } + + posMaster.positions = child4Positions.filter( + (pos: any) => pos.posMasterId === posMaster.id, + ); + } + } let orgRevisionActive: any = await this.orgRevisionRepository.findOne({ where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, @@ -9005,12 +9761,6 @@ export class ReportController extends Controller { .sort((a, b) => a.posMasterOrder - b.posMasterOrder) .map(async (posMaster) => { if (posMaster.orgChild1Id == null && posMaster.next_holder != null) { - let positionMasterProfileOld: any = null; - if (posMaster.next_holder != null) { - positionMasterProfileOld = posMaster.next_holder.current_holders.find( - (x) => x.orgRevisionId == orgRevisionActive.id, - ); - } let education: any = ""; if ( posMaster.next_holder != null && @@ -9055,25 +9805,17 @@ export class ReportController extends Controller { posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true)?.posType ?.posTypeName - : posMaster.next_holder.posType == null - ? "-" - : posMaster.next_holder.posType.posTypeName, + : "-", posLevel: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true)?.posLevel ?.posLevelName - : posMaster.next_holder.posLevel == null - ? "-" - : posMaster.next_holder.posLevel.posLevelName, + : "-", posExecutive: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posExecutive?.posExecutiveName - : positionMasterProfileOld == null - ? "-" - : positionMasterProfileOld.positions.find( - (x: any) => x.positionIsSelected == true, - )?.posExecutive?.posExecutiveName, + : "-", profileFullname: `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`, education: education == "" ? "" : education.degree, @@ -9189,6 +9931,7 @@ export class ReportController extends Controller { ); _node = null; + console.log("13"); for (let orgChild1 of orgChild1Data.filter( (orgChild1) => orgChild1.orgRootId === orgRoot.id, )) { @@ -9197,12 +9940,6 @@ export class ReportController extends Controller { .sort((a, b) => a.posMasterOrder - b.posMasterOrder) .map(async (posMaster) => { if (posMaster.orgChild2Id == null && posMaster.next_holder != null) { - let positionMasterProfileOld: any = null; - if (posMaster.next_holder != null) { - positionMasterProfileOld = posMaster.next_holder.current_holders.find( - (x) => x.orgRevisionId == orgRevisionActive.id, - ); - } let education: any = ""; if ( posMaster.next_holder != null && @@ -9234,6 +9971,7 @@ export class ReportController extends Controller { } } + console.log("14"); let node = { orgTreeName: orgChild1.orgChild1Name, orgTreeShortName: orgChild1.orgChild1ShortName, @@ -9247,25 +9985,17 @@ export class ReportController extends Controller { posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true)?.posType ?.posTypeName - : posMaster.next_holder.posType == null - ? "-" - : posMaster.next_holder.posType.posTypeName, + : "-", posLevel: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true)?.posLevel ?.posLevelName - : posMaster.next_holder.posLevel == null - ? "-" - : posMaster.next_holder.posLevel.posLevelName, + : "-", posExecutive: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posExecutive?.posExecutiveName - : positionMasterProfileOld == null - ? "-" - : positionMasterProfileOld.positions.find( - (x: any) => x.positionIsSelected == true, - )?.posExecutive?.posExecutiveName, + : "-", profileFullname: `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`, education: education == "" ? "" : education.degree, @@ -9389,20 +10119,18 @@ export class ReportController extends Controller { ); _node = null; + console.log("15"); for (let orgChild2 of orgChild2Data.filter( (orgChild2) => orgChild2.orgChild1Id === orgChild1.id, )) { + console.log("111"); await Promise.all( orgChild2.posMasters .sort((a, b) => a.posMasterOrder - b.posMasterOrder) .map(async (posMaster) => { + console.log("112"); if (posMaster.orgChild3Id == null && posMaster.next_holder != null) { - let positionMasterProfileOld: any = null; - if (posMaster.next_holder != null) { - positionMasterProfileOld = posMaster.next_holder.current_holders.find( - (x) => x.orgRevisionId == orgRevisionActive.id, - ); - } + console.log("114"); let education: any = ""; if ( posMaster.next_holder != null && @@ -9418,6 +10146,7 @@ export class ReportController extends Controller { education = _education[0]; } } + console.log("115"); let salary: any = ""; if ( posMaster.next_holder != null && @@ -9433,6 +10162,7 @@ export class ReportController extends Controller { salary = _salary[0]; } } + console.log("116"); let node = { orgTreeName: orgChild2.orgChild2Name, @@ -9447,25 +10177,17 @@ export class ReportController extends Controller { posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posType?.posTypeName - : posMaster.next_holder.posType == null - ? "-" - : posMaster.next_holder.posType.posTypeName, + : "-", posLevel: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posLevel?.posLevelName - : posMaster.next_holder.posLevel == null - ? "-" - : posMaster.next_holder.posLevel.posLevelName, + : "-", posExecutive: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posExecutive?.posExecutiveName - : positionMasterProfileOld == null - ? "-" - : positionMasterProfileOld.positions.find( - (x: any) => x.positionIsSelected == true, - )?.posExecutive?.posExecutiveName, + : "-", profileFullname: `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`, education: education == "" ? "" : education.degree, salary: salary == "" ? "" : salary.amount, @@ -9597,6 +10319,7 @@ export class ReportController extends Controller { ); _node = null; + console.log("16"); for (let orgChild3 of orgChild3Data.filter( (orgChild3) => orgChild3.orgChild2Id === orgChild2.id, )) { @@ -9605,12 +10328,6 @@ export class ReportController extends Controller { .sort((a, b) => a.posMasterOrder - b.posMasterOrder) .map(async (posMaster) => { if (posMaster.orgChild4Id == null && posMaster.next_holder != null) { - let positionMasterProfileOld: any = null; - if (posMaster.next_holder != null) { - positionMasterProfileOld = posMaster.next_holder.current_holders.find( - (x) => x.orgRevisionId == orgRevisionActive.id, - ); - } let education: any = ""; if ( posMaster.next_holder != null && @@ -9655,25 +10372,17 @@ export class ReportController extends Controller { posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posType?.posTypeName - : posMaster.next_holder.posType == null - ? "-" - : posMaster.next_holder.posType.posTypeName, + : "-", posLevel: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posLevel?.posLevelName - : posMaster.next_holder.posLevel == null - ? "-" - : posMaster.next_holder.posLevel.posLevelName, + : "-", posExecutive: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posExecutive?.posExecutiveName - : positionMasterProfileOld == null - ? "-" - : positionMasterProfileOld.positions.find( - (x: any) => x.positionIsSelected == true, - )?.posExecutive?.posExecutiveName, + : "-", profileFullname: `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`, education: education == "" ? "" : education.degree, salary: salary == "" ? "" : salary.amount, @@ -9810,6 +10519,7 @@ export class ReportController extends Controller { ); _node = null; + console.log("17"); for (let orgChild4 of orgChild4Data.filter( (orgChild4) => orgChild4.orgChild3Id === orgChild3.id, )) { @@ -9818,12 +10528,6 @@ export class ReportController extends Controller { .sort((a, b) => a.posMasterOrder - b.posMasterOrder) .map(async (posMaster) => { if (posMaster.next_holder != null) { - let positionMasterProfileOld: any = null; - if (posMaster.next_holder != null) { - positionMasterProfileOld = posMaster.next_holder.current_holders.find( - (x) => x.orgRevisionId == orgRevisionActive.id, - ); - } let education: any = ""; if ( posMaster.next_holder != null && @@ -9870,25 +10574,17 @@ export class ReportController extends Controller { posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posType?.posTypeName - : posMaster.next_holder.posType == null - ? "-" - : posMaster.next_holder.posType.posTypeName, + : "-", posLevel: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posLevel?.posLevelName - : posMaster.next_holder.posLevel == null - ? "-" - : posMaster.next_holder.posLevel.posLevelName, + : "-", posExecutive: posMaster.isSit == false ? posMaster.positions.find((x: any) => x.positionIsSelected == true) ?.posExecutive?.posExecutiveName - : positionMasterProfileOld == null - ? "-" - : positionMasterProfileOld.positions.find( - (x: any) => x.positionIsSelected == true, - )?.posExecutive?.posExecutiveName, + : "-", profileFullname: `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`, education: education == "" ? "" : education.degree, salary: salary == "" ? "" : salary.amount,