diff --git a/src/services/PositionService.ts b/src/services/PositionService.ts index 357ec2af..44916aee 100644 --- a/src/services/PositionService.ts +++ b/src/services/PositionService.ts @@ -1,4 +1,4 @@ -import { EntityManager, In } from "typeorm"; +import { In } from "typeorm"; import { SavePosMasterHistory } from "./../interfaces/OrgMapping"; import { AppDataSource } from "../database/data-source"; import { EmployeePosMaster } from "../entities/EmployeePosMaster"; @@ -17,118 +17,105 @@ export async function CreatePosMasterHistoryOfficer( request: RequestWithUser | null, type?: string | null, positionData?: { positionId?: string } | null, - manager?: EntityManager, ): Promise { - const execute = async (transactionManager: EntityManager) => { - const repoPosmaster = transactionManager.getRepository(PosMaster); - const repoHistory = transactionManager.getRepository(PosMasterHistory); - const repoOrgRevision = transactionManager.getRepository(OrgRevision); - const repoPosition = transactionManager.getRepository(Position); - - const pm = await repoPosmaster.findOne({ - where: { id: posMasterId }, - relations: [ - "positions", - "positions.posLevel", - "positions.posType", - "positions.posExecutive", - "orgRoot", - "orgChild1", - "orgChild2", - "orgChild3", - "orgChild4", - "current_holder", - "next_holder", - ], - }); - - if (!pm || !pm.ancestorDNA) { - return; - } - - const checkCurrentRevision = await repoOrgRevision.findOne({ - where: { - id: pm.orgRevisionId, - orgRevisionIsCurrent: true, - orgRevisionIsDraft: false, - }, - }); - const _null: any = null; - const h = new PosMasterHistory(); - - // query position โดยตรงจาก positionRepository - let selectedPosition: Position | null = null; - if (positionData?.positionId) { - selectedPosition = await repoPosition.findOne({ - where: { id: positionData.positionId }, - relations: { posLevel: true, posType: true, posExecutive: true }, - }); - } else { - // ใช้ logic เดิม หาจาก pm.positions ที่ positionIsSelected = true - selectedPosition = - pm.positions.length > 0 - ? pm.positions.find((p) => p.positionIsSelected === true) ?? null - : null; - } - - h.ancestorDNA = pm.ancestorDNA ? pm.ancestorDNA : _null; - if (!type || type != "DELETE") { - if (checkCurrentRevision) { - h.prefix = pm.current_holder?.prefix || _null; - h.firstName = pm.current_holder?.firstName || _null; - h.lastName = pm.current_holder?.lastName || _null; - h.profileId = pm.current_holder?.id || _null; - } else { - h.prefix = pm.next_holder?.prefix || _null; - h.firstName = pm.next_holder?.firstName || _null; - h.lastName = pm.next_holder?.lastName || _null; - } - h.position = selectedPosition?.positionName ?? _null; - h.posType = selectedPosition?.posType?.posTypeName ?? _null; - h.posLevel = selectedPosition?.posLevel?.posLevelName ?? _null; - } - h.rootDnaId = pm.orgRoot?.ancestorDNA || _null; - h.child1DnaId = pm.orgChild1?.ancestorDNA || _null; - h.child2DnaId = pm.orgChild2?.ancestorDNA || _null; - h.child3DnaId = pm.orgChild3?.ancestorDNA || _null; - h.child4DnaId = pm.orgChild4?.ancestorDNA || _null; - h.posMasterNoPrefix = pm.posMasterNoPrefix ?? _null; - h.posMasterNo = pm.posMasterNo ?? _null; - h.posMasterNoSuffix = pm.posMasterNoSuffix ?? _null; - h.posExecutive = selectedPosition?.posExecutive?.posExecutiveName ?? _null; - h.shortName = - [ - pm.orgChild4?.orgChild4ShortName, - pm.orgChild3?.orgChild3ShortName, - pm.orgChild2?.orgChild2ShortName, - pm.orgChild1?.orgChild1ShortName, - pm.orgRoot?.orgRootShortName, - ].find((s) => typeof s === "string" && s.trim().length > 0) ?? _null; - const userId = request?.user?.sub ?? ""; - const userName = request?.user?.name ?? "system"; - h.createdUserId = userId; - h.createdFullName = userName; - h.lastUpdateUserId = userId; - h.lastUpdateFullName = userName; - h.createdAt = new Date(); - h.lastUpdatedAt = new Date(); - await repoHistory.save(h); - }; - try { - if (manager) { - await execute(manager); - return true; - } + await AppDataSource.transaction(async (manager) => { + const repoPosmaster = manager.getRepository(PosMaster); + const repoHistory = manager.getRepository(PosMasterHistory); + const repoOrgRevision = manager.getRepository(OrgRevision); + const repoPosition = manager.getRepository(Position); - await AppDataSource.transaction(async (transactionManager) => { - await execute(transactionManager); + const pm = await repoPosmaster.findOne({ + where: { id: posMasterId }, + relations: [ + "positions", + "positions.posLevel", + "positions.posType", + "positions.posExecutive", + "orgRoot", + "orgChild1", + "orgChild2", + "orgChild3", + "orgChild4", + "current_holder", + "next_holder", + ], + }); + + if (!pm) return false; + if (!pm.ancestorDNA) return false; + + const checkCurrentRevision = await repoOrgRevision.findOne({ + where: { + id: pm.orgRevisionId, + orgRevisionIsCurrent: true, + orgRevisionIsDraft: false, + }, + }); + const _null: any = null; + const h = new PosMasterHistory(); + + // query position โดยตรงจาก positionRepository + let selectedPosition: Position | null = null; + if (positionData?.positionId) { + selectedPosition = await repoPosition.findOne({ + where: { id: positionData.positionId }, + relations: { posLevel: true, posType: true, posExecutive: true }, + }); + } else { + // ใช้ logic เดิม หาจาก pm.positions ที่ positionIsSelected = true + selectedPosition = + pm.positions.length > 0 + ? pm.positions.find((p) => p.positionIsSelected === true) ?? null + : null; + } + + h.ancestorDNA = pm.ancestorDNA ? pm.ancestorDNA : _null; + if (!type || type != "DELETE") { + if (checkCurrentRevision) { + h.prefix = pm.current_holder?.prefix || _null; + h.firstName = pm.current_holder?.firstName || _null; + h.lastName = pm.current_holder?.lastName || _null; + h.profileId = pm.current_holder?.id || _null; + } else { + h.prefix = pm.next_holder?.prefix || _null; + h.firstName = pm.next_holder?.firstName || _null; + h.lastName = pm.next_holder?.lastName || _null; + } + h.position = selectedPosition?.positionName ?? _null; + h.posType = selectedPosition?.posType?.posTypeName ?? _null; + h.posLevel = selectedPosition?.posLevel?.posLevelName ?? _null; + } + h.rootDnaId = pm.orgRoot?.ancestorDNA || _null; + h.child1DnaId = pm.orgChild1?.ancestorDNA || _null; + h.child2DnaId = pm.orgChild2?.ancestorDNA || _null; + h.child3DnaId = pm.orgChild3?.ancestorDNA || _null; + h.child4DnaId = pm.orgChild4?.ancestorDNA || _null; + h.posMasterNoPrefix = pm.posMasterNoPrefix ?? _null; + h.posMasterNo = pm.posMasterNo ?? _null; + h.posMasterNoSuffix = pm.posMasterNoSuffix ?? _null; + h.posExecutive = selectedPosition?.posExecutive?.posExecutiveName ?? _null; + h.shortName = + [ + pm.orgChild4?.orgChild4ShortName, + pm.orgChild3?.orgChild3ShortName, + pm.orgChild2?.orgChild2ShortName, + pm.orgChild1?.orgChild1ShortName, + pm.orgRoot?.orgRootShortName, + ].find((s) => typeof s === "string" && s.trim().length > 0) ?? _null; + const userId = request?.user?.sub ?? ""; + const userName = request?.user?.name ?? "system"; + h.createdUserId = userId; + h.createdFullName = userName; + h.lastUpdateUserId = userId; + h.lastUpdateFullName = userName; + h.createdAt = new Date(); + h.lastUpdatedAt = new Date(); + await repoHistory.save(h); }); + return true; } catch (err) { - if (manager) { - throw err; - } console.error("CreatePosMasterHistoryOfficer transaction error:", err); return false; } diff --git a/src/services/rabbitmq.ts b/src/services/rabbitmq.ts index 990cd5fb..31a4269d 100644 --- a/src/services/rabbitmq.ts +++ b/src/services/rabbitmq.ts @@ -1,4 +1,3 @@ -import { randomUUID } from "crypto"; import amqp from "amqplib"; import { AppDataSource } from "../database/data-source"; import { Command } from "../entities/Command"; @@ -21,31 +20,13 @@ import { OrgChild4 } from "../entities/OrgChild4"; import { OrgRoot } from "../entities/OrgRoot"; import { PosMasterAssign, PosMasterAssignDTO } from "../entities/PosMasterAssign"; import { Position } from "../entities/Position"; -import { In, Not, Repository } from "typeorm"; +import { In, Not } from "typeorm"; import { PosMasterAct } from "../entities/PosMasterAct"; import { PermissionOrg } from "../entities/PermissionOrg"; import { sendWebSocket } from "./webSocket"; +import { CreatePosMasterHistoryOfficer } from "./PositionService"; import { PayloadSendNoti } from "../interfaces/utils"; import { PermissionProfile } from "../entities/PermissionProfile"; -import { PosMasterHistory } from "../entities/PosMasterHistory"; - -let reconnectTimer: ReturnType | null = null; - -function scheduleReconnect() { - if (reconnectTimer) { - return; - } - - reconnectTimer = setTimeout(async () => { - reconnectTimer = null; - try { - await init(); - } catch (error) { - console.error("[AMQ] Reconnect failed:", error); - scheduleReconnect(); - } - }, 1000); -} export let sendToQueue: (payload: any) => void; export let sendToQueueOrg: (payload: any) => void; @@ -74,28 +55,10 @@ export async function init() { console.log(connection ? "[AMQ] Connection success" : "[AMQ] Connection failed"); - connection.on("error", (error) => { - console.error("[AMQ] Connection error:", error); - }); - - connection.on("close", () => { - console.error("[AMQ] Connection closed. Scheduling reconnect..."); - scheduleReconnect(); - }); - const channel = await connection.createChannel(); //----> (1.4) create Channel console.log(channel ? "[AMQ] Create channel success" : "[AMQ] Create channel failed"); - channel.on("error", (error) => { - console.error("[AMQ] Channel error:", error); - }); - - channel.on("close", () => { - console.error("[AMQ] Channel closed. Scheduling reconnect..."); - scheduleReconnect(); - }); - channel.assertQueue(queue, { durable: true }), //----> (1.5) assert queue and set durable (if "true" save to disk on RabbitMQ) channel.assertQueue(queue_org, { durable: true }), channel.assertQueue(queue_org_draft, { durable: true }), @@ -129,6 +92,8 @@ export async function init() { // createConsumer(queue2, channel, handler2); } +let retries = 0; + function createConsumer( //----> consumer queue: string, channel: amqp.Channel, @@ -138,22 +103,13 @@ function createConsumer( //----> consumer queue, async (msg) => { if (!msg) return; - try { - if (await handler(msg)) { - console.log("[AMQ] Process Consumer success"); - return channel.ack(msg); - } - console.error(`[AMQ] Process Consumer failed on queue ${queue}, acknowledging without retry`); + if ((await handler(msg)) || retries++ >= 3) { + retries = 0; + console.log("[AMQ] Process Consumer success"); return channel.ack(msg); - } catch (error) { - console.error(`[AMQ] Consumer processing error on queue ${queue}:`, error); - try { - console.error(`[AMQ] Acknowledging failed message on queue ${queue} without retry`); - channel.ack(msg); - } catch (channelError) { - console.error(`[AMQ] Failed to ack/nack message on queue ${queue}:`, channelError); - } } + console.log("[AMQ] Process Consumer failed"); + return await new Promise((resolve) => setTimeout(() => resolve(channel.nack(msg)), 3000)); }, { noAck: false }, ); @@ -449,7 +405,7 @@ async function handler_command_noti(msg: amqp.ConsumeMessage): Promise try { let profilesNotiRequest: Promise | undefined; - if (!["C-PM-10"].includes(command.commandType.code)) { + if (!(["C-PM-10"].includes(command.commandType.code))) { profilesNotiRequest = new CallAPI() .PostData( { headers: { authorization: token } }, @@ -485,14 +441,14 @@ async function handler_command_noti(msg: amqp.ConsumeMessage): Promise let profilesSend = command && command.commandSends.length > 0 ? command.commandSends - .filter((x: any) => x.profileId != null) - .map((x: any) => ({ - receiverUserId: x.profileId, - notiLink: "", - isSendMail: x.commandSendCCs.map((x: any) => x.name == "EMAIL").length > 0, - isSendInbox: x.commandSendCCs.map((x: any) => x.name == "INBOX").length > 0, - isSendNotification: true, - })) + .filter((x: any) => x.profileId != null) + .map((x: any) => ({ + receiverUserId: x.profileId, + notiLink: "", + isSendMail: x.commandSendCCs.map((x: any) => x.name == "EMAIL").length > 0, + isSendInbox: x.commandSendCCs.map((x: any) => x.name == "INBOX").length > 0, + isSendNotification: true, + })) : []; const payloadStr = await PayloadSendNoti(command.id); const profilesSendRequest = new CallAPI() @@ -526,7 +482,8 @@ async function handler_command_noti(msg: amqp.ConsumeMessage): Promise /*เฉพาะคำสั่ง C-PM-10 ให้ตัด profilesNotiRequest ที่ส่ง noti ครั้งแรกออก*/ if (["C-PM-10"].includes(command.commandType.code)) { await Promise.all([profilesSendRequest]); - } else { + } + else { await Promise.all([profilesNotiRequest!, profilesSendRequest]); } @@ -540,7 +497,7 @@ async function handler_command_noti(msg: amqp.ConsumeMessage): Promise async function handler_org(msg: amqp.ConsumeMessage): Promise { //----> condition before process consume - console.time("[AMQ] handler_org_total"); + console.time('[AMQ] handler_org_total'); const startTime = Date.now(); console.log(`[AMQ] handler_org START at ${new Date(startTime).toISOString()}`); @@ -563,30 +520,6 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { const { id, status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt } = data; console.log(`[AMQ] Received message - revisionId: ${id}, status: ${status}`); - const targetOrgRevision = await repoOrgRevision.findOne({ - where: { id }, - }); - - if (!targetOrgRevision) { - console.error(`[AMQ] Skip publish: revision ${id} not found`); - console.timeEnd("[AMQ] handler_org_total"); - return true; - } - - if (targetOrgRevision.orgRevisionIsCurrent && !targetOrgRevision.orgRevisionIsDraft) { - console.log(`[AMQ] Skip publish: revision ${id} is already current`); - console.timeEnd("[AMQ] handler_org_total"); - return true; - } - - if (!targetOrgRevision.orgRevisionIsDraft || targetOrgRevision.orgRevisionIsCurrent) { - console.log( - `[AMQ] Skip publish: revision ${id} is no longer publishable (isDraft=${targetOrgRevision.orgRevisionIsDraft}, isCurrent=${targetOrgRevision.orgRevisionIsCurrent})`, - ); - console.timeEnd("[AMQ] handler_org_total"); - return true; - } - if (user) { sendWebSocket( "send-publish-org", @@ -598,30 +531,25 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { ).catch(console.error); } - console.time("[AMQ] query_revisions"); - const [orgRevisionPublish, orgRevisionDraft] = await Promise.all([ - repoOrgRevision - .createQueryBuilder("orgRevision") - .where("orgRevision.orgRevisionIsDraft = false") - .andWhere("orgRevision.orgRevisionIsCurrent = true") - .getOne(), - repoOrgRevision - .createQueryBuilder("orgRevision") - .where("orgRevision.orgRevisionIsDraft = true") - .andWhere("orgRevision.orgRevisionIsCurrent = false") - .getOne(), - ]); - console.timeEnd("[AMQ] query_revisions"); - console.log( - `[AMQ] orgRevisionPublish found: ${orgRevisionPublish ? orgRevisionPublish.id : "null"}`, - ); - console.log(`[AMQ] orgRevisionDraft found: ${orgRevisionDraft ? orgRevisionDraft.id : "null"}`); + console.time('[AMQ] query_revisions'); + const orgRevisionPublish = await repoOrgRevision + .createQueryBuilder("orgRevision") + .where("orgRevision.orgRevisionIsDraft = false") + .andWhere("orgRevision.orgRevisionIsCurrent = true") + .getOne(); + + const orgRevisionDraft = await repoOrgRevision + .createQueryBuilder("orgRevision") + .where("orgRevision.orgRevisionIsDraft = true") + .andWhere("orgRevision.orgRevisionIsCurrent = false") + .getOne(); + console.timeEnd('[AMQ] query_revisions'); + console.log(`[AMQ] orgRevisionPublish found: ${orgRevisionPublish ? orgRevisionPublish.id : 'null'}`); + console.log(`[AMQ] orgRevisionDraft found: ${orgRevisionDraft ? orgRevisionDraft.id : 'null'}`); // Validate: ต้องมี orgRevisionPublish เสมอสำหรับการเผยแพร่ if (!orgRevisionPublish) { - console.error( - "[AMQ] Cannot publish: No current org revision found (isDraft=false, isCurrent=true)", - ); + console.error('[AMQ] Cannot publish: No current org revision found (isDraft=false, isCurrent=true)'); if (user) { sendWebSocket( "send-publish-org", @@ -637,9 +565,7 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { // Validate: ต้องมี orgRevisionDraft ที่จะเผยแพร่ if (!orgRevisionDraft) { - console.error( - "[AMQ] Cannot publish: No draft org revision found (isDraft=true, isCurrent=false)", - ); + console.error('[AMQ] Cannot publish: No draft org revision found (isDraft=true, isCurrent=false)'); if (user) { sendWebSocket( "send-publish-org", @@ -653,19 +579,11 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { return false; } - if (orgRevisionDraft.id !== targetOrgRevision.id) { - console.log( - `[AMQ] Skip publish: revision ${id} is stale because draft ${orgRevisionDraft.id} is now the active publish candidate`, - ); - console.timeEnd("[AMQ] handler_org_total"); - return true; - } - // NOTE: ย้ายการอัปเดตสถานะไปไว้หลังจากทำงานเสร็จทั้งหมด // เพื่อป้องกันกรณี timeout/retry ทำให้สถานะเพี้ยน (ทุก row เป็น false,false) try { - console.time("[AMQ] query_posMaster"); + console.time('[AMQ] query_posMaster'); const posMaster = await repoPosmaster.find({ where: { orgRevisionId: id }, relations: [ @@ -680,15 +598,15 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { "positions.posExecutive", ], }); - console.timeEnd("[AMQ] query_posMaster"); + console.timeEnd('[AMQ] query_posMaster'); console.log(`[AMQ] posMaster count: ${posMaster.length}`); - console.time("[AMQ] query_old_data"); + console.time('[AMQ] query_old_data'); const oldPosMasters = await repoPosmaster.find({ where: { orgRevisionId: orgRevisionPublish.id, }, - select: ["id", "current_holderId", "ancestorDNA"], + select: ['id', 'current_holderId', 'ancestorDNA'] }); // Task #2160 ดึง posMasterAssign ของ revision เดิม @@ -700,11 +618,11 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { }, }, }); - console.timeEnd("[AMQ] query_old_data"); + console.timeEnd('[AMQ] query_old_data'); console.log(`[AMQ] oldPosMasters count: ${oldPosMasters.length}`); console.log(`[AMQ] oldposMasterAssigns count: ${oldposMasterAssigns.length}`); - console.time("[AMQ] build_assignMap"); + console.time('[AMQ] build_assignMap'); // สร้าง assignMap เอาไว้เก็บ posMasterAssign.ancestorDNA ของ revision เดิม const assignMap = new Map(); for (const posmasterAssign of oldposMasterAssigns) { @@ -715,12 +633,12 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { assignMap.get(dna)!.push({ id: posmasterAssign.id, posMasterId: posmasterAssign.posMasterId, - assignId: posmasterAssign.assignId, + assignId: posmasterAssign.assignId }); } - console.timeEnd("[AMQ] build_assignMap"); + console.timeEnd('[AMQ] build_assignMap'); - console.time("[AMQ] query_oldposMasterAct"); + console.time('[AMQ] query_oldposMasterAct'); // ดึง posMasterAct ของ revision เดิม xxx const oldposMasterAct = await posMasterActRepository.find({ relations: ["posMaster", "posMasterChild"], @@ -730,16 +648,16 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { }, }, }); - console.timeEnd("[AMQ] query_oldposMasterAct"); + console.timeEnd('[AMQ] query_oldposMasterAct'); console.log(`[AMQ] oldposMasterAct count: ${oldposMasterAct.length}`); type ActKey = string; // `${parentDNA}|${childDNA}` - console.time("[AMQ] build_maps"); + console.time('[AMQ] build_maps'); const posMasterActMap = new Map(); for (const act of oldposMasterAct) { - const parentDNA = act.posMaster?.ancestorDNA?.trim() ?? ""; - const childDNA = act.posMasterChild?.ancestorDNA?.trim() ?? ""; + const parentDNA = act.posMaster?.ancestorDNA?.trim() ?? ''; + const childDNA = act.posMasterChild?.ancestorDNA?.trim() ?? ''; const key = `${parentDNA}|${childDNA}`; if (!posMasterActMap.has(key)) { @@ -750,7 +668,7 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { const posMasterIdMap = new Map(); for (const pm of posMaster) { - posMasterIdMap.set(pm.ancestorDNA?.trim() ?? "", pm.id); + posMasterIdMap.set(pm.ancestorDNA?.trim() ?? '', pm.id); } const oldPosMasterMap = new Map(); @@ -760,32 +678,32 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { oldPosMasterMap.set(dna, oldPm); } } - console.timeEnd("[AMQ] build_maps"); + console.timeEnd('[AMQ] build_maps'); const _null: any = null; // ===== BATCH PROCESSING: เตรียมข้อมูลก่อน loop ===== - console.time("[AMQ] prepare_batch_data"); + console.time('[AMQ] prepare_batch_data'); // 1. รวบรวม profileIds ทั้งหมดที่ต้องอัพเดท const profileIds = posMaster - .filter((item) => item.next_holderId != null) - .map((item) => item.next_holderId!) - .filter((id) => id != null && id !== ""); + .filter(item => item.next_holderId != null) + .map(item => item.next_holderId!) + .filter(id => id != null && id !== ""); // 2. Batch load profiles ทั้งหมดในครั้งเดียว (แก้ปัญหา N+1 Query) const profilesMap = new Map(); if (profileIds.length > 0) { const profiles = await repoProfile.findBy({ - id: In(profileIds), + id: In(profileIds) }); - profiles.forEach((p) => profilesMap.set(p.id, p)); + profiles.forEach(p => profilesMap.set(p.id, p)); } console.log(`[AMQ] profiles to update: ${profilesMap.size}`); // 3. เตรียม arrays สำหรับ batch operations const profilesToSave: Profile[] = []; const posMasterAssignsToSave: PosMasterAssign[] = []; - const historyRowsToSave: Partial[] = []; + const historyCreateIds: string[] = []; const posMasterUpdates: { id: string; current_holderId: string | null | undefined }[] = []; // ===== LOOP: เก็บข้อมูลทั้งหมด ===== @@ -806,7 +724,7 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { lastUpdatedAt: lastUpdatedAt, lastUpdateFullName: lastUpdateFullName, lastUpdateUserId: lastUpdateUserId, - }), + }) ); posMasterAssignsToSave.push(...newAssigns); } @@ -854,293 +772,132 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { const isHolderChanged = oldHolderId !== newHolderId; if (isHolderChanged) { - const nextHolderProfile = - item.next_holderId != null && item.next_holderId !== "" - ? profilesMap.get(item.next_holderId) - : null; - const selectedPosition = - item.positions.length > 0 - ? item.positions.find((position) => position.positionIsSelected === true) ?? null - : null; - const shortName = - [ - item.orgChild4?.orgChild4ShortName, - item.orgChild3?.orgChild3ShortName, - item.orgChild2?.orgChild2ShortName, - item.orgChild1?.orgChild1ShortName, - item.orgRoot?.orgRootShortName, - ].find((name) => typeof name === "string" && name.trim().length > 0) ?? _null; - - historyRowsToSave.push({ - ancestorDNA: item.ancestorDNA ? item.ancestorDNA : _null, - prefix: nextHolderProfile?.prefix || _null, - firstName: nextHolderProfile?.firstName || _null, - lastName: nextHolderProfile?.lastName || _null, - shortName, - posMasterNoPrefix: item.posMasterNoPrefix ?? _null, - posMasterNo: item.posMasterNo ?? _null, - posMasterNoSuffix: item.posMasterNoSuffix ?? _null, - position: selectedPosition?.positionName ?? _null, - posType: selectedPosition?.posType?.posTypeName ?? _null, - posLevel: selectedPosition?.posLevel?.posLevelName ?? _null, - posExecutive: selectedPosition?.posExecutive?.posExecutiveName ?? _null, - profileId: _null, - rootDnaId: item.orgRoot?.ancestorDNA || _null, - child1DnaId: item.orgChild1?.ancestorDNA || _null, - child2DnaId: item.orgChild2?.ancestorDNA || _null, - child3DnaId: item.orgChild3?.ancestorDNA || _null, - child4DnaId: item.orgChild4?.ancestorDNA || _null, - createdUserId: "", - createdFullName: "system", - lastUpdateUserId: "", - lastUpdateFullName: "system", - createdAt: new Date(), - lastUpdatedAt: new Date(), - }); + historyCreateIds.push(item.id); } } - console.timeEnd("[AMQ] prepare_batch_data"); - console.log( - `[AMQ] Prepared - posMasterAssignsToSave: ${posMasterAssignsToSave.length}, profilesToSave: ${profilesToSave.length}, posMasterUpdates: ${posMasterUpdates.length}, historyCreateIds: ${historyRowsToSave.length}`, - ); + console.timeEnd('[AMQ] prepare_batch_data'); + console.log(`[AMQ] Prepared - posMasterAssignsToSave: ${posMasterAssignsToSave.length}, profilesToSave: ${profilesToSave.length}, posMasterUpdates: ${posMasterUpdates.length}, historyCreateIds: ${historyCreateIds.length}`); // ===== BATCH EXECUTION: save ทีละ batch ===== - let shouldSkipPublishInTransaction = false; - await AppDataSource.transaction(async (manager) => { - const repoPosmaster = manager.getRepository(PosMaster); - const posMasterAssignRepository = manager.getRepository(PosMasterAssign); - const posMasterActRepository = manager.getRepository(PosMasterAct); - const permissionProfilesRepository = manager.getRepository(PermissionProfile); - const repoEmployeePosmaster = manager.getRepository(EmployeePosMaster); - const repoEmployeeTempPosmaster = manager.getRepository(EmployeeTempPosMaster); - const repoProfile = manager.getRepository(Profile); - const repoProfileEmployee = manager.getRepository(ProfileEmployee); - const employeePositionRepository = manager.getRepository(EmployeePosition); - const repoOrgRevision = manager.getRepository(OrgRevision); - const orgRootRepository = manager.getRepository(OrgRoot); - const child1Repository = manager.getRepository(OrgChild1); - const child2Repository = manager.getRepository(OrgChild2); - const child3Repository = manager.getRepository(OrgChild3); - const child4Repository = manager.getRepository(OrgChild4); - const posMasterHistoryRepository = manager.getRepository(PosMasterHistory); - const targetOrgRevision = await repoOrgRevision - .createQueryBuilder("orgRevision") - .setLock("pessimistic_write") - .where("orgRevision.id = :id", { id }) - .getOne(); - - if (!targetOrgRevision) { - shouldSkipPublishInTransaction = true; - return; + // 4. Batch save posMasterAssign (chunk 500) + console.time('[AMQ] batch_save_posMasterAssign'); + if (posMasterAssignsToSave.length > 0) { + const chunks = chunkArray(posMasterAssignsToSave, 500); + for (const chunk of chunks) { + await posMasterAssignRepository.save(chunk); } + } + console.timeEnd('[AMQ] batch_save_posMasterAssign'); - if (targetOrgRevision.orgRevisionIsCurrent && !targetOrgRevision.orgRevisionIsDraft) { - shouldSkipPublishInTransaction = true; - return; + // 5. Batch save profiles (chunk 200) + console.time('[AMQ] batch_save_profiles'); + if (profilesToSave.length > 0) { + const chunks = chunkArray(profilesToSave, 200); + for (const chunk of chunks) { + await repoProfile.save(chunk); } + } + console.timeEnd('[AMQ] batch_save_profiles'); - if (!targetOrgRevision.orgRevisionIsDraft || targetOrgRevision.orgRevisionIsCurrent) { - shouldSkipPublishInTransaction = true; - return; - } + // 6. Batch update posMasters + console.time('[AMQ] batch_update_posMasters'); + for (const update of posMasterUpdates) { + await repoPosmaster.update(update.id, { + current_holderId: update.current_holderId, + next_holderId: null, + lastUpdateUserId, + lastUpdateFullName, + lastUpdatedAt, + }); + } + console.timeEnd('[AMQ] batch_update_posMasters'); - const orgRevisionPublish = await repoOrgRevision - .createQueryBuilder("orgRevision") - .setLock("pessimistic_write") - .where("orgRevision.orgRevisionIsDraft = false") - .andWhere("orgRevision.orgRevisionIsCurrent = true") - .getOne(); + // 7. Batch create history + console.time('[AMQ] batch_create_history'); + for (const id of historyCreateIds) { + await CreatePosMasterHistoryOfficer(id, null); + } + console.timeEnd('[AMQ] batch_create_history'); - if (!orgRevisionPublish) { - throw new Error("[AMQ] Cannot publish in transaction: no current org revision found"); - } + // Clone oldposMasterAct + console.time('[AMQ] clone_oldposMasterAct'); + for (const act of oldposMasterAct) { + const parentDNA = act.posMaster?.ancestorDNA?.trim()?.toLowerCase() ?? ''; + const childDNA = act.posMasterChild?.ancestorDNA?.trim()?.toLowerCase() ?? ''; - const orgRevisionDraft = await repoOrgRevision - .createQueryBuilder("orgRevision") - .setLock("pessimistic_write") - .where("orgRevision.id = :id", { id }) - .andWhere("orgRevision.orgRevisionIsDraft = true") - .andWhere("orgRevision.orgRevisionIsCurrent = false") - .getOne(); + const newParentId = posMasterIdMap.get(parentDNA); + const newChildId = posMasterIdMap.get(childDNA); - if (!orgRevisionDraft) { - shouldSkipPublishInTransaction = true; - return; - } + if (!newParentId || !newChildId) continue; - // 4. Batch save posMasterAssign (chunk 500) - console.time("[AMQ] batch_save_posMasterAssign"); - if (posMasterAssignsToSave.length > 0) { - const chunks = chunkArray(posMasterAssignsToSave, 500); - for (const chunk of chunks) { - await posMasterAssignRepository.save(chunk); - } - } - console.timeEnd("[AMQ] batch_save_posMasterAssign"); + const { id, posMaster, posMasterChild, ...fields } = act; - // 5. Batch save profiles (chunk 200) - console.time("[AMQ] batch_save_profiles"); - if (profilesToSave.length > 0) { - const chunks = chunkArray(profilesToSave, 200); - for (const chunk of chunks) { - await repoProfile.save(chunk); - } - } - console.timeEnd("[AMQ] batch_save_profiles"); + const newAct = { + ...fields, + posMasterId: newParentId, + posMasterChildId: newChildId, + createdAt: new Date(), + createdFullName: user ? user.name : "system", + createdUserId: user ? user.sub : "system", + lastUpdatedAt: new Date(), + lastUpdateFullName: user ? user.name : "system", + lastUpdateUserId: user ? user.sub : "system", + }; - // 6. Batch update posMasters - console.time("[AMQ] batch_update_posMasters"); - if (posMasterUpdates.length > 0) { - const chunks = chunkArray(posMasterUpdates, 500); - const posMasterTableName = repoPosmaster.metadata.tableName; - for (const chunk of chunks as typeof posMasterUpdates[]) { - const caseClauses = chunk.map(() => "WHEN ? THEN ?").join(" "); - const wherePlaceholders = chunk.map(() => "?").join(", "); - const params = chunk.flatMap((update: (typeof posMasterUpdates)[number]) => [ - update.id, - update.current_holderId ?? null, - ]); + await posMasterActRepository.save(newAct); + } + console.timeEnd('[AMQ] clone_oldposMasterAct'); - params.push( - lastUpdateUserId, - lastUpdateFullName, - lastUpdatedAt, - ...chunk.map((update: (typeof posMasterUpdates)[number]) => update.id), - ); - - await manager.query( - `UPDATE \`${posMasterTableName}\` - SET current_holderId = CASE id ${caseClauses} END, - next_holderId = NULL, - lastUpdateUserId = ?, - lastUpdateFullName = ?, - lastUpdatedAt = ? - WHERE id IN (${wherePlaceholders})`, - params, - ); - } - } - console.timeEnd("[AMQ] batch_update_posMasters"); - - // 7. Batch create history - console.time("[AMQ] batch_create_history"); - if (historyRowsToSave.length > 0) { - const chunks = chunkArray(historyRowsToSave, 500); - for (const chunk of chunks) { - await posMasterHistoryRepository.save(posMasterHistoryRepository.create(chunk)); - } - } - console.timeEnd("[AMQ] batch_create_history"); - - // Clone oldposMasterAct - console.time("[AMQ] clone_oldposMasterAct"); - const posMasterActRowsToInsert: Partial[] = []; - for (const act of oldposMasterAct) { - const parentDNA = act.posMaster?.ancestorDNA?.trim()?.toLowerCase() ?? ""; - const childDNA = act.posMasterChild?.ancestorDNA?.trim()?.toLowerCase() ?? ""; - - const newParentId = posMasterIdMap.get(parentDNA); - const newChildId = posMasterIdMap.get(childDNA); - - if (!newParentId || !newChildId) continue; - - const { id, posMaster, posMasterChild, ...fields } = act; - - posMasterActRowsToInsert.push({ - ...fields, - posMasterId: newParentId, - posMasterChildId: newChildId, - createdAt: new Date(), - createdFullName: user ? user.name : "system", - createdUserId: user ? user.sub : "system", - lastUpdatedAt: new Date(), - lastUpdateFullName: user ? user.name : "system", - lastUpdateUserId: user ? user.sub : "system", - }); - } - if (posMasterActRowsToInsert.length > 0) { - const chunks = chunkArray(posMasterActRowsToInsert, 500); - for (const chunk of chunks) { - await posMasterActRepository.insert(chunk); - } - } - console.timeEnd("[AMQ] clone_oldposMasterAct"); - - console.time("[AMQ] clone_org_structure"); + if (orgRevisionPublish != null && orgRevisionDraft != null) { + console.time('[AMQ] clone_org_structure'); //new main revision const before = null; //ทุก orgRoot และ orgChild ข้างล่างนี้จะเป็นตัวเก่าที่ไม่ได้เป็น current revision //cone tree - console.time("[AMQ] query_old_org_structure"); + console.time('[AMQ] query_old_org_structure'); //หา dna tree - const [orgRoot, orgChild1, orgChild2, orgChild3, orgChild4] = await Promise.all([ - orgRootRepository.find({ - where: { orgRevisionId: orgRevisionPublish.id }, - }), - child1Repository.find({ - where: { orgRevisionId: orgRevisionPublish.id }, - }), - child2Repository.find({ - where: { orgRevisionId: orgRevisionPublish.id }, - }), - child3Repository.find({ - where: { orgRevisionId: orgRevisionPublish.id }, - }), - child4Repository.find({ - where: { orgRevisionId: orgRevisionPublish.id }, - }), - ]); - console.timeEnd("[AMQ] query_old_org_structure"); - console.log( - `[AMQ] Old structure - orgRoot: ${orgRoot.length}, orgChild1: ${orgChild1.length}, orgChild2: ${orgChild2.length}, orgChild3: ${orgChild3.length}, orgChild4: ${orgChild4.length}`, - ); + const orgRoot = await orgRootRepository.find({ + where: { orgRevisionId: orgRevisionPublish.id }, + }); + + const orgChild1 = await child1Repository.find({ + where: { orgRevisionId: orgRevisionPublish.id }, + }); + + const orgChild2 = await child2Repository.find({ + where: { orgRevisionId: orgRevisionPublish.id }, + }); + + const orgChild3 = await child3Repository.find({ + where: { orgRevisionId: orgRevisionPublish.id }, + }); + + const orgChild4 = await child4Repository.find({ + where: { orgRevisionId: orgRevisionPublish.id }, + }); + console.timeEnd('[AMQ] query_old_org_structure'); + console.log(`[AMQ] Old structure - orgRoot: ${orgRoot.length}, orgChild1: ${orgChild1.length}, orgChild2: ${orgChild2.length}, orgChild3: ${orgChild3.length}, orgChild4: ${orgChild4.length}`); // Task #2172 ดึง orgRoot ของ revision ใหม่ const newRoots = await orgRootRepository.find({ where: { orgRevisionId: orgRevisionDraft.id }, }); // สร้าง newRootMap เอาไว้เก็บ orgRoot.ancestorDNA ของ revision ใหม่ - const newRootMap = new Map(newRoots.map((r) => [r.ancestorDNA, r.id])); - const emptyAncestorDNA = "00000000-0000-0000-0000-000000000000"; - const hasEmptyAncestorDNA = (ancestorDNA?: string | null) => - ancestorDNA == null || ancestorDNA === emptyAncestorDNA; - const hasSelfOrEmptyAncestorDNA = (node: { id: string; ancestorDNA: string | null }) => - node.ancestorDNA === node.id || hasEmptyAncestorDNA(node.ancestorDNA); - const findMatchedNodeByAncestorDNA = ( - nodes: T[], - node: T, - ) => - nodes.find((item) => { - if (hasSelfOrEmptyAncestorDNA(node)) { - return hasEmptyAncestorDNA(item.ancestorDNA); - } - return item.ancestorDNA === node.ancestorDNA; - }); - const [ - orgRootCurrent, - orgChild1Current, - orgChild2Current, - orgChild3Current, - orgChild4Current, - ] = await Promise.all([ - orgRootRepository.find({ where: { orgRevisionId: orgRevisionDraft.id } }), - child1Repository.find({ where: { orgRevisionId: orgRevisionDraft.id } }), - child2Repository.find({ where: { orgRevisionId: orgRevisionDraft.id } }), - child3Repository.find({ where: { orgRevisionId: orgRevisionDraft.id } }), - child4Repository.find({ where: { orgRevisionId: orgRevisionDraft.id } }), - ]); + const newRootMap = new Map( + newRoots.map(r => [r.ancestorDNA, r.id]) + ); - console.time("[AMQ] clone_permissionProfiles"); + console.time('[AMQ] clone_permissionProfiles'); // ดึง permissionProfiles ของ revision เดิม const oldPermissionProfiles = await permissionProfilesRepository.find({ relations: ["orgRootTree"], where: { orgRootTree: { orgRevisionId: orgRevisionPublish.id, - }, - }, + } + } }); const inserts: any[] = []; for (const permiss of oldPermissionProfiles) { @@ -1165,40 +922,37 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { if (inserts.length > 0) { await permissionProfilesRepository.insert(inserts); } - console.timeEnd("[AMQ] clone_permissionProfiles"); + console.timeEnd('[AMQ] clone_permissionProfiles'); - console.time("[AMQ] query_employee_org_structures"); - const [orgemployeePosMaster, orgemployeeTempPosMaster] = await Promise.all([ - repoEmployeePosmaster.find({ - where: { orgRevisionId: orgRevisionPublish.id }, - relations: ["positions"], - }), - repoEmployeeTempPosmaster.find({ - where: { orgRevisionId: orgRevisionPublish.id }, - relations: ["positions"], - }), - ]); - console.timeEnd("[AMQ] query_employee_org_structures"); + //หา dna posmaster ถ้าไม่มีให้เอาตัวเองเป็น dna + console.time('[AMQ] query_employeePosMaster'); + const orgemployeePosMaster = await repoEmployeePosmaster.find({ + where: { orgRevisionId: orgRevisionPublish.id }, + relations: ["positions"], + }); + console.timeEnd('[AMQ] query_employeePosMaster'); console.log(`[AMQ] orgemployeePosMaster count: ${orgemployeePosMaster.length}`); - console.log(`[AMQ] orgemployeeTempPosMaster count: ${orgemployeeTempPosMaster.length}`); - const currentHolderIds = Array.from( - new Set( - orgemployeePosMaster - .map((item) => item.current_holderId) - .filter((holderId): holderId is string => !!holderId), - ), + let _orgemployeePosMaster: EmployeePosMaster[]; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // _orgemployeePosMaster = orgemployeePosMaster.map((x) => ({ + // ...x, + // ancestorDNA: + // x.ancestorDNA == null || x.ancestorDNA == "00000000-0000-0000-0000-000000000000" + // ? x.id + // : x.ancestorDNA, + // })); + // await repoEmployeePosmaster.save(_orgemployeePosMaster); + const validProfileIds = new Set( + (await repoProfileEmployee.find({ select: ["id"] })).map((p) => p.id), ); - const validProfileIds = new Set(); - if (currentHolderIds.length > 0) { - const profiles = await repoProfileEmployee.find({ - select: ["id"], - where: { id: In(currentHolderIds) }, - }); - profiles.forEach((profile) => validProfileIds.add(profile.id)); - } - const _orgemployeePosMaster: EmployeePosMaster[] = orgemployeePosMaster.map((x) => ({ + _orgemployeePosMaster = orgemployeePosMaster.map((x) => ({ ...x, current_holderId: x.current_holderId && validProfileIds.has(x.current_holderId) ? x.current_holderId : null, @@ -1207,15 +961,8 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { ? x.id : x.ancestorDNA, })); - const _orgemployeeTempPosMaster: EmployeeTempPosMaster[] = orgemployeeTempPosMaster.map((x) => ({ - ...x, - ancestorDNA: - x.ancestorDNA == null || x.ancestorDNA == "00000000-0000-0000-0000-000000000000" - ? x.id - : x.ancestorDNA, - })); - console.time("[AMQ] insert_employeePosMaster"); + console.time('[AMQ] insert_employeePosMaster'); await repoEmployeePosmaster .createQueryBuilder() .insert() @@ -1226,171 +973,33 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { overwrite: ["ancestorDNA"], }) .execute(); - console.timeEnd("[AMQ] insert_employeePosMaster"); + console.timeEnd('[AMQ] insert_employeePosMaster'); - const groupByParentId = ( - items: T[], - getParentId: (item: T) => string | null | undefined, - ) => { - const grouped = new Map(); - for (const item of items) { - const parentId = getParentId(item); - if (!parentId) { - continue; - } - const current = grouped.get(parentId); - if (current) { - current.push(item); - } else { - grouped.set(parentId, [item]); - } - } - return grouped; - }; - - const buildEmployeeNodeKey = (item: { - orgRootId?: string | null; - orgChild1Id?: string | null; - orgChild2Id?: string | null; - orgChild3Id?: string | null; - orgChild4Id?: string | null; - }) => { - if (item.orgChild4Id) return `child4:${item.orgChild4Id}`; - if (item.orgChild3Id && item.orgChild4Id == null) return `child3:${item.orgChild3Id}`; - if (item.orgChild2Id && item.orgChild3Id == null) return `child2:${item.orgChild2Id}`; - if (item.orgChild1Id && item.orgChild2Id == null) return `child1:${item.orgChild1Id}`; - if (item.orgRootId && item.orgChild1Id == null) return `root:${item.orgRootId}`; - return null; - }; - - const groupByEmployeeNode = < - T extends { - orgRootId?: string | null; - orgChild1Id?: string | null; - orgChild2Id?: string | null; - orgChild3Id?: string | null; - orgChild4Id?: string | null; - }, - >( - items: T[], - ) => { - const grouped = new Map(); - for (const item of items) { - const key = buildEmployeeNodeKey(item); - if (!key) { - continue; - } - const current = grouped.get(key); - if (current) { - current.push(item); - } else { - grouped.set(key, [item]); - } - } - return grouped; - }; - - const employeePosMasterByNode = groupByEmployeeNode(_orgemployeePosMaster); - const employeeTempPosMasterByNode = groupByEmployeeNode(_orgemployeeTempPosMaster); - const getNodeKey = (level: "root" | "child1" | "child2" | "child3" | "child4", id: string) => - `${level}:${id}`; - const orgChild1ByRoot = groupByParentId(orgChild1, (item) => item.orgRootId); - const orgChild2ByChild1 = groupByParentId(orgChild2, (item) => item.orgChild1Id); - const orgChild3ByChild2 = groupByParentId(orgChild3, (item) => item.orgChild2Id); - const orgChild4ByChild3 = groupByParentId(orgChild4, (item) => item.orgChild3Id); - type OrgDestinationIds = { - orgRootId?: string | null; - orgChild1Id?: string | null; - orgChild2Id?: string | null; - orgChild3Id?: string | null; - orgChild4Id?: string | null; - }; - type CloneEmployeeSource = { - positions: EmployeePosition[]; - } & (EmployeePosMaster | EmployeeTempPosMaster); - const buildAuditFields = (timestamp: Date) => ({ - createdUserId: "", - createdFullName: "System Administrator", - createdAt: timestamp, - lastUpdateUserId: "", - lastUpdateFullName: "System Administrator", - lastUpdatedAt: timestamp, + // } + //หา dna posmaster ถ้าไม่มีให้เอาตัวเองเป็น dna + console.time('[AMQ] query_employeeTempPosMaster'); + const orgemployeeTempPosMaster = await repoEmployeeTempPosmaster.find({ + where: { orgRevisionId: orgRevisionPublish.id }, + relations: ["positions"], }); - const buildColumnData = (repository: Repository, source: T): Partial => { - const row = {} as Partial; - const target = row as Record; - const sourceRecord = source as Record; - for (const column of repository.metadata.columns) { - target[column.propertyName] = sourceRecord[column.propertyName]; - } - return row; - }; - const insertInChunks = async ( - repository: Repository, - rows: Partial[], - chunkSize: number, - ) => { - if (rows.length === 0) { - return; - } - for (const chunk of chunkArray(rows, chunkSize) as Partial[][]) { - await repository.insert(chunk as Parameters["insert"]>[0]); - } - }; - const buildEmployeeCloneBatch = ( - items: T[], - parentRepository: Repository, - positionParentKey: "posMasterId" | "posMasterTempId", - targetIds: OrgDestinationIds, - ) => { - const parentRows: Partial[] = []; - const positionRows: Partial[] = []; - - for (const item of items) { - const parentId = randomUUID(); - const parentTimestamp = new Date(); - parentRows.push({ - ...buildColumnData(parentRepository, item), - id: parentId, - orgRevisionId: orgRevisionDraft.id, - ...targetIds, - ...buildAuditFields(parentTimestamp), - }); - - for (const position of item.positions ?? []) { - const positionTimestamp = new Date(); - positionRows.push({ - ...buildColumnData(employeePositionRepository, position), - id: randomUUID(), - posMasterId: positionParentKey === "posMasterId" ? parentId : undefined, - posMasterTempId: - positionParentKey === "posMasterTempId" ? parentId : undefined, - ...buildAuditFields(positionTimestamp), - }); - } - } - - return { parentRows, positionRows }; - }; - const cloneEmployeeNodeBatch = async ( - items: T[], - parentRepository: Repository, - positionParentKey: "posMasterId" | "posMasterTempId", - targetIds: OrgDestinationIds, - ) => { - if (items.length === 0) { - return; - } - const { parentRows, positionRows } = buildEmployeeCloneBatch( - items, - parentRepository, - positionParentKey, - targetIds, - ); - await insertInChunks(parentRepository, parentRows, 200); - await insertInChunks(employeePositionRepository, positionRows, 500); - }; + console.timeEnd('[AMQ] query_employeeTempPosMaster'); + console.log(`[AMQ] orgemployeeTempPosMaster count: ${orgemployeeTempPosMaster.length}`); + let _orgemployeeTempPosMaster: EmployeeTempPosMaster[]; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + _orgemployeeTempPosMaster = orgemployeeTempPosMaster.map((x) => ({ + ...x, + ancestorDNA: + x.ancestorDNA == null || x.ancestorDNA == "00000000-0000-0000-0000-000000000000" + ? x.id + : x.ancestorDNA, + })); + // await repoEmployeeTempPosmaster.save(_orgemployeeTempPosMaster); await repoEmployeeTempPosmaster .createQueryBuilder() .insert() @@ -1401,255 +1010,872 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { overwrite: ["ancestorDNA"], }) .execute(); + // } - //create org - console.time("[AMQ] forEach_orgRoot"); + //create org - forEach orgRoot (WARNING: async forEach without await) + console.time('[AMQ] forEach_orgRoot'); console.log(`[AMQ] Starting forEach orgRoot loop (${orgRoot.length} items)`); - for (const x of orgRoot) { - const dataId = x.id; - const matchedOrgRoot = findMatchedNodeByAncestorDNA(orgRootCurrent, x); + let processedOrgRoot = 0; + orgRoot.forEach(async (x: any) => { + const itemStartTime = Date.now(); + var dataId = x.id; - const filteredEmployeePosMaster = employeePosMasterByNode.get(getNodeKey("root", dataId)) ?? []; + const orgRootCurrent = await orgRootRepository.find({ + where: { orgRevisionId: orgRevisionDraft.id }, + }); - await cloneEmployeeNodeBatch( - filteredEmployeePosMaster, - repoEmployeePosmaster, - "posMasterId", - { orgRootId: matchedOrgRoot?.id ?? null }, - ); - - await cloneEmployeeNodeBatch( - employeeTempPosMasterByNode.get(getNodeKey("root", dataId)) ?? [], - repoEmployeeTempPosmaster, - "posMasterTempId", - { orgRootId: matchedOrgRoot?.id ?? null }, - ); - - for (const x of orgChild1ByRoot.get(dataId) ?? []) { - const data1Id = x.id; - const matchedOrgChild1 = findMatchedNodeByAncestorDNA(orgChild1Current, x); - await cloneEmployeeNodeBatch( - employeePosMasterByNode.get(getNodeKey("child1", data1Id)) ?? [], - repoEmployeePosmaster, - "posMasterId", - { - orgRootId: matchedOrgRoot?.id ?? null, - orgChild1Id: matchedOrgChild1?.id ?? null, - }, - ); - - await cloneEmployeeNodeBatch( - employeeTempPosMasterByNode.get(getNodeKey("child1", data1Id)) ?? [], - repoEmployeeTempPosmaster, - "posMasterTempId", - { - orgRootId: matchedOrgRoot?.id ?? null, - orgChild1Id: matchedOrgChild1?.id ?? null, - }, - ); - - for (const x of orgChild2ByChild1.get(data1Id) ?? []) { - const data2Id = x.id; - const matchedOrgChild2 = findMatchedNodeByAncestorDNA(orgChild2Current, x); - await cloneEmployeeNodeBatch( - employeePosMasterByNode.get(getNodeKey("child2", data2Id)) ?? [], - repoEmployeePosmaster, - "posMasterId", - { - orgRootId: matchedOrgRoot?.id ?? null, - orgChild1Id: matchedOrgChild1?.id ?? null, - orgChild2Id: matchedOrgChild2?.id ?? null, - }, + const matchedOrgRoot = orgRootCurrent.find((i: OrgRoot) => { + if ( + x.ancestorDNA === x.id || // ถ้า ancestorDNA ถูกตั้งเป็น id ตัวเอง + x.ancestorDNA === null || + x.ancestorDNA === "00000000-0000-0000-0000-000000000000" + ) { + return ( + i.ancestorDNA === null || i.ancestorDNA === "00000000-0000-0000-0000-000000000000" ); + } + return i.ancestorDNA === x.ancestorDNA; + }); - await cloneEmployeeNodeBatch( - employeeTempPosMasterByNode.get(getNodeKey("child2", data2Id)) ?? [], - repoEmployeeTempPosmaster, - "posMasterTempId", - { - orgRootId: dataId, - orgChild1Id: data1Id, - orgChild2Id: data2Id, - }, - ); + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + //create employeePosmaster + const filteredEmployeePosMaster = _orgemployeePosMaster + .filter((x: EmployeePosMaster) => x.orgRootId == dataId && x.orgChild1Id == null); - for (const x of orgChild3ByChild2.get(data2Id) ?? []) { - const data3Id = x.id; - const matchedOrgChild3 = findMatchedNodeByAncestorDNA(orgChild3Current, x); - await cloneEmployeeNodeBatch( - employeePosMasterByNode.get(getNodeKey("child3", data3Id)) ?? [], - repoEmployeePosmaster, - "posMasterId", - { - orgRootId: matchedOrgRoot?.id ?? null, - orgChild1Id: matchedOrgChild1?.id ?? null, - orgChild2Id: matchedOrgChild2?.id ?? null, - orgChild3Id: matchedOrgChild3?.id ?? null, - }, - ); + await Promise.all( + filteredEmployeePosMaster + .map(async (item: any) => { + delete item.id; + const employeePosMaster = Object.assign(new EmployeePosMaster(), item); + employeePosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.current_holderId = item.current_holderId; + // } else { + // // employeePosMaster.next_holderId = null; + // employeePosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.authRoleId = item.authRoleId; + // } else { + // employeePosMaster.authRoleId = null; + // } + // employeePosMaster.current_holderId = null; + employeePosMaster.orgRevisionId = orgRevisionDraft.id; + employeePosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeePosMaster.createdUserId = ""; + employeePosMaster.createdFullName = "System Administrator"; + employeePosMaster.createdAt = new Date(); + employeePosMaster.lastUpdateUserId = ""; + employeePosMaster.lastUpdateFullName = "System Administrator"; + employeePosMaster.lastUpdatedAt = new Date(); + await repoEmployeePosmaster.save(employeePosMaster); - await cloneEmployeeNodeBatch( - employeeTempPosMasterByNode.get(getNodeKey("child3", data3Id)) ?? [], - repoEmployeeTempPosmaster, - "posMasterTempId", - { - orgRootId: matchedOrgRoot?.id ?? null, - orgChild1Id: matchedOrgChild1?.id ?? null, - orgChild2Id: matchedOrgChild2?.id ?? null, - orgChild3Id: matchedOrgChild3?.id ?? null, - }, - ); - - for (const x of orgChild4ByChild3.get(data3Id) ?? []) { - const data4Id = x.id; - const matchedOrgChild4 = findMatchedNodeByAncestorDNA(orgChild4Current, x); - await cloneEmployeeNodeBatch( - employeePosMasterByNode.get(getNodeKey("child4", data4Id)) ?? [], - repoEmployeePosmaster, - "posMasterId", - { - orgRootId: matchedOrgRoot?.id ?? null, - orgChild1Id: matchedOrgChild1?.id ?? null, - orgChild2Id: matchedOrgChild2?.id ?? null, - orgChild3Id: matchedOrgChild3?.id ?? null, - orgChild4Id: matchedOrgChild4?.id ?? null, - }, + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, ); + employeePosition.posMasterId = employeePosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + //create employeeTempPosmaster + await Promise.all( + _orgemployeeTempPosMaster + .filter((x: EmployeeTempPosMaster) => x.orgRootId == dataId && x.orgChild1Id == null) + .map(async (item: any) => { + delete item.id; + const employeeTempPosMaster = Object.assign(new EmployeeTempPosMaster(), item); + employeeTempPosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.current_holderId = item.current_holderId; + // } else { + // // employeeTempPosMaster.next_holderId = null; + // employeeTempPosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.authRoleId = item.authRoleId; + // } else { + // employeeTempPosMaster.authRoleId = null; + // } + // employeeTempPosMaster.current_holderId = null; + employeeTempPosMaster.orgRevisionId = orgRevisionDraft.id; + employeeTempPosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeeTempPosMaster.createdUserId = ""; + employeeTempPosMaster.createdFullName = "System Administrator"; + employeeTempPosMaster.createdAt = new Date(); + employeeTempPosMaster.lastUpdateUserId = ""; + employeeTempPosMaster.lastUpdateFullName = "System Administrator"; + employeeTempPosMaster.lastUpdatedAt = new Date(); + await repoEmployeeTempPosmaster.save(employeeTempPosMaster); - await cloneEmployeeNodeBatch( - employeeTempPosMasterByNode.get(getNodeKey("child4", data4Id)) ?? [], - repoEmployeeTempPosmaster, - "posMasterTempId", - { - orgRootId: matchedOrgRoot?.id ?? null, - orgChild1Id: matchedOrgChild1?.id ?? null, - orgChild2Id: matchedOrgChild2?.id ?? null, - orgChild3Id: matchedOrgChild3?.id ?? null, - orgChild4Id: matchedOrgChild4?.id ?? null, - }, + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterTempId = employeeTempPosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + // } + + //create org + orgChild1 + .filter((x: OrgChild1) => x.orgRootId == dataId) + .forEach(async (x: any) => { + var data1Id = x.id; + const orgChild1Current = await child1Repository.find({ + where: { orgRevisionId: orgRevisionDraft.id }, + }); + + const matchedOrgChild1 = orgChild1Current.find((i: OrgChild1) => { + if ( + x.ancestorDNA === x.id || // ถ้า ancestorDNA ถูกตั้งเป็น id ตัวเอง + x.ancestorDNA === null || + x.ancestorDNA === "00000000-0000-0000-0000-000000000000" + ) { + return ( + i.ancestorDNA === null || i.ancestorDNA === "00000000-0000-0000-0000-000000000000" ); } - } - } - } - } + return i.ancestorDNA === x.ancestorDNA; + }); + // ("[in case Child1] ancestorDNA", `${x.orgChild1Id == matchedOrgChild1?.id}`); + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + //create employeePosmaster + await Promise.all( + _orgemployeePosMaster + .filter((x: EmployeePosMaster) => x.orgChild1Id == data1Id && x.orgChild2Id == null) + .map(async (item: any) => { + delete item.id; + // console.log("[in case Child1] orgChild1Id == data1Id"); + const employeePosMaster = Object.assign(new EmployeePosMaster(), item); + employeePosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.current_holderId = item.current_holderId; + // } else { + // // employeePosMaster.next_holderId = null; + // employeePosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.authRoleId = item.authRoleId; + // } else { + // employeePosMaster.authRoleId = null; + // } + // employeePosMaster.current_holderId = null; + employeePosMaster.orgRevisionId = orgRevisionDraft.id; + employeePosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeePosMaster.orgChild1Id = matchedOrgChild1?.id ?? null; + employeePosMaster.createdUserId = ""; + employeePosMaster.createdFullName = "System Administrator"; + employeePosMaster.createdAt = new Date(); + employeePosMaster.lastUpdateUserId = ""; + employeePosMaster.lastUpdateFullName = "System Administrator"; + employeePosMaster.lastUpdatedAt = new Date(); + await repoEmployeePosmaster.save(employeePosMaster); - const [employeePosMaster, employeeTempPosMaster] = await Promise.all([ - repoEmployeePosmaster.find({ - where: { orgRevisionId: orgRevisionDraft.id }, - relations: ["positions", "positions.posLevel", "positions.posType"], - }), - repoEmployeeTempPosmaster.find({ - where: { orgRevisionId: orgRevisionDraft.id }, - relations: ["positions", "positions.posLevel", "positions.posType"], - }), - ]); - const profileEmployeeIds = Array.from( - new Set( - [...employeePosMaster, ...employeeTempPosMaster] - .map((item) => item.next_holderId) - .filter((profileId): profileId is string => !!profileId), - ), - ); - const profileEmployeeMap = new Map(); - if (profileEmployeeIds.length > 0) { - const profiles = await repoProfileEmployee.findBy({ - id: In(profileEmployeeIds), - }); - profiles.forEach((profile) => profileEmployeeMap.set(profile.id, profile)); - } - const updatedProfileEmployeeIds = new Set(); - const employeePosMasterIdsToTouch: string[] = []; - const employeeTempPosMasterIdsToTouch: string[] = []; + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterId = employeePosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + // create employeeTempPosmaster + await Promise.all( + _orgemployeeTempPosMaster + .filter( + (x: EmployeeTempPosMaster) => x.orgChild1Id == data1Id && x.orgChild2Id == null, + ) + .map(async (item: any) => { + delete item.id; + const employeeTempPosMaster = Object.assign(new EmployeeTempPosMaster(), item); + employeeTempPosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.current_holderId = item.current_holderId; + // } else { + // // employeeTempPosMaster.next_holderId = null; + // employeeTempPosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.authRoleId = item.authRoleId; + // } else { + // employeeTempPosMaster.authRoleId = null; + // } + // employeeTempPosMaster.current_holderId = null; + employeeTempPosMaster.orgRevisionId = orgRevisionDraft.id; + employeeTempPosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeeTempPosMaster.orgChild1Id = matchedOrgChild1?.id ?? null; + employeeTempPosMaster.createdUserId = ""; + employeeTempPosMaster.createdFullName = "System Administrator"; + employeeTempPosMaster.createdAt = new Date(); + employeeTempPosMaster.lastUpdateUserId = ""; + employeeTempPosMaster.lastUpdateFullName = "System Administrator"; + employeeTempPosMaster.lastUpdatedAt = new Date(); + await repoEmployeeTempPosmaster.save(employeeTempPosMaster); + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterTempId = employeeTempPosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + // } + + //create org + orgChild2 + .filter((x: OrgChild2) => x.orgChild1Id == data1Id) + .forEach(async (x: any) => { + var data2Id = x.id; + const orgChild2Current = await child2Repository.find({ + where: { orgRevisionId: orgRevisionDraft.id }, + }); + + const matchedOrgChild2 = orgChild2Current.find((i: OrgChild2) => { + if ( + x.ancestorDNA === x.id || // ถ้า ancestorDNA ถูกตั้งเป็น id ตัวเอง + x.ancestorDNA === null || + x.ancestorDNA === "00000000-0000-0000-0000-000000000000" + ) { + return ( + i.ancestorDNA === null || + i.ancestorDNA === "00000000-0000-0000-0000-000000000000" + ); + } + return i.ancestorDNA === x.ancestorDNA; + }); + // console.log("[in case Child2] ancestorDNA", `${x.orgChild2Id == matchedOrgChild2?.id}`); + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + //create employeePosmaster + await Promise.all( + _orgemployeePosMaster + .filter( + (x: EmployeePosMaster) => x.orgChild2Id == data2Id && x.orgChild3Id == null, + ) + .map(async (item: any) => { + delete item.id; + // console.log("[in case Child2] orgChild2Id == data2Id"); + const employeePosMaster = Object.assign(new EmployeePosMaster(), item); + employeePosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.current_holderId = item.current_holderId; + // } else { + // // employeePosMaster.next_holderId = null; + // employeePosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.authRoleId = item.authRoleId; + // } else { + // employeePosMaster.authRoleId = null; + // } + // employeePosMaster.current_holderId = null; + employeePosMaster.orgRevisionId = orgRevisionDraft.id; + employeePosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeePosMaster.orgChild1Id = matchedOrgChild1?.id ?? null; + employeePosMaster.orgChild2Id = matchedOrgChild2?.id ?? null; + employeePosMaster.createdUserId = ""; + employeePosMaster.createdFullName = "System Administrator"; + employeePosMaster.createdAt = new Date(); + employeePosMaster.lastUpdateUserId = ""; + employeePosMaster.lastUpdateFullName = "System Administrator"; + employeePosMaster.lastUpdatedAt = new Date(); + await repoEmployeePosmaster.save(employeePosMaster); + + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterId = employeePosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + // create employeeTempPosmaster + await Promise.all( + _orgemployeeTempPosMaster + .filter( + (x: EmployeeTempPosMaster) => + x.orgChild2Id == data2Id && x.orgChild3Id == null, + ) + .map(async (item: any) => { + delete item.id; + const employeeTempPosMaster = Object.assign( + new EmployeeTempPosMaster(), + item, + ); + employeeTempPosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.current_holderId = item.current_holderId; + // } else { + // // employeeTempPosMaster.next_holderId = null; + // employeeTempPosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.authRoleId = item.authRoleId; + // } else { + // employeeTempPosMaster.authRoleId = null; + // } + // employeeTempPosMaster.current_holderId = null; + employeeTempPosMaster.orgRevisionId = orgRevisionDraft.id; + employeeTempPosMaster.orgRootId = dataId; + employeeTempPosMaster.orgChild1Id = data1Id; + employeeTempPosMaster.orgChild2Id = data2Id; + employeeTempPosMaster.createdUserId = ""; + employeeTempPosMaster.createdFullName = "System Administrator"; + employeeTempPosMaster.createdAt = new Date(); + employeeTempPosMaster.lastUpdateUserId = ""; + employeeTempPosMaster.lastUpdateFullName = "System Administrator"; + employeeTempPosMaster.lastUpdatedAt = new Date(); + await repoEmployeeTempPosmaster.save(employeeTempPosMaster); + + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterTempId = employeeTempPosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + // } + + //create org + orgChild3 + .filter((x: OrgChild3) => x.orgChild2Id == data2Id) + .forEach(async (x: any) => { + var data3Id = x.id; + const orgChild3Current = await child3Repository.find({ + where: { orgRevisionId: orgRevisionDraft.id }, + }); + + const matchedOrgChild3 = orgChild3Current.find((i: OrgChild3) => { + if ( + x.ancestorDNA === x.id || // ถ้า ancestorDNA ถูกตั้งเป็น id ตัวเอง + x.ancestorDNA === null || + x.ancestorDNA === "00000000-0000-0000-0000-000000000000" + ) { + return ( + i.ancestorDNA === null || + i.ancestorDNA === "00000000-0000-0000-0000-000000000000" + ); + } + return i.ancestorDNA === x.ancestorDNA; + }); + // console.log("[in case Child3] ancestorDNA", `${x.orgChild3Id == matchedOrgChild3?.id}`); + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + //create employeePosmaster + await Promise.all( + _orgemployeePosMaster + .filter( + (x: EmployeePosMaster) => + x.orgChild3Id == data3Id && x.orgChild4Id == null, + ) + .map(async (item: any) => { + delete item.id; + // console.log("[in case Child3] orgChild3Id == data3Id"); + const employeePosMaster = Object.assign(new EmployeePosMaster(), item); + employeePosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.current_holderId = item.current_holderId; + // } else { + // // employeePosMaster.next_holderId = null; + // employeePosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.authRoleId = item.authRoleId; + // } else { + // employeePosMaster.authRoleId = null; + // } + // employeePosMaster.current_holderId = null; + employeePosMaster.orgRevisionId = orgRevisionDraft.id; + employeePosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeePosMaster.orgChild1Id = matchedOrgChild1?.id ?? null; + employeePosMaster.orgChild2Id = matchedOrgChild2?.id ?? null; + employeePosMaster.orgChild3Id = matchedOrgChild3?.id ?? null; + employeePosMaster.createdUserId = ""; + employeePosMaster.createdFullName = "System Administrator"; + employeePosMaster.createdAt = new Date(); + employeePosMaster.lastUpdateUserId = ""; + employeePosMaster.lastUpdateFullName = "System Administrator"; + employeePosMaster.lastUpdatedAt = new Date(); + await repoEmployeePosmaster.save(employeePosMaster); + + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterId = employeePosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + // create employeeTempPosmaster + await Promise.all( + _orgemployeeTempPosMaster + .filter( + (x: EmployeeTempPosMaster) => + x.orgChild3Id == data3Id && x.orgChild4Id == null, + ) + .map(async (item: any) => { + delete item.id; + const employeeTempPosMaster = Object.assign( + new EmployeeTempPosMaster(), + item, + ); + employeeTempPosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.current_holderId = item.current_holderId; + // } else { + // // employeeTempPosMaster.next_holderId = null; + // employeeTempPosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.authRoleId = item.authRoleId; + // } else { + // employeeTempPosMaster.authRoleId = null; + // } + // employeeTempPosMaster.current_holderId = null; + employeeTempPosMaster.orgRevisionId = orgRevisionDraft.id; + employeeTempPosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeeTempPosMaster.orgChild1Id = matchedOrgChild1?.id ?? null; + employeeTempPosMaster.orgChild2Id = matchedOrgChild2?.id ?? null; + employeeTempPosMaster.orgChild3Id = matchedOrgChild3?.id ?? null; + employeeTempPosMaster.createdUserId = ""; + employeeTempPosMaster.createdFullName = "System Administrator"; + employeeTempPosMaster.createdAt = new Date(); + employeeTempPosMaster.lastUpdateUserId = ""; + employeeTempPosMaster.lastUpdateFullName = "System Administrator"; + employeeTempPosMaster.lastUpdatedAt = new Date(); + await repoEmployeeTempPosmaster.save(employeeTempPosMaster); + + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterTempId = employeeTempPosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + // } + + //create org + orgChild4 + .filter((x: OrgChild4) => x.orgChild3Id == data3Id) + .forEach(async (x: any) => { + var data4Id = x.id; + const orgChild4Current = await child4Repository.find({ + where: { orgRevisionId: orgRevisionDraft.id }, + }); + + const matchedOrgChild4 = orgChild4Current.find((i: OrgChild4) => { + if ( + x.ancestorDNA === x.id || // ถ้า ancestorDNA ถูกตั้งเป็น id ตัวเอง + x.ancestorDNA === null || + x.ancestorDNA === "00000000-0000-0000-0000-000000000000" + ) { + return ( + i.ancestorDNA === null || + i.ancestorDNA === "00000000-0000-0000-0000-000000000000" + ); + } + return i.ancestorDNA === x.ancestorDNA; + }); + // console.log("[in case Child4] ancestorDNA", `${x.orgChild4Id == matchedOrgChild4?.id}`); + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + //create employeePosmaster + await Promise.all( + _orgemployeePosMaster + .filter((x: EmployeePosMaster) => x.orgChild4Id == data4Id) + .map(async (item: any) => { + delete item.id; + // console.log("[in case Child4] orgChild4Id == data4Id"); + const employeePosMaster = Object.assign( + new EmployeePosMaster(), + item, + ); + employeePosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.current_holderId = item.current_holderId; + // } else { + // // employeePosMaster.next_holderId = null; + // employeePosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeePosMaster.authRoleId = item.authRoleId; + // } else { + // employeePosMaster.authRoleId = null; + // } + // employeePosMaster.current_holderId = null; + employeePosMaster.orgRevisionId = orgRevisionDraft.id; + employeePosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeePosMaster.orgChild1Id = matchedOrgChild1?.id ?? null; + employeePosMaster.orgChild2Id = matchedOrgChild2?.id ?? null; + employeePosMaster.orgChild3Id = matchedOrgChild3?.id ?? null; + employeePosMaster.orgChild4Id = matchedOrgChild4?.id ?? null; + employeePosMaster.createdUserId = ""; + employeePosMaster.createdFullName = "System Administrator"; + employeePosMaster.createdAt = new Date(); + employeePosMaster.lastUpdateUserId = ""; + employeePosMaster.lastUpdateFullName = "System Administrator"; + employeePosMaster.lastUpdatedAt = new Date(); + await repoEmployeePosmaster.save(employeePosMaster); + + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterId = employeePosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + //create employeeTempPosmaster + await Promise.all( + _orgemployeeTempPosMaster + .filter((x: EmployeeTempPosMaster) => x.orgChild4Id == data4Id) + .map(async (item: any) => { + delete item.id; + const employeeTempPosMaster = Object.assign( + new EmployeeTempPosMaster(), + item, + ); + employeeTempPosMaster.positions = []; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.current_holderId = item.current_holderId; + // } else { + // // employeeTempPosMaster.next_holderId = null; + // employeeTempPosMaster.isSit = false; + // } + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + // ) { + // employeeTempPosMaster.authRoleId = item.authRoleId; + // } else { + // employeeTempPosMaster.authRoleId = null; + // } + // employeeTempPosMaster.current_holderId = null; + employeeTempPosMaster.orgRevisionId = orgRevisionDraft.id; + employeeTempPosMaster.orgRootId = matchedOrgRoot?.id ?? null; + employeeTempPosMaster.orgChild1Id = matchedOrgChild1?.id ?? null; + employeeTempPosMaster.orgChild2Id = matchedOrgChild2?.id ?? null; + employeeTempPosMaster.orgChild3Id = matchedOrgChild3?.id ?? null; + employeeTempPosMaster.orgChild4Id = matchedOrgChild4?.id ?? null; + employeeTempPosMaster.createdUserId = ""; + employeeTempPosMaster.createdFullName = "System Administrator"; + employeeTempPosMaster.createdAt = new Date(); + employeeTempPosMaster.lastUpdateUserId = ""; + employeeTempPosMaster.lastUpdateFullName = "System Administrator"; + employeeTempPosMaster.lastUpdatedAt = new Date(); + await repoEmployeeTempPosmaster.save(employeeTempPosMaster); + + //create employeePosition + item.positions.map(async (pos: any) => { + delete pos.id; + const employeePosition: EmployeePosition = Object.assign( + new EmployeePosition(), + pos, + ); + employeePosition.posMasterTempId = employeeTempPosMaster.id; + // if ( + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + // requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + // ) { + // employeePosition.positionIsSelected = false; + // } + employeePosition.createdUserId = ""; + employeePosition.createdFullName = "System Administrator"; + employeePosition.createdAt = new Date(); + employeePosition.lastUpdateUserId = ""; + employeePosition.lastUpdateFullName = "System Administrator"; + employeePosition.lastUpdatedAt = new Date(); + await employeePositionRepository.save(employeePosition); + }); + }), + ); + // } + }); + }); + }); + }); + }); + // } + + const employeePosMaster = await repoEmployeePosmaster.find({ + where: { orgRevisionId: orgRevisionDraft.id }, + relations: ["positions", "positions.posLevel", "positions.posType"], + }); for (const item of employeePosMaster) { if (item.next_holderId != null) { - const profile = profileEmployeeMap.get(item.next_holderId); - const position = item.positions.find((x) => x.positionIsSelected == true); + const profile = await repoProfileEmployee.findOne({ + where: { id: item.next_holderId == null ? "" : item.next_holderId }, + }); + const position = await item.positions.find((x) => x.positionIsSelected == true); const _null: any = null; if (profile != null) { profile.posLevelId = position?.posLevelId ?? _null; profile.posTypeId = position?.posTypeId ?? _null; profile.position = position?.positionName ?? _null; - updatedProfileEmployeeIds.add(profile.id); + await repoProfileEmployee.save(profile); } } - employeePosMasterIdsToTouch.push(item.id); + // item.current_holderId = item.next_holderId; + // item.next_holderId = null; + item.lastUpdateUserId = lastUpdateUserId; + item.lastUpdateFullName = lastUpdateFullName; + item.lastUpdatedAt = lastUpdatedAt; + await repoEmployeePosmaster.save(item).catch((e) => console.log(e)); } + const employeeTempPosMaster = await repoEmployeeTempPosmaster.find({ + where: { orgRevisionId: orgRevisionDraft.id }, + relations: ["positions", "positions.posLevel", "positions.posType"], + }); for (const item of employeeTempPosMaster) { if (item.next_holderId != null) { - const profile = profileEmployeeMap.get(item.next_holderId); - const position = item.positions.find((x) => x.positionIsSelected == true); + const profile = await repoProfileEmployee.findOne({ + where: { id: item.next_holderId == null ? "" : item.next_holderId }, + }); + const position = await item.positions.find((x) => x.positionIsSelected == true); const _null: any = null; if (profile != null) { profile.posLevelId = position?.posLevelId ?? _null; profile.posTypeId = position?.posTypeId ?? _null; profile.position = position?.positionName ?? _null; - updatedProfileEmployeeIds.add(profile.id); + await repoProfileEmployee.save(profile); } } - employeeTempPosMasterIdsToTouch.push(item.id); + // item.current_holderId = item.next_holderId; + // item.next_holderId = null; + item.lastUpdateUserId = lastUpdateUserId; + item.lastUpdateFullName = lastUpdateFullName; + item.lastUpdatedAt = lastUpdatedAt; + await repoEmployeeTempPosmaster.save(item).catch((e) => console.log(e)); } - if (employeePosMasterIdsToTouch.length > 0) { - const chunks = chunkArray(employeePosMasterIdsToTouch, 500); - const employeePosMasterTableName = repoEmployeePosmaster.metadata.tableName; - for (const chunk of chunks) { - const wherePlaceholders = chunk.map(() => "?").join(", "); - await manager.query( - `UPDATE \`${employeePosMasterTableName}\` - SET lastUpdateUserId = ?, - lastUpdateFullName = ?, - lastUpdatedAt = ? - WHERE id IN (${wherePlaceholders})`, - [lastUpdateUserId, lastUpdateFullName, lastUpdatedAt, ...chunk], - ); - } - } - if (employeeTempPosMasterIdsToTouch.length > 0) { - const chunks = chunkArray(employeeTempPosMasterIdsToTouch, 500); - const employeeTempPosMasterTableName = repoEmployeeTempPosmaster.metadata.tableName; - for (const chunk of chunks) { - const wherePlaceholders = chunk.map(() => "?").join(", "); - await manager.query( - `UPDATE \`${employeeTempPosMasterTableName}\` - SET lastUpdateUserId = ?, - lastUpdateFullName = ?, - lastUpdatedAt = ? - WHERE id IN (${wherePlaceholders})`, - [lastUpdateUserId, lastUpdateFullName, lastUpdatedAt, ...chunk], - ); - } - } - if (updatedProfileEmployeeIds.size > 0) { - const profilesToSave = Array.from(updatedProfileEmployeeIds) - .map((profileId) => profileEmployeeMap.get(profileId)) - .filter((profile): profile is ProfileEmployee => !!profile); - const chunks = chunkArray(profilesToSave, 200); - for (const chunk of chunks) { - await repoProfileEmployee.save(chunk); - } - } - console.timeEnd("[AMQ] clone_org_structure"); - - console.time("[AMQ] save_revision_status"); - orgRevisionPublish.orgRevisionIsDraft = false; - orgRevisionPublish.orgRevisionIsCurrent = false; - await repoOrgRevision.save(orgRevisionPublish); - - orgRevisionDraft.orgRevisionIsCurrent = true; - orgRevisionDraft.orgRevisionIsDraft = false; - await repoOrgRevision.save(orgRevisionDraft); - console.timeEnd("[AMQ] save_revision_status"); - }); - - if (shouldSkipPublishInTransaction) { - console.log( - `[AMQ] Skip publish in transaction: revision ${id} state changed before write phase`, - ); - console.timeEnd("[AMQ] handler_org_total"); - return true; } - console.log("[AMQ] Excecute Organization Success"); if (user) { sendWebSocket( @@ -1661,9 +1887,21 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { { userId: user?.sub }, ).catch(console.error); } + console.timeEnd('[AMQ] clone_org_structure'); + + // อัปเดตสถานะ orgRevision หลังจากทำงานเสร็จทั้งหมด + console.time('[AMQ] save_revision_status'); + orgRevisionPublish.orgRevisionIsDraft = false; + orgRevisionPublish.orgRevisionIsCurrent = false; + await repoOrgRevision.save(orgRevisionPublish); + + orgRevisionDraft.orgRevisionIsCurrent = true; + orgRevisionDraft.orgRevisionIsDraft = false; + await repoOrgRevision.save(orgRevisionDraft); + console.timeEnd('[AMQ] save_revision_status'); console.log(`[AMQ] handler_org SUCCESS - Total time: ${Date.now() - startTime}ms`); - console.timeEnd("[AMQ] handler_org_total"); + console.timeEnd('[AMQ] handler_org_total'); return true; } catch (error) { const totalTime = Date.now() - startTime; @@ -1678,7 +1916,7 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { { userId: user?.sub }, ).catch(console.error); } - console.timeEnd("[AMQ] handler_org_total"); + console.timeEnd('[AMQ] handler_org_total'); return false; } } @@ -2353,8 +2591,7 @@ async function handler_org_draft(msg: amqp.ConsumeMessage): Promise { }); await posMasterAssignRepository.delete({ posMasterId: In(_posMasters.map((x) => x.id)) }); await posMasterActRepository.delete({ posMasterId: In(_posMasters.map((x) => x.id)) }); //ใช้ posMasterId ของ revision: draft *แต่ยังไม่เจอช็อดไหนที่ใช้โครงสร้างแบบร่างในรักษาการแทน - await posMasterActRepository.delete({ - //ใช้ posMasterId ของ revision: draft *แต่ยังไม่เจอช็อดไหนที่ใช้โครงสร้างแบบร่างในรักษาการแทน + await posMasterActRepository.delete({ //ใช้ posMasterId ของ revision: draft *แต่ยังไม่เจอช็อดไหนที่ใช้โครงสร้างแบบร่างในรักษาการแทน posMasterChildId: In(_posMasters.map((x) => x.id)), }); // await posMasterRepository.remove(_posMasters); @@ -2382,26 +2619,24 @@ async function handler_org_draft(msg: amqp.ConsumeMessage): Promise { await child2Repository.delete({ orgRevisionId: In(_orgRevisions.map((x) => x.id)) }); await child1Repository.delete({ orgRevisionId: In(_orgRevisions.map((x) => x.id)) }); // Task #2160 อัพเดทหน้าที่จัดการโครงสร้างแบบร่าง - if ( - [ - "ORG", - "ORG_POSITION", - "ORG_POSITION_PERSON", - "ORG_POSITION_ROLE", - "ORG_POSITION_PERSON_ROLE", - ].includes(requestBody.typeDraft?.toUpperCase()) - ) { + if (["ORG", "ORG_POSITION", "ORG_POSITION_PERSON", "ORG_POSITION_ROLE", "ORG_POSITION_PERSON_ROLE"].includes(requestBody.typeDraft?.toUpperCase())) { const _newRoots = await orgRootRepository.find({ - where: { orgRevisionId: revision.id }, + where: { orgRevisionId: revision.id } }); - const newRootMap = new Map(_newRoots.map((r) => [r.ancestorDNA, r.id])); + const newRootMap = new Map( + _newRoots.map(r => [r.ancestorDNA, r.id]) + ); for (const oldRoot of _roots) { const newRootId = newRootMap.get(oldRoot.ancestorDNA); if (!newRootId) continue; // อัพเดท orgRootId ที่อยู่ภายใต้ orgRevision แบบร่างเดิมเป็นของ orgRevision แบบร่างใหม่ - await permissionOrgRepository.update({ orgRootId: oldRoot.id }, { orgRootId: newRootId }); + await permissionOrgRepository.update( + { orgRootId: oldRoot.id }, + { orgRootId: newRootId } + ); } - } else { + } + else { await permissionOrgRepository.delete({ orgRootId: In(_roots.map((x) => x.id)), });