hrms-api-org/src/controllers/OrganizationController.ts
waruneeauy fb4196cfa2
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m1s
fix keycloak user & update isDelete
2026-04-02 16:32:29 +07:00

9189 lines
378 KiB
TypeScript

import { RoleKeycloak } from "./../entities/RoleKeycloak";
import { ProfileEmployee } from "./../entities/ProfileEmployee";
import { EmployeePosition } from "./../entities/EmployeePosition";
import { EmployeePosMaster } from "./../entities/EmployeePosMaster";
import { Position } from "./../entities/Position";
import { ProfileSalaryHistory } from "./../entities/ProfileSalaryHistory";
import { ProfileSalary } from "./../entities/ProfileSalary";
import {
Controller,
Get,
Post,
Put,
Route,
Security,
Tags,
Body,
Path,
Request,
Response,
} from "tsoa";
import { CreateOrgRevision, OrgRevision } from "../entities/OrgRevision";
import { AppDataSource } from "../database/data-source";
import HttpSuccess from "../interfaces/http-success";
import { OrgChild1 } from "../entities/OrgChild1";
import HttpError from "../interfaces/http-error";
import HttpStatusCode from "../interfaces/http-status";
import { In, IsNull, Not, Like } from "typeorm";
import { OrgRoot } from "../entities/OrgRoot";
import { OrgChild2 } from "../entities/OrgChild2";
import { OrgChild3 } from "../entities/OrgChild3";
import { OrgChild4 } from "../entities/OrgChild4";
import { PosMaster } from "../entities/PosMaster";
import { Profile } from "../entities/Profile";
import { RequestWithUser } from "../middlewares/user";
import permission from "../interfaces/permission";
import {
checkQueueInProgress,
resolveNodeId,
resolveNodeLevel,
setLogDataDiff,
} from "../interfaces/utils";
import { sendToQueueOrg, sendToQueueOrgDraft } from "../services/rabbitmq";
import { PosType } from "../entities/PosType";
import { PosLevel } from "../entities/PosLevel";
import { PermissionOrg } from "../entities/PermissionOrg";
import {
deleteUser,
getToken,
createUser,
getUserByUsername,
getRoles,
addUserRoles,
updateUserAttributes,
} from "../keycloak";
import {
getPositionCountsAggregated,
getPositionCount,
PositionCountsByNode,
} from "../services/OrganizationService";
import {
BatchSavePosMasterHistoryOfficer,
CreatePosMasterHistoryEmployee,
CreatePosMasterHistoryOfficer,
SavePosMasterHistoryOfficer,
} from "../services/PositionService";
import { orgStructureCache } from "../utils/OrgStructureCache";
import { OrgIdMapping, AllOrgMappings, SavePosMasterHistory } from "../interfaces/OrgMapping";
import { OrgPermissionData, NodeLevel } from "../interfaces/OrgTypes";
import { formatPosMaster, generateLabelName, filterPosMasters } from "../utils/org-formatting";
@Route("api/v1/org")
@Tags("Organization")
@Security("bearerAuth")
@Response(
HttpStatusCode.INTERNAL_SERVER_ERROR,
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class OrganizationController extends Controller {
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
private orgRootRepository = AppDataSource.getRepository(OrgRoot);
private child1Repository = AppDataSource.getRepository(OrgChild1);
private child2Repository = AppDataSource.getRepository(OrgChild2);
private child3Repository = AppDataSource.getRepository(OrgChild3);
private child4Repository = AppDataSource.getRepository(OrgChild4);
private posMasterRepository = AppDataSource.getRepository(PosMaster);
private profileRepo = AppDataSource.getRepository(Profile);
private posTypeRepository = AppDataSource.getRepository(PosType);
private posLevelRepository = AppDataSource.getRepository(PosLevel);
private permissionOrgRepository = AppDataSource.getRepository(PermissionOrg);
private profileSalaryRepository = AppDataSource.getRepository(ProfileSalary);
private salaryHistoryRepo = AppDataSource.getRepository(ProfileSalaryHistory);
private positionRepository = AppDataSource.getRepository(Position);
private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee);
private employeePosMasterRepository = AppDataSource.getRepository(EmployeePosMaster);
private employeePositionRepository = AppDataSource.getRepository(EmployeePosition);
private roleKeycloakRepo = AppDataSource.getRepository(RoleKeycloak);
/**
* API ล้างข้อมูล
*
* @summary ล้างข้อมูล
*
*/
@Get("clear-db")
async ClearDb() {
return new HttpSuccess();
}
/**
* API รายการประวัติโครงสร้าง
*
* @summary ORG_020 - รายการประวัติโครงสร้าง #21
*
*/
@Get("history")
async GetHistory() {
const orgRevision = await this.orgRevisionRepository.find({
select: ["id", "orgRevisionName", "orgRevisionIsCurrent", "createdAt", "orgRevisionIsDraft"],
order: { createdAt: "DESC" },
});
// if (!orgRevision) {
// return new HttpSuccess([]);
// }
const mapOrgRevisions = orgRevision.map((revision) => ({
orgRevisionId: revision.id,
orgRevisionName: revision.orgRevisionName,
orgRevisionIsCurrent: revision.orgRevisionIsCurrent,
orgRevisionCreatedAt: revision.createdAt,
orgRevisionIsDraft: revision.orgRevisionIsDraft,
}));
return new HttpSuccess(mapOrgRevisions);
}
/**
* API โครงสร้างปัจจุบันที่ใช้อยู่
*
* @summary ORG_021 - โครงสร้างปัจจุบันที่ใช้อยู่ #22
*
*/
@Get("active")
async GetActive() {
const orgRevisionActive = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
});
const orgRevisionDraf = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true },
});
const mapData = {
activeId: orgRevisionActive == null ? null : orgRevisionActive.id,
activeName: orgRevisionActive == null ? null : orgRevisionActive.orgRevisionName,
draftId: orgRevisionDraf == null ? null : orgRevisionDraf.id,
draftName: orgRevisionDraf == null ? null : orgRevisionDraf.orgRevisionName,
orgPublishDate: orgRevisionDraf == null ? null : orgRevisionDraf.orgPublishDate,
isPublic: orgRevisionDraf == null || orgRevisionDraf.orgRevisionName == null ? false : true,
};
return new HttpSuccess(mapData);
}
/**
* API สร้างแบบร่างโครงสร้าง
*
* @summary ORG_022 - สร้างโครงสร้างใหม่ #23
*
*/
@Post("draft")
async CreateOrgRevision(
@Body() requestBody: CreateOrgRevision,
@Request() request: RequestWithUser,
) {
try {
// CheckQueueInProgress
const [isBusyDraft, isBusyPublish] = await Promise.all([
checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG_DRAFT}`),
checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG}`),
]);
// console.log("✅ ตรวจสอบแล้ว Draft Busy:", isBusyDraft);
// console.log("✅ ตรวจสอบแล้ว Publish Busy:", isBusyPublish);
if (isBusyDraft || isBusyPublish) {
// console.log("🚫 พบว่ามีงานอยู่ในคิว — error")
throw new HttpError(
HttpStatusCode.CONFLICT,
"ไม่สามารถดำเนินการได้ หากกำลังเผยแพร่หรือสร้างแบบร่างโครงสร้างหน่วยงาน",
);
}
//new main revision
const before = null;
const revision = Object.assign(new OrgRevision(), requestBody) as OrgRevision;
revision.orgRevisionIsDraft = true;
revision.orgRevisionIsCurrent = false;
revision.createdUserId = request.user.sub;
revision.createdFullName = request.user.name;
revision.lastUpdateUserId = request.user.sub;
revision.lastUpdateFullName = request.user.name;
revision.createdAt = new Date();
revision.lastUpdatedAt = new Date();
await this.orgRevisionRepository.save(revision, { data: request });
setLogDataDiff(request, { before, after: revision });
const msg = {
data: {
requestBody: requestBody,
request: request.user,
revision: revision,
},
user: request.user,
};
await sendToQueueOrgDraft(msg);
return new HttpSuccess("Draft is being created... Processing in the background.");
} catch (error: any) {
throw error;
}
}
/**
* API สร้างแบบร่างโครงสร้าง
*
* @summary ORG_022 - สร้างโครงสร้างใหม่ #23
*
*/
@Post("finddna")
async FindDnaOrg(
@Body()
requestBody: {
root: string[] | null;
child1: string[] | null;
child2: string[] | null;
child3: string[] | null;
child4: string[] | null;
privilege: string;
},
@Request() request: RequestWithUser,
) {
const _data = [];
if (requestBody.root != null && requestBody.root.length > 0) {
for (const x of requestBody.root) {
const data = await this.orgRootRepository.findOne({
where: { id: x },
});
if (data) {
_data.push(data.ancestorDNA);
}
}
requestBody.root = _data;
}
const _data1 = [];
if (requestBody.child1 != null && requestBody.child1.length > 0) {
for (const x of requestBody.child1) {
const data = await this.child1Repository.findOne({
where: { id: x },
});
if (data) {
_data1.push(data.ancestorDNA);
}
}
requestBody.child1 = _data1;
}
const _data2 = [];
if (requestBody.child2 != null && requestBody.child2.length > 0) {
for (const x of requestBody.child2) {
const data = await this.child2Repository.findOne({
where: { id: x },
});
if (data) {
_data2.push(data.ancestorDNA);
}
}
requestBody.child2 = _data2;
}
const _data3 = [];
if (requestBody.child3 != null && requestBody.child3.length > 0) {
for (const x of requestBody.child3) {
const data = await this.child3Repository.findOne({
where: { id: x },
});
if (data) {
_data3.push(data.ancestorDNA);
}
}
requestBody.child3 = _data3;
}
const _data4 = [];
if (requestBody.child4 != null && requestBody.child4.length > 0) {
for (const x of requestBody.child4) {
const data = await this.child4Repository.findOne({
where: { id: x },
});
if (data) {
_data4.push(data.ancestorDNA);
}
}
requestBody.child4 = _data4;
}
return new HttpSuccess(requestBody);
}
/**
* API หา ORG DNA ID
*
* @summary หา ORG DNA ID
*
*/
@Get("finddna-by-keycloak/{keycloakId}")
async FindDnaOrgByKeycloakId(@Path() keycloakId: string) {
let reply: any;
const profileByKeycloak: any = await this.profileRepo.findOne({
where: { keycloak: keycloakId },
select: ["id", "keycloak"],
});
const orgRevision = await this.orgRevisionRepository.findOne({
select: ["id"],
where: {
orgRevisionIsDraft: false,
orgRevisionIsCurrent: true,
},
});
const posMaster = await AppDataSource.getRepository(PosMaster)
.createQueryBuilder("pos")
.leftJoin("pos.orgRoot", "orgRoot")
.leftJoin("pos.orgChild1", "orgChild1")
.leftJoin("pos.orgChild2", "orgChild2")
.leftJoin("pos.orgChild3", "orgChild3")
.leftJoin("pos.orgChild4", "orgChild4")
.where("pos.current_holderId = :holderId", {
holderId: profileByKeycloak.id,
})
.andWhere("pos.orgRevisionId = :revId", {
revId: orgRevision?.id,
})
.select([
"pos.id",
"orgRoot.ancestorDNA as rootDnaId",
"orgChild1.ancestorDNA as child1DnaId",
"orgChild2.ancestorDNA as child2DnaId",
"orgChild3.ancestorDNA as child3DnaId",
"orgChild4.ancestorDNA as child4DnaId",
])
.getRawOne();
if (!posMaster) {
reply = {
rootDnaId: null,
child1DnaId: null,
child2DnaId: null,
child3DnaId: null,
child4DnaId: null,
};
} else {
reply = {
rootDnaId: posMaster.rootDnaId,
child1DnaId: posMaster.child1DnaId,
child2DnaId: posMaster.child2DnaId,
child3DnaId: posMaster.child3DnaId,
child4DnaId: posMaster.child4DnaId,
};
}
return new HttpSuccess(reply);
}
/**
* API เช็คสถานะโครงสร้างว่าส่งคนไปออกคำสั่งหรือไม่
*
* @summary API เช็คสถานะโครงสร้างว่าส่งคนไปออกคำสั่งหรือไม่
*
* @param {string} id Id OrgRevison
*/
@Get("lock/{id}")
async GetById(@Request() request: RequestWithUser, @Path() id: string) {
//add check permission
const orgRevision = await this.orgRevisionRepository.findOne({
where: { id: id },
});
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้าง");
}
return new HttpSuccess(orgRevision.isLock);
}
/**
* API รายละเอียดโครงสร้าง
*
* @summary ORG_023 - รายละเอียดโครงสร้าง (ADMIN Menu) #25
*
*/
@Get("admin/{id}")
async detailForAdmin(@Path() id: string, @Request() request: RequestWithUser) {
// let _data: any = {
// root: null,
// child1: null,
// child2: null,
// child3: null,
// child4: null,
// };
const orgRevision = await this.orgRevisionRepository.findOne({ where: { id } });
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
}
// let attrOwnership = null;
if (
orgRevision.orgRevisionIsDraft == true &&
orgRevision.orgRevisionIsCurrent == false &&
request.user.role.includes("SUPER_ADMIN")
// attrOwnership == false
) {
const profile = await this.profileRepo.findOne({
where: { keycloak: request.user.sub },
// relations: ["permissionProfiles"],
});
if (!profile) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งานในทะเบียนประวัติ");
}
// _data = {
// root: profile.permissionProfiles.map((x) => x.orgRootId),
// child1: null,
// child2: null,
// child3: null,
// child4: null,
// };
}
const orgRootData = await AppDataSource.getRepository(OrgRoot)
.createQueryBuilder("orgRoot")
.where("orgRoot.orgRevisionId = :id", { id })
// .andWhere(
// _data.root != undefined && _data.root != null
// ? _data.root[0] != null
// ? `orgRoot.id IN (:...node)`
// : `orgRoot.id is null`
// : "1=1",
// {
// node: _data.root,
// },
// )
.select([
"orgRoot.id",
"orgRoot.isDeputy",
"orgRoot.isCommission",
"orgRoot.orgRootName",
"orgRoot.orgRootShortName",
"orgRoot.orgRootCode",
"orgRoot.orgRootOrder",
"orgRoot.orgRootPhoneEx",
"orgRoot.orgRootPhoneIn",
"orgRoot.orgRootFax",
"orgRoot.orgRevisionId",
"orgRoot.orgRootRank",
"orgRoot.orgRootRankSub",
"orgRoot.DEPARTMENT_CODE",
"orgRoot.DIVISION_CODE",
"orgRoot.SECTION_CODE",
"orgRoot.JOB_CODE",
"orgRoot.responsibility",
])
.orderBy("orgRoot.orgRootOrder", "ASC")
.getMany();
const orgRootIds = orgRootData.map((orgRoot) => orgRoot.id) || null;
const orgChild1Data =
orgRootIds && orgRootIds.length > 0
? await AppDataSource.getRepository(OrgChild1)
.createQueryBuilder("orgChild1")
.where("orgChild1.orgRootId IN (:...ids)", { ids: orgRootIds })
// .andWhere(
// _data.child1 != undefined && _data.child1 != null
// ? _data.child1[0] != null
// ? `orgChild1.id IN (:...node)`
// : `orgChild1.id is null`
// : "1=1",
// {
// node: _data.child1,
// },
// )
.select([
"orgChild1.id",
"orgChild1.isOfficer",
"orgChild1.isInformation",
"orgChild1.orgChild1Name",
"orgChild1.orgChild1ShortName",
"orgChild1.orgChild1Code",
"orgChild1.orgChild1Order",
"orgChild1.orgChild1PhoneEx",
"orgChild1.orgChild1PhoneIn",
"orgChild1.orgChild1Fax",
"orgChild1.orgRootId",
"orgChild1.orgChild1Rank",
"orgChild1.orgChild1RankSub",
"orgChild1.DEPARTMENT_CODE",
"orgChild1.DIVISION_CODE",
"orgChild1.SECTION_CODE",
"orgChild1.JOB_CODE",
"orgChild1.responsibility",
])
.orderBy("orgChild1.orgChild1Order", "ASC")
.getMany()
: [];
const orgChild1Ids = orgChild1Data.map((orgChild1) => orgChild1.id) || null;
const orgChild2Data =
orgChild1Ids && orgChild1Ids.length > 0
? await AppDataSource.getRepository(OrgChild2)
.createQueryBuilder("orgChild2")
.where("orgChild2.orgChild1Id IN (:...ids)", { ids: orgChild1Ids })
// .andWhere(
// _data.child2 != undefined && _data.child2 != null
// ? _data.child2[0] != null
// ? `orgChild2.id IN (:...node)`
// : `orgChild2.id is null`
// : "1=1",
// {
// node: _data.child2,
// },
// )
.select([
"orgChild2.id",
"orgChild2.orgChild2Name",
"orgChild2.orgChild2ShortName",
"orgChild2.orgChild2Code",
"orgChild2.orgChild2Order",
"orgChild2.orgChild2PhoneEx",
"orgChild2.orgChild2PhoneIn",
"orgChild2.orgChild2Fax",
"orgChild2.orgRootId",
"orgChild2.orgChild2Rank",
"orgChild2.orgChild2RankSub",
"orgChild2.DEPARTMENT_CODE",
"orgChild2.DIVISION_CODE",
"orgChild2.SECTION_CODE",
"orgChild2.JOB_CODE",
"orgChild2.orgChild1Id",
"orgChild2.responsibility",
])
.orderBy("orgChild2.orgChild2Order", "ASC")
.getMany()
: [];
const orgChild2Ids = orgChild2Data.map((orgChild2) => orgChild2.id) || null;
const orgChild3Data =
orgChild2Ids && orgChild2Ids.length > 0
? await AppDataSource.getRepository(OrgChild3)
.createQueryBuilder("orgChild3")
.where("orgChild3.orgChild2Id IN (:...ids)", { ids: orgChild2Ids })
// .andWhere(
// _data.child3 != undefined && _data.child3 != null
// ? _data.child3[0] != null
// ? `orgChild3.id IN (:...node)`
// : `orgChild3.id is null`
// : "1=1",
// {
// node: _data.child3,
// },
// )
.select([
"orgChild3.id",
"orgChild3.orgChild3Name",
"orgChild3.orgChild3ShortName",
"orgChild3.orgChild3Code",
"orgChild3.orgChild3Order",
"orgChild3.orgChild3PhoneEx",
"orgChild3.orgChild3PhoneIn",
"orgChild3.orgChild3Fax",
"orgChild3.orgRootId",
"orgChild3.orgChild3Rank",
"orgChild3.orgChild3RankSub",
"orgChild3.DEPARTMENT_CODE",
"orgChild3.DIVISION_CODE",
"orgChild3.SECTION_CODE",
"orgChild3.JOB_CODE",
"orgChild3.orgChild2Id",
"orgChild3.responsibility",
])
.orderBy("orgChild3.orgChild3Order", "ASC")
.getMany()
: [];
const orgChild3Ids = orgChild3Data.map((orgChild3) => orgChild3.id) || null;
const orgChild4Data =
orgChild3Ids && orgChild3Ids.length > 0
? await AppDataSource.getRepository(OrgChild4)
.createQueryBuilder("orgChild4")
.where("orgChild4.orgChild3Id IN (:...ids)", { ids: orgChild3Ids })
// .andWhere(
// _data.child4 != undefined && _data.child4 != null
// ? _data.child4[0] != null
// ? `orgChild4.id IN (:...node)`
// : `orgChild4.id is null`
// : "1=1",
// {
// node: _data.child4,
// },
// )
.select([
"orgChild4.id",
"orgChild4.orgChild4Name",
"orgChild4.orgChild4ShortName",
"orgChild4.orgChild4Code",
"orgChild4.orgChild4Order",
"orgChild4.orgChild4PhoneEx",
"orgChild4.orgChild4PhoneIn",
"orgChild4.orgChild4Fax",
"orgChild4.orgRootId",
"orgChild4.orgChild4Rank",
"orgChild4.orgChild4RankSub",
"orgChild4.DEPARTMENT_CODE",
"orgChild4.DIVISION_CODE",
"orgChild4.SECTION_CODE",
"orgChild4.JOB_CODE",
"orgChild4.orgChild3Id",
"orgChild4.responsibility",
])
.orderBy("orgChild4.orgChild4Order", "ASC")
.getMany()
: [];
const formattedData = await Promise.all(
orgRootData.map(async (orgRoot) => {
return {
orgTreeId: orgRoot.id,
orgLevel: 0,
orgName: orgRoot.orgRootName,
orgTreeName: orgRoot.orgRootName,
orgTreeShortName: orgRoot.orgRootShortName,
orgTreeCode: orgRoot.orgRootCode,
orgCode: orgRoot.orgRootCode + "00",
orgTreeRank: orgRoot.orgRootRank,
orgTreeRankSub: orgRoot.orgRootRankSub,
DEPARTMENT_CODE: orgRoot.DEPARTMENT_CODE,
DIVISION_CODE: orgRoot.DIVISION_CODE,
SECTION_CODE: orgRoot.SECTION_CODE,
JOB_CODE: orgRoot.JOB_CODE,
orgTreeOrder: orgRoot.orgRootOrder,
orgTreePhoneEx: orgRoot.orgRootPhoneEx,
orgTreePhoneIn: orgRoot.orgRootPhoneIn,
orgTreeFax: orgRoot.orgRootFax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgRoot.responsibility,
isOfficer: false,
isDeputy: orgRoot.isDeputy,
isCommission: orgRoot.isCommission,
labelName:
orgRoot.orgRootName + " " + orgRoot.orgRootCode + "00" + " " + orgRoot.orgRootShortName,
totalPosition: await this.posMasterRepository.count({
where: { orgRevisionId: orgRoot.orgRevisionId, orgRootId: orgRoot.id },
}),
totalPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
current_holderId: IsNull() || "",
},
}),
totalPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
next_holderId: IsNull() || "",
},
}),
totalRootPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
},
}),
totalRootPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
current_holderId: IsNull() || "",
},
}),
totalRootPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
next_holderId: IsNull() || "",
},
}),
children: await Promise.all(
orgChild1Data
.filter((orgChild1) => orgChild1.orgRootId === orgRoot.id)
.map(async (orgChild1) => ({
orgTreeId: orgChild1.id,
orgRootId: orgRoot.id,
orgLevel: 1,
orgName: `${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild1.orgChild1Name,
orgTreeShortName: orgChild1.orgChild1ShortName,
orgTreeCode: orgChild1.orgChild1Code,
orgCode: orgRoot.orgRootCode + orgChild1.orgChild1Code,
orgTreeRank: orgChild1.orgChild1Rank,
orgTreeRankSub: orgChild1.orgChild1RankSub,
DEPARTMENT_CODE: orgChild1.DEPARTMENT_CODE,
DIVISION_CODE: orgChild1.DIVISION_CODE,
SECTION_CODE: orgChild1.SECTION_CODE,
JOB_CODE: orgChild1.JOB_CODE,
orgTreeOrder: orgChild1.orgChild1Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild1.orgChild1PhoneEx,
orgTreePhoneIn: orgChild1.orgChild1PhoneIn,
orgTreeFax: orgChild1.orgChild1Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild1.responsibility,
isOfficer: orgChild1.isOfficer,
isInformation: orgChild1.isInformation,
labelName:
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName,
totalPosition: await this.posMasterRepository.count({
where: { orgRevisionId: orgRoot.orgRevisionId, orgChild1Id: orgChild1.id },
}),
totalPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild1Id: orgChild1.id,
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild1Id: orgChild1.id,
current_holderId: IsNull() || "",
},
}),
totalPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild1Id: orgChild1.id,
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild1Id: orgChild1.id,
next_holderId: IsNull() || "",
},
}),
totalRootPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
},
}),
totalRootPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
current_holderId: IsNull() || "",
},
}),
totalRootPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
next_holderId: IsNull() || "",
},
}),
children: await Promise.all(
orgChild2Data
.filter((orgChild2) => orgChild2.orgChild1Id === orgChild1.id)
.map(async (orgChild2) => ({
orgTreeId: orgChild2.id,
orgRootId: orgChild1.id,
orgLevel: 2,
orgName: `${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild2.orgChild2Name,
orgTreeShortName: orgChild2.orgChild2ShortName,
orgTreeCode: orgChild2.orgChild2Code,
orgCode: orgRoot.orgRootCode + orgChild2.orgChild2Code,
orgTreeRank: orgChild2.orgChild2Rank,
orgTreeRankSub: orgChild2.orgChild2RankSub,
DEPARTMENT_CODE: orgChild2.DEPARTMENT_CODE,
DIVISION_CODE: orgChild2.DIVISION_CODE,
SECTION_CODE: orgChild2.SECTION_CODE,
JOB_CODE: orgChild2.JOB_CODE,
orgTreeOrder: orgChild2.orgChild2Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild2.orgChild2PhoneEx,
orgTreePhoneIn: orgChild2.orgChild2PhoneIn,
orgTreeFax: orgChild2.orgChild2Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild2.responsibility,
isOfficer: orgChild1.isOfficer,
labelName:
orgChild2.orgChild2Name +
" " +
orgRoot.orgRootCode +
orgChild2.orgChild2Code +
" " +
orgChild2.orgChild2ShortName,
totalPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild2Id: orgChild2.id,
},
}),
totalPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild2Id: orgChild2.id,
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild2Id: orgChild2.id,
current_holderId: IsNull() || "",
},
}),
totalPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild2Id: orgChild2.id,
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild2Id: orgChild2.id,
next_holderId: IsNull() || "",
},
}),
totalRootPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
},
}),
totalRootPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
current_holderId: IsNull() || "",
},
}),
totalRootPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
next_holderId: IsNull() || "",
},
}),
children: await Promise.all(
orgChild3Data
.filter((orgChild3) => orgChild3.orgChild2Id === orgChild2.id)
.map(async (orgChild3) => ({
orgTreeId: orgChild3.id,
orgRootId: orgChild2.id,
orgLevel: 3,
orgName: `${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild3.orgChild3Name,
orgTreeShortName: orgChild3.orgChild3ShortName,
orgTreeCode: orgChild3.orgChild3Code,
orgCode: orgRoot.orgRootCode + orgChild3.orgChild3Code,
orgTreeRank: orgChild3.orgChild3Rank,
orgTreeRankSub: orgChild3.orgChild3RankSub,
DEPARTMENT_CODE: orgChild3.DEPARTMENT_CODE,
DIVISION_CODE: orgChild3.DIVISION_CODE,
SECTION_CODE: orgChild3.SECTION_CODE,
JOB_CODE: orgChild3.JOB_CODE,
orgTreeOrder: orgChild3.orgChild3Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild3.orgChild3PhoneEx,
orgTreePhoneIn: orgChild3.orgChild3PhoneIn,
orgTreeFax: orgChild3.orgChild3Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild3.responsibility,
isOfficer: orgChild1.isOfficer,
labelName:
orgChild3.orgChild3Name +
" " +
orgRoot.orgRootCode +
orgChild3.orgChild3Code +
" " +
orgChild3.orgChild3ShortName,
totalPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild3Id: orgChild3.id,
},
}),
totalPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild3Id: orgChild3.id,
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild3Id: orgChild3.id,
current_holderId: IsNull() || "",
},
}),
totalPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild3Id: orgChild3.id,
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild3Id: orgChild3.id,
next_holderId: IsNull() || "",
},
}),
totalRootPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: IsNull() || "",
},
}),
totalRootPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: IsNull() || "",
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: IsNull() || "",
current_holderId: IsNull() || "",
},
}),
totalRootPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: IsNull() || "",
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: IsNull() || "",
next_holderId: IsNull() || "",
},
}),
children: await Promise.all(
orgChild4Data
.filter((orgChild4) => orgChild4.orgChild3Id === orgChild3.id)
.map(async (orgChild4) => ({
orgTreeId: orgChild4.id,
orgRootId: orgChild3.id,
orgLevel: 4,
orgName: `${orgChild4.orgChild4Name}/${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild4.orgChild4Name,
orgTreeShortName: orgChild4.orgChild4ShortName,
orgTreeCode: orgChild4.orgChild4Code,
orgCode: orgRoot.orgRootCode + orgChild4.orgChild4Code,
orgTreeRank: orgChild4.orgChild4Rank,
orgTreeRankSub: orgChild4.orgChild4RankSub,
DEPARTMENT_CODE: orgChild4.DEPARTMENT_CODE,
DIVISION_CODE: orgChild4.DIVISION_CODE,
SECTION_CODE: orgChild4.SECTION_CODE,
JOB_CODE: orgChild4.JOB_CODE,
orgTreeOrder: orgChild4.orgChild4Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild4.orgChild4PhoneEx,
orgTreePhoneIn: orgChild4.orgChild4PhoneIn,
orgTreeFax: orgChild4.orgChild4Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild4.responsibility,
isOfficer: orgChild1.isOfficer,
labelName:
orgChild4.orgChild4Name +
" " +
orgRoot.orgRootCode +
orgChild4.orgChild4Code +
" " +
orgChild4.orgChild4ShortName,
totalPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild4Id: orgChild4.id,
},
}),
totalPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild4Id: orgChild4.id,
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild4Id: orgChild4.id,
current_holderId: IsNull() || "",
},
}),
totalPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild4Id: orgChild4.id,
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgChild4Id: orgChild4.id,
next_holderId: IsNull() || "",
},
}),
totalRootPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: orgChild4.id,
},
}),
totalRootPositionCurrentUse: await this.posMasterRepository.count(
{
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: orgChild4.id,
current_holderId: Not(IsNull()) || Not(""),
},
},
),
totalRootPositionCurrentVacant:
await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: orgChild4.id,
current_holderId: IsNull() || "",
},
}),
totalRootPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: orgChild4.id,
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionNextVacant: await this.posMasterRepository.count(
{
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: orgChild1.id,
orgChild2Id: orgChild2.id,
orgChild3Id: orgChild3.id,
orgChild4Id: orgChild4.id,
next_holderId: IsNull() || "",
},
},
),
})),
),
})),
),
})),
),
})),
),
};
}),
);
return new HttpSuccess(formattedData);
}
/**
* API รายละเอียดโครงสร้าง
*
* @summary ORG_023 - รายละเอียดโครงสร้าง (ADMIN) #25
*
*/
@Get("super-admin/{id}")
async detailSuperAdmin(@Path() id: string, @Request() request: RequestWithUser) {
const orgRevision = await this.orgRevisionRepository.findOne({
where: { id: id },
});
if (!orgRevision) return new HttpSuccess([]);
let rootId: any = null;
if (!request.user.role.includes("SUPER_ADMIN")) {
const profile = await this.profileRepo.findOne({
where: {
keycloak: request.user.sub,
},
select: ["id"],
});
if (profile == null) return new HttpSuccess([]);
const posMaster = await this.posMasterRepository.findOne({
where:
orgRevision.orgRevisionIsCurrent && !orgRevision.orgRevisionIsDraft
? {
orgRevisionId: id,
current_holderId: profile.id,
}
: {
orgRevisionId: id,
next_holderId: profile.id,
},
});
if (!posMaster) return new HttpSuccess([]);
rootId = posMaster.orgRootId;
}
// OPTIMIZED: Check cache first
const cachedResponse = await orgStructureCache.get(id, rootId);
if (cachedResponse) {
return new HttpSuccess(cachedResponse);
}
// OPTIMIZED: Get all position counts in ONE query (closed)
// const { orgRootMap, orgChild1Map, orgChild2Map, orgChild3Map, orgChild4Map, rootPosMap } =
// await getPositionCounts(id);
// OPTIMIZED: Fetch orgRoot first, then fetch all child levels in parallel
const orgRootData = await AppDataSource.getRepository(OrgRoot)
.createQueryBuilder("orgRoot")
.where("orgRoot.orgRevisionId = :id", { id })
.andWhere(rootId != null ? `orgRoot.id = :rootId` : "1=1", {
rootId: rootId,
})
.orderBy("orgRoot.orgRootOrder", "ASC")
.getMany();
const orgRootIds = orgRootData.map((orgRoot) => orgRoot.id);
// OPTIMIZED: Fetch all child levels in parallel using orgRevisionId
// This is faster than sequential queries that depend on parent IDs
const [orgChild1AllData, orgChild2AllData, orgChild3AllData, orgChild4AllData] =
await Promise.all([
AppDataSource.getRepository(OrgChild1)
.createQueryBuilder("orgChild1")
.where("orgChild1.orgRevisionId = :id", { id })
.orderBy("orgChild1.orgChild1Order", "ASC")
.getMany(),
AppDataSource.getRepository(OrgChild2)
.createQueryBuilder("orgChild2")
.where("orgChild2.orgRevisionId = :id", { id })
.orderBy("orgChild2.orgChild2Order", "ASC")
.getMany(),
AppDataSource.getRepository(OrgChild3)
.createQueryBuilder("orgChild3")
.where("orgChild3.orgRevisionId = :id", { id })
.orderBy("orgChild3.orgChild3Order", "ASC")
.getMany(),
AppDataSource.getRepository(OrgChild4)
.createQueryBuilder("orgChild4")
.where("orgChild4.orgRevisionId = :id", { id })
.orderBy("orgChild4.orgChild4Order", "ASC")
.getMany(),
]);
// Filter child1 data by orgRootIds (maintains backward compatibility)
const orgChild1Data =
orgRootIds && orgRootIds.length > 0
? orgChild1AllData.filter((orgChild1) => orgRootIds.includes(orgChild1.orgRootId))
: [];
// Build maps for efficient filtering of deeper levels
const orgChild1Ids = orgChild1Data.map((orgChild1) => orgChild1.id);
const orgChild2Data =
orgChild1Ids && orgChild1Ids.length > 0
? orgChild2AllData.filter((orgChild2) => orgChild1Ids.includes(orgChild2.orgChild1Id))
: [];
const orgChild2Ids = orgChild2Data.map((orgChild2) => orgChild2.id);
const orgChild3Data =
orgChild2Ids && orgChild2Ids.length > 0
? orgChild3AllData.filter((orgChild3) => orgChild2Ids.includes(orgChild3.orgChild2Id))
: [];
const orgChild3Ids = orgChild3Data.map((orgChild3) => orgChild3.id);
const orgChild4Data =
orgChild3Ids && orgChild3Ids.length > 0
? orgChild4AllData.filter((orgChild4) => orgChild3Ids.includes(orgChild4.orgChild3Id))
: [];
// OPTIMIZED: Build formatted data using pre-calculated counts (no nested queries!)
const formattedData = orgRootData.map((orgRoot) => {
// const rootCounts = getCounts(orgRootMap, orgRoot.id);
// const rootPosCounts = getRootCounts(rootPosMap, orgRoot.id);
return {
orgTreeId: orgRoot.id,
orgLevel: 0,
orgName: orgRoot.orgRootName,
orgTreeName: orgRoot.orgRootName,
orgTreeShortName: orgRoot.orgRootShortName,
orgTreeCode: orgRoot.orgRootCode,
orgCode: orgRoot.orgRootCode + "00",
orgTreeRank: orgRoot.orgRootRank,
orgTreeRankSub: orgRoot.orgRootRankSub,
orgRootDnaId: orgRoot.ancestorDNA,
DEPARTMENT_CODE: orgRoot.DEPARTMENT_CODE,
DIVISION_CODE: orgRoot.DIVISION_CODE,
SECTION_CODE: orgRoot.SECTION_CODE,
JOB_CODE: orgRoot.JOB_CODE,
orgTreeOrder: orgRoot.orgRootOrder,
orgTreePhoneEx: orgRoot.orgRootPhoneEx,
orgTreePhoneIn: orgRoot.orgRootPhoneIn,
orgTreeFax: orgRoot.orgRootFax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
isDeputy: orgRoot.isDeputy,
isCommission: orgRoot.isCommission,
responsibility: orgRoot.responsibility,
labelName:
orgRoot.orgRootName + " " + orgRoot.orgRootCode + "00" + " " + orgRoot.orgRootShortName,
// totalPosition: rootCounts.totalPosition,
// totalPositionCurrentUse: rootCounts.totalPositionCurrentUse,
// totalPositionCurrentVacant: rootCounts.totalPositionCurrentVacant,
// totalPositionNextUse: rootCounts.totalPositionNextUse,
// totalPositionNextVacant: rootCounts.totalPositionNextVacant,
// totalRootPosition: rootPosCounts.totalRootPosition,
// totalRootPositionCurrentUse: rootPosCounts.totalRootPositionCurrentUse,
// totalRootPositionCurrentVacant: rootPosCounts.totalRootPositionCurrentVacant,
// totalRootPositionNextUse: rootPosCounts.totalRootPositionNextUse,
// totalRootPositionNextVacant: rootPosCounts.totalRootPositionNextVacant,
children: orgChild1Data
.filter((orgChild1) => orgChild1.orgRootId === orgRoot.id)
.map((orgChild1) => {
// const child1Counts = getCounts(orgChild1Map, orgChild1.id);
// const child1PosKey = `${orgRoot.id}-${orgChild1.id}`;
// const child1PosCounts = getRootCounts(rootPosMap, child1PosKey);
return {
orgTreeId: orgChild1.id,
orgRootId: orgRoot.id,
orgLevel: 1,
orgName: `${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild1.orgChild1Name,
orgTreeShortName: orgChild1.orgChild1ShortName,
orgTreeCode: orgChild1.orgChild1Code,
orgCode: orgRoot.orgRootCode + orgChild1.orgChild1Code,
orgTreeRank: orgChild1.orgChild1Rank,
orgTreeRankSub: orgChild1.orgChild1RankSub,
orgRootDnaId: orgRoot.ancestorDNA,
orgChild1DnaId: orgChild1.ancestorDNA,
DEPARTMENT_CODE: orgChild1.DEPARTMENT_CODE,
DIVISION_CODE: orgChild1.DIVISION_CODE,
SECTION_CODE: orgChild1.SECTION_CODE,
JOB_CODE: orgChild1.JOB_CODE,
orgTreeOrder: orgChild1.orgChild1Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild1.orgChild1PhoneEx,
orgTreePhoneIn: orgChild1.orgChild1PhoneIn,
orgTreeFax: orgChild1.orgChild1Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild1.responsibility,
isOfficer: orgChild1.isOfficer,
isInformation: orgChild1.isInformation,
labelName:
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName,
// totalPosition: child1Counts.totalPosition,
// totalPositionCurrentUse: child1Counts.totalPositionCurrentUse,
// totalPositionCurrentVacant: child1Counts.totalPositionCurrentVacant,
// totalPositionNextUse: child1Counts.totalPositionNextUse,
// totalPositionNextVacant: child1Counts.totalPositionNextVacant,
// totalRootPosition: child1PosCounts.totalRootPosition,
// totalRootPositionCurrentUse: child1PosCounts.totalRootPositionCurrentUse,
// totalRootPositionCurrentVacant: child1PosCounts.totalRootPositionCurrentVacant,
// totalRootPositionNextUse: child1PosCounts.totalRootPositionNextUse,
// totalRootPositionNextVacant: child1PosCounts.totalRootPositionNextVacant,
children: orgChild2Data
.filter((orgChild2) => orgChild2.orgChild1Id === orgChild1.id)
.map((orgChild2) => {
// const child2Counts = getCounts(orgChild2Map, orgChild2.id);
// const child2PosKey = `${orgRoot.id}-${orgChild1.id}-${orgChild2.id}`;
// const child2PosCounts = getRootCounts(rootPosMap, child2PosKey);
return {
orgTreeId: orgChild2.id,
orgRootId: orgChild1.id,
orgLevel: 2,
orgName: `${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild2.orgChild2Name,
orgTreeShortName: orgChild2.orgChild2ShortName,
orgTreeCode: orgChild2.orgChild2Code,
orgCode: orgRoot.orgRootCode + orgChild2.orgChild2Code,
orgTreeRank: orgChild2.orgChild2Rank,
orgTreeRankSub: orgChild2.orgChild2RankSub,
orgRootDnaId: orgRoot.ancestorDNA,
orgChild1DnaId: orgChild1.ancestorDNA,
orgChild2DnaId: orgChild2.ancestorDNA,
DEPARTMENT_CODE: orgChild2.DEPARTMENT_CODE,
DIVISION_CODE: orgChild2.DIVISION_CODE,
SECTION_CODE: orgChild2.SECTION_CODE,
JOB_CODE: orgChild2.JOB_CODE,
orgTreeOrder: orgChild2.orgChild2Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild2.orgChild2PhoneEx,
orgTreePhoneIn: orgChild2.orgChild2PhoneIn,
orgTreeFax: orgChild2.orgChild2Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild2.responsibility,
labelName:
orgChild2.orgChild2Name +
" " +
orgRoot.orgRootCode +
orgChild2.orgChild2Code +
" " +
orgChild2.orgChild2ShortName,
// totalPosition: child2Counts.totalPosition,
// totalPositionCurrentUse: child2Counts.totalPositionCurrentUse,
// totalPositionCurrentVacant: child2Counts.totalPositionCurrentVacant,
// totalPositionNextUse: child2Counts.totalPositionNextUse,
// totalPositionNextVacant: child2Counts.totalPositionNextVacant,
// totalRootPosition: child2PosCounts.totalRootPosition,
// totalRootPositionCurrentUse: child2PosCounts.totalRootPositionCurrentUse,
// totalRootPositionCurrentVacant: child2PosCounts.totalRootPositionCurrentVacant,
// totalRootPositionNextUse: child2PosCounts.totalRootPositionNextUse,
// totalRootPositionNextVacant: child2PosCounts.totalRootPositionNextVacant,
children: orgChild3Data
.filter((orgChild3) => orgChild3.orgChild2Id === orgChild2.id)
.map((orgChild3) => {
// const child3Counts = getCounts(orgChild3Map, orgChild3.id);
// const child3PosKey = `${orgRoot.id}-${orgChild1.id}-${orgChild2.id}-${orgChild3.id}`;
// const child3PosCounts = getRootCounts(rootPosMap, child3PosKey);
return {
orgTreeId: orgChild3.id,
orgRootId: orgChild2.id,
orgLevel: 3,
orgName: `${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild3.orgChild3Name,
orgTreeShortName: orgChild3.orgChild3ShortName,
orgTreeCode: orgChild3.orgChild3Code,
orgCode: orgRoot.orgRootCode + orgChild3.orgChild3Code,
orgTreeRank: orgChild3.orgChild3Rank,
orgTreeRankSub: orgChild3.orgChild3RankSub,
orgRootDnaId: orgRoot.ancestorDNA,
orgChild1DnaId: orgChild1.ancestorDNA,
orgChild2DnaId: orgChild2.ancestorDNA,
orgChild3DnaId: orgChild3.ancestorDNA,
DEPARTMENT_CODE: orgChild3.DEPARTMENT_CODE,
DIVISION_CODE: orgChild3.DIVISION_CODE,
SECTION_CODE: orgChild3.SECTION_CODE,
JOB_CODE: orgChild3.JOB_CODE,
orgTreeOrder: orgChild3.orgChild3Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild3.orgChild3PhoneEx,
orgTreePhoneIn: orgChild3.orgChild3PhoneIn,
orgTreeFax: orgChild3.orgChild3Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild3.responsibility,
labelName:
orgChild3.orgChild3Name +
" " +
orgRoot.orgRootCode +
orgChild3.orgChild3Code +
" " +
orgChild3.orgChild3ShortName,
// totalPosition: child3Counts.totalPosition,
// totalPositionCurrentUse: child3Counts.totalPositionCurrentUse,
// totalPositionCurrentVacant: child3Counts.totalPositionCurrentVacant,
// totalPositionNextUse: child3Counts.totalPositionNextUse,
// totalPositionNextVacant: child3Counts.totalPositionNextVacant,
// totalRootPosition: child3PosCounts.totalRootPosition,
// totalRootPositionCurrentUse: child3PosCounts.totalRootPositionCurrentUse,
// totalRootPositionCurrentVacant:
// child3PosCounts.totalRootPositionCurrentVacant,
// totalRootPositionNextUse: child3PosCounts.totalRootPositionNextUse,
// totalRootPositionNextVacant: child3PosCounts.totalRootPositionNextVacant,
children: orgChild4Data
.filter((orgChild4) => orgChild4.orgChild3Id === orgChild3.id)
.map((orgChild4) => {
// const child4Counts = getCounts(orgChild4Map, orgChild4.id);
// const child4PosKey = `${orgRoot.id}-${orgChild1.id}-${orgChild2.id}-${orgChild3.id}-${orgChild4.id}`;
// const child4PosCounts = getRootCounts(rootPosMap, child4PosKey);
return {
orgTreeId: orgChild4.id,
orgRootId: orgChild3.id,
orgLevel: 4,
orgName: `${orgChild4.orgChild4Name}/${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild4.orgChild4Name,
orgTreeShortName: orgChild4.orgChild4ShortName,
orgTreeCode: orgChild4.orgChild4Code,
orgCode: orgRoot.orgRootCode + orgChild4.orgChild4Code,
orgTreeRank: orgChild4.orgChild4Rank,
orgTreeRankSub: orgChild4.orgChild4RankSub,
orgRootDnaId: orgRoot.ancestorDNA,
orgChild1DnaId: orgChild1.ancestorDNA,
orgChild2DnaId: orgChild2.ancestorDNA,
orgChild3DnaId: orgChild3.ancestorDNA,
orgChild4DnaId: orgChild4.ancestorDNA,
DEPARTMENT_CODE: orgChild4.DEPARTMENT_CODE,
DIVISION_CODE: orgChild4.DIVISION_CODE,
SECTION_CODE: orgChild4.SECTION_CODE,
JOB_CODE: orgChild4.JOB_CODE,
orgTreeOrder: orgChild4.orgChild4Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild4.orgChild4PhoneEx,
orgTreePhoneIn: orgChild4.orgChild4PhoneIn,
orgTreeFax: orgChild4.orgChild4Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild4.responsibility,
labelName:
orgChild4.orgChild4Name +
" " +
orgRoot.orgRootCode +
orgChild4.orgChild4Code +
" " +
orgChild4.orgChild4ShortName,
// totalPosition: child4Counts.totalPosition,
// totalPositionCurrentUse: child4Counts.totalPositionCurrentUse,
// totalPositionCurrentVacant: child4Counts.totalPositionCurrentVacant,
// totalPositionNextUse: child4Counts.totalPositionNextUse,
// totalPositionNextVacant: child4Counts.totalPositionNextVacant,
// totalRootPosition: child4PosCounts.totalRootPosition,
// totalRootPositionCurrentUse:
// child4PosCounts.totalRootPositionCurrentUse,
// totalRootPositionCurrentVacant:
// child4PosCounts.totalRootPositionCurrentVacant,
// totalRootPositionNextUse: child4PosCounts.totalRootPositionNextUse,
// totalRootPositionNextVacant:
// child4PosCounts.totalRootPositionNextVacant,
children: [],
};
}),
};
}),
};
}),
};
}),
};
});
// OPTIMIZED: Cache the result
await orgStructureCache.set(id, rootId, formattedData);
return new HttpSuccess(formattedData);
}
/**
* API รายละเอียดโครงสร้าง
*
* @summary ORG_023 - รายละเอียดโครงสร้าง (ADMIN) #25
*
*/
@Get("{id}")
async detail(@Path() id: string, @Request() request: RequestWithUser) {
let _data: any = {
root: null,
child1: null,
child2: null,
child3: null,
child4: null,
};
let _data1: any = {
root: null,
};
const orgRevision = await this.orgRevisionRepository.findOne({ where: { id } });
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
}
let _privilege = await new permission().PermissionOrgList(request, "SYS_ORG");
const attrOwnership = _privilege.root === null ? true : false;
const profile = await this.profileRepo.findOne({
where: { keycloak: request.user.sub },
relations: ["permissionProfiles", "current_holders", "current_holders.posMasterAssigns"],
});
if (!profile) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งานในทะเบียนประวัติ");
}
let profileAssign = profile.current_holders
?.find((x) => x.orgRevisionId === id)
?.posMasterAssigns.find((x) => x.assignId === "SYS_ORG");
if (orgRevision.orgRevisionIsDraft && !orgRevision.orgRevisionIsCurrent && !attrOwnership) {
if (Array.isArray(profile.permissionProfiles) && profile.permissionProfiles.length > 0) {
_data.root = profile.permissionProfiles.map((x) => x.orgRootId);
} else {
return new HttpSuccess({ remark: "", data: [] });
}
}
// กำหนดการเข้าถึงข้อมูลตามสถานะและสิทธิ์
const isCurrentActive = !orgRevision.orgRevisionIsDraft && orgRevision.orgRevisionIsCurrent;
if (isCurrentActive) {
if (profileAssign && _privilege.privilege !== "OWNER" && _privilege.privilege !== "PARENT") {
if (_privilege.privilege == "NORMAL") {
const holder = profile.current_holders.find((x) => x.orgRevisionId === id);
if (!holder) return;
_data.root = [holder.orgRootId];
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
_data.child3 = [holder.orgChild3Id];
_data.child4 = [holder.orgChild4Id];
} else if (_privilege.privilege == "CHILD" || _privilege.privilege == "BROTHER") {
const holder = profile.current_holders.find((x) => x.orgRevisionId === id);
if (!holder) return;
_data.root = [holder.orgRootId];
if (_privilege.root && _privilege.child1 === null) {
} else if (_privilege.child1 && _privilege.child2 === null) {
_data.child1 = [holder.orgChild1Id];
} else if (_privilege.child2 && _privilege.child3 === null) {
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
} else if (_privilege.child3 && _privilege.child4 === null) {
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
_data.child3 = [holder.orgChild3Id];
_data.child4 = [holder.orgChild4Id];
}
} else {
_data.root = [profile.current_holders.find((x) => x.orgRevisionId === id)?.orgRootId];
}
} else {
if (!attrOwnership) _data = _privilege;
}
}
const _revision = await this.orgRevisionRepository.findOne({
where: { id: id },
});
if (!_revision) throw new HttpError(HttpStatusCode.NOT_FOUND, "not found.");
const orgRootData = await AppDataSource.getRepository(OrgRoot)
.createQueryBuilder("orgRoot")
.where("orgRoot.orgRevisionId = :id", { id })
.andWhere(
_data.root !== undefined && _data.root !== null
? _data.root[0] !== null
? `orgRoot.id IN (:...node)`
: `orgRoot.id is null`
: "1=1",
{
node: _data.root,
},
)
.select([
"orgRoot.ancestorDNA",
"orgRoot.id",
"orgRoot.misId",
"orgRoot.isDeputy",
"orgRoot.isCommission",
"orgRoot.orgRootName",
"orgRoot.orgRootShortName",
"orgRoot.orgRootCode",
"orgRoot.orgRootOrder",
"orgRoot.orgRootPhoneEx",
"orgRoot.orgRootPhoneIn",
"orgRoot.orgRootFax",
"orgRoot.orgRevisionId",
"orgRoot.orgRootRank",
"orgRoot.orgRootRankSub",
"orgRoot.DEPARTMENT_CODE",
"orgRoot.DIVISION_CODE",
"orgRoot.SECTION_CODE",
"orgRoot.JOB_CODE",
"orgRoot.responsibility",
])
.orderBy("orgRoot.orgRootOrder", "ASC")
.getMany();
const orgRootIds = orgRootData.map((orgRoot) => orgRoot.id) || null;
const orgChild1Data =
orgRootIds && orgRootIds.length > 0
? await AppDataSource.getRepository(OrgChild1)
.createQueryBuilder("orgChild1")
.where("orgChild1.orgRootId IN (:...ids)", { ids: orgRootIds })
.andWhere(
_data.child1 !== undefined && _data.child1 !== null
? _data.child1[0] !== null
? `orgChild1.id IN (:...node)`
: `orgChild1.id is null`
: "1=1",
{
node: _data.child1,
},
)
.select([
"orgChild1.id",
"orgChild1.misId",
"orgChild1.isOfficer",
"orgChild1.isInformation",
"orgChild1.orgChild1Name",
"orgChild1.orgChild1ShortName",
"orgChild1.orgChild1Code",
"orgChild1.orgChild1Order",
"orgChild1.orgChild1PhoneEx",
"orgChild1.orgChild1PhoneIn",
"orgChild1.orgChild1Fax",
"orgChild1.orgRootId",
"orgChild1.orgChild1Rank",
"orgChild1.orgChild1RankSub",
"orgChild1.DEPARTMENT_CODE",
"orgChild1.DIVISION_CODE",
"orgChild1.SECTION_CODE",
"orgChild1.JOB_CODE",
"orgChild1.responsibility",
])
.orderBy("orgChild1.orgChild1Order", "ASC")
.getMany()
: [];
const orgChild1Ids = orgChild1Data.map((orgChild1) => orgChild1.id) || null;
const orgChild2Data =
orgChild1Ids && orgChild1Ids.length > 0
? await AppDataSource.getRepository(OrgChild2)
.createQueryBuilder("orgChild2")
.where("orgChild2.orgChild1Id IN (:...ids)", { ids: orgChild1Ids })
.andWhere(
_data.child2 !== undefined && _data.child2 !== null
? _data.child2[0] !== null
? `orgChild2.id IN (:...node)`
: `orgChild2.id is null`
: "1=1",
{
node: _data.child2,
},
)
.select([
"orgChild2.id",
"orgChild2.misId",
"orgChild2.orgChild2Name",
"orgChild2.orgChild2ShortName",
"orgChild2.orgChild2Code",
"orgChild2.orgChild2Order",
"orgChild2.orgChild2PhoneEx",
"orgChild2.orgChild2PhoneIn",
"orgChild2.orgChild2Fax",
"orgChild2.orgRootId",
"orgChild2.orgChild2Rank",
"orgChild2.orgChild2RankSub",
"orgChild2.DEPARTMENT_CODE",
"orgChild2.DIVISION_CODE",
"orgChild2.SECTION_CODE",
"orgChild2.JOB_CODE",
"orgChild2.orgChild1Id",
"orgChild2.responsibility",
])
.orderBy("orgChild2.orgChild2Order", "ASC")
.getMany()
: [];
const orgChild2Ids = orgChild2Data.map((orgChild2) => orgChild2.id) || null;
const orgChild3Data =
orgChild2Ids && orgChild2Ids.length > 0
? await AppDataSource.getRepository(OrgChild3)
.createQueryBuilder("orgChild3")
.where("orgChild3.orgChild2Id IN (:...ids)", { ids: orgChild2Ids })
.andWhere(
_data.child3 !== undefined && _data.child3 !== null
? _data.child3[0] !== null
? `orgChild3.id IN (:...node)`
: `orgChild3.id is null`
: "1=1",
{
node: _data.child3,
},
)
.select([
"orgChild3.id",
"orgChild3.misId",
"orgChild3.orgChild3Name",
"orgChild3.orgChild3ShortName",
"orgChild3.orgChild3Code",
"orgChild3.orgChild3Order",
"orgChild3.orgChild3PhoneEx",
"orgChild3.orgChild3PhoneIn",
"orgChild3.orgChild3Fax",
"orgChild3.orgRootId",
"orgChild3.orgChild3Rank",
"orgChild3.orgChild3RankSub",
"orgChild3.DEPARTMENT_CODE",
"orgChild3.DIVISION_CODE",
"orgChild3.SECTION_CODE",
"orgChild3.JOB_CODE",
"orgChild3.orgChild2Id",
"orgChild3.responsibility",
])
.orderBy("orgChild3.orgChild3Order", "ASC")
.getMany()
: [];
const orgChild3Ids = orgChild3Data.map((orgChild3) => orgChild3.id) || null;
const orgChild4Data =
orgChild3Ids && orgChild3Ids.length > 0
? await AppDataSource.getRepository(OrgChild4)
.createQueryBuilder("orgChild4")
.where("orgChild4.orgChild3Id IN (:...ids)", { ids: orgChild3Ids })
.andWhere(
_data.child4 !== undefined && _data.child4 !== null
? _data.child4[0] !== null
? `orgChild4.id IN (:...node)`
: `orgChild4.id is null`
: "1=1",
{
node: _data.child4,
},
)
.select([
"orgChild4.id",
"orgChild4.misId",
"orgChild4.orgChild4Name",
"orgChild4.orgChild4ShortName",
"orgChild4.orgChild4Code",
"orgChild4.orgChild4Order",
"orgChild4.orgChild4PhoneEx",
"orgChild4.orgChild4PhoneIn",
"orgChild4.orgChild4Fax",
"orgChild4.orgRootId",
"orgChild4.orgChild4Rank",
"orgChild4.orgChild4RankSub",
"orgChild4.DEPARTMENT_CODE",
"orgChild4.DIVISION_CODE",
"orgChild4.SECTION_CODE",
"orgChild4.JOB_CODE",
"orgChild4.orgChild3Id",
"orgChild4.responsibility",
])
.orderBy("orgChild4.orgChild4Order", "ASC")
.getMany()
: [];
const formattedData = await Promise.all(
orgRootData.map(async (orgRoot) => {
return {
orgDnaId: orgRoot.ancestorDNA,
orgTreeId: orgRoot.id,
orgLevel: 0,
misId: orgRoot.misId,
orgName: orgRoot.orgRootName,
orgTreeName: orgRoot.orgRootName,
orgTreeShortName: orgRoot.orgRootShortName,
orgTreeCode: orgRoot.orgRootCode,
orgCode: orgRoot.orgRootCode + "00",
orgTreeRank: orgRoot.orgRootRank,
orgTreeRankSub: orgRoot.orgRootRankSub,
DEPARTMENT_CODE: orgRoot.DEPARTMENT_CODE,
DIVISION_CODE: orgRoot.DIVISION_CODE,
SECTION_CODE: orgRoot.SECTION_CODE,
JOB_CODE: orgRoot.JOB_CODE,
orgTreeOrder: orgRoot.orgRootOrder,
orgTreePhoneEx: orgRoot.orgRootPhoneEx,
orgTreePhoneIn: orgRoot.orgRootPhoneIn,
orgTreeFax: orgRoot.orgRootFax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
isDeputy: orgRoot.isDeputy,
isCommission: orgRoot.isCommission,
responsibility: orgRoot.responsibility,
labelName:
orgRoot.orgRootName + " " + orgRoot.orgRootCode + "00" + " " + orgRoot.orgRootShortName,
children: await Promise.all(
orgChild1Data
.filter((orgChild1) => orgChild1.orgRootId === orgRoot.id)
.map(async (orgChild1) => ({
orgTreeId: orgChild1.id,
orgRootId: orgRoot.id,
orgLevel: 1,
misId: orgChild1.misId,
orgName: `${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild1.orgChild1Name,
orgTreeShortName: orgChild1.orgChild1ShortName,
orgTreeCode: orgChild1.orgChild1Code,
orgCode: orgRoot.orgRootCode + orgChild1.orgChild1Code,
orgTreeRank: orgChild1.orgChild1Rank,
orgTreeRankSub: orgChild1.orgChild1RankSub,
DEPARTMENT_CODE: orgChild1.DEPARTMENT_CODE,
DIVISION_CODE: orgChild1.DIVISION_CODE,
SECTION_CODE: orgChild1.SECTION_CODE,
JOB_CODE: orgChild1.JOB_CODE,
orgTreeOrder: orgChild1.orgChild1Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild1.orgChild1PhoneEx,
orgTreePhoneIn: orgChild1.orgChild1PhoneIn,
orgTreeFax: orgChild1.orgChild1Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild1.responsibility,
isOfficer: orgChild1.isOfficer,
isInformation: orgChild1.isInformation,
labelName:
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName +
"/" +
orgRoot.orgRootName +
" " +
orgRoot.orgRootCode +
"00" +
" " +
orgRoot.orgRootShortName,
children: await Promise.all(
orgChild2Data
.filter((orgChild2) => orgChild2.orgChild1Id === orgChild1.id)
.map(async (orgChild2) => ({
orgTreeId: orgChild2.id,
orgRootId: orgChild1.id,
orgLevel: 2,
misId: orgChild2.misId,
orgName: `${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild2.orgChild2Name,
orgTreeShortName: orgChild2.orgChild2ShortName,
orgTreeCode: orgChild2.orgChild2Code,
orgCode: orgRoot.orgRootCode + orgChild2.orgChild2Code,
orgTreeRank: orgChild2.orgChild2Rank,
orgTreeRankSub: orgChild2.orgChild2RankSub,
DEPARTMENT_CODE: orgChild2.DEPARTMENT_CODE,
DIVISION_CODE: orgChild2.DIVISION_CODE,
SECTION_CODE: orgChild2.SECTION_CODE,
JOB_CODE: orgChild2.JOB_CODE,
orgTreeOrder: orgChild2.orgChild2Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild2.orgChild2PhoneEx,
orgTreePhoneIn: orgChild2.orgChild2PhoneIn,
orgTreeFax: orgChild2.orgChild2Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild2.responsibility,
labelName:
orgChild2.orgChild2Name +
" " +
orgRoot.orgRootCode +
orgChild2.orgChild2Code +
" " +
orgChild2.orgChild2ShortName +
"/" +
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName +
"/" +
orgRoot.orgRootName +
" " +
orgRoot.orgRootCode +
"00" +
" " +
orgRoot.orgRootShortName,
children: await Promise.all(
orgChild3Data
.filter((orgChild3) => orgChild3.orgChild2Id === orgChild2.id)
.map(async (orgChild3) => ({
orgTreeId: orgChild3.id,
orgRootId: orgChild2.id,
orgLevel: 3,
misId: orgChild3.misId,
orgName: `${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild3.orgChild3Name,
orgTreeShortName: orgChild3.orgChild3ShortName,
orgTreeCode: orgChild3.orgChild3Code,
orgCode: orgRoot.orgRootCode + orgChild3.orgChild3Code,
orgTreeRank: orgChild3.orgChild3Rank,
orgTreeRankSub: orgChild3.orgChild3RankSub,
DEPARTMENT_CODE: orgChild3.DEPARTMENT_CODE,
DIVISION_CODE: orgChild3.DIVISION_CODE,
SECTION_CODE: orgChild3.SECTION_CODE,
JOB_CODE: orgChild3.JOB_CODE,
orgTreeOrder: orgChild3.orgChild3Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild3.orgChild3PhoneEx,
orgTreePhoneIn: orgChild3.orgChild3PhoneIn,
orgTreeFax: orgChild3.orgChild3Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild3.responsibility,
labelName:
orgChild3.orgChild3Name +
" " +
orgRoot.orgRootCode +
orgChild3.orgChild3Code +
" " +
orgChild3.orgChild3ShortName +
"/" +
orgChild2.orgChild2Name +
" " +
orgRoot.orgRootCode +
orgChild2.orgChild2Code +
" " +
orgChild2.orgChild2ShortName +
"/" +
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName +
"/" +
orgRoot.orgRootName +
" " +
orgRoot.orgRootCode +
"00" +
" " +
orgRoot.orgRootShortName,
children: await Promise.all(
orgChild4Data
.filter((orgChild4) => orgChild4.orgChild3Id === orgChild3.id)
.map(async (orgChild4) => ({
orgTreeId: orgChild4.id,
orgRootId: orgChild3.id,
orgLevel: 4,
misId: orgChild4.misId,
orgName: `${orgChild4.orgChild4Name}/${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild4.orgChild4Name,
orgTreeShortName: orgChild4.orgChild4ShortName,
orgTreeCode: orgChild4.orgChild4Code,
orgCode: orgRoot.orgRootCode + orgChild4.orgChild4Code,
orgTreeRank: orgChild4.orgChild4Rank,
orgTreeRankSub: orgChild4.orgChild4RankSub,
DEPARTMENT_CODE: orgChild4.DEPARTMENT_CODE,
DIVISION_CODE: orgChild4.DIVISION_CODE,
SECTION_CODE: orgChild4.SECTION_CODE,
JOB_CODE: orgChild4.JOB_CODE,
orgTreeOrder: orgChild4.orgChild4Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild4.orgChild4PhoneEx,
orgTreePhoneIn: orgChild4.orgChild4PhoneIn,
orgTreeFax: orgChild4.orgChild4Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild4.responsibility,
labelName:
orgChild4.orgChild4Name +
" " +
orgRoot.orgRootCode +
orgChild4.orgChild4Code +
" " +
orgChild4.orgChild4ShortName +
"/" +
orgChild3.orgChild3Name +
" " +
orgRoot.orgRootCode +
orgChild3.orgChild3Code +
" " +
orgChild3.orgChild3ShortName +
"/" +
orgChild2.orgChild2Name +
" " +
orgRoot.orgRootCode +
orgChild2.orgChild2Code +
" " +
orgChild2.orgChild2ShortName +
"/" +
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName +
"/" +
orgRoot.orgRootName +
" " +
orgRoot.orgRootCode +
"00" +
" " +
orgRoot.orgRootShortName,
})),
),
})),
),
})),
),
})),
),
};
}),
);
// return new HttpSuccess({ remark: _revision.remark, data: formattedData });
return new HttpSuccess({ remark: _revision.remark, data: formattedData });
}
/**
* API ตั้งเวลาเผยแพร่
*
* @summary ORG_025 - ตั้งเวลาเผยแพร่ (ADMIN) #27
*
* @param {string} id Id revison
*/
@Put("/set/publish/{id}")
async Edit(
@Path() id: string,
@Body() requestBody: { orgPublishDate: Date },
@Request() request: RequestWithUser,
) {
// await new permission().PermissionUpdate(request, "SYS_ORG");//ไม่แน่ใจOFFปิดไว้ก่อน
const orgRevision = await this.orgRevisionRepository.findOne({
where: {
id: id,
orgRevisionIsDraft: true,
orgRevisionIsCurrent: false,
},
});
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. RevisionId");
}
const before = structuredClone(orgRevision);
orgRevision.lastUpdateUserId = request.user.sub;
orgRevision.lastUpdateFullName = request.user.name;
orgRevision.lastUpdatedAt = new Date();
orgRevision.orgPublishDate = requestBody.orgPublishDate;
this.orgRevisionRepository.merge(orgRevision, requestBody);
await this.orgRevisionRepository.save(orgRevision, { data: request });
setLogDataDiff(request, { before, after: orgRevision });
return new HttpSuccess();
}
/**
* API ประวัติหน่วยงาน
*
* @summary ORG_039 - ประวัติหน่วยงาน (ADMIN) #42
*
*/
@Post("/history/publish")
async GetHistoryPublish(
@Body()
requestBody: {
id: string;
type: number;
},
@Request() request: RequestWithUser,
) {
if (requestBody.type == 1) {
const orgChild1 = await this.child1Repository.findOne({
where: { id: requestBody.id },
});
if (!orgChild1) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. Child1");
}
const datas = await this.child1Repository
.createQueryBuilder("child1")
.where("child1.ancestorDNA = :ancestorDNA", { ancestorDNA: orgChild1.ancestorDNA })
.andWhere("child1.ancestorDNA <> :nullUUID", {
nullUUID: "00000000-0000-0000-0000-000000000000",
})
.andWhere("child1.ancestorDNA IS NOT NULL")
.leftJoinAndSelect("child1.orgRevision", "orgRevision")
.orderBy("child1.lastUpdatedAt", "DESC")
.getMany();
const _data = datas.map((item) => ({
id: item.id,
orgRevisionName: item.orgRevision == null ? null : item.orgRevision.orgRevisionName,
name: item.orgChild1Name,
lastUpdatedAt: item.lastUpdatedAt,
}));
return new HttpSuccess(_data);
} else if (requestBody.type == 2) {
const orgChild2 = await this.child2Repository.findOne({
where: { id: requestBody.id },
});
if (!orgChild2) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. Child2");
}
const datas = await this.child2Repository
.createQueryBuilder("child2")
.where("child2.ancestorDNA = :ancestorDNA", { ancestorDNA: orgChild2.ancestorDNA })
.andWhere("child2.ancestorDNA <> :nullUUID", {
nullUUID: "00000000-0000-0000-0000-000000000000",
})
.andWhere("child2.ancestorDNA IS NOT NULL")
.leftJoinAndSelect("child2.orgRevision", "orgRevision")
.orderBy("child2.lastUpdatedAt", "DESC")
.getMany();
const _data = datas.map((item) => ({
id: item.id,
orgRevisionName: item.orgRevision == null ? null : item.orgRevision.orgRevisionName,
name: item.orgChild2Name,
lastUpdatedAt: item.lastUpdatedAt,
}));
return new HttpSuccess(_data);
} else if (requestBody.type == 3) {
const orgChild3 = await this.child3Repository.findOne({
where: { id: requestBody.id },
});
if (!orgChild3) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. Child3");
}
const datas = await this.child3Repository
.createQueryBuilder("child3")
.where("child3.ancestorDNA = :ancestorDNA", { ancestorDNA: orgChild3.ancestorDNA })
.andWhere("child3.ancestorDNA <> :nullUUID", {
nullUUID: "00000000-0000-0000-0000-000000000000",
})
.andWhere("child3.ancestorDNA IS NOT NULL")
.leftJoinAndSelect("child3.orgRevision", "orgRevision")
.orderBy("child3.lastUpdatedAt", "DESC")
.getMany();
const _data = datas.map((item) => ({
id: item.id,
orgRevisionName: item.orgRevision == null ? null : item.orgRevision.orgRevisionName,
name: item.orgChild3Name,
lastUpdatedAt: item.lastUpdatedAt,
}));
return new HttpSuccess(_data);
} else if (requestBody.type == 4) {
const orgChild4 = await this.child4Repository.findOne({
where: { id: requestBody.id },
});
if (!orgChild4) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. Child4");
}
const datas = await this.child4Repository
.createQueryBuilder("child4")
.where("child4.ancestorDNA = :ancestorDNA", { ancestorDNA: orgChild4.ancestorDNA })
.andWhere("child4.ancestorDNA <> :nullUUID", {
nullUUID: "00000000-0000-0000-0000-000000000000",
})
.andWhere("child4.ancestorDNA IS NOT NULL")
.leftJoinAndSelect("child4.orgRevision", "orgRevision")
.orderBy("child4.lastUpdatedAt", "DESC")
.getMany();
const _data = datas.map((item) => ({
id: item.id,
orgRevisionName: item.orgRevision == null ? null : item.orgRevision.orgRevisionName,
name: item.orgChild4Name,
lastUpdatedAt: item.lastUpdatedAt,
}));
return new HttpSuccess(_data);
} else {
const orgRoot = await this.orgRootRepository.findOne({
where: { id: requestBody.id },
});
if (!orgRoot) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. Root");
}
const datas = await this.orgRootRepository
.createQueryBuilder("root")
.where("root.ancestorDNA = :ancestorDNA", { ancestorDNA: orgRoot.ancestorDNA })
.andWhere("root.ancestorDNA <> :nullUUID", {
nullUUID: "00000000-0000-0000-0000-000000000000",
})
.andWhere("root.ancestorDNA IS NOT NULL")
.leftJoinAndSelect("root.orgRevision", "orgRevision")
.orderBy("root.lastUpdatedAt", "DESC")
.getMany();
const _data = datas.map((item) => ({
id: item.id,
orgRevisionName: item.orgRevision == null ? null : item.orgRevision.orgRevisionName,
name: item.orgRootName,
lastUpdatedAt: item.lastUpdatedAt,
}));
return new HttpSuccess(_data);
}
}
/**
* API จัดลำดับโครงสร้าง
*
* @summary ORG_038 - จัดลำดับโครงสร้าง (ADMIN) #41
*
*/
@Post("sort")
async Sort(
@Body() requestBody: { id: string; type: number; sortId: string[] },
@Request() request: RequestWithUser,
) {
await new permission().PermissionUpdate(request, "SYS_ORG");
const before = null;
switch (requestBody.type) {
case 0: {
const revisionId = await this.orgRevisionRepository.findOne({
where: { id: requestBody.id },
});
if (!revisionId?.id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found revisionId: " + requestBody.id);
}
const listRootId = await this.orgRootRepository.find({
where: { orgRevisionId: requestBody.id },
select: ["id", "orgRootOrder"],
});
if (!listRootId) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId.");
}
const sortData = listRootId.map((data) => ({
id: data.id,
orgRootOrder: requestBody.sortId.indexOf(data.id) + 1,
}));
await this.orgRootRepository.save(sortData, { data: request });
setLogDataDiff(request, { before, after: sortData });
break;
}
case 1: {
const rootId = await this.orgRootRepository.findOne({ where: { id: requestBody.id } });
if (!rootId?.id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId: " + requestBody.id);
}
const listChild1Id = await this.child1Repository.find({
where: { orgRootId: requestBody.id },
select: ["id", "orgChild1Order"],
});
if (!listChild1Id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1Id.");
}
const sortData = listChild1Id.map((data) => ({
id: data.id,
orgChild1Order: requestBody.sortId.indexOf(data.id) + 1,
}));
await this.child1Repository.save(sortData, { data: request });
setLogDataDiff(request, { before, after: sortData });
break;
}
case 2: {
const child1Id = await this.child1Repository.findOne({ where: { id: requestBody.id } });
if (!child1Id?.id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1Id: " + requestBody.id);
}
const listChild2Id = await this.child2Repository.find({
where: { orgChild1Id: requestBody.id },
select: ["id", "orgChild2Order"],
});
if (!listChild2Id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2Id.");
}
const sortData = listChild2Id.map((data) => ({
id: data.id,
orgChild2Order: requestBody.sortId.indexOf(data.id) + 1,
}));
await this.child2Repository.save(sortData, { data: request });
setLogDataDiff(request, { before, after: sortData });
break;
}
case 3: {
const child2Id = await this.child2Repository.findOne({ where: { id: requestBody.id } });
if (!child2Id?.id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2Id: " + requestBody.id);
}
const listChild3Id = await this.child3Repository.find({
where: { orgChild2Id: requestBody.id },
select: ["id", "orgChild3Order"],
});
if (!listChild3Id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child3Id.");
}
const sortData = listChild3Id.map((data) => ({
id: data.id,
orgChild3Order: requestBody.sortId.indexOf(data.id) + 1,
}));
await this.child3Repository.save(sortData, { data: request });
setLogDataDiff(request, { before, after: sortData });
break;
}
case 4: {
const child3Id = await this.child3Repository.findOne({ where: { id: requestBody.id } });
if (!child3Id?.id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child3Id: " + requestBody.id);
}
const listChild4Id = await this.child4Repository.find({
where: { orgChild3Id: requestBody.id },
select: ["id", "orgChild4Order"],
});
if (!listChild4Id) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child4Id.");
}
const sortData = listChild4Id.map((data) => ({
id: data.id,
orgChild4Order: requestBody.sortId.indexOf(data.id) + 1,
}));
await this.child4Repository.save(sortData, { data: request });
setLogDataDiff(request, { before, after: sortData });
break;
}
default:
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: " + requestBody.type);
}
return new HttpSuccess();
}
/**
* API เผยแพร่ข้อมูล
*
* @summary ORG_071 - เผยแพร่ข้อมูล (ADMIN) #57
*
* @param {string} id Id revison
*/
@Get("get/publish")
async runPublish(@Request() request: RequestWithUser) {
try {
// CheckQueueInProgress
// console.log("🚀 ตรวจสอบว่ามีงานอยู่ในคิว");
const [isBusyDraft, isBusyPublish] = await Promise.all([
checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG_DRAFT}`),
checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG}`),
]);
// console.log("✅ ตรวจสอบแล้ว Draft Busy:", isBusyDraft);
// console.log("✅ ตรวจสอบแล้ว Publish Busy:", isBusyPublish);
if (isBusyDraft || isBusyPublish) {
// console.log("🚫 พบว่ามีงานอยู่ในคิว — error")
throw new HttpError(
HttpStatusCode.CONFLICT,
"ไม่สามารถดำเนินการได้ หากกำลังเผยแพร่หรือสร้างแบบร่างโครงสร้างหน่วยงาน",
);
}
const today = new Date();
today.setHours(0, 0, 0, 0); // Set time to the beginning of the day
const orgRevisionDraft = await this.orgRevisionRepository
.createQueryBuilder("orgRevision")
.where("orgRevision.orgRevisionIsDraft = true")
.andWhere("orgRevision.orgRevisionIsCurrent = false")
// .andWhere("DATE(orgRevision.orgPublishDate) = :today", { today })
.getOne();
if (!orgRevisionDraft) {
return new HttpSuccess();
// throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่มีข้อมูลเผยแพร่");
}
// if (orgRevisionPublish) {
// orgRevisionPublish.orgRevisionIsDraft = false;
// orgRevisionPublish.orgRevisionIsCurrent = false;
// await this.orgRevisionRepository.save(orgRevisionPublish);
// }
// orgRevisionDraft.orgRevisionIsCurrent = true;
// orgRevisionDraft.orgRevisionIsDraft = false;
// await this.orgRevisionRepository.save(orgRevisionDraft);
const msg = {
data: {
id: orgRevisionDraft.id,
status: "NOW",
lastUpdateUserId: request.user.sub,
lastUpdateFullName: request.user.name,
lastUpdatedAt: new Date(),
},
user: request.user,
token: request.headers["authorization"],
};
await sendToQueueOrg(msg);
return new HttpSuccess();
} catch (error: any) {
throw error;
}
}
/**
* Cronjob
*/
async cronjobRevision() {
const today = new Date();
today.setUTCHours(0, 0, 0, 0); // Set time to the beginning of the day
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
const orgRevisionDraft = await this.orgRevisionRepository
.createQueryBuilder("orgRevision")
.where("orgRevision.orgRevisionIsDraft = true")
.andWhere("orgRevision.orgRevisionIsCurrent = false")
.andWhere("orgRevision.orgPublishDate BETWEEN :today AND :tomorrow", { today, tomorrow })
.getOne();
if (!orgRevisionDraft) {
return new HttpSuccess();
}
// if (orgRevisionPublish) {
// orgRevisionPublish.orgRevisionIsDraft = false;
// orgRevisionPublish.orgRevisionIsCurrent = false;
// await this.orgRevisionRepository.save(orgRevisionPublish);
// }
// orgRevisionDraft.orgRevisionIsCurrent = true;
// orgRevisionDraft.orgRevisionIsDraft = false;
// await this.orgRevisionRepository.save(orgRevisionDraft);
// const posMaster = await this.posMasterRepository.find({
// where: { orgRevisionId: orgRevisionDraft.id },
// });
// posMaster.forEach(async (item) => {
// // if(item.next_holderId != null){
// item.current_holderId = item.next_holderId;
// item.next_holderId = null;
// await this.posMasterRepository.save(item);
// // }
// });
const msg = {
data: {
id: orgRevisionDraft.id,
status: "ON_SCHEDULE",
lastUpdateUserId: "system",
lastUpdateFullName: "system",
lastUpdatedAt: new Date(),
},
};
sendToQueueOrg(msg);
return new HttpSuccess();
}
/**
* API Organizational Chart
*
* @summary Organizational Chart
*
* @param {string} revisionId Id revison
*/
@Get("org-chart/{revisionId}")
async orgchart(@Path() revisionId: string) {
const data = await this.orgRevisionRepository.findOne({
where: { id: revisionId },
});
if (!data) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้าง");
}
let posMasterRoot: any;
let posMasterChild1: any;
let posMasterChild2: any;
let posMasterChild3: any;
let posMasterChild4: any;
if (data.orgRevisionIsCurrent == true && data.orgRevisionIsDraft == false) {
// ใช้ query เดียวแทน 5 queries แยก เพื่อความเร็วในการทำงาน
const allPosMasters = await this.posMasterRepository.find({
where: {
orgRevisionId: data.id,
},
relations: [
"current_holder",
"orgRoot",
"orgChild1",
"orgChild2",
"orgChild3",
"orgChild4",
],
order: {
orgRoot: {
orgRootOrder: "ASC",
},
posMasterOrder: "ASC",
posMasterNo: "ASC",
},
});
// แยกข้อมูลด้วย JavaScript แทนการใช้ database queries หลาย ๆ ครั้ง
posMasterRoot = allPosMasters.filter((item) => item.orgChild1Id === null);
posMasterChild1 = allPosMasters.filter(
(item) => item.orgChild2Id === null && item.orgChild1Id !== null,
);
posMasterChild2 = allPosMasters.filter(
(item) => item.orgChild3Id === null && item.orgChild2Id !== null,
);
posMasterChild3 = allPosMasters.filter(
(item) => item.orgChild4Id === null && item.orgChild3Id !== null,
);
posMasterChild4 = allPosMasters.filter((item) => item.orgChild4Id !== null);
// สร้าง Maps เพื่อ lookup ที่เร็วขึ้น แทนการใช้ filter หลายรอบ
const rootByOrgRootId = new Map<string, PosMaster[]>();
const child1ByOrgRootId = new Map<string, PosMaster[]>();
const child1ByOrgChild1Id = new Map<string, PosMaster[]>();
const child2ByOrgChild1Id = new Map<string, PosMaster[]>();
const child2ByOrgChild2Id = new Map<string, PosMaster[]>();
const child3ByOrgChild2Id = new Map<string, PosMaster[]>();
const child3ByOrgChild3Id = new Map<string, PosMaster[]>();
const child4ByOrgChild3Id = new Map<string, PosMaster[]>();
// Pre-compute all lookups เพื่อหลีกเลี่ยงการ filter ซ้ำๆ
posMasterRoot.forEach((item: PosMaster) => {
if (item.current_holderId) {
if (item.isDirector) {
// Root directors will be processed in main loop
} else {
// Group root non-directors by orgRootId
const key = item.orgRootId || "";
if (!rootByOrgRootId.has(key)) rootByOrgRootId.set(key, []);
rootByOrgRootId.get(key)!.push(item);
}
}
});
posMasterChild1.forEach((item: PosMaster) => {
if (item.isDirector) {
// Group child1 directors by orgRootId
const key = item.orgRootId || "";
if (!child1ByOrgRootId.has(key)) child1ByOrgRootId.set(key, []);
child1ByOrgRootId.get(key)!.push(item);
} else if (item.current_holderId) {
// Group child1 non-directors by orgChild1Id
const key = item.orgChild1Id || "";
if (!child1ByOrgChild1Id.has(key)) child1ByOrgChild1Id.set(key, []);
child1ByOrgChild1Id.get(key)!.push(item);
}
});
posMasterChild2.forEach((item: PosMaster) => {
if (item.isDirector) {
// Group child2 directors by orgChild1Id
const key = item.orgChild1Id || "";
if (!child2ByOrgChild1Id.has(key)) child2ByOrgChild1Id.set(key, []);
child2ByOrgChild1Id.get(key)!.push(item);
} else if (item.current_holderId) {
// Group child2 non-directors by orgChild2Id
const key = item.orgChild2Id || "";
if (!child2ByOrgChild2Id.has(key)) child2ByOrgChild2Id.set(key, []);
child2ByOrgChild2Id.get(key)!.push(item);
}
});
posMasterChild3.forEach((item: PosMaster) => {
if (item.isDirector) {
// Group child3 directors by orgChild2Id
const key = item.orgChild2Id || "";
if (!child3ByOrgChild2Id.has(key)) child3ByOrgChild2Id.set(key, []);
child3ByOrgChild2Id.get(key)!.push(item);
} else if (item.current_holderId) {
// Group child3 non-directors by orgChild3Id
const key = item.orgChild3Id || "";
if (!child3ByOrgChild3Id.has(key)) child3ByOrgChild3Id.set(key, []);
child3ByOrgChild3Id.get(key)!.push(item);
}
});
posMasterChild4.forEach((item: PosMaster) => {
if (item.isDirector) {
// Group child4 directors by orgChild3Id
const key = item.orgChild3Id || "";
if (!child4ByOrgChild3Id.has(key)) child4ByOrgChild3Id.set(key, []);
child4ByOrgChild3Id.get(key)!.push(item);
}
});
// Helper function เพื่อสร้าง node object
const createNode = (item: PosMaster, level: number, holder: any, orgInfo: any) => ({
level,
personID: holder?.id ?? "",
name: holder ? `${holder.firstName} ${holder.lastName}` : "ว่าง",
avatar:
holder?.avatar && holder?.avatarName ? `${holder.avatar}/${holder.avatarName}` : null,
positionName: holder?.position ?? "",
positionNum: `${orgInfo.shortName} ${item.posMasterNo}`,
positionNumInt: item.posMasterNo,
departmentName: orgInfo.name,
organizationId: orgInfo.id,
children: [] as any[],
});
let formattedData = posMasterRoot
.filter((x: any) => x.current_holderId != null && x.isDirector)
.map((x0: PosMaster) => {
const childLevel1: any[] = [];
// Add root non-directors (Level 2)
const rootNonDirectors = rootByOrgRootId.get(x0.orgRootId || "") || [];
rootNonDirectors.forEach((x00: PosMaster) => {
childLevel1.push(
createNode(x00, 2, x00.current_holder, {
shortName: x00.orgRoot.orgRootShortName,
name: x00.orgRoot.orgRootName,
id: x00.orgRoot.id,
}),
);
});
// Add child1 directors (Level 2)
const child1Directors = child1ByOrgRootId.get(x0.orgRootId || "") || [];
child1Directors.forEach((x1: PosMaster) => {
const childLevel2: any[] = [];
// Add child1 non-directors (Level 3)
const child1NonDirectors = child1ByOrgChild1Id.get(x1.orgChild1Id || "") || [];
child1NonDirectors.forEach((x11: PosMaster) => {
childLevel2.push(
createNode(x11, 3, x11.current_holder, {
shortName: x11.orgChild1.orgChild1ShortName,
name: x11.orgChild1.orgChild1Name,
id: x11.orgChild1.id,
}),
);
});
// Add child2 directors (Level 3)
const child2Directors = child2ByOrgChild1Id.get(x1.orgChild1Id || "") || [];
child2Directors.forEach((x2: PosMaster) => {
const childLevel3: any[] = [];
// Add child2 non-directors (Level 4)
const child2NonDirectors = child2ByOrgChild2Id.get(x2.orgChild2Id || "") || [];
child2NonDirectors.forEach((x22: PosMaster) => {
childLevel3.push(
createNode(x22, 4, x22.current_holder, {
shortName: x22.orgChild2.orgChild2ShortName,
name: x22.orgChild2.orgChild2Name,
id: x22.orgChild2.id,
}),
);
});
// Add child3 directors (Level 4)
const child3Directors = child3ByOrgChild2Id.get(x2.orgChild2Id || "") || [];
child3Directors.forEach((x3: PosMaster) => {
const childLevel4: any[] = [];
// Add child3 non-directors (Level 5)
const child3NonDirectors = child3ByOrgChild3Id.get(x3.orgChild3Id || "") || [];
child3NonDirectors.forEach((x33: PosMaster) => {
childLevel4.push(
createNode(x33, 5, x33.current_holder, {
shortName: x33.orgChild3.orgChild3ShortName,
name: x33.orgChild3.orgChild3Name,
id: x33.orgChild3.id,
}),
);
});
// Add child4 directors (Level 5)
const child4Directors = child4ByOrgChild3Id.get(x3.orgChild3Id || "") || [];
child4Directors.forEach((x4: PosMaster) => {
const childLevel5: any[] = [];
// Add child4 non-directors (Level 5)
posMasterChild4
.filter(
(x: PosMaster) =>
!x.isDirector && x.current_holderId && x.orgChild3Id === x4.orgChild3Id,
)
.forEach((x44: PosMaster) => {
childLevel5.push(
createNode(x44, 5, x44.current_holder, {
shortName: x44.orgChild4.orgChild4ShortName,
name: x44.orgChild4.orgChild4Name,
id: x44.orgChild4.id,
}),
);
});
const child4Node = createNode(x4, 4, x4.current_holder, {
shortName: x4.orgChild4.orgChild4ShortName,
name: x4.orgChild4.orgChild4Name,
id: x4.orgChild4.id,
});
child4Node.children = childLevel5;
childLevel4.push(child4Node);
});
const child3Node = createNode(x3, 4, x3.current_holder, {
shortName: x3.orgChild3.orgChild3ShortName,
name: x3.orgChild3.orgChild3Name,
id: x3.orgChild3.id,
});
child3Node.children = childLevel4;
childLevel3.push(child3Node);
});
const child2Node = createNode(x2, 3, x2.current_holder, {
shortName: x2.orgChild2.orgChild2ShortName,
name: x2.orgChild2.orgChild2Name,
id: x2.orgChild2.id,
});
child2Node.children = childLevel3;
childLevel2.push(child2Node);
});
const child1Node = createNode(x1, 2, x1.current_holder, {
shortName: x1.orgChild1.orgChild1ShortName,
name: x1.orgChild1.orgChild1Name,
id: x1.orgChild1.id,
});
child1Node.children = childLevel2;
childLevel1.push(child1Node);
});
// Root Level 1
const rootNode = createNode(x0, 1, x0.current_holder, {
shortName: x0.orgRoot.orgRootShortName,
name: x0.orgRoot.orgRootName,
id: x0.orgRoot.id,
});
rootNode.children = childLevel1;
return rootNode;
});
const formattedData_ = {
personID: "",
name: "",
avatar: "",
positionName: "",
positionNum: "",
positionNumInt: null,
departmentName: data.orgRevisionName,
organizationId: data.id,
children: formattedData,
};
return new HttpSuccess([formattedData_]);
} else if (data.orgRevisionIsCurrent == false && data.orgRevisionIsDraft == true) {
// ใช้ query เดียวแทน 5 queries แยก เพื่อความเร็วในการทำงาน
const allPosMasters = await this.posMasterRepository.find({
where: {
orgRevisionId: data.id,
// next_holderId: Not(IsNull()),
},
relations: ["next_holder", "orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"],
});
// แยกข้อมูลด้วย JavaScript แทนการใช้ database queries หลาย ๆ ครั้ง
posMasterRoot = allPosMasters.filter((item) => item.orgChild1Id === null);
posMasterChild1 = allPosMasters.filter(
(item) => item.orgChild2Id === null && item.orgChild1Id !== null,
);
posMasterChild2 = allPosMasters.filter(
(item) => item.orgChild3Id === null && item.orgChild2Id !== null,
);
posMasterChild3 = allPosMasters.filter(
(item) => item.orgChild4Id === null && item.orgChild3Id !== null,
);
posMasterChild4 = allPosMasters.filter((item) => item.orgChild4Id !== null);
// สร้าง Maps เพื่อ lookup ที่เร็วขึ้น แทนการใช้ filter หลายรอบ สำหรับ draft version
const rootByOrgRootIdDraft = new Map<string, PosMaster[]>();
const child1ByOrgRootIdDraft = new Map<string, PosMaster[]>();
const child1ByOrgChild1IdDraft = new Map<string, PosMaster[]>();
const child2ByOrgChild1IdDraft = new Map<string, PosMaster[]>();
const child2ByOrgChild2IdDraft = new Map<string, PosMaster[]>();
const child3ByOrgChild2IdDraft = new Map<string, PosMaster[]>();
const child3ByOrgChild3IdDraft = new Map<string, PosMaster[]>();
const child4ByOrgChild3IdDraft = new Map<string, PosMaster[]>();
// Pre-compute all lookups เพื่อหลีกเลี่ยงการ filter ซ้ำๆ สำหรับ draft version
posMasterRoot.forEach((item: PosMaster) => {
if (item.next_holderId) {
if (item.isDirector) {
// Root directors will be processed in main loop
} else {
// Group root non-directors by orgRootId
const key = item.orgRootId || "";
if (!rootByOrgRootIdDraft.has(key)) rootByOrgRootIdDraft.set(key, []);
rootByOrgRootIdDraft.get(key)!.push(item);
}
}
});
posMasterChild1.forEach((item: PosMaster) => {
if (item.isDirector) {
// Group child1 directors by orgRootId
const key = item.orgRootId || "";
if (!child1ByOrgRootIdDraft.has(key)) child1ByOrgRootIdDraft.set(key, []);
child1ByOrgRootIdDraft.get(key)!.push(item);
} else if (item.next_holderId) {
// Group child1 non-directors by orgChild1Id
const key = item.orgChild1Id || "";
if (!child1ByOrgChild1IdDraft.has(key)) child1ByOrgChild1IdDraft.set(key, []);
child1ByOrgChild1IdDraft.get(key)!.push(item);
}
});
posMasterChild2.forEach((item: PosMaster) => {
if (item.isDirector) {
// Group child2 directors by orgChild1Id
const key = item.orgChild1Id || "";
if (!child2ByOrgChild1IdDraft.has(key)) child2ByOrgChild1IdDraft.set(key, []);
child2ByOrgChild1IdDraft.get(key)!.push(item);
} else if (item.next_holderId) {
// Group child2 non-directors by orgChild2Id
const key = item.orgChild2Id || "";
if (!child2ByOrgChild2IdDraft.has(key)) child2ByOrgChild2IdDraft.set(key, []);
child2ByOrgChild2IdDraft.get(key)!.push(item);
}
});
posMasterChild3.forEach((item: PosMaster) => {
if (item.isDirector) {
// Group child3 directors by orgChild2Id
const key = item.orgChild2Id || "";
if (!child3ByOrgChild2IdDraft.has(key)) child3ByOrgChild2IdDraft.set(key, []);
child3ByOrgChild2IdDraft.get(key)!.push(item);
} else if (item.next_holderId) {
// Group child3 non-directors by orgChild3Id
const key = item.orgChild3Id || "";
if (!child3ByOrgChild3IdDraft.has(key)) child3ByOrgChild3IdDraft.set(key, []);
child3ByOrgChild3IdDraft.get(key)!.push(item);
}
});
posMasterChild4.forEach((item: PosMaster) => {
if (item.isDirector) {
// Group child4 directors by orgChild3Id
const key = item.orgChild3Id || "";
if (!child4ByOrgChild3IdDraft.has(key)) child4ByOrgChild3IdDraft.set(key, []);
child4ByOrgChild3IdDraft.get(key)!.push(item);
}
});
// Helper function เพื่อสร้าง node object สำหรับ draft version
const createNodeDraft = (item: PosMaster, level: number, holder: any, orgInfo: any) => ({
level,
personID: holder?.id ?? "",
name: holder ? `${holder.firstName} ${holder.lastName}` : "ว่าง",
avatar:
holder?.avatar && holder?.avatarName ? `${holder.avatar}/${holder.avatarName}` : null,
positionName: holder?.position ?? "",
positionNum: `${orgInfo.shortName} ${item.posMasterNo}`,
positionNumInt: item.posMasterNo,
departmentName: orgInfo.name,
organizationId: orgInfo.id,
children: [] as any[],
});
let formattedData = posMasterRoot
.filter((x: any) => x.next_holderId != null && x.isDirector)
.map((x0: PosMaster) => {
const childLevel1: any[] = [];
// Add root non-directors (Level 2)
const rootNonDirectors = rootByOrgRootIdDraft.get(x0.orgRootId || "") || [];
rootNonDirectors.forEach((x00: PosMaster) => {
childLevel1.push(
createNodeDraft(x00, 2, x00.next_holder, {
shortName: x00.orgRoot.orgRootShortName,
name: x00.orgRoot.orgRootName,
id: x00.orgRoot.id,
}),
);
});
// Add child1 directors (Level 2)
const child1Directors = child1ByOrgRootIdDraft.get(x0.orgRootId || "") || [];
child1Directors.forEach((x1: PosMaster) => {
const childLevel2: any[] = [];
// Add child1 non-directors (Level 3)
const child1NonDirectors = child1ByOrgChild1IdDraft.get(x1.orgChild1Id || "") || [];
child1NonDirectors.forEach((x11: PosMaster) => {
childLevel2.push(
createNodeDraft(x11, 3, x11.next_holder, {
shortName: x11.orgChild1.orgChild1ShortName,
name: x11.orgChild1.orgChild1Name,
id: x11.orgChild1.id,
}),
);
});
// Add child2 directors (Level 3)
const child2Directors = child2ByOrgChild1IdDraft.get(x1.orgChild1Id || "") || [];
child2Directors.forEach((x2: PosMaster) => {
const childLevel3: any[] = [];
// Add child2 non-directors (Level 4)
const child2NonDirectors = child2ByOrgChild2IdDraft.get(x2.orgChild2Id || "") || [];
child2NonDirectors.forEach((x22: PosMaster) => {
childLevel3.push(
createNodeDraft(x22, 4, x22.next_holder, {
shortName: x22.orgChild2.orgChild2ShortName,
name: x22.orgChild2.orgChild2Name,
id: x22.orgChild2.id,
}),
);
});
// Add child3 directors (Level 4)
const child3Directors = child3ByOrgChild2IdDraft.get(x2.orgChild2Id || "") || [];
child3Directors.forEach((x3: PosMaster) => {
const childLevel4: any[] = [];
// Add child3 non-directors (Level 5)
const child3NonDirectors = child3ByOrgChild3IdDraft.get(x3.orgChild3Id || "") || [];
child3NonDirectors.forEach((x33: PosMaster) => {
childLevel4.push(
createNodeDraft(x33, 5, x33.next_holder, {
shortName: x33.orgChild3.orgChild3ShortName,
name: x33.orgChild3.orgChild3Name,
id: x33.orgChild3.id,
}),
);
});
// Add child4 directors (Level 5)
const child4Directors = child4ByOrgChild3IdDraft.get(x3.orgChild3Id || "") || [];
child4Directors.forEach((x4: PosMaster) => {
const childLevel5: any[] = [];
// Add child4 non-directors (Level 5)
posMasterChild4
.filter(
(x: PosMaster) =>
!x.isDirector && x.next_holderId && x.orgChild3Id === x4.orgChild3Id,
)
.forEach((x44: PosMaster) => {
childLevel5.push(
createNodeDraft(x44, 5, x44.next_holder, {
shortName: x44.orgChild4.orgChild4ShortName,
name: x44.orgChild4.orgChild4Name,
id: x44.orgChild4.id,
}),
);
});
const child4Node = createNodeDraft(x4, 4, x4.next_holder, {
shortName: x4.orgChild4.orgChild4ShortName,
name: x4.orgChild4.orgChild4Name,
id: x4.orgChild4.id,
});
child4Node.children = childLevel5;
childLevel4.push(child4Node);
});
const child3Node = createNodeDraft(x3, 4, x3.next_holder, {
shortName: x3.orgChild3.orgChild3ShortName,
name: x3.orgChild3.orgChild3Name,
id: x3.orgChild3.id,
});
child3Node.children = childLevel4;
childLevel3.push(child3Node);
});
const child2Node = createNodeDraft(x2, 3, x2.next_holder, {
shortName: x2.orgChild2.orgChild2ShortName,
name: x2.orgChild2.orgChild2Name,
id: x2.orgChild2.id,
});
child2Node.children = childLevel3;
childLevel2.push(child2Node);
});
const child1Node = createNodeDraft(x1, 2, x1.next_holder, {
shortName: x1.orgChild1.orgChild1ShortName,
name: x1.orgChild1.orgChild1Name,
id: x1.orgChild1.id,
});
child1Node.children = childLevel2;
childLevel1.push(child1Node);
});
// Root Level 1
const rootNode = createNodeDraft(x0, 1, x0.next_holder, {
shortName: x0.orgRoot.orgRootShortName,
name: x0.orgRoot.orgRootName,
id: x0.orgRoot.id,
});
rootNode.children = childLevel1;
return rootNode;
});
const formattedData_ = {
personID: "",
name: "",
avatar: "",
positionName: "",
positionNum: "",
positionNumInt: null,
departmentName: data.orgRevisionName,
organizationId: data.id,
children: formattedData,
};
return new HttpSuccess([formattedData_]);
} else {
return new HttpSuccess([
{
personID: "",
name: "",
avatar: "",
positionName: "",
positionNum: "",
positionNumInt: null,
departmentName: data.orgRevisionName,
organizationId: data.id,
children: [],
},
]);
}
}
/**
* API Organizational Chart
*
* @summary Organizational Chart
*
* @param {string} revisionId Id revison
*/
@Get("org-chart/{revisionId}/{rootId}")
async orgChartByRoot(@Path() revisionId: string, @Path() rootId: string) {
// get revision data
const data = await this.orgRevisionRepository.findOne({ where: { id: revisionId } });
if (!data) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้าง");
}
type OrgInfo = { shortName: string; name: string; id: string };
let fieldId: "current_holderId" | "next_holderId" = "current_holderId";
let relations: string[] =
rootId === "root"
? ["current_holder", "orgRoot"]
: ["current_holder", "orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"];
if (data.orgRevisionIsCurrent === false && data.orgRevisionIsDraft === true) {
fieldId = "next_holderId";
relations =
rootId === "root"
? ["next_holder", "orgRoot"]
: ["next_holder", "orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"];
}
const where =
rootId === "root"
? { orgRevisionId: data.id, posMasterNo: 1 }
: { orgRevisionId: data.id, orgRootId: rootId };
const allPosMasters = await this.posMasterRepository.find({
where,
relations,
order: {
orgRoot: { orgRootOrder: "ASC" },
posMasterOrder: "ASC",
posMasterNo: "ASC",
},
});
// Split positions by level
const posMasterRoot = allPosMasters.filter((item) => item.orgChild1Id === null);
const posMasterChild1 =
rootId !== "root"
? allPosMasters.filter((item) => item.orgChild2Id === null && item.orgChild1Id !== null)
: [];
const posMasterChild2 =
rootId !== "root"
? allPosMasters.filter((item) => item.orgChild3Id === null && item.orgChild2Id !== null)
: [];
const posMasterChild3 =
rootId !== "root"
? allPosMasters.filter((item) => item.orgChild4Id === null && item.orgChild3Id !== null)
: [];
const posMasterChild4 =
rootId !== "root" ? allPosMasters.filter((item) => item.orgChild4Id !== null) : [];
// Find the minimum posMasterNo for each orgRootId
const minPosMasterNoByOrgRootId = new Map<string, number>();
posMasterRoot.forEach((x) => {
const orgRootId = x.orgRootId ?? "";
const currentMin = minPosMasterNoByOrgRootId.get(orgRootId);
if (
(currentMin === undefined || x.posMasterNo < currentMin) &&
(x as any)[fieldId] != null &&
x.isDirector
) {
minPosMasterNoByOrgRootId.set(orgRootId, x.posMasterNo);
}
});
// Utility to group by key
function groupBy<T>(
arr: T[],
keyFn: (item: T) => string | number | undefined | null,
): Map<string, T[]> {
const map = new Map<string, T[]>();
for (const item of arr) {
let key = keyFn(item);
if (key === undefined || key === null) key = "";
key = String(key);
if (!map.has(key)) map.set(key, []);
map.get(key)!.push(item);
}
return map;
}
// Build lookup maps
const rootByOrgRootId = groupBy(
posMasterRoot.filter(
(item) =>
((item as any)[fieldId] && !item.isDirector) ||
(item.isDirector &&
minPosMasterNoByOrgRootId.get(item.orgRootId ?? "") !== item.posMasterNo),
),
(item) => item.orgRootId ?? "",
);
const child1ByOrgRootId = groupBy(
posMasterChild1.filter((item) => item.isDirector),
(item) => item.orgRootId ?? "",
);
const child1ByOrgChild1Id = groupBy(
posMasterChild1.filter((item) => (item as any)[fieldId] && !item.isDirector),
(item) => item.orgChild1Id ?? "",
);
const child2ByOrgChild1Id = groupBy(
posMasterChild2.filter((item) => item.isDirector),
(item) => item.orgChild1Id ?? "",
);
const child2ByOrgChild2Id = groupBy(
posMasterChild2.filter((item) => (item as any)[fieldId] && !item.isDirector),
(item) => item.orgChild2Id ?? "",
);
const child3ByOrgChild2Id = groupBy(
posMasterChild3.filter((item) => item.isDirector),
(item) => item.orgChild2Id ?? "",
);
const child3ByOrgChild3Id = groupBy(
posMasterChild3.filter((item) => (item as any)[fieldId] && !item.isDirector),
(item) => item.orgChild3Id ?? "",
);
const child4ByOrgChild3Id = groupBy(
posMasterChild4.filter((item) => item.isDirector),
(item) => item.orgChild3Id ?? "",
);
// Helper to create node
function createNode(item: any, level: number, orgInfo: OrgInfo): any {
const holder = fieldId === "current_holderId" ? item.current_holder : item.next_holder;
return {
level,
personID: holder?.id ?? "",
name: holder ? `${holder.firstName} ${holder.lastName}` : "ว่าง",
avatar:
holder?.avatar && holder?.avatarName ? `${holder.avatar}/${holder.avatarName}` : null,
positionName: holder?.position ?? "",
positionNum: `${orgInfo.shortName} ${item.posMasterNo}`,
positionNumInt: item.posMasterNo,
departmentName: orgInfo.name,
organizationId: orgInfo.id,
children: [],
};
}
// Recursive builder for children
function buildChildren(level: number, parent: any, orgInfo: OrgInfo): any[] {
if (level === 2) {
// Level 2: child1 non-directors and child2 directors
const children: any[] = [];
// Root non-directors
(
rootByOrgRootId
.get(parent.orgRootId)
?.filter(
(x00) =>
!x00.isDirector ||
(x00.isDirector &&
minPosMasterNoByOrgRootId.get(x00.orgRootId ?? "") !== x00.posMasterNo),
) || []
).forEach((x00) => {
children.push(
createNode(x00, 2, {
shortName: x00.orgRoot.orgRootShortName,
name: x00.orgRoot.orgRootName,
id: x00.orgRoot.id,
}),
);
});
if (rootId !== "root") {
// Child1 directors
(child1ByOrgRootId.get(parent.orgRootId) || []).forEach((x1) => {
const childLevel2 = buildChildren(3, x1, {
shortName: x1.orgChild1.orgChild1ShortName,
name: x1.orgChild1.orgChild1Name,
id: x1.orgChild1.id,
});
const node = createNode(x1, 2, {
shortName: x1.orgChild1.orgChild1ShortName,
name: x1.orgChild1.orgChild1Name,
id: x1.orgChild1.id,
});
node.children = childLevel2;
children.push(node);
});
}
return children;
} else if (level === 3) {
// Level 3: child1 non-directors and child2 directors
const children: any[] = [];
(child1ByOrgChild1Id.get(parent.orgChild1Id) || []).forEach((x11) => {
children.push(
createNode(x11, 3, {
shortName: x11.orgChild1.orgChild1ShortName,
name: x11.orgChild1.orgChild1Name,
id: x11.orgChild1.id,
}),
);
});
(child2ByOrgChild1Id.get(parent.orgChild1Id) || []).forEach((x2) => {
const childLevel3 = buildChildren(4, x2, {
shortName: x2.orgChild2.orgChild2ShortName,
name: x2.orgChild2.orgChild2Name,
id: x2.orgChild2.id,
});
const node = createNode(x2, 3, {
shortName: x2.orgChild2.orgChild2ShortName,
name: x2.orgChild2.orgChild2Name,
id: x2.orgChild2.id,
});
node.children = childLevel3;
children.push(node);
});
return children;
} else if (level === 4) {
// Level 4: child2 non-directors and child3 directors
const children: any[] = [];
(child2ByOrgChild2Id.get(parent.orgChild2Id) || []).forEach((x22) => {
children.push(
createNode(x22, 4, {
shortName: x22.orgChild2.orgChild2ShortName,
name: x22.orgChild2.orgChild2Name,
id: x22.orgChild2.id,
}),
);
});
(child3ByOrgChild2Id.get(parent.orgChild2Id) || []).forEach((x3) => {
const childLevel4 = buildChildren(5, x3, {
shortName: x3.orgChild3.orgChild3ShortName,
name: x3.orgChild3.orgChild3Name,
id: x3.orgChild3.id,
});
const node = createNode(x3, 4, {
shortName: x3.orgChild3.orgChild3ShortName,
name: x3.orgChild3.orgChild3Name,
id: x3.orgChild3.id,
});
node.children = childLevel4;
children.push(node);
});
return children;
} else if (level === 5) {
// Level 5: child3 non-directors and child4 directors
const children: any[] = [];
(child3ByOrgChild3Id.get(parent.orgChild3Id) || []).forEach((x33) => {
children.push(
createNode(x33, 5, {
shortName: x33.orgChild3.orgChild3ShortName,
name: x33.orgChild3.orgChild3Name,
id: x33.orgChild3.id,
}),
);
});
(child4ByOrgChild3Id.get(parent.orgChild3Id) || []).forEach((x4) => {
// Level 5: child4 directors and their non-directors
const childLevel5: any[] = [];
posMasterChild4
.filter((x) => !x.isDirector && (x as any)[fieldId] && x.orgChild3Id === x4.orgChild3Id)
.forEach((x44) => {
childLevel5.push(
createNode(x44, 5, {
shortName: x44.orgChild4.orgChild4ShortName,
name: x44.orgChild4.orgChild4Name,
id: x44.orgChild4.id,
}),
);
});
const node = createNode(x4, 4, {
shortName: x4.orgChild4.orgChild4ShortName,
name: x4.orgChild4.orgChild4Name,
id: x4.orgChild4.id,
});
node.children = childLevel5;
children.push(node);
});
return children;
}
return [];
}
// Build root nodes
const formattedData = posMasterRoot
.filter(
(x: any) =>
x.isDirector && minPosMasterNoByOrgRootId.get(x.orgRootId ?? "") === x.posMasterNo,
)
.map((x0) => {
const rootNode = createNode(x0, 1, {
shortName: x0.orgRoot.orgRootShortName,
name: x0.orgRoot.orgRootName,
id: x0.orgRoot.id,
});
rootNode.children = buildChildren(2, x0, {
shortName: x0.orgRoot.orgRootShortName,
name: x0.orgRoot.orgRootName,
id: x0.orgRoot.id,
});
return rootNode;
});
const formattedData_ =
rootId === "root"
? [
{
personID: "",
name: "",
avatar: "",
positionName: "",
positionNum: "",
positionNumInt: null,
departmentName: data.orgRevisionName,
organizationId: data.id,
children: formattedData,
},
]
: formattedData;
return new HttpSuccess(formattedData_);
}
// /**
// * API Organizational StructChart
// *
// * @summary Organizational StructChart
// *
// */
// @Get("struct-chart/{idNode}/{type}")
// async structchart(@Path() idNode: string, type: number) {
// switch (type) {
// case 0: {
// const data = await this.orgRevisionRepository.findOne({
// where: { id: idNode },
// relations: [
// "orgRoots",
// "orgRoots.orgChild1s",
// "orgRoots.orgChild1s.orgChild2s",
// "orgRoots.orgChild1s.orgChild2s.orgChild3s",
// "orgRoots.orgChild1s.orgChild2s.orgChild3s.orgChild4s",
// ],
// });
// if (!data) {
// throw new HttpError(HttpStatusCode.NOT_FOUND, "not found revision");
// }
// const formattedData = {
// departmentName: data.orgRevisionName,
// deptID: data.id,
// type: 0,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgRevisionId: data.id },
// }),
// totalPositionVacant:
// data.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// data.orgRoots
// .sort((a, b) => a.orgRootOrder - b.orgRootOrder)
// .map(async (orgRoot: OrgRoot) => {
// return {
// departmentName: orgRoot.orgRootName,
// deptID: orgRoot.id,
// type: 1,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgRevisionId: data.id, orgRootId: orgRoot.id },
// }),
// totalPositionVacant:
// data.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgRoot.orgChild1s
// .sort((a, b) => a.orgChild1Order - b.orgChild1Order)
// .map(async (orgChild1) => ({
// departmentName: orgChild1.orgChild1Name,
// deptID: orgChild1.id,
// type: 2,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// },
// }),
// totalPositionVacant:
// data.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // orgChild1Id: orgChild1.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // orgChild1Id: orgChild1.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgChild1.orgChild2s
// .sort((a, b) => a.orgChild2Order - b.orgChild2Order)
// .map(async (orgChild2) => ({
// departmentName: orgChild2.orgChild2Name,
// deptID: orgChild2.id,
// type: 3,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// },
// }),
// totalPositionVacant:
// data.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgChild2.orgChild3s
// .sort((a, b) => a.orgChild3Order - b.orgChild3Order)
// .map(async (orgChild3) => ({
// departmentName: orgChild3.orgChild3Name,
// deptID: orgChild3.id,
// type: 4,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// },
// }),
// totalPositionVacant:
// data.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant:
// // await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count(
// // {
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // next_holderId: IsNull() || "",
// // },
// // },
// // ),
// children: await Promise.all(
// orgChild3.orgChild4s
// .sort((a, b) => a.orgChild4Order - b.orgChild4Order)
// .map(async (orgChild4) => ({
// departmentName: orgChild4.orgChild4Name,
// deptID: orgChild4.id,
// type: 5,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// },
// }),
// totalPositionVacant:
// data.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant:
// // await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // orgChild4Id: orgChild4.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant:
// // await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgRootId: orgRoot.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // orgChild4Id: orgChild4.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// })),
// ),
// })),
// ),
// })),
// ),
// })),
// ),
// };
// }),
// ),
// };
// return new HttpSuccess([formattedData]);
// }
// case 1: {
// const data = await this.orgRootRepository.findOne({
// where: { id: idNode },
// relations: [
// "orgRevision",
// "orgChild1s",
// "orgChild1s.orgChild2s",
// "orgChild1s.orgChild2s.orgChild3s",
// "orgChild1s.orgChild2s.orgChild3s.orgChild4s",
// ],
// });
// if (!data) {
// throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId");
// }
// const formattedData = {
// departmentName: data.orgRootName,
// deptID: data.id,
// type: 1,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgRootId: data.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// data.orgChild1s
// .sort((a, b) => a.orgChild1Order - b.orgChild1Order)
// .map(async (orgChild1) => ({
// departmentName: orgChild1.orgChild1Name,
// deptID: orgChild1.id,
// type: 2,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgRootId: data.id, orgChild1Id: orgChild1.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // orgChild1Id: orgChild1.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // orgChild1Id: orgChild1.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgChild1.orgChild2s
// .sort((a, b) => a.orgChild2Order - b.orgChild2Order)
// .map(async (orgChild2) => ({
// departmentName: orgChild2.orgChild2Name,
// deptID: orgChild2.id,
// type: 3,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// },
// }),
// totalPositionCurrentVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgChild2.orgChild3s
// .sort((a, b) => a.orgChild3Order - b.orgChild3Order)
// .map(async (orgChild3) => ({
// departmentName: orgChild3.orgChild3Name,
// deptID: orgChild3.id,
// type: 4,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgChild3.orgChild4s
// .sort((a, b) => a.orgChild4Order - b.orgChild4Order)
// .map(async (orgChild4) => ({
// departmentName: orgChild4.orgChild4Name,
// deptID: orgChild4.id,
// type: 5,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRootId: data.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant:
// // await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // orgChild4Id: orgChild4.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRootId: data.id,
// // orgChild1Id: orgChild1.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // orgChild4Id: orgChild4.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// })),
// ),
// })),
// ),
// })),
// ),
// })),
// ),
// };
// return new HttpSuccess([formattedData]);
// }
// case 2: {
// const data = await this.child1Repository.findOne({
// where: { id: idNode },
// relations: [
// "orgRevision",
// "orgChild2s",
// "orgChild2s.orgChild3s",
// "orgChild2s.orgChild3s.orgChild4s",
// ],
// });
// if (!data) {
// throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1Id");
// }
// const formattedData = {
// departmentName: data.orgChild1Name,
// deptID: data.id,
// type: 2,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgChild1Id: data.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgChild1Id: data.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgChild1Id: data.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild1Id: data.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild1Id: data.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// data.orgChild2s
// .sort((a, b) => a.orgChild2Order - b.orgChild2Order)
// .map(async (orgChild2) => ({
// departmentName: orgChild2.orgChild2Name,
// deptID: orgChild2.id,
// type: 3,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgChild1Id: data.id, orgChild2Id: orgChild2.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgChild1Id: data.id,
// orgChild2Id: orgChild2.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgChild1Id: data.id,
// orgChild2Id: orgChild2.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild1Id: data.id,
// // orgChild2Id: orgChild2.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild1Id: data.id,
// // orgChild2Id: orgChild2.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgChild2.orgChild3s
// .sort((a, b) => a.orgChild3Order - b.orgChild3Order)
// .map(async (orgChild3) => ({
// departmentName: orgChild3.orgChild3Name,
// deptID: orgChild3.id,
// type: 4,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgChild3.orgChild4s
// .sort((a, b) => a.orgChild4Order - b.orgChild4Order)
// .map(async (orgChild4) => ({
// departmentName: orgChild4.orgChild4Name,
// deptID: orgChild4.id,
// type: 5,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgRevisionId: data.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // orgChild4Id: orgChild4.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgRevisionId: data.id,
// // orgChild2Id: orgChild2.id,
// // orgChild3Id: orgChild3.id,
// // orgChild4Id: orgChild4.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// })),
// ),
// })),
// ),
// })),
// ),
// };
// return new HttpSuccess([formattedData]);
// }
// case 3: {
// const data = await this.child2Repository.findOne({
// where: { id: idNode },
// relations: ["orgRevision", "orgChild3s", "orgChild3s.orgChild4s"],
// });
// if (!data) {
// throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2Id");
// }
// const formattedData = {
// departmentName: data.orgChild2Name,
// deptID: data.id,
// type: 3,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgChild2Id: data.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgChild2Id: data.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgChild2Id: data.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild2Id: data.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild2Id: data.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// data.orgChild3s
// .sort((a, b) => a.orgChild3Order - b.orgChild3Order)
// .map(async (orgChild3) => ({
// departmentName: orgChild3.orgChild3Name,
// deptID: orgChild3.id,
// type: 4,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgChild2Id: data.id, orgChild3Id: orgChild3.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgChild2Id: data.id,
// orgChild3Id: orgChild3.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgChild2Id: data.id,
// orgChild3Id: orgChild3.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild2Id: data.id,
// // orgChild3Id: orgChild3.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild2Id: data.id,
// // orgChild3Id: orgChild3.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// orgChild3.orgChild4s
// .sort((a, b) => a.orgChild4Order - b.orgChild4Order)
// .map(async (orgChild4) => ({
// departmentName: orgChild4.orgChild4Name,
// deptID: orgChild4.id,
// type: 5,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: {
// orgChild2Id: data.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgChild2Id: data.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgChild2Id: data.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild2Id: data.id,
// // orgChild3Id: orgChild3.id,
// // orgChild4Id: orgChild4.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild2Id: data.id,
// // orgChild3Id: orgChild3.id,
// // orgChild4Id: orgChild4.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// })),
// ),
// })),
// ),
// };
// return new HttpSuccess([formattedData]);
// }
// case 4: {
// const data = await this.child3Repository.findOne({
// where: { id: idNode },
// relations: ["orgRevision", "orgChild4s"],
// });
// if (!data) {
// throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child3Id");
// }
// const formattedData = {
// departmentName: data.orgChild3Name,
// deptID: data.id,
// type: 4,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgChild3Id: data.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgChild3Id: data.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgChild3Id: data.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild3Id: data.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild3Id: data.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// children: await Promise.all(
// data.orgChild4s
// .sort((a, b) => a.orgChild4Order - b.orgChild4Order)
// .map(async (orgChild4) => ({
// departmentName: orgChild4.orgChild4Name,
// deptID: orgChild4.id,
// type: 5,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgChild3Id: data.id, orgChild4Id: orgChild4.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgChild3Id: data.id,
// orgChild4Id: orgChild4.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgChild3Id: data.id,
// orgChild4Id: orgChild4.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild3Id: data.id,
// // orgChild4Id: orgChild4.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild3Id: data.id,
// // orgChild4Id: orgChild4.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// })),
// ),
// };
// return new HttpSuccess([formattedData]);
// }
// case 5: {
// const data = await this.child4Repository.findOne({
// where: { id: idNode },
// relations: ["orgRevision"],
// });
// if (!data) {
// throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child4Id");
// }
// const formattedData = {
// departmentName: data.orgChild4Name,
// deptID: data.id,
// type: 5,
// // heads:
// totalPositionCount: await this.posMasterRepository.count({
// where: { orgChild4Id: data.id },
// }),
// totalPositionVacant:
// data.orgRevision.orgRevisionIsDraft == true
// ? await this.posMasterRepository.count({
// where: {
// orgChild4Id: data.id,
// next_holderId: IsNull() || "",
// },
// })
// : await this.posMasterRepository.count({
// where: {
// orgChild4Id: data.id,
// current_holderId: IsNull() || "",
// },
// }),
// // totalPositionCurrentVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild4Id: data.id,
// // current_holderId: IsNull() || "",
// // },
// // }),
// // totalPositionNextVacant: await this.posMasterRepository.count({
// // where: {
// // orgChild4Id: data.id,
// // next_holderId: IsNull() || "",
// // },
// // }),
// };
// return new HttpSuccess([formattedData]);
// }
// default:
// throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: ");
// }
// }
/**
* API Organizational StructChart V2 (Optimized)
*
* @summary Organizational StructChart - Optimized with batch queries to prevent N+1 problem
*
*/
@Get("struct-chart/{idNode}/{type}")
async structchartV2(@Path() idNode: string, type: number) {
// Fetch orgRevisionId and isDraft status first
let orgRevisionId: string | null = null;
let isDraft = false;
switch (type) {
case 0:
const revision = await this.orgRevisionRepository.findOne({ where: { id: idNode } });
orgRevisionId = revision?.id || null;
isDraft = revision?.orgRevisionIsDraft || false;
break;
case 1: {
const root = await this.orgRootRepository.findOne({
where: { id: idNode },
relations: ["orgRevision"],
});
orgRevisionId = root?.orgRevision?.id || null;
isDraft = root?.orgRevision?.orgRevisionIsDraft || false;
break;
}
case 2: {
const child1 = await this.child1Repository.findOne({
where: { id: idNode },
relations: ["orgRevision"],
});
orgRevisionId = child1?.orgRevision?.id || null;
isDraft = child1?.orgRevision?.orgRevisionIsDraft || false;
break;
}
case 3: {
const child2 = await this.child2Repository.findOne({
where: { id: idNode },
relations: ["orgRevision"],
});
orgRevisionId = child2?.orgRevision?.id || null;
isDraft = child2?.orgRevision?.orgRevisionIsDraft || false;
break;
}
case 4: {
const child3 = await this.child3Repository.findOne({
where: { id: idNode },
relations: ["orgRevision"],
});
orgRevisionId = child3?.orgRevision?.id || null;
isDraft = child3?.orgRevision?.orgRevisionIsDraft || false;
break;
}
case 5: {
const child4 = await this.child4Repository.findOne({
where: { id: idNode },
relations: ["orgRevision"],
});
orgRevisionId = child4?.orgRevision?.id || null;
isDraft = child4?.orgRevision?.orgRevisionIsDraft || false;
break;
}
default:
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: ");
}
if (!orgRevisionId) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found revision");
}
// Fetch all position counts in a single batch query (optimized)
const positionCounts = await getPositionCountsAggregated(orgRevisionId);
switch (type) {
case 0: {
const data = await this.orgRevisionRepository.findOne({
where: { id: idNode },
relations: [
"orgRoots",
"orgRoots.orgChild1s",
"orgRoots.orgChild1s.orgChild2s",
"orgRoots.orgChild1s.orgChild2s.orgChild3s",
"orgRoots.orgChild1s.orgChild2s.orgChild3s.orgChild4s",
],
});
if (!data) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found revision");
}
const formattedData = {
departmentName: data.orgRevisionName,
deptID: data.id,
type: 0,
totalPositionCount: this.sumAllCounts(positionCounts.orgRootMap),
totalPositionVacant: this.sumAllVacantCounts(positionCounts.orgRootMap, isDraft),
children: this.buildOrgRoots(data.orgRoots, positionCounts, isDraft),
};
return new HttpSuccess([formattedData]);
}
case 1: {
const data = await this.orgRootRepository.findOne({
where: { id: idNode },
relations: [
"orgRevision",
"orgChild1s",
"orgChild1s.orgChild2s",
"orgChild1s.orgChild2s.orgChild3s",
"orgChild1s.orgChild2s.orgChild3s.orgChild4s",
],
});
if (!data) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId");
}
const rootCounts = getPositionCount(positionCounts.orgRootMap, data.id);
const formattedData = {
departmentName: data.orgRootName,
deptID: data.id,
type: 1,
totalPositionCount: rootCounts.totalCount,
totalPositionVacant: isDraft ? rootCounts.nextVacantCount : rootCounts.currentVacantCount,
children: this.buildOrgChild1s(data.orgChild1s, positionCounts, isDraft),
};
return new HttpSuccess([formattedData]);
}
case 2: {
const data = await this.child1Repository.findOne({
where: { id: idNode },
relations: [
"orgRevision",
"orgChild2s",
"orgChild2s.orgChild3s",
"orgChild2s.orgChild3s.orgChild4s",
],
});
if (!data) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1Id");
}
const child1Counts = getPositionCount(positionCounts.orgChild1Map, data.id);
const formattedData = {
departmentName: data.orgChild1Name,
deptID: data.id,
type: 2,
totalPositionCount: child1Counts.totalCount,
totalPositionVacant: isDraft
? child1Counts.nextVacantCount
: child1Counts.currentVacantCount,
children: this.buildOrgChild2s(data.orgChild2s, positionCounts, isDraft),
};
return new HttpSuccess([formattedData]);
}
case 3: {
const data = await this.child2Repository.findOne({
where: { id: idNode },
relations: ["orgRevision", "orgChild3s", "orgChild3s.orgChild4s"],
});
if (!data) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2Id");
}
const child2Counts = getPositionCount(positionCounts.orgChild2Map, data.id);
const formattedData = {
departmentName: data.orgChild2Name,
deptID: data.id,
type: 3,
totalPositionCount: child2Counts.totalCount,
totalPositionVacant: isDraft
? child2Counts.nextVacantCount
: child2Counts.currentVacantCount,
children: this.buildOrgChild3s(data.orgChild3s, positionCounts, isDraft),
};
return new HttpSuccess([formattedData]);
}
case 4: {
const data = await this.child3Repository.findOne({
where: { id: idNode },
relations: ["orgRevision", "orgChild4s"],
});
if (!data) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child3Id");
}
const child3Counts = getPositionCount(positionCounts.orgChild3Map, data.id);
const formattedData = {
departmentName: data.orgChild3Name,
deptID: data.id,
type: 4,
totalPositionCount: child3Counts.totalCount,
totalPositionVacant: isDraft
? child3Counts.nextVacantCount
: child3Counts.currentVacantCount,
children: this.buildOrgChild4s(data.orgChild4s, positionCounts, isDraft),
};
return new HttpSuccess([formattedData]);
}
case 5: {
const data = await this.child4Repository.findOne({
where: { id: idNode },
relations: ["orgRevision"],
});
if (!data) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child4Id");
}
const child4Counts = getPositionCount(positionCounts.orgChild4Map, data.id);
const formattedData = {
departmentName: data.orgChild4Name,
deptID: data.id,
type: 5,
totalPositionCount: child4Counts.totalCount,
totalPositionVacant: isDraft
? child4Counts.nextVacantCount
: child4Counts.currentVacantCount,
};
return new HttpSuccess([formattedData]);
}
default:
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: ");
}
}
/**
* API เช็ค node
*
* @summary เช็ค node (ADMIN)
*
*/
@Post("find/node")
async findNodeAll(@Body() requestBody: { node: number; nodeId: string }) {
switch (requestBody.node) {
case 0: {
const data = await this.orgRootRepository.findOne({
where: { id: requestBody.nodeId },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId.");
}
return new HttpSuccess([data.id]);
}
case 1: {
const data = await this.child1Repository.findOne({
where: { id: requestBody.nodeId },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1.");
}
return new HttpSuccess([data.orgRootId, data.id]);
}
case 2: {
const data = await this.child2Repository.findOne({
where: { id: requestBody.nodeId },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2.");
}
return new HttpSuccess([data.orgRootId, data.orgChild1Id, data.id]);
}
case 3: {
const data = await this.child3Repository.findOne({
where: { id: requestBody.nodeId },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child3.");
}
return new HttpSuccess([data.orgRootId, data.orgChild1Id, data.orgChild2Id, data.id]);
}
case 4: {
const data = await this.child4Repository.findOne({
where: { id: requestBody.nodeId },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child4.");
}
return new HttpSuccess([
data.orgRootId,
data.orgChild1Id,
data.orgChild2Id,
data.orgChild3Id,
data.id,
]);
}
default:
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: " + requestBody.node);
}
}
/**
* API เช็ค node
*
* @summary เช็ค node (ADMIN)
*
*/
@Post("find/node-all")
async findNodeAllOrg(@Body() requestBody: { node: number | null; nodeId: string | null }) {
let orgRootRankSub1 = ["BUREAU", "OFFICE"];
let orgRootRankSub2 = ["DISTRICT"];
let data1: any;
let data2: any;
switch (requestBody.node) {
case 0: {
const _data1 = await this.orgRootRepository.find({
where: {
id: requestBody.nodeId ?? "",
orgRootRankSub: In(orgRootRankSub1),
},
order: { orgRootOrder: "ASC" },
});
const _data2 = await this.orgRootRepository.find({
where: [
{
id: requestBody.nodeId ?? "",
orgRootRankSub: In(orgRootRankSub2),
},
{
id: requestBody.nodeId ?? "",
orgRootRankSub: IsNull(),
},
],
order: { orgRootOrder: "ASC" },
});
data1 = _data1.map((y) => ({
name: y.orgRootName,
rootId: y.id,
rootDnaId: y.ancestorDNA,
child1Id: null,
child1DnaId: null,
child2Id: null,
child2DnaId: null,
child3Id: null,
child3DnaId: null,
child4Id: null,
child4DnaId: null,
}));
data2 = _data2.map((y) => ({
name: y.orgRootName,
rootId: y.id,
rootDnaId: y.ancestorDNA,
child1Id: null,
child1DnaId: null,
child2Id: null,
child2DnaId: null,
child3Id: null,
child3DnaId: null,
child4Id: null,
child4DnaId: null,
}));
break;
}
case 1: {
const _data1 = await this.child1Repository.find({
where: {
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: In(orgRootRankSub1),
},
},
order: {
orgRoot: { orgRootOrder: "ASC" },
},
relations: ["orgRoot"],
});
const _data2 = await this.child1Repository.find({
where: [
{
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: In(orgRootRankSub2),
},
},
{
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: IsNull(),
},
},
],
order: {
orgRoot: { orgRootOrder: "ASC" },
},
relations: ["orgRoot"],
});
data1 = _data1.map((y) => ({
name: y.orgRoot.orgRootName,
rootId: y.orgRoot.id,
rootDnaId: y.orgRoot.ancestorDNA,
child1Id: y.id,
child1DnaId: y.ancestorDNA,
child2Id: null,
child2DnaId: null,
child3Id: null,
child3DnaId: null,
child4Id: null,
child4DnaId: null,
}));
data2 = _data2.map((y) => ({
name: y.orgRoot.orgRootName,
rootId: y.orgRoot.id,
rootDnaId: y.orgRoot.ancestorDNA,
child1Id: y.id,
child1DnaId: y.ancestorDNA,
child2Id: null,
child2DnaId: null,
child3Id: null,
child3DnaId: null,
child4Id: null,
child4DnaId: null,
}));
break;
}
case 2: {
const _data1 = await this.child2Repository.find({
where: {
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: In(orgRootRankSub1),
},
},
order: {
orgRoot: { orgRootOrder: "ASC" },
},
relations: ["orgRoot", "orgChild1"],
});
const _data2 = await this.child2Repository.find({
where: [
{
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: In(orgRootRankSub2),
},
},
{
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: IsNull(),
},
},
],
order: {
orgRoot: { orgRootOrder: "ASC" },
},
relations: ["orgRoot", "orgChild1"],
});
data1 = _data1.map((y) => ({
name: y.orgRoot.orgRootName,
rootId: y.orgRoot.id,
rootDnaId: y.orgRoot.ancestorDNA,
child1Id: y.orgChild1.id,
child1DnaId: y.orgChild1.ancestorDNA,
child2Id: y.id,
child2DnaId: y.ancestorDNA,
child3Id: null,
child3DnaId: null,
child4Id: null,
child4DnaId: null,
}));
data2 = _data2.map((y) => ({
name: y.orgRoot.orgRootName,
rootId: y.orgRoot.id,
rootDnaId: y.orgRoot.ancestorDNA,
child1Id: y.orgChild1.id,
child1DnaId: y.orgChild1.ancestorDNA,
child2Id: y.id,
child2DnaId: y.ancestorDNA,
child3Id: null,
child3DnaId: null,
child4Id: null,
child4DnaId: null,
}));
break;
}
case 3: {
const _data1 = await this.child3Repository.find({
where: {
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: In(orgRootRankSub1),
},
},
order: {
orgRoot: { orgRootOrder: "ASC" },
},
relations: ["orgRoot", "orgChild1", "orgChild2"],
});
const _data2 = await this.child3Repository.find({
where: [
{
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: In(orgRootRankSub2),
},
},
{
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: IsNull(),
},
},
],
order: {
orgRoot: { orgRootOrder: "ASC" },
},
relations: ["orgRoot", "orgChild1", "orgChild2"],
});
data1 = _data1.map((y) => ({
name: y.orgRoot.orgRootName,
rootId: y.orgRoot.id,
rootDnaId: y.orgRoot.ancestorDNA,
child1Id: y.orgChild1.id,
child1DnaId: y.orgChild1.ancestorDNA,
child2Id: y.orgChild2.id,
child2DnaId: y.orgChild2.ancestorDNA,
child3Id: y.id,
child3DnaId: y.ancestorDNA,
child4Id: null,
child4DnaId: null,
}));
data2 = _data2.map((y) => ({
name: y.orgRoot.orgRootName,
rootId: y.orgRoot.id,
rootDnaId: y.orgRoot.ancestorDNA,
child1Id: y.orgChild1.id,
child1DnaId: y.orgChild1.ancestorDNA,
child2Id: y.orgChild2.id,
child2DnaId: y.orgChild2.ancestorDNA,
child3Id: y.id,
child3DnaId: y.ancestorDNA,
child4Id: null,
child4DnaId: null,
}));
break;
}
case 4: {
const _data1 = await this.child4Repository.find({
where: {
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: In(orgRootRankSub1),
},
},
order: {
orgRoot: { orgRootOrder: "ASC" },
},
relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3"],
});
const _data2 = await this.child4Repository.find({
where: [
{
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: In(orgRootRankSub2),
},
},
{
id: requestBody.nodeId ?? "",
orgRoot: {
orgRootRankSub: IsNull(),
},
},
],
order: {
orgRoot: { orgRootOrder: "ASC" },
},
relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3"],
});
data1 = _data1.map((y) => ({
name: y.orgRoot.orgRootName,
rootId: y.orgRoot.id,
rootDnaId: y.orgRoot.ancestorDNA,
child1Id: y.orgChild1.id,
child1DnaId: y.orgChild1.ancestorDNA,
child2Id: y.orgChild2.id,
child2DnaId: y.orgChild2.ancestorDNA,
child3Id: y.orgChild3.id,
child3DnaId: y.orgChild3.ancestorDNA,
child4Id: y.id,
child4DnaId: y.ancestorDNA,
}));
data2 = _data2.map((y) => ({
name: y.orgRoot.orgRootName,
rootId: y.orgRoot.id,
rootDnaId: y.orgRoot.ancestorDNA,
child1Id: y.orgChild1.id,
child1DnaId: y.orgChild1.ancestorDNA,
child2Id: y.orgChild2.id,
child2DnaId: y.orgChild2.ancestorDNA,
child3Id: y.orgChild3.id,
child3DnaId: y.orgChild3.ancestorDNA,
child4Id: y.id,
child4DnaId: y.ancestorDNA,
}));
break;
}
default: {
const orgRevision = await this.orgRevisionRepository.findOne({
where: {
orgRevisionIsCurrent: true,
orgRevisionIsDraft: false,
},
});
const _data1 = await this.orgRootRepository.find({
where: {
orgRevisionId: orgRevision?.id,
orgRootRankSub: In(orgRootRankSub1),
},
order: { orgRootOrder: "ASC" },
});
const _data2 = await this.orgRootRepository.find({
where: [
{
orgRevisionId: orgRevision?.id,
orgRootRankSub: In(orgRootRankSub2),
},
{
orgRevisionId: orgRevision?.id,
orgRootRankSub: IsNull(),
},
],
order: { orgRootOrder: "ASC" },
});
data1 = _data1.map((y) => ({
name: y.orgRootName,
rootId: y.id,
rootDnaId: y.ancestorDNA,
child1Id: null,
child2Id: null,
child3Id: null,
child4Id: null,
}));
data2 = _data2.map((y) => ({
name: y.orgRootName,
rootId: y.id,
rootDnaId: y.ancestorDNA,
child1Id: null,
child2Id: null,
child3Id: null,
child4Id: null,
}));
}
}
return new HttpSuccess({ isRootTrue: data1, isRootFalse: data2 });
}
/**
* API เช็ค node detail
*
* @summary เช็ค node detail (ADMIN)
*
*/
@Post("find/all")
async findNodeAllDetail(@Body() requestBody: { node: number; nodeId: string }) {
switch (requestBody.node) {
case 0: {
const data = await this.orgRootRepository.findOne({
where: { id: requestBody.nodeId },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId.");
}
return new HttpSuccess({
rootId: data.id,
rootDnaId: data.ancestorDNA,
root: data.orgRootName,
rootShortName: data.orgRootShortName,
});
}
case 1: {
const data = await this.child1Repository.findOne({
where: { id: requestBody.nodeId },
relations: {
orgRoot: true,
},
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1.");
}
return new HttpSuccess({
rootId: data.orgRootId,
rootDnaId: data.orgRoot == null ? null : data.orgRoot.ancestorDNA,
root: data.orgRoot == null ? null : data.orgRoot.orgRootName,
rootShortName: data.orgRoot == null ? null : data.orgRoot.orgRootShortName,
child1Id: data.id,
child1DnaId: data.ancestorDNA,
child1: data.orgChild1Name,
child1ShortName: data.orgChild1ShortName,
});
}
case 2: {
const data = await this.child2Repository.findOne({
where: { id: requestBody.nodeId },
relations: {
orgRoot: true,
orgChild1: true,
},
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2.");
}
return new HttpSuccess({
rootId: data.orgRootId,
rootDnaId: data.orgRoot == null ? null : data.orgRoot.ancestorDNA,
root: data.orgRoot == null ? null : data.orgRoot.orgRootName,
rootShortName: data.orgRoot == null ? null : data.orgRoot.orgRootShortName,
child1Id: data.orgChild1Id,
child1DnaId: data.orgChild1 == null ? null : data.orgChild1.ancestorDNA,
child1: data.orgChild1 == null ? null : data.orgChild1.orgChild1Name,
child1ShortName: data.orgChild1 == null ? null : data.orgChild1.orgChild1ShortName,
child2Id: data.id,
child2DnaId: data.ancestorDNA,
child2: data.orgChild2Name,
child2ShortName: data.orgChild2ShortName,
});
}
case 3: {
const data = await this.child3Repository.findOne({
where: { id: requestBody.nodeId },
relations: {
orgRoot: true,
orgChild1: true,
orgChild2: true,
},
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child3.");
}
return new HttpSuccess({
rootId: data.orgRootId,
rootDnaId: data.orgRoot == null ? null : data.orgRoot.ancestorDNA,
root: data.orgRoot == null ? null : data.orgRoot.orgRootName,
rootShortName: data.orgRoot == null ? null : data.orgRoot.orgRootShortName,
child1Id: data.orgChild1Id,
child1DnaId: data.orgChild1 == null ? null : data.orgChild1.ancestorDNA,
child1: data.orgChild1 == null ? null : data.orgChild1.orgChild1Name,
child1ShortName: data.orgChild1 == null ? null : data.orgChild1.orgChild1ShortName,
child2Id: data.orgChild2Id,
child2DnaId: data.orgChild2 == null ? null : data.orgChild2.ancestorDNA,
child2: data.orgChild2 == null ? null : data.orgChild2.orgChild2Name,
child2ShortName: data.orgChild2 == null ? null : data.orgChild2.orgChild2ShortName,
child3Id: data.id,
child3DnaId: data.ancestorDNA,
child3: data.orgChild3Name,
child3ShortName: data.orgChild3ShortName,
});
}
case 4: {
const data = await this.child4Repository.findOne({
where: { id: requestBody.nodeId },
relations: {
orgRoot: true,
orgChild1: true,
orgChild2: true,
orgChild3: true,
},
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child4.");
}
return new HttpSuccess({
rootId: data.orgRootId,
rootDnaId: data.orgRoot == null ? null : data.orgRoot.ancestorDNA,
root: data.orgRoot == null ? null : data.orgRoot.orgRootName,
rootShortName: data.orgRoot == null ? null : data.orgRoot.orgRootShortName,
child1Id: data.orgChild1Id,
child1DnaId: data.orgChild1 == null ? null : data.orgChild1.ancestorDNA,
child1: data.orgChild1 == null ? null : data.orgChild1.orgChild1Name,
child1ShortName: data.orgChild1 == null ? null : data.orgChild1.orgChild1ShortName,
child2Id: data.orgChild2Id,
child2DnaId: data.orgChild2 == null ? null : data.orgChild2.ancestorDNA,
child2: data.orgChild2 == null ? null : data.orgChild2.orgChild2Name,
child2ShortName: data.orgChild2 == null ? null : data.orgChild2.orgChild2ShortName,
child3Id: data.orgChild3Id,
child3DnaId: data.orgChild3 == null ? null : data.orgChild3.ancestorDNA,
child3: data.orgChild3 == null ? null : data.orgChild3.orgChild3Name,
child3ShortName: data.orgChild3 == null ? null : data.orgChild3.orgChild3ShortName,
child4Id: data.id,
child4DnaId: data.ancestorDNA,
child4: data.orgChild4Name,
child4ShortName: data.orgChild4ShortName,
});
}
default:
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: " + requestBody.node);
}
}
/**
* API เช็ค node detail
*
* @summary เช็ค node detail (ADMIN)
*
*/
@Post("find/allv2")
async findNodeAllDetailV2(@Body() requestBody: { node: number; nodeId: string }) {
switch (requestBody.node) {
case 0: {
const data = await this.orgRootRepository.findOne({
where: { ancestorDNA: requestBody.nodeId },
order: { createdAt: "DESC" },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId.");
}
return new HttpSuccess({
rootId: data.id,
rootDnaId: data.ancestorDNA,
root: data.orgRootName,
rootShortName: data.orgRootShortName,
});
}
case 1: {
const data = await this.child1Repository.findOne({
where: { ancestorDNA: requestBody.nodeId },
relations: {
orgRoot: true,
},
order: { createdAt: "DESC" },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1.");
}
return new HttpSuccess({
rootId: data.orgRootId,
rootDnaId: data.orgRoot == null ? null : data.orgRoot.ancestorDNA,
root: data.orgRoot == null ? null : data.orgRoot.orgRootName,
rootShortName: data.orgRoot == null ? null : data.orgRoot.orgRootShortName,
child1Id: data.id,
child1DnaId: data.ancestorDNA,
child1: data.orgChild1Name,
child1ShortName: data.orgChild1ShortName,
});
}
case 2: {
const data = await this.child2Repository.findOne({
where: { ancestorDNA: requestBody.nodeId },
relations: {
orgRoot: true,
orgChild1: true,
},
order: { createdAt: "DESC" },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2.");
}
return new HttpSuccess({
rootId: data.orgRootId,
rootDnaId: data.orgRoot == null ? null : data.orgRoot.ancestorDNA,
root: data.orgRoot == null ? null : data.orgRoot.orgRootName,
rootShortName: data.orgRoot == null ? null : data.orgRoot.orgRootShortName,
child1Id: data.orgChild1Id,
child1DnaId: data.orgChild1 == null ? null : data.orgChild1.ancestorDNA,
child1: data.orgChild1 == null ? null : data.orgChild1.orgChild1Name,
child1ShortName: data.orgChild1 == null ? null : data.orgChild1.orgChild1ShortName,
child2Id: data.id,
child2DnaId: data.ancestorDNA,
child2: data.orgChild2Name,
child2ShortName: data.orgChild2ShortName,
});
}
case 3: {
const data = await this.child3Repository.findOne({
where: { ancestorDNA: requestBody.nodeId },
relations: {
orgRoot: true,
orgChild1: true,
orgChild2: true,
},
order: { createdAt: "DESC" },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child3.");
}
return new HttpSuccess({
rootId: data.orgRootId,
rootDnaId: data.orgRoot == null ? null : data.orgRoot.ancestorDNA,
root: data.orgRoot == null ? null : data.orgRoot.orgRootName,
rootShortName: data.orgRoot == null ? null : data.orgRoot.orgRootShortName,
child1Id: data.orgChild1Id,
child1DnaId: data.orgChild1 == null ? null : data.orgChild1.ancestorDNA,
child1: data.orgChild1 == null ? null : data.orgChild1.orgChild1Name,
child1ShortName: data.orgChild1 == null ? null : data.orgChild1.orgChild1ShortName,
child2Id: data.orgChild2Id,
child2DnaId: data.orgChild2 == null ? null : data.orgChild2.ancestorDNA,
child2: data.orgChild2 == null ? null : data.orgChild2.orgChild2Name,
child2ShortName: data.orgChild2 == null ? null : data.orgChild2.orgChild2ShortName,
child3Id: data.id,
child3DnaId: data.ancestorDNA,
child3: data.orgChild3Name,
child3ShortName: data.orgChild3ShortName,
});
}
case 4: {
const data = await this.child4Repository.findOne({
where: { ancestorDNA: requestBody.nodeId },
relations: {
orgRoot: true,
orgChild1: true,
orgChild2: true,
orgChild3: true,
},
order: { createdAt: "DESC" },
});
if (data == null) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child4.");
}
return new HttpSuccess({
rootId: data.orgRootId,
rootDnaId: data.orgRoot == null ? null : data.orgRoot.ancestorDNA,
root: data.orgRoot == null ? null : data.orgRoot.orgRootName,
rootShortName: data.orgRoot == null ? null : data.orgRoot.orgRootShortName,
child1Id: data.orgChild1Id,
child1DnaId: data.orgChild1 == null ? null : data.orgChild1.ancestorDNA,
child1: data.orgChild1 == null ? null : data.orgChild1.orgChild1Name,
child1ShortName: data.orgChild1 == null ? null : data.orgChild1.orgChild1ShortName,
child2Id: data.orgChild2Id,
child2DnaId: data.orgChild2 == null ? null : data.orgChild2.ancestorDNA,
child2: data.orgChild2 == null ? null : data.orgChild2.orgChild2Name,
child2ShortName: data.orgChild2 == null ? null : data.orgChild2.orgChild2ShortName,
child3Id: data.orgChild3Id,
child3DnaId: data.orgChild3 == null ? null : data.orgChild3.ancestorDNA,
child3: data.orgChild3 == null ? null : data.orgChild3.orgChild3Name,
child3ShortName: data.orgChild3 == null ? null : data.orgChild3.orgChild3ShortName,
child4Id: data.id,
child4DnaId: data.ancestorDNA,
child4: data.orgChild4Name,
child4ShortName: data.orgChild4ShortName,
});
}
default:
throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: " + requestBody.node);
}
}
/**
* API หาสำนักทั้งหมด
*
* @summary หาสำนักทั้งหมด
*
*/
@Get("active/root")
async GetActiveRoot() {
const orgRevisionActive = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
});
if (!orgRevisionActive) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่เผยแพร่อยู่ตอนนี้");
}
const data = await this.orgRootRepository.find({
where: { orgRevisionId: orgRevisionActive.id },
relations: [
"orgRevision",
"orgChild1s",
"orgChild1s.orgChild2s",
"orgChild1s.orgChild2s.orgChild3s",
"orgChild1s.orgChild2s.orgChild3s.orgChild4s",
],
order: {
orgChild1s: {
orgChild1Order: "ASC",
orgChild2s: {
orgChild2Order: "ASC",
orgChild3s: {
orgChild3Order: "ASC",
orgChild4s: {
orgChild4Order: "ASC",
},
},
},
},
},
});
return new HttpSuccess(data);
}
/**
* API หาสำนักทั้งหมด
*
* @summary หาสำนักทั้งหมด
*
*/
@Get("active/root/id")
async GetActiveRootId() {
const orgRevisionActive = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
});
if (!orgRevisionActive) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่เผยแพร่อยู่ตอนนี้");
}
const data = await this.orgRootRepository.find({
where: { orgRevisionId: orgRevisionActive.id },
order: {
orgRootOrder: "ASC",
},
});
return new HttpSuccess(data.map((x) => x.id));
}
/**
* API หาสำนักทั้งหมด
*
* @summary หาสำนักทั้งหมด
*
*/
@Get("active/root/all")
async GetActiveRootAll() {
const orgRevisionActive = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
});
if (!orgRevisionActive) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่เผยแพร่อยู่ตอนนี้");
}
const data = await this.orgRootRepository.find({
where: {
orgRevisionId: orgRevisionActive.id,
id: In([
"d7e98989-b5ce-47d6-93c3-ab63ed486348",
"6f9b30e1-757a-40d5-b053-61eb1b91c0f0",
"eaf65f33-25e9-4956-9dba-5d909f5eb595",
"87c5bc89-300c-4b6a-99e4-26371436caa2",
"982d33af-4eb5-4cc8-9c9f-b3ccadbb66d7",
"e0545eca-5d0a-4a1c-8bbd-e3e25c2521db",
]),
},
order: {
orgRootOrder: "ASC",
},
});
return new HttpSuccess(data);
}
/**
* API
*
* @summary
*
*/
@Get("active/root/latest")
async GetActiveRootIdLatest() {
const orgRevisionActive = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
});
if (!orgRevisionActive) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่เผยแพร่อยู่ตอนนี้");
}
return new HttpSuccess(orgRevisionActive.id);
}
/**
* API หาสำนักทั้งหมด by revision
*
* @summary หาสำนักทั้งหมด by revision
*
*/
@Get("active/root/{revisionId}")
async GetActiveRootByRevision(@Path() revisionId: string) {
const rawData = await this.orgRootRepository.find({
where: { orgRevisionId: revisionId },
relations: [
"orgRevision",
"orgChild1s",
"orgChild1s.orgChild2s",
"orgChild1s.orgChild2s.orgChild3s",
"orgChild1s.orgChild2s.orgChild3s.orgChild4s",
],
order: {
orgRootOrder: "ASC",
orgChild1s: {
orgChild1Order: "ASC",
orgChild2s: {
orgChild2Order: "ASC",
orgChild3s: {
orgChild3Order: "ASC",
orgChild4s: {
orgChild4Order: "ASC",
},
},
},
},
},
});
const data = rawData.map((item) => ({
...item,
orgRootCode: item.orgRootCode + "00",
}));
return new HttpSuccess(data);
}
/**
* API หา revision ล่าสุด
*
* @summary หา revision ล่าสุด
*
*/
@Get("revision/latest")
async salaryGen() {
const findRevision = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: true },
});
if (!findRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างล่าสุด");
}
return new HttpSuccess(findRevision.id);
}
/**
* API รายละเอียดโครงสร้าง
*
* @summary รายละเอียดโครงสร้าง (ADMIN)
*
*/
@Get("act/{id}")
async detailAct(@Path() id: string, @Request() request: RequestWithUser) {
let _data: OrgPermissionData = {
root: null,
child1: null,
child2: null,
child3: null,
child4: null,
};
// if (!request.user.role.includes("SUPER_ADMIN")) {
// _data = await new permission().PermissionOrgList(request, "SYS_ACTING");
// }
const _privilege = await new permission().PermissionOrgList(request, "SYS_ACTING");
const orgRevision = await this.orgRevisionRepository.findOne({ where: { id } });
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
}
const attrOwnership = _privilege.root === null ? true : false;
const profile = await this.profileRepo.findOne({
where: { keycloak: request.user.sub },
relations: ["permissionProfiles", "current_holders", "current_holders.posMasterAssigns"],
});
if (!profile) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งานในทะเบียนประวัติ");
}
let profileAssign = profile.current_holders
?.find((x) => x.orgRevisionId === id)
?.posMasterAssigns.find((x) => x.assignId === "SYS_ORG");
if (orgRevision.orgRevisionIsDraft && !orgRevision.orgRevisionIsCurrent && !attrOwnership) {
if (Array.isArray(profile.permissionProfiles) && profile.permissionProfiles.length > 0) {
_data.root = profile.permissionProfiles.map((x) => x.orgRootId);
} else {
return new HttpSuccess({ remark: "", data: [] });
}
}
// กำหนดการเข้าถึงข้อมูลตามสถานะและสิทธิ์
const isCurrentActive = !orgRevision.orgRevisionIsDraft && orgRevision.orgRevisionIsCurrent;
if (isCurrentActive) {
if (profileAssign && _privilege.privilege !== "OWNER" && _privilege.privilege !== "PARENT") {
if (_privilege.privilege == "NORMAL") {
const holder = profile.current_holders.find((x) => x.orgRevisionId === id);
if (!holder) return new HttpSuccess({ remark: "", data: [] });
_data.root = [holder.orgRootId];
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
_data.child3 = [holder.orgChild3Id];
_data.child4 = [holder.orgChild4Id];
} else if (_privilege.privilege == "CHILD" || _privilege.privilege == "BROTHER") {
const holder = profile.current_holders.find((x) => x.orgRevisionId === id);
if (!holder) return new HttpSuccess({ remark: "", data: [] });
_data.root = [holder.orgRootId];
if (_privilege.root && _privilege.child1 === null) {
} else if (_privilege.child1 && _privilege.child2 === null) {
_data.child1 = [holder.orgChild1Id];
} else if (_privilege.child2 && _privilege.child3 === null) {
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
} else if (_privilege.child3 && _privilege.child4 === null) {
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
_data.child3 = [holder.orgChild3Id];
_data.child4 = [holder.orgChild4Id];
}
} else {
_data.root = [profile.current_holders.find((x) => x.orgRevisionId === id)?.orgRootId];
}
} else {
if (!attrOwnership) _data = _privilege;
}
}
const orgDna = await new permission().checkDna(request, request.user.sub);
let level: NodeLevel = resolveNodeLevel(orgDna);
const orgRootData = await AppDataSource.getRepository(OrgRoot)
.createQueryBuilder("orgRoot")
.select([
"orgRoot.id",
"orgRoot.orgRootName",
"orgRoot.orgRootShortName",
"orgRoot.orgRootCode",
"orgRoot.orgRootOrder",
])
.addSelect([
"posMasters.id",
"posMasters.posMasterNo",
"posMasters.orgChild1Id",
"posMasters.isDirector",
])
.addSelect(["current_holder.prefix", "current_holder.firstName", "current_holder.lastName"])
.where("orgRoot.orgRevisionId = :id", { id })
.andWhere(
_data.root != undefined && _data.root != null
? _data.root[0] != null
? `orgRoot.id IN (:...node)`
: `orgRoot.id is null`
: "1=1",
{
node: _data.root,
},
)
.leftJoin("orgRoot.posMasters", "posMasters")
.leftJoin("posMasters.current_holder", "current_holder")
.orderBy("orgRoot.orgRootOrder", "ASC")
.getMany();
const orgRootIds = orgRootData.map((orgRoot) => orgRoot.id) || null;
const orgChild1Data =
orgRootIds && orgRootIds.length > 0
? await AppDataSource.getRepository(OrgChild1)
.createQueryBuilder("orgChild1")
.select([
"orgChild1.id",
"orgChild1.orgRootId",
"orgChild1.orgChild1Name",
"orgChild1.orgChild1ShortName",
"orgChild1.orgChild1Code",
"orgChild1.orgChild1Order",
])
.addSelect([
"posMasters.id",
"posMasters.posMasterNo",
"posMasters.orgChild2Id",
"posMasters.isDirector",
])
.addSelect([
"current_holder.prefix",
"current_holder.firstName",
"current_holder.lastName",
])
.where("orgChild1.orgRootId IN (:...ids)", { ids: orgRootIds })
.andWhere(
_data.child1 != undefined && _data.child1 != null
? _data.child1[0] != null
? `orgChild1.id IN (:...node)`
: `orgChild1.id is null`
: "1=1",
{
node: _data.child1,
},
)
.leftJoin("orgChild1.posMasters", "posMasters")
.leftJoin("posMasters.current_holder", "current_holder")
.orderBy("orgChild1.orgChild1Order", "ASC")
.getMany()
: [];
const orgChild1Ids = orgChild1Data.map((orgChild1) => orgChild1.id) || null;
const orgChild2Data =
orgChild1Ids && orgChild1Ids.length > 0
? await AppDataSource.getRepository(OrgChild2)
.createQueryBuilder("orgChild2")
.select([
"orgChild2.id",
"orgChild2.orgChild1Id",
"orgChild2.orgChild2Name",
"orgChild2.orgChild2ShortName",
"orgChild2.orgChild2Code",
"orgChild2.orgChild2Order",
])
.addSelect([
"posMasters.id",
"posMasters.posMasterNo",
"posMasters.orgChild3Id",
"posMasters.isDirector",
])
.addSelect([
"current_holder.prefix",
"current_holder.firstName",
"current_holder.lastName",
])
.where("orgChild2.orgChild1Id IN (:...ids)", { ids: orgChild1Ids })
.andWhere(
_data.child2 != undefined && _data.child2 != null
? _data.child2[0] != null
? `orgChild2.id IN (:...node)`
: `orgChild2.id is null`
: "1=1",
{
node: _data.child2,
},
)
.leftJoin("orgChild2.posMasters", "posMasters")
.leftJoin("posMasters.current_holder", "current_holder")
.orderBy("orgChild2.orgChild2Order", "ASC")
.getMany()
: [];
const orgChild2Ids = orgChild2Data.map((orgChild2) => orgChild2.id) || null;
const orgChild3Data =
orgChild2Ids && orgChild2Ids.length > 0
? await AppDataSource.getRepository(OrgChild3)
.createQueryBuilder("orgChild3")
.select([
"orgChild3.id",
"orgChild3.orgChild2Id",
"orgChild3.orgChild3Name",
"orgChild3.orgChild3ShortName",
"orgChild3.orgChild3Code",
"orgChild3.orgChild3Order",
])
.addSelect([
"posMasters.id",
"posMasters.posMasterNo",
"posMasters.orgChild4Id",
"posMasters.isDirector",
])
.addSelect([
"current_holder.prefix",
"current_holder.firstName",
"current_holder.lastName",
])
.where("orgChild3.orgChild2Id IN (:...ids)", { ids: orgChild2Ids })
.andWhere(
_data.child3 != undefined && _data.child3 != null
? _data.child3[0] != null
? `orgChild3.id IN (:...node)`
: `orgChild3.id is null`
: "1=1",
{
node: _data.child3,
},
)
.leftJoin("orgChild3.posMasters", "posMasters")
.leftJoin("posMasters.current_holder", "current_holder")
.orderBy("orgChild3.orgChild3Order", "ASC")
.getMany()
: [];
const orgChild3Ids = orgChild3Data.map((orgChild3) => orgChild3.id) || null;
const orgChild4Data =
orgChild3Ids && orgChild3Ids.length > 0
? await AppDataSource.getRepository(OrgChild4)
.createQueryBuilder("orgChild4")
.select([
"orgChild4.id",
"orgChild4.orgChild3Id",
"orgChild4.orgChild4Name",
"orgChild4.orgChild4ShortName",
"orgChild4.orgChild4Code",
"orgChild4.orgChild4Order",
])
.addSelect(["posMasters.id", "posMasters.posMasterNo", "posMasters.isDirector"])
.addSelect([
"current_holder.prefix",
"current_holder.firstName",
"current_holder.lastName",
])
.where("orgChild4.orgChild3Id IN (:...ids)", { ids: orgChild3Ids })
.andWhere(
_data.child4 != undefined && _data.child4 != null
? _data.child4[0] != null
? `orgChild4.id IN (:...node)`
: `orgChild4.id is null`
: "1=1",
{
node: _data.child4,
},
)
.leftJoin("orgChild4.posMasters", "posMasters")
.leftJoin("posMasters.current_holder", "current_holder")
.orderBy("orgChild4.orgChild4Order", "ASC")
.getMany()
: [];
const cannotViewRootPosMaster =
_privilege.privilege === "PARENT" ||
(_privilege.privilege === "BROTHER" && level !== null && level > 1) ||
(_privilege.privilege === "CHILD" && level !== null && level > 0) ||
(_privilege.privilege === "NORMAL" && level !== null && level !== 0);
const cannotViewChild1PosMaster =
(_privilege.privilege === "PARENT" && level !== null && level > 1) ||
(_privilege.privilege === "BROTHER" && level !== null && level > 2) ||
(_privilege.privilege === "CHILD" && level !== null && level > 1) ||
(_privilege.privilege === "NORMAL" && level !== 1);
const cannotViewChild2PosMaster =
(_privilege.privilege === "PARENT" && level !== null && level > 2) ||
(_privilege.privilege === "BROTHER" && level !== null && level > 3) ||
(_privilege.privilege === "CHILD" && level !== null && level > 2) ||
(_privilege.privilege === "NORMAL" && level !== 2);
const cannotViewChild3PosMaster =
(_privilege.privilege === "PARENT" && level !== null && level > 3) ||
(_privilege.privilege === "BROTHER" && level !== null && level > 4) ||
(_privilege.privilege === "CHILD" && level !== null && level > 3) ||
(_privilege.privilege === "NORMAL" && level !== 3);
const cannotViewChild4PosMaster =
(_privilege.privilege === "PARENT" && level !== null && level > 4) ||
(_privilege.privilege === "CHILD" && level !== null && level > 4) ||
(_privilege.privilege === "NORMAL" && level !== 4);
const formattedData = orgRootData.map((orgRoot) => ({
orgTreeId: orgRoot.id,
orgLevel: 0,
orgName: orgRoot.orgRootName,
orgTreeName: orgRoot.orgRootName,
orgTreeShortName: orgRoot.orgRootShortName,
orgTreeCode: orgRoot.orgRootCode,
orgCode: orgRoot.orgRootCode + "00",
orgRootName: orgRoot.orgRootName,
labelName: generateLabelName(
orgRoot.orgRootName,
orgRoot.orgRootCode + "00",
orgRoot.orgRootShortName,
orgRoot.orgRootName,
orgRoot.orgRootCode,
orgRoot.orgRootShortName,
),
posMaster: cannotViewRootPosMaster
? []
: filterPosMasters(orgRoot.posMasters, "orgChild1Id").map((x) =>
formatPosMaster(x, orgRoot.orgRootShortName, orgRoot.id, 0),
),
children: orgChild1Data
.filter((orgChild1) => orgChild1.orgRootId === orgRoot.id)
.map((orgChild1) => ({
orgTreeId: orgChild1.id,
orgRootId: orgRoot.id,
orgLevel: 1,
orgName: `${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild1.orgChild1Name,
orgTreeShortName: orgChild1.orgChild1ShortName,
orgTreeCode: orgChild1.orgChild1Code,
orgCode: orgRoot.orgRootCode + orgChild1.orgChild1Code,
orgRootName: orgRoot.orgRootName,
labelName: generateLabelName(
orgChild1.orgChild1Name,
orgChild1.orgChild1Code,
orgChild1.orgChild1ShortName,
orgRoot.orgRootName,
orgRoot.orgRootCode,
orgRoot.orgRootShortName,
),
posMaster: cannotViewChild1PosMaster
? []
: filterPosMasters(orgChild1.posMasters, "orgChild2Id").map((x) =>
formatPosMaster(x, orgChild1.orgChild1ShortName, orgChild1.id, 1),
),
children: orgChild2Data
.filter((orgChild2) => orgChild2.orgChild1Id === orgChild1.id)
.map((orgChild2) => ({
orgTreeId: orgChild2.id,
orgRootId: orgChild1.id,
orgLevel: 2,
orgName: `${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild2.orgChild2Name,
orgTreeShortName: orgChild2.orgChild2ShortName,
orgTreeCode: orgChild2.orgChild2Code,
orgCode: orgRoot.orgRootCode + orgChild2.orgChild2Code,
orgRootName: orgRoot.orgRootName,
labelName: generateLabelName(
orgChild2.orgChild2Name,
orgChild2.orgChild2Code,
orgChild2.orgChild2ShortName,
orgRoot.orgRootName,
orgRoot.orgRootCode,
orgRoot.orgRootShortName,
[orgChild1.orgChild1Name],
[orgChild1.orgChild1Code],
[orgChild1.orgChild1ShortName],
),
posMaster: cannotViewChild2PosMaster
? []
: filterPosMasters(orgChild2.posMasters, "orgChild3Id").map((x) =>
formatPosMaster(x, orgChild2.orgChild2ShortName, orgChild2.id, 2),
),
children: orgChild3Data
.filter((orgChild3) => orgChild3.orgChild2Id === orgChild2.id)
.map((orgChild3) => ({
orgTreeId: orgChild3.id,
orgRootId: orgChild2.id,
orgLevel: 3,
orgName: `${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild3.orgChild3Name,
orgTreeShortName: orgChild3.orgChild3ShortName,
orgTreeCode: orgChild3.orgChild3Code,
orgCode: orgRoot.orgRootCode + orgChild3.orgChild3Code,
orgRootName: orgRoot.orgRootName,
labelName: generateLabelName(
orgChild3.orgChild3Name,
orgChild3.orgChild3Code,
orgChild3.orgChild3ShortName,
orgRoot.orgRootName,
orgRoot.orgRootCode,
orgRoot.orgRootShortName,
[orgChild2.orgChild2Name, orgChild1.orgChild1Name],
[orgChild2.orgChild2Code, orgChild1.orgChild1Code],
[orgChild2.orgChild2ShortName, orgChild1.orgChild1ShortName],
),
posMaster: cannotViewChild3PosMaster
? []
: filterPosMasters(orgChild3.posMasters, "orgChild4Id").map((x) =>
formatPosMaster(x, orgChild3.orgChild3ShortName, orgChild3.id, 3),
),
children: orgChild4Data
.filter((orgChild4) => orgChild4.orgChild3Id === orgChild3.id)
.map((orgChild4) => ({
orgTreeId: orgChild4.id,
orgRootId: orgChild3.id,
orgLevel: 4,
orgName: `${orgChild4.orgChild4Name}/${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`,
orgTreeName: orgChild4.orgChild4Name,
orgTreeShortName: orgChild4.orgChild4ShortName,
orgTreeCode: orgChild4.orgChild4Code,
orgCode: orgRoot.orgRootCode + orgChild4.orgChild4Code,
orgRootName: orgRoot.orgRootName,
labelName: generateLabelName(
orgChild4.orgChild4Name,
orgChild4.orgChild4Code,
orgChild4.orgChild4ShortName,
orgRoot.orgRootName,
orgRoot.orgRootCode,
orgRoot.orgRootShortName,
[orgChild3.orgChild3Name, orgChild2.orgChild2Name, orgChild1.orgChild1Name],
[orgChild3.orgChild3Code, orgChild2.orgChild2Code, orgChild1.orgChild1Code],
[
orgChild3.orgChild3ShortName,
orgChild2.orgChild2ShortName,
orgChild1.orgChild1ShortName,
],
),
posMaster: cannotViewChild4PosMaster
? []
: orgChild4.posMasters
.filter((x) => x.isDirector === true)
.map((x) =>
formatPosMaster(x, orgChild4.orgChild4ShortName, orgChild4.id, 4),
),
})),
})),
})),
})),
}));
return new HttpSuccess(formattedData);
}
/**
* API
*
* @summary (ADMIN)
*
* @param {string} id
*/
@Get("approver/{id}")
async getUserRootOrg(@Path() id: string, @Request() request: RequestWithUser) {
if (id == "00000000-0000-0000-0000-000000000000") {
const maps = {
id: "00000000-0000-0000-0000-000000000000",
name: "",
positionName: "ปลัดกรุงเทพมหานคร",
};
return new HttpSuccess(maps);
}
const root = await this.orgRootRepository.findOne({
where: { id: id },
});
if (!root) throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. Root");
const posMaster = await this.posMasterRepository.find({
where: { orgRootId: root.id, orgChild1Id: IsNull(), current_holder: Not(IsNull()) },
relations: ["current_holder"],
});
if (!posMaster) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");
const maps = posMaster.map((posMaster) => ({
id: posMaster?.current_holder?.id,
name: `${posMaster?.current_holder?.prefix}${posMaster?.current_holder?.firstName} ${posMaster?.current_holder?.lastName}`,
positionName: posMaster?.current_holder?.position,
}));
return new HttpSuccess(maps);
}
/**
* API รายละเอียดโครงสร้าง
*
* @summary ORG_023 - รายละเอียดโครงสร้าง (ADMIN) #25
*
*/
@Get("system/{id}/{system}")
async detailBySystem(
@Path() id: string,
@Path() system: string,
@Request() request: RequestWithUser,
) {
const orgRevision = await this.orgRevisionRepository.findOne({ where: { id } });
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
}
let _data: any = {
root: null,
child1: null,
child2: null,
child3: null,
child4: null,
};
if (
(orgRevision.orgRevisionIsDraft == true && orgRevision.orgRevisionIsCurrent == false) ||
system != "SYS_ORG"
) {
_data = await new permission().PermissionOrgList(request, system.trim().toUpperCase());
}
const profile = await this.profileRepo.findOne({
where: { keycloak: request.user.sub },
relations: ["permissionProfiles", "current_holders"],
});
if (!profile) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งานในทะเบียนประวัติ");
}
let _privilege = await new permission().PermissionOrgList(request, system);
const attrOwnership = _privilege.root === null ? true : false;
if (orgRevision.orgRevisionIsDraft && !orgRevision.orgRevisionIsCurrent && !attrOwnership) {
if (Array.isArray(profile.permissionProfiles) && profile.permissionProfiles.length > 0) {
_data.root = profile.permissionProfiles.map((x) => x.orgRootId);
} else {
return new HttpSuccess({ remark: "", data: [] });
}
}
// กำหนดการเข้าถึงข้อมูลตามสถานะและสิทธิ์
const isCurrentActive = !orgRevision.orgRevisionIsDraft && orgRevision.orgRevisionIsCurrent;
if (isCurrentActive) {
if (_privilege.privilege !== "OWNER" && _privilege.privilege !== "PARENT") {
if (_privilege.privilege == "NORMAL") {
const holder = profile.current_holders.find((x) => x.orgRevisionId === id);
if (!holder) return;
_data.root = [holder.orgRootId];
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
_data.child3 = [holder.orgChild3Id];
_data.child4 = [holder.orgChild4Id];
} else if (_privilege.privilege == "CHILD" || _privilege.privilege == "BROTHER") {
const holder = profile.current_holders.find((x) => x.orgRevisionId === id);
if (!holder) return;
_data.root = [holder.orgRootId];
if (_privilege.root && _privilege.child1 === null) {
} else if (_privilege.child1 && _privilege.child2 === null) {
_data.child1 = [holder.orgChild1Id];
} else if (_privilege.child2 && _privilege.child3 === null) {
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
} else if (_privilege.child3 && _privilege.child4 === null) {
_data.child1 = [holder.orgChild1Id];
_data.child2 = [holder.orgChild2Id];
_data.child3 = [holder.orgChild3Id];
_data.child4 = [holder.orgChild4Id];
}
} else {
_data.root = [profile.current_holders.find((x) => x.orgRevisionId === id)?.orgRootId];
}
} else {
if (!attrOwnership) _data = _privilege;
}
}
const orgRootData = await AppDataSource.getRepository(OrgRoot)
.createQueryBuilder("orgRoot")
.where("orgRoot.orgRevisionId = :id", { id })
.andWhere(
_data.root != undefined && _data.root != null
? _data.root[0] != null
? `orgRoot.id IN (:...node)`
: `orgRoot.id is null`
: "1=1",
{
node: _data.root,
},
)
.select([
"orgRoot.id",
"orgRoot.ancestorDNA",
"orgRoot.orgRootName",
"orgRoot.orgRootShortName",
"orgRoot.orgRootCode",
"orgRoot.orgRootOrder",
"orgRoot.orgRootPhoneEx",
"orgRoot.orgRootPhoneIn",
"orgRoot.orgRootFax",
"orgRoot.orgRevisionId",
"orgRoot.orgRootRank",
"orgRoot.orgRootRankSub",
"orgRoot.DEPARTMENT_CODE",
"orgRoot.DIVISION_CODE",
"orgRoot.SECTION_CODE",
"orgRoot.JOB_CODE",
"orgRoot.responsibility",
])
.orderBy("orgRoot.orgRootOrder", "ASC")
.getMany();
const orgRootIds = orgRootData.map((orgRoot) => orgRoot.id) || null;
const orgChild1Data =
orgRootIds && orgRootIds.length > 0
? await AppDataSource.getRepository(OrgChild1)
.createQueryBuilder("orgChild1")
.where("orgChild1.orgRootId IN (:...ids)", { ids: orgRootIds })
.andWhere(
_data.child1 != undefined && _data.child1 != null
? _data.child1[0] != null
? `orgChild1.id IN (:...node)`
: `orgChild1.id is ${_data.privilege == "PARENT" ? "not null" : "null"}`
: "1=1",
{
node: _data.child1,
},
)
.select([
"orgChild1.id",
"orgChild1.ancestorDNA",
"orgChild1.orgChild1Name",
"orgChild1.orgChild1ShortName",
"orgChild1.orgChild1Code",
"orgChild1.orgChild1Order",
"orgChild1.orgChild1PhoneEx",
"orgChild1.orgChild1PhoneIn",
"orgChild1.orgChild1Fax",
"orgChild1.orgRootId",
"orgChild1.orgChild1Rank",
"orgChild1.orgChild1RankSub",
"orgChild1.DEPARTMENT_CODE",
"orgChild1.DIVISION_CODE",
"orgChild1.SECTION_CODE",
"orgChild1.JOB_CODE",
"orgChild1.responsibility",
])
.orderBy("orgChild1.orgChild1Order", "ASC")
.getMany()
: [];
const orgChild1Ids = orgChild1Data.map((orgChild1) => orgChild1.id) || null;
const orgChild2Data =
orgChild1Ids && orgChild1Ids.length > 0
? await AppDataSource.getRepository(OrgChild2)
.createQueryBuilder("orgChild2")
.where("orgChild2.orgChild1Id IN (:...ids)", { ids: orgChild1Ids })
.andWhere(
_data.child2 != undefined && _data.child2 != null
? _data.child2[0] != null
? `orgChild2.id IN (:...node)`
: `orgChild2.id is null`
: "1=1",
{
node: _data.child2,
},
)
.select([
"orgChild2.id",
"orgChild2.ancestorDNA",
"orgChild2.orgChild2Name",
"orgChild2.orgChild2ShortName",
"orgChild2.orgChild2Code",
"orgChild2.orgChild2Order",
"orgChild2.orgChild2PhoneEx",
"orgChild2.orgChild2PhoneIn",
"orgChild2.orgChild2Fax",
"orgChild2.orgRootId",
"orgChild2.orgChild2Rank",
"orgChild2.orgChild2RankSub",
"orgChild2.DEPARTMENT_CODE",
"orgChild2.DIVISION_CODE",
"orgChild2.SECTION_CODE",
"orgChild2.JOB_CODE",
"orgChild2.orgChild1Id",
"orgChild2.responsibility",
])
.orderBy("orgChild2.orgChild2Order", "ASC")
.getMany()
: [];
const orgChild2Ids = orgChild2Data.map((orgChild2) => orgChild2.id) || null;
const orgChild3Data =
orgChild2Ids && orgChild2Ids.length > 0
? await AppDataSource.getRepository(OrgChild3)
.createQueryBuilder("orgChild3")
.where("orgChild3.orgChild2Id IN (:...ids)", { ids: orgChild2Ids })
.andWhere(
_data.child3 != undefined && _data.child3 != null
? _data.child3[0] != null
? `orgChild3.id IN (:...node)`
: `orgChild3.id is null`
: "1=1",
{
node: _data.child3,
},
)
.select([
"orgChild3.id",
"orgChild3.ancestorDNA",
"orgChild3.orgChild3Name",
"orgChild3.orgChild3ShortName",
"orgChild3.orgChild3Code",
"orgChild3.orgChild3Order",
"orgChild3.orgChild3PhoneEx",
"orgChild3.orgChild3PhoneIn",
"orgChild3.orgChild3Fax",
"orgChild3.orgRootId",
"orgChild3.orgChild3Rank",
"orgChild3.orgChild3RankSub",
"orgChild3.DEPARTMENT_CODE",
"orgChild3.DIVISION_CODE",
"orgChild3.SECTION_CODE",
"orgChild3.JOB_CODE",
"orgChild3.orgChild2Id",
"orgChild3.responsibility",
])
.orderBy("orgChild3.orgChild3Order", "ASC")
.getMany()
: [];
const orgChild3Ids = orgChild3Data.map((orgChild3) => orgChild3.id) || null;
const orgChild4Data =
orgChild3Ids && orgChild3Ids.length > 0
? await AppDataSource.getRepository(OrgChild4)
.createQueryBuilder("orgChild4")
.where("orgChild4.orgChild3Id IN (:...ids)", { ids: orgChild3Ids })
.andWhere(
_data.child4 != undefined && _data.child4 != null
? _data.child4[0] != null
? `orgChild4.id IN (:...node)`
: `orgChild4.id is null`
: "1=1",
{
node: _data.child4,
},
)
.select([
"orgChild4.id",
"orgChild4.ancestorDNA",
"orgChild4.orgChild4Name",
"orgChild4.orgChild4ShortName",
"orgChild4.orgChild4Code",
"orgChild4.orgChild4Order",
"orgChild4.orgChild4PhoneEx",
"orgChild4.orgChild4PhoneIn",
"orgChild4.orgChild4Fax",
"orgChild4.orgRootId",
"orgChild4.orgChild4Rank",
"orgChild4.orgChild4RankSub",
"orgChild4.DEPARTMENT_CODE",
"orgChild4.DIVISION_CODE",
"orgChild4.SECTION_CODE",
"orgChild4.JOB_CODE",
"orgChild4.orgChild3Id",
"orgChild4.responsibility",
])
.orderBy("orgChild4.orgChild4Order", "ASC")
.getMany()
: [];
// const formattedData = orgRootData.map((orgRoot) => {
const formattedData = await Promise.all(
orgRootData.map(async (orgRoot) => {
// const sum0 = await this.posMasterRepository.find({
// where: { orgRevisionId: orgRoot.orgRevisionId, orgRootId: orgRoot.id },
// select: [
// "current_holderId",
// "next_holderId",
// "orgRootId",
// "orgChild1Id",
// "orgChild2Id",
// "orgChild3Id",
// "orgChild4Id",
// ],
// });
return {
orgTreeId: orgRoot.id,
orgTreeDnaId: orgRoot.ancestorDNA,
orgLevel: 0,
orgName: orgRoot.orgRootName,
orgTreeName: orgRoot.orgRootName,
orgTreeShortName: orgRoot.orgRootShortName,
orgTreeCode: orgRoot.orgRootCode,
orgCode: orgRoot.orgRootCode + "00",
orgTreeRank: orgRoot.orgRootRank,
orgTreeRankSub: orgRoot.orgRootRankSub,
DEPARTMENT_CODE: orgRoot.DEPARTMENT_CODE,
DIVISION_CODE: orgRoot.DIVISION_CODE,
SECTION_CODE: orgRoot.SECTION_CODE,
JOB_CODE: orgRoot.JOB_CODE,
orgTreeOrder: orgRoot.orgRootOrder,
orgTreePhoneEx: orgRoot.orgRootPhoneEx,
orgTreePhoneIn: orgRoot.orgRootPhoneIn,
orgTreeFax: orgRoot.orgRootFax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgRoot.responsibility,
labelName:
orgRoot.orgRootName + " " + orgRoot.orgRootCode + "00" + " " + orgRoot.orgRootShortName,
// totalPosition: sum0.length + 1,
// totalPositionCurrentUse:
// sum0.filter((x) => x.current_holderId != null && x.current_holderId != "").length + 1,
// totalPositionCurrentVacant:
// sum0.filter((x) => x.current_holderId == null || x.current_holderId == "").length + 1,
// totalPositionNextUse:
// sum0.filter((x) => x.next_holderId != null && x.next_holderId != "").length + 1,
// totalPositionNextVacant:
// sum0.filter((x) => x.next_holderId == null || x.next_holderId == "").length + 1,
// totalRootPosition:
// sum0.filter(
// (x) =>
// (x.orgChild1Id == null || x.orgChild1Id == "") &&
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == ""),
// ).length + 1,
// totalRootPositionCurrentUse:
// sum0.filter(
// (x) =>
// (x.orgChild1Id == null || x.orgChild1Id == "") &&
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// x.current_holderId != null &&
// x.current_holderId != "",
// ).length + 1,
// totalRootPositionCurrentVacant:
// sum0.filter(
// (x) =>
// (x.orgChild1Id == null || x.orgChild1Id == "") &&
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// (x.current_holderId == null || x.current_holderId == ""),
// ).length + 1,
// totalRootPositionNextUse:
// sum0.filter(
// (x) =>
// (x.orgChild1Id == null || x.orgChild1Id == "") &&
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// x.next_holderId != null &&
// x.next_holderId != "",
// ).length + 1,
// totalRootPositionNextVacant:
// sum0.filter(
// (x) =>
// (x.orgChild1Id == null || x.orgChild1Id == "") &&
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// (x.next_holderId == null || x.next_holderId == ""),
// ).length + 1,
children: await Promise.all(
orgChild1Data
.filter((orgChild1) => orgChild1.orgRootId === orgRoot.id)
.map(async (orgChild1) => {
// const sum1 = await this.posMasterRepository.find({
// where: {
// orgRevisionId: orgRoot.orgRevisionId,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// },
// select: [
// "current_holderId",
// "next_holderId",
// "orgRootId",
// "orgChild1Id",
// "orgChild2Id",
// "orgChild3Id",
// "orgChild4Id",
// ],
// });
return {
orgTreeId: orgChild1.id,
orgTreeDnaId: orgChild1.ancestorDNA,
orgRootId: orgRoot.id,
orgRootDnaId: orgRoot.ancestorDNA,
orgLevel: 1,
orgName: `${orgChild1.orgChild1Name} ${orgRoot.orgRootName}`,
orgTreeName: orgChild1.orgChild1Name,
orgTreeShortName: orgChild1.orgChild1ShortName,
orgTreeCode: orgChild1.orgChild1Code,
orgCode: orgRoot.orgRootCode + orgChild1.orgChild1Code,
orgTreeRank: orgChild1.orgChild1Rank,
orgTreeRankSub: orgChild1.orgChild1RankSub,
DEPARTMENT_CODE: orgChild1.DEPARTMENT_CODE,
DIVISION_CODE: orgChild1.DIVISION_CODE,
SECTION_CODE: orgChild1.SECTION_CODE,
JOB_CODE: orgChild1.JOB_CODE,
orgTreeOrder: orgChild1.orgChild1Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild1.orgChild1PhoneEx,
orgTreePhoneIn: orgChild1.orgChild1PhoneIn,
orgTreeFax: orgChild1.orgChild1Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild1.responsibility,
labelName:
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName +
"/" +
orgRoot.orgRootName +
" " +
orgRoot.orgRootCode +
"00" +
" " +
orgRoot.orgRootShortName,
// totalPosition: sum1.length + 1,
// totalPositionCurrentUse:
// sum1.filter((x) => x.current_holderId != null && x.current_holderId != "")
// .length + 1,
// totalPositionCurrentVacant:
// sum1.filter((x) => x.current_holderId == null || x.current_holderId == "")
// .length + 1,
// totalPositionNextUse:
// sum1.filter((x) => x.next_holderId != null && x.next_holderId != "").length + 1,
// totalPositionNextVacant:
// sum1.filter((x) => x.next_holderId == null || x.next_holderId == "").length + 1,
// totalRootPosition:
// sum1.filter(
// (x) =>
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == ""),
// ).length + 1,
// totalRootPositionCurrentUse:
// sum1.filter(
// (x) =>
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// x.current_holderId != null &&
// x.current_holderId != "",
// ).length + 1,
// totalRootPositionCurrentVacant:
// sum1.filter(
// (x) =>
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// (x.current_holderId == null || x.current_holderId == ""),
// ).length + 1,
// totalRootPositionNextUse:
// sum1.filter(
// (x) =>
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// x.next_holderId != null &&
// x.next_holderId != "",
// ).length + 1,
// totalRootPositionNextVacant:
// sum1.filter(
// (x) =>
// (x.orgChild2Id == null || x.orgChild2Id == "") &&
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// (x.next_holderId == null || x.next_holderId == ""),
// ).length + 1,
children: await Promise.all(
orgChild2Data
.filter((orgChild2) => orgChild2.orgChild1Id === orgChild1.id)
.map(async (orgChild2) => {
// const sum2 = await this.posMasterRepository.find({
// where: {
// orgRevisionId: orgRoot.orgRevisionId,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// },
// select: [
// "current_holderId",
// "next_holderId",
// "orgRootId",
// "orgChild1Id",
// "orgChild2Id",
// "orgChild3Id",
// "orgChild4Id",
// ],
// });
return {
orgTreeId: orgChild2.id,
orgTreeDnaId: orgChild2.ancestorDNA,
orgRootId: orgChild1.id,
orgRootDnaId: orgChild1.ancestorDNA,
orgLevel: 2,
orgName: `${orgChild2.orgChild2Name} ${orgChild1.orgChild1Name} ${orgRoot.orgRootName}`,
orgTreeName: orgChild2.orgChild2Name,
orgTreeShortName: orgChild2.orgChild2ShortName,
orgTreeCode: orgChild2.orgChild2Code,
orgCode: orgRoot.orgRootCode + orgChild2.orgChild2Code,
orgTreeRank: orgChild2.orgChild2Rank,
orgTreeRankSub: orgChild2.orgChild2RankSub,
DEPARTMENT_CODE: orgChild2.DEPARTMENT_CODE,
DIVISION_CODE: orgChild2.DIVISION_CODE,
SECTION_CODE: orgChild2.SECTION_CODE,
JOB_CODE: orgChild2.JOB_CODE,
orgTreeOrder: orgChild2.orgChild2Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild2.orgChild2PhoneEx,
orgTreePhoneIn: orgChild2.orgChild2PhoneIn,
orgTreeFax: orgChild2.orgChild2Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild2.responsibility,
labelName:
orgChild2.orgChild2Name +
" " +
orgRoot.orgRootCode +
orgChild2.orgChild2Code +
" " +
orgChild2.orgChild2ShortName +
"/" +
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName +
"/" +
orgRoot.orgRootName +
" " +
orgRoot.orgRootCode +
"00" +
" " +
orgRoot.orgRootShortName,
// totalPosition: sum2.length + 1,
// totalPositionCurrentUse:
// sum2.filter(
// (x) => x.current_holderId != null && x.current_holderId != "",
// ).length + 1,
// totalPositionCurrentVacant:
// sum2.filter(
// (x) => x.current_holderId == null || x.current_holderId == "",
// ).length + 1,
// totalPositionNextUse:
// sum2.filter((x) => x.next_holderId != null && x.next_holderId != "")
// .length + 1,
// totalPositionNextVacant:
// sum2.filter((x) => x.next_holderId == null || x.next_holderId == "")
// .length + 1,
// totalRootPosition:
// sum2.filter(
// (x) =>
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == ""),
// ).length + 1,
// totalRootPositionCurrentUse:
// sum2.filter(
// (x) =>
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// x.current_holderId != null &&
// x.current_holderId != "",
// ).length + 1,
// totalRootPositionCurrentVacant:
// sum2.filter(
// (x) =>
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// (x.current_holderId == null || x.current_holderId == ""),
// ).length + 1,
// totalRootPositionNextUse:
// sum2.filter(
// (x) =>
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// x.next_holderId != null &&
// x.next_holderId != "",
// ).length + 1,
// totalRootPositionNextVacant:
// sum2.filter(
// (x) =>
// (x.orgChild3Id == null || x.orgChild3Id == "") &&
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// (x.next_holderId == null || x.next_holderId == ""),
// ).length + 1,
children: await Promise.all(
orgChild3Data
.filter((orgChild3) => orgChild3.orgChild2Id === orgChild2.id)
.map(async (orgChild3) => {
// const sum3 = await this.posMasterRepository.find({
// where: {
// orgRevisionId: orgRoot.orgRevisionId,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// },
// select: [
// "current_holderId",
// "next_holderId",
// "orgRootId",
// "orgChild1Id",
// "orgChild2Id",
// "orgChild3Id",
// "orgChild4Id",
// ],
// });
return {
orgTreeId: orgChild3.id,
orgTreeDnaId: orgChild3.ancestorDNA,
orgRootId: orgChild2.id,
orgRootDnaId: orgChild2.ancestorDNA,
orgLevel: 3,
orgName: `${orgChild3.orgChild3Name} ${orgChild2.orgChild2Name} ${orgChild1.orgChild1Name} ${orgRoot.orgRootName}`,
orgTreeName: orgChild3.orgChild3Name,
orgTreeShortName: orgChild3.orgChild3ShortName,
orgTreeCode: orgChild3.orgChild3Code,
orgCode: orgRoot.orgRootCode + orgChild3.orgChild3Code,
orgTreeRank: orgChild3.orgChild3Rank,
orgTreeRankSub: orgChild3.orgChild3RankSub,
DEPARTMENT_CODE: orgChild3.DEPARTMENT_CODE,
DIVISION_CODE: orgChild3.DIVISION_CODE,
SECTION_CODE: orgChild3.SECTION_CODE,
JOB_CODE: orgChild3.JOB_CODE,
orgTreeOrder: orgChild3.orgChild3Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild3.orgChild3PhoneEx,
orgTreePhoneIn: orgChild3.orgChild3PhoneIn,
orgTreeFax: orgChild3.orgChild3Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild3.responsibility,
labelName:
orgChild3.orgChild3Name +
" " +
orgRoot.orgRootCode +
orgChild3.orgChild3Code +
" " +
orgChild3.orgChild3ShortName +
"/" +
orgChild2.orgChild2Name +
" " +
orgRoot.orgRootCode +
orgChild2.orgChild2Code +
" " +
orgChild2.orgChild2ShortName +
"/" +
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName +
"/" +
orgRoot.orgRootName +
" " +
orgRoot.orgRootCode +
"00" +
" " +
orgRoot.orgRootShortName,
// totalPosition: sum3.length + 1,
// totalPositionCurrentUse:
// sum3.filter(
// (x) => x.current_holderId != null && x.current_holderId != "",
// ).length + 1,
// totalPositionCurrentVacant:
// sum3.filter(
// (x) => x.current_holderId == null || x.current_holderId == "",
// ).length + 1,
// totalPositionNextUse:
// sum3.filter(
// (x) => x.next_holderId != null && x.next_holderId != "",
// ).length + 1,
// totalPositionNextVacant:
// sum3.filter(
// (x) => x.next_holderId == null || x.next_holderId == "",
// ).length + 1,
// totalRootPosition:
// sum3.filter((x) => x.orgChild4Id == null || x.orgChild4Id == "")
// .length + 1,
// totalRootPositionCurrentUse:
// sum3.filter(
// (x) =>
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// x.current_holderId != null &&
// x.current_holderId != "",
// ).length + 1,
// totalRootPositionCurrentVacant:
// sum3.filter(
// (x) =>
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// (x.current_holderId == null || x.current_holderId == ""),
// ).length + 1,
// totalRootPositionNextUse:
// sum3.filter(
// (x) =>
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// x.next_holderId != null &&
// x.next_holderId != "",
// ).length + 1,
// totalRootPositionNextVacant:
// sum3.filter(
// (x) =>
// (x.orgChild4Id == null || x.orgChild4Id == "") &&
// (x.next_holderId == null || x.next_holderId == ""),
// ).length + 1,
children: await Promise.all(
orgChild4Data
.filter((orgChild4) => orgChild4.orgChild3Id === orgChild3.id)
.map(async (orgChild4) => {
// const sum4 = await this.posMasterRepository.find({
// where: {
// orgRevisionId: orgRoot.orgRevisionId,
// orgRootId: orgRoot.id,
// orgChild1Id: orgChild1.id,
// orgChild2Id: orgChild2.id,
// orgChild3Id: orgChild3.id,
// orgChild4Id: orgChild4.id,
// },
// select: [
// "current_holderId",
// "next_holderId",
// "orgRootId",
// "orgChild1Id",
// "orgChild2Id",
// "orgChild3Id",
// "orgChild4Id",
// ],
// });
return {
orgTreeId: orgChild4.id,
orgTreeDnaId: orgChild4.ancestorDNA,
orgRootId: orgChild3.id,
orgRootDnaId: orgChild3.ancestorDNA,
orgLevel: 4,
orgName: `${orgChild4.orgChild4Name} ${orgChild3.orgChild3Name} ${orgChild2.orgChild2Name} ${orgChild1.orgChild1Name} ${orgRoot.orgRootName}`,
orgTreeName: orgChild4.orgChild4Name,
orgTreeShortName: orgChild4.orgChild4ShortName,
orgTreeCode: orgChild4.orgChild4Code,
orgCode: orgRoot.orgRootCode + orgChild4.orgChild4Code,
orgTreeRank: orgChild4.orgChild4Rank,
orgTreeRankSub: orgChild4.orgChild4RankSub,
DEPARTMENT_CODE: orgChild4.DEPARTMENT_CODE,
DIVISION_CODE: orgChild4.DIVISION_CODE,
SECTION_CODE: orgChild4.SECTION_CODE,
JOB_CODE: orgChild4.JOB_CODE,
orgTreeOrder: orgChild4.orgChild4Order,
orgRootCode: orgRoot.orgRootCode,
orgTreePhoneEx: orgChild4.orgChild4PhoneEx,
orgTreePhoneIn: orgChild4.orgChild4PhoneIn,
orgTreeFax: orgChild4.orgChild4Fax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgChild4.responsibility,
labelName:
orgChild4.orgChild4Name +
" " +
orgRoot.orgRootCode +
orgChild4.orgChild4Code +
" " +
orgChild4.orgChild4ShortName +
"/" +
orgChild3.orgChild3Name +
" " +
orgRoot.orgRootCode +
orgChild3.orgChild3Code +
" " +
orgChild3.orgChild3ShortName +
"/" +
orgChild2.orgChild2Name +
" " +
orgRoot.orgRootCode +
orgChild2.orgChild2Code +
" " +
orgChild2.orgChild2ShortName +
"/" +
orgChild1.orgChild1Name +
" " +
orgRoot.orgRootCode +
orgChild1.orgChild1Code +
" " +
orgChild1.orgChild1ShortName +
"/" +
orgRoot.orgRootName +
" " +
orgRoot.orgRootCode +
"00" +
" " +
orgRoot.orgRootShortName,
// totalPosition: sum4.length + 1,
// totalPositionCurrentUse:
// sum4.filter(
// (x) =>
// x.current_holderId != null &&
// x.current_holderId != "",
// ).length + 1,
// totalPositionCurrentVacant:
// sum4.filter(
// (x) =>
// x.current_holderId == null ||
// x.current_holderId == "",
// ).length + 1,
// totalPositionNextUse:
// sum4.filter(
// (x) =>
// x.next_holderId != null && x.next_holderId != "",
// ).length + 1,
// totalPositionNextVacant:
// sum4.filter(
// (x) =>
// x.next_holderId == null || x.next_holderId == "",
// ).length + 1,
// totalRootPosition: sum4.length + 1,
// totalRootPositionCurrentUse:
// sum4.filter(
// (x) =>
// x.current_holderId != null &&
// x.current_holderId != "",
// ).length + 1,
// totalRootPositionCurrentVacant:
// sum4.filter(
// (x) =>
// x.current_holderId == null ||
// x.current_holderId == "",
// ).length + 1,
// totalRootPositionNextUse:
// sum4.filter(
// (x) =>
// x.next_holderId != null && x.next_holderId != "",
// ).length + 1,
// totalRootPositionNextVacant:
// sum4.filter(
// (x) =>
// x.next_holderId == null || x.next_holderId == "",
// ).length + 1,
};
}),
),
};
}),
),
};
}),
),
};
}),
),
};
}),
);
return new HttpSuccess(formattedData);
}
/**
* API รายละเอียดโครงสร้าง
*
* @summary ORG_023 - รายละเอียดโครงสร้าง (ADMIN) #25
*
*/
@Get("system-root/{id}/{system}")
async detailBySystemRoot(
@Path() id: string,
@Path() system: string,
@Request() request: RequestWithUser,
) {
const orgRevision = await this.orgRevisionRepository.findOne({ where: { id } });
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
}
let _data = {
root: null,
child1: null,
child2: null,
child3: null,
child4: null,
};
if (orgRevision.orgRevisionIsDraft == true && orgRevision.orgRevisionIsCurrent == false) {
_data = await new permission().PermissionOrgList(request, system.trim().toUpperCase());
}
const orgRootData = await AppDataSource.getRepository(OrgRoot)
.createQueryBuilder("orgRoot")
.where("orgRoot.orgRevisionId = :id", { id })
.andWhere(
_data.root != undefined && _data.root != null
? _data.root[0] != null
? `orgRoot.id IN (:...node)`
: `orgRoot.id is null`
: "1=1",
{
node: _data.root,
},
)
.select([
"orgRoot.id",
"orgRoot.orgRootName",
"orgRoot.orgRootShortName",
"orgRoot.orgRootCode",
"orgRoot.orgRootOrder",
"orgRoot.orgRootPhoneEx",
"orgRoot.orgRootPhoneIn",
"orgRoot.orgRootFax",
"orgRoot.orgRevisionId",
"orgRoot.orgRootRank",
"orgRoot.orgRootRankSub",
"orgRoot.responsibility",
"orgRoot.isDeputy",
])
.orderBy("orgRoot.orgRootOrder", "ASC")
.getMany();
const formattedData = await Promise.all(
orgRootData.map(async (orgRoot) => {
return {
orgTreeId: orgRoot.id,
orgLevel: 0,
isDeputy: orgRoot.isDeputy,
orgName: orgRoot.orgRootName,
orgTreeName: orgRoot.orgRootName,
orgTreeShortName: orgRoot.orgRootShortName,
orgTreeCode: orgRoot.orgRootCode,
orgCode: orgRoot.orgRootCode + "00",
orgTreeRank: orgRoot.orgRootRank,
orgTreeRankSub: orgRoot.orgRootRankSub,
orgTreeOrder: orgRoot.orgRootOrder,
orgTreePhoneEx: orgRoot.orgRootPhoneEx,
orgTreePhoneIn: orgRoot.orgRootPhoneIn,
orgTreeFax: orgRoot.orgRootFax,
orgRevisionId: orgRoot.orgRevisionId,
orgRootName: orgRoot.orgRootName,
responsibility: orgRoot.responsibility,
labelName:
orgRoot.orgRootName + " " + orgRoot.orgRootCode + "00" + " " + orgRoot.orgRootShortName,
totalPosition: await this.posMasterRepository.count({
where: { orgRevisionId: orgRoot.orgRevisionId, orgRootId: orgRoot.id },
}),
totalPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
current_holderId: IsNull() || "",
},
}),
totalPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
next_holderId: IsNull() || "",
},
}),
totalRootPosition: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
},
}),
totalRootPositionCurrentUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
current_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionCurrentVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
current_holderId: IsNull() || "",
},
}),
totalRootPositionNextUse: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
next_holderId: Not(IsNull()) || Not(""),
},
}),
totalRootPositionNextVacant: await this.posMasterRepository.count({
where: {
orgRevisionId: orgRoot.orgRevisionId,
orgRootId: orgRoot.id,
orgChild1Id: IsNull() || "",
orgChild2Id: IsNull() || "",
orgChild3Id: IsNull() || "",
orgChild4Id: IsNull() || "",
next_holderId: IsNull() || "",
},
}),
};
}),
);
return new HttpSuccess(formattedData);
}
/**
* API เช็ค org ในระบบ
*
* @summary - เช็ค org ในระบบ (ADMIN)
*
*/
@Get("check/child1/{id}")
async findIsOfficerChild1(@Path() id: string, @Request() request: RequestWithUser) {
const orgRevision = await this.orgRevisionRepository.findOne({
where: { id },
relations: ["orgChild1s"],
});
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
}
const check = orgRevision.orgChild1s.find((x) => x.isOfficer == true);
return new HttpSuccess(check != null);
}
/**
* API เช็ค org ในระบบ
*
* @summary - เช็ค org ในระบบ (ADMIN)
*
*/
@Get("check/root/{id}")
async findIsDeputyRoot(@Path() id: string, @Request() request: RequestWithUser) {
const orgRevision = await this.orgRevisionRepository.findOne({
where: { id },
relations: ["orgRoots"],
});
if (!orgRevision) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
}
const check = orgRevision.orgRoots.find((x) => x.isDeputy == true);
return new HttpSuccess(check != null);
}
/**
* API หา สกก1
*
* @summary - หา สกก1 (ADMIN)
*
*/
@Get("find/head/officer")
async findIsHeadOfficer(@Request() request: RequestWithUser) {
const posMaster = await this.posMasterRepository.find({
where: {
orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
orgRoot: { isCommission: true },
orgChild1Id: IsNull(),
isDirector: true,
current_holderId: Not(IsNull()),
// posMasterActs: { statusReport: "DONE" },
// posMasterActChilds: { statusReport: "DONE" },
},
order: { posMasterOrder: "ASC", posMasterActChilds: { posMasterOrder: "ASC" } },
relations: [
"current_holder",
// "posMasterActChilds",
// "posMasterActChilds.posMasterChild",
// "posMasterActChilds.posMasterChild.current_holder",
],
});
if (posMaster.length <= 0) {
return new HttpSuccess({
name: "......................................................",
position: "......................................................",
});
}
if (posMaster[0].current_holder == null) {
const posMaster = await this.posMasterRepository.find({
where: {
orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
orgRoot: { isCommission: true },
orgChild1Id: IsNull(),
isDirector: true,
posMasterActs: { statusReport: "DONE" },
posMasterActChilds: { statusReport: "DONE" },
},
order: { posMasterOrder: "ASC", posMasterActChilds: { posMasterOrder: "ASC" } },
relations: [
"current_holder",
"posMasterActChilds",
"posMasterActChilds.posMasterChild",
"posMasterActChilds.posMasterChild.current_holder",
],
});
if (
posMaster[0].posMasterActChilds.length <= 0 ||
posMaster[0].posMasterActChilds[0].posMasterChild == null ||
posMaster[0].posMasterActChilds[0].posMasterChild.current_holder == null
) {
return new HttpSuccess({
name: "......................................................",
position: "......................................................",
});
}
return new HttpSuccess({
name: `${posMaster[0].posMasterActChilds[0].posMasterChild.current_holder.prefix}${posMaster[0].posMasterActChilds[0].posMasterChild.current_holder.firstName} ${posMaster[0].posMasterActChilds[0].posMasterChild.current_holder.lastName}`,
position: posMaster[0].posMasterActChilds[0].posMasterChild.current_holder.position,
});
} else {
return new HttpSuccess({
name: `${posMaster[0].current_holder.prefix}${posMaster[0].current_holder.firstName} ${posMaster[0].current_holder.lastName}`,
position: posMaster[0].current_holder.position,
});
}
}
/**
* API ลำดับโครงสร้าง
*
* @summary - ลำดับโครงสร้าง (ADMIN)
*
*/
@Get("root/search/sort")
async searchSortRootLevelType(@Request() request: RequestWithUser) {
// const root1 = await this.orgRootRepository.find({
// where: {
// orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
// DEPARTMENT_CODE: Not("50"),
// },
// order: { isDeputy: "DESC", orgRootOrder: "ASC" },
// select: ["orgRootName"],
// });
// const root2 = await this.orgRootRepository.find({
// where: {
// orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
// DEPARTMENT_CODE: "50",
// },
// order: { orgRootName: "ASC" },
// select: ["orgRootName"],
// });
// const root = [...root1, ...root2];
// const child1 = await this.child1Repository.find({
// where: {
// orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
// },
// order: { orgChild1Order: "ASC" },
// select: ["orgChild1Name"],
// });
// const child2 = await this.child2Repository.find({
// where: {
// orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
// },
// order: { orgChild2Order: "ASC" },
// select: ["orgChild2Name"],
// });
// const child3 = await this.child3Repository.find({
// where: {
// orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
// },
// order: { orgChild3Order: "ASC" },
// select: ["orgChild3Name"],
// });
// const child4 = await this.child4Repository.find({
// where: {
// orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
// },
// order: { orgChild4Order: "ASC" },
// select: ["orgChild4Name"],
// });
// const hospital = await this.child1Repository.find({
// where: [
// {
// orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
// orgRoot: { isDeputy: true },
// },
// {
// orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
// orgChild1RankSub: "HOSPITAL",
// },
// ],
// select: ["orgChild1Name"],
// });
// const posType = await this.posTypeRepository.find({
// order: { posTypeRank: "DESC" },
// select: ["posTypeName"],
// });
// const posLevel = await this.posLevelRepository.find({
// order: { posLevelRank: "DESC" },
// select: ["posLevelName"],
// });
const [roots, child1, child2, child3, child4, hospital, posType, posLevel] = await Promise.all([
// ===== ROOT =====
this.orgRootRepository
.createQueryBuilder("root")
.innerJoin("root.orgRevision", "rev")
.select(["root.orgRootName AS orgRootName"])
.where("rev.orgRevisionIsDraft = false")
.andWhere("rev.orgRevisionIsCurrent = true")
.orderBy("CASE WHEN root.DEPARTMENT_CODE = '50' THEN 1 ELSE 0 END", "ASC")
.addOrderBy("root.isDeputy", "DESC")
.addOrderBy("root.orgRootOrder", "ASC")
.addOrderBy("root.orgRootName", "ASC")
.getRawMany(),
// ===== CHILD 1 =====
this.child1Repository
.createQueryBuilder("c1")
.innerJoin("c1.orgRevision", "rev")
.select("c1.orgChild1Name", "orgChild1Name")
.where("rev.orgRevisionIsDraft = false")
.andWhere("rev.orgRevisionIsCurrent = true")
.orderBy("c1.orgChild1Order", "ASC")
.getRawMany(),
// ===== CHILD 2 =====
this.child2Repository
.createQueryBuilder("c2")
.innerJoin("c2.orgRevision", "rev")
.select("c2.orgChild2Name", "orgChild2Name")
.where("rev.orgRevisionIsDraft = false")
.andWhere("rev.orgRevisionIsCurrent = true")
.orderBy("c2.orgChild2Order", "ASC")
.getRawMany(),
// ===== CHILD 3 =====
this.child3Repository
.createQueryBuilder("c3")
.innerJoin("c3.orgRevision", "rev")
.select("c3.orgChild3Name", "orgChild3Name")
.where("rev.orgRevisionIsDraft = false")
.andWhere("rev.orgRevisionIsCurrent = true")
.orderBy("c3.orgChild3Order", "ASC")
.getRawMany(),
// ===== CHILD 4 =====
this.child4Repository
.createQueryBuilder("c4")
.innerJoin("c4.orgRevision", "rev")
.select("c4.orgChild4Name", "orgChild4Name")
.where("rev.orgRevisionIsDraft = false")
.andWhere("rev.orgRevisionIsCurrent = true")
.orderBy("c4.orgChild4Order", "ASC")
.getRawMany(),
// ===== HOSPITAL =====
this.child1Repository
.createQueryBuilder("c1")
.innerJoin("c1.orgRevision", "rev")
.leftJoin("c1.orgRoot", "root")
.select("c1.orgChild1Name", "orgChild1Name")
.where("rev.orgRevisionIsDraft = false")
.andWhere("rev.orgRevisionIsCurrent = true")
.andWhere("(root.isDeputy = true OR c1.orgChild1RankSub = :rank)", { rank: "HOSPITAL" })
.getRawMany(),
// ===== POSITION TYPE =====
this.posTypeRepository
.createQueryBuilder("pt")
.select("pt.posTypeName", "posTypeName")
.orderBy("pt.posTypeRank", "DESC")
.getRawMany(),
// ===== POSITION LEVEL =====
this.posLevelRepository
.createQueryBuilder("pl")
.select("pl.posLevelName", "posLevelName")
.orderBy("pl.posLevelRank", "DESC")
.getRawMany(),
]);
return new HttpSuccess({
root: roots.map((x) => x.orgRootName),
child1: child1.map((x) => x.orgChild1Name),
child2: child2.map((x) => x.orgChild2Name),
child3: child3.map((x) => x.orgChild3Name),
child4: child4.map((x) => x.orgChild4Name),
hospital: hospital.map((x) => x.orgChild1Name),
posTypeNameOrder: posType.map((x) => x.posTypeName),
posLevelNameOrder: posLevel.map((x) => x.posLevelName),
});
}
/**
* API เพิ่มสิทธิ์โครงสร้าง
*
* @summary - เพิ่มสิทธิ์โครงสร้าง (ADMIN)
*
*/
@Get("root/add/permission/{child1Id}")
async addRootPermission(@Path() child1Id: string, @Request() request: RequestWithUser) {
const profiles = await this.profileRepo.find({
where: {
keycloak: Not(IsNull()),
current_holders: {
orgChild1Id: child1Id,
},
},
});
const orgRoots = await this.orgRootRepository.find({
where: {
orgRevision: {
orgRevisionIsDraft: true,
orgRevisionIsCurrent: false,
},
},
});
for await (const root of orgRoots) {
const _permissionOrg = profiles.map((profile) => {
const permission = new PermissionOrg();
permission.orgRootId = root.id;
permission.profileId = profile.id;
permission.createdUserId = request.user.sub;
permission.createdFullName = request.user.name;
permission.lastUpdateUserId = request.user.sub;
permission.lastUpdateFullName = request.user.name;
permission.createdAt = new Date();
permission.lastUpdatedAt = new Date();
return permission;
});
await this.permissionOrgRepository.save(_permissionOrg);
}
return new HttpSuccess();
}
/**
* API ลบข้าราชการในโครงสร้าง
*
* @summary - ลบข้าราชการในโครงสร้าง (ADMIN)
*
*/
@Get("delete/profile-officer/org/{orgRevisionId}")
async deleteOfficerRetireInOrg(
@Path() orgRevisionId: string,
@Request() request: RequestWithUser,
) {
const posMasters = await this.posMasterRepository.find({
where: {
orgRevisionId,
current_holderId: Not(IsNull()),
current_holder: {
isLeave: true,
isRetirement: true,
},
// positions: { positionIsSelected: true },
},
relations: ["positions"],
});
let checkOfficer = 0;
await Promise.all([
posMasters.map(async (posMaster) => {
posMaster.current_holderId = null;
posMaster.isSit = false;
if (posMaster.positions) {
for (const position of posMaster.positions) {
position.positionIsSelected = false;
await this.positionRepository.save(position);
checkOfficer += 1;
}
}
await this.posMasterRepository.save(posMaster);
await CreatePosMasterHistoryOfficer(posMaster.id, null);
}),
]);
return new HttpSuccess({
totalOfficer: posMasters.length,
officerSuccessAmount: checkOfficer,
});
}
/**
* API ลบลูกจ้างในโครงสร้าง
*
* @summary - ลบลูกจ้างในโครงสร้าง (ADMIN)
*
*/
@Get("delete/profile-emp/org/{orgRevisionId}")
async deleteRetireEmpInOrg(@Path() orgRevisionId: string, @Request() request: RequestWithUser) {
const posMastersEmployee = await this.employeePosMasterRepository.find({
where: {
orgRevisionId,
current_holderId: Not(IsNull()),
current_holder: {
isLeave: true,
isRetirement: true,
},
// positions: { positionIsSelected: true },
},
relations: ["positions"],
});
let checkEmployee = 0;
await Promise.all(
posMastersEmployee.map(async (posMaster) => {
posMaster.current_holderId = null;
posMaster.isSit = false;
if (posMaster.positions) {
for (const position of posMaster.positions) {
position.positionIsSelected = false;
await this.employeePositionRepository.save(position);
checkEmployee += 1;
}
}
await this.employeePosMasterRepository.save(posMaster);
await CreatePosMasterHistoryEmployee(posMaster.id, null);
}),
);
return new HttpSuccess({
totalEmployee: posMastersEmployee.length,
employeeSuccessAmount: checkEmployee,
});
}
/**
* API บันทึกลงประวัติตำแหน่ง
*
* @summary - บันทึกลงประวัติตำแหน่ง (ADMIN)
*
*/
@Get("save/profile/position-history")
async saveRetireToPositionHistory(@Request() request: RequestWithUser) {
const [profileLeave, profileEmployeeLeave] = await Promise.all([
this.profileRepo.find({
where: {
isLeave: true,
isRetirement: true,
leaveType: IsNull(),
},
}),
this.profileEmployeeRepo.find({
where: {
isLeave: true,
isRetirement: true,
leaveType: IsNull(),
},
}),
]);
let checkOfficer: number = 0;
await Promise.all(
profileLeave.map(async (profile: any) => {
const dest_item = await this.profileSalaryRepository.findOne({
where: { profileId: profile.id },
order: { order: "DESC" },
});
const data: any = {
order: dest_item == null ? 1 : dest_item.order + 1,
amount: null,
positionSalaryAmount: null,
mouthSalaryAmount: null,
profileId: profile.id,
posNo: null,
positionExecutive: null,
positionType: null,
positionLevel: null,
amountSpecial: null,
orgRoot: null,
orgChild1: null,
orgChild2: null,
orgChild3: null,
orgChild4: null,
commandYear: new Date().getFullYear() + 543,
commandDateAffect: profile.dateLeave,
commandCode: "16",
commandName: "พ้นจากราชการ",
posNoAbb: null,
isEntry: false,
positionName: "เกษียณอายุราชการ",
createdUserId: request.user.sub,
createdFullName: request.user.name,
lastUpdateUserId: request.user.sub,
lastUpdateFullName: request.user.name,
createdAt: new Date(),
lastUpdatedAt: new Date(),
remark: "ประกาศคณะอนุกรรมการสามัญข้าราชการกรุงเทพมหานครสามัญ ลว. 31 มี.ค. 68", // script เกษียณจริง ๆ ให้เอา “วันที่ประกาศเกษียณฉบับแรก” มาลงในเอกสารอ้างอิง
isGovernment: false,
};
const history = new ProfileSalaryHistory();
Object.assign(history, { ...data, id: undefined });
data.dateGovernment = profile.dateLeave;
const savedData = await this.profileSalaryRepository.save(data);
history.profileSalaryId = savedData.id;
await this.salaryHistoryRepo.save(history);
checkOfficer += 1;
}),
);
let checkEmployee: number = 0;
await Promise.all(
profileEmployeeLeave.map(async (profile: any) => {
const dest_item = await this.profileSalaryRepository.findOne({
where: { profileEmployeeId: profile.id },
order: { order: "DESC" },
});
const data: any = {
order: dest_item == null ? 1 : dest_item.order + 1,
amount: null,
positionSalaryAmount: null,
mouthSalaryAmount: null,
profileEmployeeId: profile.id,
posNo: null,
positionExecutive: null,
positionType: null,
positionLevel: null,
amountSpecial: null,
orgRoot: null,
orgChild1: null,
orgChild2: null,
orgChild3: null,
orgChild4: null,
commandYear: new Date().getFullYear() + 543,
commandDateAffect: profile.dateLeave,
commandCode: "16",
commandName: "พ้นจากราชการ",
posNoAbb: null,
isEntry: false,
positionName: "เกษียณอายุราชการ",
createdUserId: request.user.sub,
createdFullName: request.user.name,
lastUpdateUserId: request.user.sub,
lastUpdateFullName: request.user.name,
createdAt: new Date(),
lastUpdatedAt: new Date(),
remark: "ประกาศคณะอนุกรรมการสามัญข้าราชการกรุงเทพมหานครสามัญ ลว. 31 มี.ค. 68", // script เกษียณจริง ๆ ให้เอา “วันที่ประกาศเกษียณฉบับแรก” มาลงในเอกสารอ้างอิง
isGovernment: false,
};
const history = new ProfileSalaryHistory();
Object.assign(history, { ...data, id: undefined });
data.dateGovernment = profile.dateLeave;
const savedData = await this.profileSalaryRepository.save(data);
history.profileSalaryId = savedData.id;
await this.salaryHistoryRepo.save(history);
checkEmployee += 1;
}),
);
// จำนวนคนที่บันทึกลงประวัติตำแหน่ง
const totalOfficer = profileLeave.length;
const totalEmployee = profileEmployeeLeave.length;
// จำนวนคนที่ถูกบันทึกลงประวัติตำแหน่งสำเร็จ
return new HttpSuccess({
totalOfficer,
totalEmployee,
officerSuccessAmount: checkOfficer,
successEmployeeAmount: checkEmployee,
});
}
/**
* API แก้ไขเหตุผลการลาออก และปลดจาก keycloak
*
* @summary - แก้ไขเหตุผลการลาออก และปลดจาก keycloak (ADMIN)
*
*/
@Get("update/profile/leave-reason")
async updateRetireReason() {
const [profileLeave, profileEmployeeLeave, token] = await Promise.all([
this.profileRepo.find({
where: {
isLeave: true,
isRetirement: true,
leaveType: IsNull(),
},
}),
this.profileEmployeeRepo.find({
where: {
isLeave: true,
isRetirement: true,
leaveType: IsNull(),
},
}),
getToken(),
]);
if (!token)
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถเชื่อมต่อ Keycloak");
let checkOfficer: number = 0;
let notDeleteOfficer: string[] = [];
await Promise.all(
profileLeave.map(async (profile) => {
profile.leaveReason = "เกษียณอายุราชการ";
profile.leaveType = "RETIRE";
profile.isActive = false;
if (profile.keycloak != null && profile.keycloak != "" && profile.isDelete === false) {
const delUserKeycloak = await deleteUser(profile.keycloak, token);
if (delUserKeycloak) {
// profile.keycloak = "";
profile.isDelete = true;
profile.roleKeycloaks = [];
checkOfficer += 1;
} else {
// push array not delete
notDeleteOfficer.push(profile.keycloak);
}
}
await this.profileRepo.save(profile);
}),
);
let checkEmployee: number = 0;
let notDeleteEmployee: string[] = [];
await Promise.all(
profileEmployeeLeave.map(async (profileEmp) => {
profileEmp.leaveReason = "เกษียณอายุราชการ";
profileEmp.leaveType = "RETIRE";
profileEmp.leaveDate = new Date("2025-09-30");
profileEmp.dateLeave = new Date("2025-09-30");
profileEmp.lastUpdatedAt = new Date();
profileEmp.isActive = false;
if (profileEmp.keycloak != null && profileEmp.keycloak != "" && profileEmp.isDelete === false) {
const delUserKeycloak = await deleteUser(profileEmp.keycloak, token);
if (delUserKeycloak) {
// profileEmp.keycloak = "";
profileEmp.isDelete = true;
profileEmp.roleKeycloaks = [];
checkEmployee += 1;
} else {
// push array not delete
notDeleteEmployee.push(profileEmp.keycloak);
}
}
await this.profileEmployeeRepo.save(profileEmp);
}),
);
// loop batch at 50 profiles
// const chunkSize = 50;
// for (let i = 0; i < profileLeave.length; i += chunkSize) {
// const chunk = profileLeave.slice(i, i + chunkSize);
// await Promise.all(
// chunk.map(async (profile) => {
// profile.leaveReason = "เกษียณอายุราชการ";
// profile.isActive = false;
// if (profile.keycloak != null && profile.keycloak != "") {
// const delUserKeycloak = await deleteUser(profile.keycloak, token);
// if (delUserKeycloak) {
// profile.keycloak = "";
// profile.roleKeycloaks = [];
// check += 1;
// } else {
// // push array not delete
// notDelete.push(profile.keycloak);
// }
// }
// await this.profileEmployeeRepo.save(profile);
// }),
// );
// }
// จำนวนคนที่ถูกแก้ไขเหตุผลการลาออก
const total = profileLeave.length;
return new HttpSuccess({
total,
successOfficerAmount: checkOfficer,
notDeleteOfficer,
successEmployeeAmount: checkEmployee,
notDeleteEmployee,
});
}
/**
* API สร้าง keycloak ใหม่สำหรับข้าราชการที่รันเกษียณผิด
*
* @summary - สร้าง keycloak ใหม่สำหรับข้าราชการที่รันเกษียณผิด (ADMIN)
*
*/
@Get("update/org/profile-officer/create-keycloak")
async createKeycloakForOfficer(@Request() request: RequestWithUser) {
const [profiles, token] = await Promise.all([
this.profileRepo.find({
where: {
keycloak: IsNull(),
isActive: true,
},
relations: ["roleKeycloaks"],
}),
getToken(),
]);
if (!token)
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถเชื่อมต่อ Keycloak");
let check: number = 0;
for await (const _item of profiles) {
let password = _item.citizenId;
if (_item.birthDate != null) {
const _date = new Date(_item.birthDate.toDateString())
.getDate()
.toString()
.padStart(2, "0");
const _month = (new Date(_item.birthDate.toDateString()).getMonth() + 1)
.toString()
.padStart(2, "0");
const _year = new Date(_item.birthDate.toDateString()).getFullYear() + 543;
password = `${_date}${_month}${_year}`;
}
const checkUser = await getUserByUsername(_item.citizenId, token);
let userId: any = "";
if (checkUser.length == 0) {
userId = await createUser(
_item.citizenId,
password,
{
firstName: _item.firstName,
lastName: _item.lastName,
// email: _item.email,
},
token,
);
if (typeof userId !== "string") {
throw new Error(userId.errorMessage);
}
} else {
userId = checkUser[0].id;
}
const list = await getRoles("", token);
if (!Array.isArray(list)) throw new Error("Failed. Cannot get role(s) data from the server.");
const result = await addUserRoles(
userId,
list.filter((v) => v.id == "8a1a0dc9-304c-4e5b-a90a-65f841048212"),
token,
);
if (!result) {
throw new Error("Failed. Cannot set user's role.");
}
if (typeof userId === "string") {
_item.keycloak = userId;
}
const roleKeycloak = await this.roleKeycloakRepo.find({
where: { id: "8a1a0dc9-304c-4e5b-a90a-65f841048212" },
});
if (_item) {
_item.roleKeycloaks = Array.from(new Set([..._item.roleKeycloaks, ...roleKeycloak]));
this.profileRepo.save(_item);
check += 1;
}
}
const total = profiles.length;
return new HttpSuccess({ total, successAmount: check });
}
/**
* API สร้าง keycloak ใหม่สำหรับลูกจ้างที่รันเกษียณผิด
*
* @summary - สร้าง keycloak ใหม่สำหรับลูกจ้างที่รันเกษียณผิด (ADMIN)
*
*/
@Get("update/org/profile-employee/create-keycloak")
async createKeycloakForEmployee(@Request() request: RequestWithUser) {
let check: number = 0;
const profiles = await this.profileEmployeeRepo.find({
where: {
keycloak: IsNull(),
isLeave: false,
isRetirement: false,
},
order: { citizenId: "ASC" },
relations: ["roleKeycloaks"],
});
// ดึงข้อมูลที่ใช้บ่อยก่อน (cache)
const rolesList = await getRoles();
if (!Array.isArray(rolesList))
throw new Error("Failed. Cannot get role(s) data from the server.");
const roleKeycloak = await this.roleKeycloakRepo.find({
where: { id: "8a1a0dc9-304c-4e5b-a90a-65f841048212" },
});
// Process แบบ batch เพื่อลดการเรียก API ทีละตัว
const batchSize = 100;
const batches = [];
for (let i = 0; i < profiles.length; i += batchSize) {
batches.push(profiles.slice(i, i + batchSize));
}
for (const batch of batches) {
await Promise.all(
batch.map(async (_item) => {
let password = _item.citizenId;
if (_item.birthDate != null) {
const _date = new Date(_item.birthDate.toDateString())
.getDate()
.toString()
.padStart(2, "0");
const _month = (new Date(_item.birthDate.toDateString()).getMonth() + 1)
.toString()
.padStart(2, "0");
const _year = new Date(_item.birthDate.toDateString()).getFullYear() + 543;
password = `${_date}${_month}${_year}`;
}
try {
const checkUser = await getUserByUsername(_item.citizenId);
let userId: any = "";
if (checkUser.length == 0) {
userId = await createUser(_item.citizenId, password, {
firstName: _item.firstName,
lastName: _item.lastName,
});
if (typeof userId !== "string") {
console.error(`Failed to create user for ${_item.citizenId}:`, userId.errorMessage);
return;
}
} else {
userId = checkUser[0].id;
}
const result = await addUserRoles(
userId,
rolesList.filter((v) => v.id == "8a1a0dc9-304c-4e5b-a90a-65f841048212"),
);
if (!result) {
console.error(`Failed to set role for user ${_item.citizenId}`);
return;
}
if (typeof userId === "string") {
_item.keycloak = userId;
}
if (_item) {
_item.roleKeycloaks = Array.from(new Set([..._item.roleKeycloaks, ...roleKeycloak]));
check += 1;
_item = await this.profileEmployeeRepo.save(_item);
// update user attribute in keycloak
await updateUserAttributes(_item.keycloak, {
profileId: [_item.id],
prefix: [_item.prefix || ""],
});
}
} catch (error) {
console.error(`Error processing ${_item.citizenId}:`, error);
}
}),
);
}
const total = profiles.length;
return new HttpSuccess({ total, successAmount: check });
}
/**
* API ย้ายโครงสร้างแบบร่างไปโครงสร้างปัจจุบัน โดยอ้างอิงตาม rootId
*
* @summary - ย้ายโครงสร้างและตำแหน่งจากแบบร่างไปโครงสร้างปัจจุบัน โดยอ้างอิงตาม rootId
*
*/
@Post("move-draft-to-current/{rootDnaId}")
async moveDraftToCurrent(@Path() rootDnaId: string, @Request() request: RequestWithUser) {
const queryRunner = AppDataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
// permission owner only ??
// this code check...
// part 1 ข้อมูลโครงสร้าง
const [drafRevision, currentRevision] = await Promise.all([
this.orgRevisionRepository.findOne({
where: {
orgRevisionIsDraft: true,
orgRevisionIsCurrent: false,
},
select: ["id"],
}),
this.orgRevisionRepository.findOne({
where: {
orgRevisionIsDraft: false,
orgRevisionIsCurrent: true,
},
select: ["id"],
}),
]);
if (!drafRevision || !currentRevision)
return new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
const drafRevisionId = drafRevision.id;
const currentRevisionId = currentRevision.id;
// ตรวจสอบว่ามี rootDnaId ในโครงสร้างร่าง และในโครงสร้างปัจจุบันหรือไม่
let [orgRootDraft, orgRootCurrent] = await Promise.all([
this.orgRootRepository.findOne({
where: {
ancestorDNA: rootDnaId,
orgRevisionId: drafRevisionId,
},
// select: ["id"],
}),
this.orgRootRepository.findOne({
where: {
ancestorDNA: rootDnaId,
orgRevisionId: currentRevisionId,
},
select: ["id"],
}),
]);
if (!orgRootDraft) return new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้างร่าง");
// if current record not found, create new one
if (!orgRootCurrent) {
// Create new current record using draft's ID
const newCurrentRoot = queryRunner.manager.create(OrgRoot, {
...orgRootDraft,
id: undefined, // Let database generate new ID
orgRevisionId: currentRevisionId, // Change to current revision
});
const savedRoot = await queryRunner.manager.save(OrgRoot, newCurrentRoot);
orgRootCurrent = savedRoot; // Use saved record for sync
}
// Part 1: Differential sync of organization structure (bottom-up)
// Build mapping incrementally as we process each level
const allMappings: AllOrgMappings = {
orgRoot: { byAncestorDNA: new Map(), byDraftId: new Map() },
orgChild1: { byAncestorDNA: new Map(), byDraftId: new Map() },
orgChild2: { byAncestorDNA: new Map(), byDraftId: new Map() },
orgChild3: { byAncestorDNA: new Map(), byDraftId: new Map() },
orgChild4: { byAncestorDNA: new Map(), byDraftId: new Map() },
};
// Track sync statistics for organization nodes
const orgSyncStats: Record<string, { deleted: number; updated: number; inserted: number }> =
{};
// Process from top (Root) to bottom (Child4) to handle foreign key constraints
// OrgRoot (sync first - no parent dependencies)
// If we manually created orgRootCurrent, skip syncOrgLevel and set up mapping directly
// to avoid double insert (syncOrgLevel would try to insert again because IDs don't match)
let orgRootResult: {
mapping: OrgIdMapping;
counts: { deleted: number; updated: number; inserted: number };
};
if (
orgRootCurrent &&
orgRootDraft &&
orgRootCurrent.ancestorDNA === orgRootDraft.ancestorDNA
) {
// Manually created - set up mapping directly
const rootMapping: OrgIdMapping = {
byAncestorDNA: new Map([[orgRootDraft.ancestorDNA, orgRootCurrent.id]]),
byDraftId: new Map([[orgRootDraft.id, orgRootCurrent.id]]),
};
orgRootResult = {
mapping: rootMapping,
counts: { deleted: 0, updated: 0, inserted: 1 }, // Count as insert since we created it
};
} else {
// Not manually created - use normal syncOrgLevel flow
orgRootResult = await this.syncOrgLevel(
queryRunner,
OrgRoot,
this.orgRootRepository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
}
allMappings.orgRoot = orgRootResult.mapping;
orgSyncStats.orgRoot = orgRootResult.counts;
// Child1 (parent OrgRoot already synced)
const child1Result = await this.syncOrgLevel(
queryRunner,
OrgChild1,
this.child1Repository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
allMappings.orgChild1 = child1Result.mapping;
orgSyncStats.orgChild1 = child1Result.counts;
// Child2 (parents OrgRoot and Child1 already synced)
const child2Result = await this.syncOrgLevel(
queryRunner,
OrgChild2,
this.child2Repository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
allMappings.orgChild2 = child2Result.mapping;
orgSyncStats.orgChild2 = child2Result.counts;
// Child3 (parents OrgRoot, Child1, Child2 already synced)
const child3Result = await this.syncOrgLevel(
queryRunner,
OrgChild3,
this.child3Repository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
allMappings.orgChild3 = child3Result.mapping;
orgSyncStats.orgChild3 = child3Result.counts;
// Child4 (parents OrgRoot, Child1, Child2, Child3 already synced)
const child4Result = await this.syncOrgLevel(
queryRunner,
OrgChild4,
this.child4Repository,
drafRevisionId,
currentRevisionId,
allMappings,
orgRootDraft?.id,
orgRootCurrent?.id,
);
allMappings.orgChild4 = child4Result.mapping;
orgSyncStats.orgChild4 = child4Result.counts;
// Part 2: Sync position data using new org IDs from Part 1
// 2.1 Clear current_holderId for affected positions (keep existing logic)
// Get draft organization IDs under the given rootDnaId to find positions to clear
const draftOrgIds = {
orgRoot: [...allMappings.orgRoot.byDraftId.keys()],
orgChild1: [...allMappings.orgChild1.byDraftId.keys()],
orgChild2: [...allMappings.orgChild2.byDraftId.keys()],
orgChild3: [...allMappings.orgChild3.byDraftId.keys()],
orgChild4: [...allMappings.orgChild4.byDraftId.keys()],
};
// Get current organization IDs from the mappings (moved up for reuse)
const currentOrgIds = {
orgRoot: [...allMappings.orgRoot.byDraftId.values()],
orgChild1: [...allMappings.orgChild1.byDraftId.values()],
orgChild2: [...allMappings.orgChild2.byDraftId.values()],
orgChild3: [...allMappings.orgChild3.byDraftId.values()],
orgChild4: [...allMappings.orgChild4.byDraftId.values()],
};
// Get draft positions that belong to any org under the rootDnaId
const posMasterDraft = await this.posMasterRepository.find({
where: [
{ orgRevisionId: drafRevisionId, orgRootId: In(draftOrgIds.orgRoot) },
{ orgRevisionId: drafRevisionId, orgChild1Id: In(draftOrgIds.orgChild1) },
{ orgRevisionId: drafRevisionId, orgChild2Id: In(draftOrgIds.orgChild2) },
{ orgRevisionId: drafRevisionId, orgChild3Id: In(draftOrgIds.orgChild3) },
{ orgRevisionId: drafRevisionId, orgChild4Id: In(draftOrgIds.orgChild4) },
],
});
// Special case: If draft has no positions, delete all current positions
if (posMasterDraft.length <= 0) {
// Fetch current positions
const posMasterCurrent = await this.posMasterRepository.find({
where: [
{ orgRevisionId: currentRevisionId, orgRootId: In(currentOrgIds.orgRoot) },
{ orgRevisionId: currentRevisionId, orgChild1Id: In(currentOrgIds.orgChild1) },
{ orgRevisionId: currentRevisionId, orgChild2Id: In(currentOrgIds.orgChild2) },
{ orgRevisionId: currentRevisionId, orgChild3Id: In(currentOrgIds.orgChild3) },
{ orgRevisionId: currentRevisionId, orgChild4Id: In(currentOrgIds.orgChild4) },
],
});
if (posMasterCurrent.length > 0) {
const toDeleteIds = posMasterCurrent.map((p) => p.id);
// Cascade delete positions first
await queryRunner.manager.delete(Position, { posMasterId: In(toDeleteIds) });
// Then delete posMaster records
await queryRunner.manager.delete(PosMaster, toDeleteIds);
// Save history
const deleteHistoryOps = posMasterCurrent.map((pos) => ({
posMasterDnaId: pos.ancestorDNA,
profileId: null,
pm: null,
}));
await BatchSavePosMasterHistoryOfficer(queryRunner, deleteHistoryOps);
}
// Build summary for this special case
const summary = {
message: "ย้ายโครงสร้างสำเร็จ",
organization: {
orgRoot: orgSyncStats.orgRoot,
orgChild1: orgSyncStats.orgChild1,
orgChild2: orgSyncStats.orgChild2,
orgChild3: orgSyncStats.orgChild3,
orgChild4: orgSyncStats.orgChild4,
},
positionMaster: {
deleted: posMasterCurrent.length,
updated: 0,
inserted: 0,
},
position: { deleted: 0, updated: 0, inserted: 0 },
};
await queryRunner.commitTransaction();
return new HttpSuccess(summary);
}
// Clear current_holderId for positions that will have new holders
const nextHolderIds = posMasterDraft
.filter((x) => x.next_holderId != null)
.map((x) => x.next_holderId) as string[];
if (nextHolderIds.length > 0) {
// FIX: Fetch positions first before updating (to avoid race condition)
const posMastersToUpdate = await queryRunner.manager.find(PosMaster, {
where: {
orgRevisionId: currentRevisionId,
current_holderId: In(nextHolderIds),
},
});
// Save history BEFORE clearing current_holderId
const historyOps = posMastersToUpdate
.filter((x) => x.orgRootId != orgRootCurrent?.id)
.map((pos) => ({
posMasterDnaId: pos.ancestorDNA,
profileId: null,
pm: null,
}));
await BatchSavePosMasterHistoryOfficer(queryRunner, historyOps);
// Now clear current_holderId
await queryRunner.manager.update(
PosMaster,
{
orgRevisionId: currentRevisionId,
current_holderId: In(nextHolderIds),
},
{ current_holderId: null, isSit: false },
);
}
// 2.2 Fetch current positions for comparison
const posMasterCurrent = await this.posMasterRepository.find({
where: [
{ orgRevisionId: currentRevisionId, orgRootId: In(currentOrgIds.orgRoot) },
{ orgRevisionId: currentRevisionId, orgChild1Id: In(currentOrgIds.orgChild1) },
{ orgRevisionId: currentRevisionId, orgChild2Id: In(currentOrgIds.orgChild2) },
{ orgRevisionId: currentRevisionId, orgChild3Id: In(currentOrgIds.orgChild3) },
{ orgRevisionId: currentRevisionId, orgChild4Id: In(currentOrgIds.orgChild4) },
],
});
// Build lookup map
const currentByDNA = new Map(posMasterCurrent.map((p) => [p.ancestorDNA, p]));
// 2.3 Batch DELETE: positions in current but not in draft
const toDelete = posMasterCurrent.filter(
(curr) => !posMasterDraft.some((d) => d.ancestorDNA === curr.ancestorDNA),
);
if (toDelete.length > 0) {
const toDeleteIds = toDelete.map((p) => p.id);
// Cascade delete positions first
await queryRunner.manager.delete(Position, { posMasterId: In(toDeleteIds) });
// Then delete posMaster records
await queryRunner.manager.delete(PosMaster, toDeleteIds);
const deleteHistoryOps = toDelete.map((pos) => ({
posMasterDnaId: pos.ancestorDNA,
profileId: null,
pm: null,
}));
await BatchSavePosMasterHistoryOfficer(queryRunner, deleteHistoryOps);
}
// 2.4 Process draft positions (UPDATE or INSERT)
const toUpdate: PosMaster[] = [];
const toInsert: any[] = [];
// Track draft PosMaster ID to current PosMaster ID mapping for position sync
// Type: Map<draftPosMasterId, [currentPosMasterId, nextHolderId]>
const posMasterMapping: Map<string, [string, string | null | undefined]> = new Map();
for (const draftPos of posMasterDraft) {
const current = currentByDNA.get(draftPos.ancestorDNA);
// Map organization IDs using new IDs from Part 1
const orgRootId = this.resolveOrgId(draftPos.orgRootId ?? null, allMappings.orgRoot);
const orgChild1Id = this.resolveOrgId(draftPos.orgChild1Id ?? null, allMappings.orgChild1);
const orgChild2Id = this.resolveOrgId(draftPos.orgChild2Id ?? null, allMappings.orgChild2);
const orgChild3Id = this.resolveOrgId(draftPos.orgChild3Id ?? null, allMappings.orgChild3);
const orgChild4Id = this.resolveOrgId(draftPos.orgChild4Id ?? null, allMappings.orgChild4);
if (current) {
// UPDATE existing position
Object.assign(current, {
createdAt: draftPos.createdAt,
createdUserId: draftPos.createdUserId,
createdFullName: draftPos.createdFullName,
lastUpdatedAt: new Date(),
lastUpdateUserId: request.user.sub,
lastUpdateFullName: request.user.name,
posMasterNoPrefix: draftPos.posMasterNoPrefix,
posMasterNoSuffix: draftPos.posMasterNoSuffix,
posMasterNo: draftPos.posMasterNo,
posMasterOrder: draftPos.posMasterOrder,
orgRootId,
orgChild1Id,
orgChild2Id,
orgChild3Id,
orgChild4Id,
current_holderId: draftPos.next_holderId,
isSit: draftPos.isSit,
reason: draftPos.reason,
isDirector: draftPos.isDirector,
isStaff: draftPos.isStaff,
positionSign: draftPos.positionSign,
statusReport: "DONE",
isCondition: draftPos.isCondition,
conditionReason: draftPos.conditionReason,
});
toUpdate.push(current);
if (draftPos.next_holderId === null) {
await SavePosMasterHistoryOfficer(queryRunner, draftPos.ancestorDNA, null, null);
}
// Track mapping for position sync
posMasterMapping.set(draftPos.id, [current.id, draftPos.next_holderId]);
} else {
// INSERT new position
const newPosMaster = queryRunner.manager.create(PosMaster, {
...draftPos,
id: undefined,
orgRevisionId: currentRevisionId,
orgRootId,
orgChild1Id,
orgChild2Id,
orgChild3Id,
orgChild4Id,
current_holderId: draftPos.next_holderId,
statusReport: "DONE",
});
toInsert.push(newPosMaster);
}
}
// Batch save updates and inserts
if (toUpdate.length > 0) {
await queryRunner.manager.save(toUpdate);
}
if (toInsert.length > 0) {
const saved = await queryRunner.manager.save(toInsert);
// Track mapping for newly inserted posMasters
// saved is an array, map each to its draft ID
if (Array.isArray(saved)) {
for (let i = 0; i < saved.length; i++) {
const draftPos = posMasterDraft.filter((d) => !currentByDNA.has(d.ancestorDNA))[i];
if (draftPos && saved[i]) {
posMasterMapping.set(draftPos.id, [saved[i].id, draftPos.next_holderId]);
}
}
}
}
// 2.5 Sync positions table for all affected posMasters (BATCH operation for performance)
const positionSyncStats = await this.syncAllPositionsBatch(
queryRunner,
posMasterMapping,
drafRevisionId,
currentRevisionId,
);
// Build comprehensive summary
const summary = {
message: "ย้ายโครงสร้างสำเร็จ",
organization: {
orgRoot: orgSyncStats.orgRoot,
orgChild1: orgSyncStats.orgChild1,
orgChild2: orgSyncStats.orgChild2,
orgChild3: orgSyncStats.orgChild3,
orgChild4: orgSyncStats.orgChild4,
},
positionMaster: {
deleted: toDelete.length,
updated: toUpdate.length,
inserted: toInsert.length,
},
position: positionSyncStats,
};
await queryRunner.commitTransaction();
return new HttpSuccess(summary);
} catch (error) {
console.error("Error moving draft to current:", error);
await queryRunner.rollbackTransaction();
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดในการย้ายโครงสร้าง");
} finally {
if (queryRunner.isTransactionActive) {
await queryRunner.rollbackTransaction();
}
await queryRunner.release();
}
}
/**
* Helper function: Map draft ID to current ID using the mapping
*/
private resolveOrgId(draftId: string | null, mapping: OrgIdMapping): string | null {
if (!draftId) return null;
return mapping.byDraftId.get(draftId) ?? null;
}
/**
* Helper function: Cascade delete positions before deleting org node
*/
private async cascadeDeletePositions(
queryRunner: any,
node: any,
entityClass: any,
): Promise<void> {
const whereClause: any = {
orgRevisionId: node.orgRevisionId,
};
// Determine which FK field to use based on entity type
if (entityClass === OrgRoot) {
whereClause.orgRootId = node.id;
} else if (entityClass === OrgChild1) {
whereClause.orgChild1Id = node.id;
} else if (entityClass === OrgChild2) {
whereClause.orgChild2Id = node.id;
} else if (entityClass === OrgChild3) {
whereClause.orgChild3Id = node.id;
} else if (entityClass === OrgChild4) {
whereClause.orgChild4Id = node.id;
}
await queryRunner.manager.delete(PosMaster, whereClause);
}
/**
* Helper function: Generic differential sync for each org level
* Performs DELETE (nodes not in draft), UPDATE (existing nodes), INSERT (new nodes)
*/
private async syncOrgLevel<T extends OrgRoot | OrgChild1 | OrgChild2 | OrgChild3 | OrgChild4>(
queryRunner: any,
entityClass: any,
repository: any,
draftRevisionId: string,
currentRevisionId: string,
parentMappings?: AllOrgMappings,
draftOrgRootId?: string,
currentOrgRootId?: string,
): Promise<{
mapping: OrgIdMapping;
counts: { deleted: number; updated: number; inserted: number };
}> {
// 1. Fetch draft and current nodes under the given rootDnaId
// Build WHERE condition for draft nodes
const draftWhere: any = {
orgRevisionId: draftRevisionId,
};
if (
draftOrgRootId &&
(entityClass === OrgChild1 ||
entityClass === OrgChild2 ||
entityClass === OrgChild3 ||
entityClass === OrgChild4)
) {
draftWhere.orgRootId = draftOrgRootId;
} else if (entityClass === OrgRoot) {
draftWhere.id = draftOrgRootId;
}
// Build WHERE condition for current nodes
const currentWhere: any = {
orgRevisionId: currentRevisionId,
};
if (
currentOrgRootId &&
(entityClass === OrgChild1 ||
entityClass === OrgChild2 ||
entityClass === OrgChild3 ||
entityClass === OrgChild4)
) {
currentWhere.orgRootId = currentOrgRootId;
} else if (entityClass === OrgRoot) {
currentWhere.id = currentOrgRootId;
}
const [draftNodes, currentNodes] = await Promise.all([
repository.find({ where: draftWhere }),
repository.find({ where: currentWhere }),
]);
// 2. Build lookup maps for efficient matching by ancestorDNA
const draftByDNA = new Map(draftNodes.map((n: any) => [n.ancestorDNA, n]));
const currentByDNA = new Map(currentNodes.map((n: any) => [n.ancestorDNA, n]));
const mapping: OrgIdMapping = {
byAncestorDNA: new Map(),
byDraftId: new Map(),
};
// 3. DELETE: Current nodes not in draft (cascade delete positions first)
const toDelete = currentNodes.filter((curr: any) => !draftByDNA.has(curr.ancestorDNA));
for (const node of toDelete) {
// Cascade delete positions first
await this.cascadeDeletePositions(queryRunner, node, entityClass);
await queryRunner.manager.delete(entityClass, node.id);
}
// 4. UPDATE: Nodes that exist in both draft and current (matched by ancestorDNA)
const toUpdate = draftNodes.filter((draft: any) => currentByDNA.has(draft.ancestorDNA));
for (const draft of toUpdate) {
const current: any = currentByDNA.get(draft.ancestorDNA)!;
// Build update data with mapped parent IDs
const updateData: any = {
...draft,
id: current.id,
orgRevisionId: currentRevisionId,
};
// Map parent IDs based on entity level
if (entityClass === OrgChild1 && draft.orgRootId && parentMappings) {
updateData.orgRootId =
parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
} else if (entityClass === OrgChild2) {
if (draft.orgRootId && parentMappings) {
updateData.orgRootId =
parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
}
if (draft.orgChild1Id && parentMappings) {
updateData.orgChild1Id =
parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
}
} else if (entityClass === OrgChild3) {
if (draft.orgRootId && parentMappings) {
updateData.orgRootId =
parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
}
if (draft.orgChild1Id && parentMappings) {
updateData.orgChild1Id =
parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
}
if (draft.orgChild2Id && parentMappings) {
updateData.orgChild2Id =
parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id) ?? draft.orgChild2Id;
}
} else if (entityClass === OrgChild4) {
if (draft.orgRootId && parentMappings) {
updateData.orgRootId =
parentMappings.orgRoot.byDraftId.get(draft.orgRootId) ?? draft.orgRootId;
}
if (draft.orgChild1Id && parentMappings) {
updateData.orgChild1Id =
parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id) ?? draft.orgChild1Id;
}
if (draft.orgChild2Id && parentMappings) {
updateData.orgChild2Id =
parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id) ?? draft.orgChild2Id;
}
if (draft.orgChild3Id && parentMappings) {
updateData.orgChild3Id =
parentMappings.orgChild3.byDraftId.get(draft.orgChild3Id) ?? draft.orgChild3Id;
}
}
await queryRunner.manager.update(entityClass, current.id, updateData);
mapping.byAncestorDNA.set(draft.ancestorDNA, current.id);
mapping.byDraftId.set(draft.id, current.id);
}
// 5. INSERT: Draft nodes not in current
const toInsert = draftNodes.filter((draft: any) => !currentByDNA.has(draft.ancestorDNA));
for (const draft of toInsert) {
const newNode: any = queryRunner.manager.create(entityClass, {
...draft,
id: undefined,
orgRevisionId: currentRevisionId,
});
// Map parent IDs based on entity level
if (entityClass === OrgChild1 && draft.orgRootId) {
if (draft.orgRootId === draftOrgRootId) {
newNode.orgRootId = currentOrgRootId;
} else if (parentMappings) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId);
}
} else if (entityClass === OrgChild2) {
if (draft.orgRootId) {
if (draft.orgRootId === draftOrgRootId) {
newNode.orgRootId = currentOrgRootId;
} else if (parentMappings) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId);
}
}
if (draft.orgChild1Id && parentMappings) {
const mappedChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id);
if (mappedChild1Id) {
newNode.orgChild1Id = mappedChild1Id;
}
}
} else if (entityClass === OrgChild3) {
if (draft.orgRootId) {
if (draft.orgRootId === draftOrgRootId) {
newNode.orgRootId = currentOrgRootId;
} else if (parentMappings) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId);
}
}
if (draft.orgChild1Id && parentMappings) {
const mappedChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id);
if (mappedChild1Id) {
newNode.orgChild1Id = mappedChild1Id;
}
}
if (draft.orgChild2Id && parentMappings) {
const mappedChild2Id = parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id);
if (mappedChild2Id) {
newNode.orgChild2Id = mappedChild2Id;
}
}
} else if (entityClass === OrgChild4) {
if (draft.orgRootId) {
if (draft.orgRootId === draftOrgRootId) {
newNode.orgRootId = currentOrgRootId;
} else if (parentMappings) {
newNode.orgRootId = parentMappings.orgRoot.byDraftId.get(draft.orgRootId);
}
}
if (draft.orgChild1Id && parentMappings) {
const mappedChild1Id = parentMappings.orgChild1.byDraftId.get(draft.orgChild1Id);
if (mappedChild1Id) {
newNode.orgChild1Id = mappedChild1Id;
}
}
if (draft.orgChild2Id && parentMappings) {
const mappedChild2Id = parentMappings.orgChild2.byDraftId.get(draft.orgChild2Id);
if (mappedChild2Id) {
newNode.orgChild2Id = mappedChild2Id;
}
}
if (draft.orgChild3Id && parentMappings) {
const mappedChild3Id = parentMappings.orgChild3.byDraftId.get(draft.orgChild3Id);
if (mappedChild3Id) {
newNode.orgChild3Id = mappedChild3Id;
}
}
}
const saved = await queryRunner.manager.save(newNode);
mapping.byAncestorDNA.set(draft.ancestorDNA, saved.id);
mapping.byDraftId.set(draft.id, saved.id);
}
return {
mapping,
counts: {
deleted: toDelete.length,
updated: toUpdate.length,
inserted: toInsert.length,
},
};
}
/**
* Batch version: Sync positions for ALL posMasters in a single operation
* This significantly reduces database round trips for large organizations
*/
private async syncAllPositionsBatch(
queryRunner: any,
posMasterMapping: Map<string, [string, string | null | undefined]>,
_draftRevisionId: string,
_currentRevisionId: string,
): Promise<{ deleted: number; updated: number; inserted: number }> {
// Extract draft and current posMaster IDs
const draftPosMasterIds = Array.from(posMasterMapping.keys());
const currentPosMasterIds = Array.from(posMasterMapping.values()).map(
([currentId]) => currentId,
);
if (draftPosMasterIds.length === 0) {
return { deleted: 0, updated: 0, inserted: 0 };
}
// Fetch draft PosMasters with relations for history tracking
const draftPosMasters = await queryRunner.manager.find(PosMaster, {
where: { id: In(draftPosMasterIds) },
relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4", "next_holder"],
});
// Fetch ALL positions for ALL posMasters in just 2 queries
const [allDraftPositions, allCurrentPositions] = await Promise.all([
queryRunner.manager.find(Position, {
where: {
posMasterId: In(draftPosMasterIds),
},
relations: ["posType", "posLevel", "posExecutive"],
order: { orderNo: "ASC" },
}),
queryRunner.manager.find(Position, {
where: {
posMasterId: In(currentPosMasterIds),
},
}),
]);
// Group positions by posMasterId for processing
const draftPositionsByMaster = new Map<string, any[]>();
for (const pos of allDraftPositions) {
if (!draftPositionsByMaster.has(pos.posMasterId)) {
draftPositionsByMaster.set(pos.posMasterId, []);
}
draftPositionsByMaster.get(pos.posMasterId)!.push(pos);
}
const currentPositionsByMaster = new Map<string, any[]>();
for (const pos of allCurrentPositions) {
if (!currentPositionsByMaster.has(pos.posMasterId)) {
currentPositionsByMaster.set(pos.posMasterId, []);
}
currentPositionsByMaster.get(pos.posMasterId)!.push(pos);
}
// Collect all operations
const allToDelete: string[] = [];
const allToDeleteHistory: string[] = [];
const allToUpdate: Array<{ id: string; data: any }> = [];
const allToInsert: Array<any> = [];
const profileUpdates: Map<string, any> = new Map();
// Create a map for quick lookup of draft PosMasters with relations
const draftPosMasterMap = new Map(draftPosMasters.map((pm: PosMaster) => [pm.id, pm]));
// Collect PosMasterHistory calls for selected positions
const historyCalls: Array<{
ancestorDNA: string;
profileId: string | null;
historyData: SavePosMasterHistory;
}> = [];
// Process each posMaster mapping
for (const [draftPosMasterId, [currentPosMasterId, nextHolderId]] of posMasterMapping) {
const draftPositions = draftPositionsByMaster.get(draftPosMasterId) || [];
const currentPositions = currentPositionsByMaster.get(currentPosMasterId) || [];
// If no draft positions, mark all current positions for deletion
if (draftPositions.length === 0) {
allToDelete.push(...currentPositions.map((p: any) => p.id));
allToDeleteHistory.push(...currentPositions.map((p: any) => p.ancestorDNA));
continue;
}
// Build map for tracking
const currentByOrderNo = new Map(currentPositions.map((p: any) => [p.orderNo, p]));
const draftOrderNos = new Set(draftPositions.map((p: any) => p.orderNo));
// Mark for deletion: current positions not in draft (by orderNo)
for (const currentPos of currentPositions) {
if (!draftOrderNos.has(currentPos.orderNo)) {
allToDelete.push(currentPos.id);
allToDeleteHistory.push(currentPos.ancestorDNA);
}
}
// Process UPDATE and INSERT
for (const draftPos of draftPositions) {
const current = currentByOrderNo.get(draftPos.orderNo);
if (current) {
// UPDATE existing position - collect for batch update
allToUpdate.push({
id: current.id,
data: {
positionName: draftPos.positionName,
positionField: draftPos.positionField,
posTypeId: draftPos.posTypeId,
posLevelId: draftPos.posLevelId,
posExecutiveId: draftPos.posExecutiveId,
positionExecutiveField: draftPos.positionExecutiveField,
positionArea: draftPos.positionArea,
isSpecial: draftPos.isSpecial,
orderNo: draftPos.orderNo,
positionIsSelected: draftPos.positionIsSelected,
lastUpdateFullName: draftPos.lastUpdateFullName,
lastUpdatedAt: new Date(),
},
});
} else {
// INSERT new position - collect for batch insert
allToInsert.push({
...draftPos,
id: undefined,
posMasterId: currentPosMasterId,
});
}
// Collect history data for the selected position
const draftPosMaster = draftPosMasterMap.get(draftPosMasterId) as any;
// Collect profile update for the selected position
// ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
if (nextHolderId != null && draftPos.positionIsSelected && !draftPosMaster?.isSit) {
profileUpdates.set(nextHolderId, {
position: draftPos.positionName,
posTypeId: draftPos.posTypeId,
posLevelId: draftPos.posLevelId,
});
if (draftPosMaster && draftPosMaster.ancestorDNA) {
// Find the selected position from draft positions
const selectedPos =
draftPositions.find((p) => p.positionIsSelected === true) || draftPos;
historyCalls.push({
ancestorDNA: draftPosMaster.ancestorDNA,
profileId: nextHolderId,
historyData: {
prefix: draftPosMaster.next_holder?.prefix ?? null,
firstName: draftPosMaster.next_holder?.firstName ?? null,
lastName: draftPosMaster.next_holder?.lastName ?? null,
position: selectedPos.positionName ?? null,
posType: (selectedPos as any).posType?.posTypeName ?? null,
posLevel: (selectedPos as any).posLevel?.posLevelName ?? null,
posExecutive: (selectedPos as any).posExecutive?.posExecutiveName ?? null,
profileId: nextHolderId,
rootDnaId: draftPosMaster.orgRoot?.ancestorDNA ?? null,
child1DnaId: draftPosMaster.orgChild1?.ancestorDNA ?? null,
child2DnaId: draftPosMaster.orgChild2?.ancestorDNA ?? null,
child3DnaId: draftPosMaster.orgChild3?.ancestorDNA ?? null,
child4DnaId: draftPosMaster.orgChild4?.ancestorDNA ?? null,
shortName:
[
draftPosMaster.orgChild4?.orgChild4ShortName,
draftPosMaster.orgChild3?.orgChild3ShortName,
draftPosMaster.orgChild2?.orgChild2ShortName,
draftPosMaster.orgChild1?.orgChild1ShortName,
draftPosMaster.orgRoot?.orgRootShortName,
].find((s) => typeof s === "string" && s.trim().length > 0) ?? null,
posMasterNoPrefix: draftPosMaster.posMasterNoPrefix ?? null,
posMasterNo: draftPosMaster.posMasterNo ?? null,
posMasterNoSuffix: draftPosMaster.posMasterNoSuffix ?? null,
},
});
}
}
}
}
// Execute bulk operations
let deletedCount = 0;
let updatedCount = 0;
let insertedCount = 0;
// Bulk DELETE
if (allToDelete.length > 0) {
await queryRunner.manager.delete(Position, allToDelete);
const deleteOps = allToDeleteHistory.map((ancestorDNA) => ({
posMasterDnaId: ancestorDNA,
profileId: null,
pm: null,
}));
await BatchSavePosMasterHistoryOfficer(queryRunner, deleteOps);
deletedCount = allToDelete.length;
}
// Bulk UPDATE (batch by 100 to avoid query size limits)
if (allToUpdate.length > 0) {
const batchSize = 100;
for (let i = 0; i < allToUpdate.length; i += batchSize) {
const batch = allToUpdate.slice(i, i + batchSize);
await Promise.all(
batch.map(({ id, data }) => queryRunner.manager.update(Position, id, data)),
);
}
updatedCount = allToUpdate.length;
}
// Bulk INSERT
if (allToInsert.length > 0) {
const batchSize = 100;
for (let i = 0; i < allToInsert.length; i += batchSize) {
const batch = allToInsert.slice(i, i + batchSize);
await queryRunner.manager.save(Position, batch);
}
insertedCount = allToInsert.length;
}
// Bulk UPDATE profiles
if (profileUpdates.size > 0) {
const profileUpdateEntries = Array.from(profileUpdates.entries());
await Promise.all(
profileUpdateEntries.map(([profileId, data]) =>
queryRunner.manager.update(Profile, profileId, data),
),
);
}
// Save PosMasterHistory for updated positions
if (historyCalls.length > 0) {
await BatchSavePosMasterHistoryOfficer(
queryRunner,
historyCalls.map(({ ancestorDNA, profileId, historyData }) => ({
posMasterDnaId: ancestorDNA,
profileId,
pm: historyData,
})),
);
}
return { deleted: deletedCount, updated: updatedCount, inserted: insertedCount };
}
/**
* Helper: Sum all counts from a map (for root level total)
*/
private sumAllCounts(map: Map<string, { totalCount: number }>): number {
let sum = 0;
for (const value of map.values()) {
sum += value.totalCount;
}
return sum;
}
/**
* Helper: Sum all vacant counts from a map
*/
private sumAllVacantCounts(
map: Map<string, { currentVacantCount: number; nextVacantCount: number }>,
isDraft: boolean,
): number {
let sum = 0;
for (const value of map.values()) {
sum += isDraft ? value.nextVacantCount : value.currentVacantCount;
}
return sum;
}
/**
* Helper: Build orgRoots children array with pre-fetched counts
*/
private buildOrgRoots(
orgRoots: OrgRoot[],
positionCounts: PositionCountsByNode,
isDraft: boolean,
) {
if (!orgRoots) return [];
return orgRoots
.sort((a, b) => a.orgRootOrder - b.orgRootOrder)
.map((orgRoot) => {
const counts = getPositionCount(positionCounts.orgRootMap, orgRoot.id);
return {
departmentName: orgRoot.orgRootName,
deptID: orgRoot.id,
type: 1,
totalPositionCount: counts.totalCount,
totalPositionVacant: isDraft ? counts.nextVacantCount : counts.currentVacantCount,
children: this.buildOrgChild1s(orgRoot.orgChild1s, positionCounts, isDraft),
};
});
}
/**
* Helper: Build orgChild1s children array with pre-fetched counts
*/
private buildOrgChild1s(
orgChild1s: OrgChild1[],
positionCounts: PositionCountsByNode,
isDraft: boolean,
) {
if (!orgChild1s) return [];
return orgChild1s
.sort((a, b) => a.orgChild1Order - b.orgChild1Order)
.map((orgChild1) => {
const counts = getPositionCount(positionCounts.orgChild1Map, orgChild1.id);
return {
departmentName: orgChild1.orgChild1Name,
deptID: orgChild1.id,
type: 2,
totalPositionCount: counts.totalCount,
totalPositionVacant: isDraft ? counts.nextVacantCount : counts.currentVacantCount,
children: this.buildOrgChild2s(orgChild1.orgChild2s, positionCounts, isDraft),
};
});
}
/**
* Helper: Build orgChild2s children array with pre-fetched counts
*/
private buildOrgChild2s(
orgChild2s: OrgChild2[],
positionCounts: PositionCountsByNode,
isDraft: boolean,
) {
if (!orgChild2s) return [];
return orgChild2s
.sort((a, b) => a.orgChild2Order - b.orgChild2Order)
.map((orgChild2) => {
const counts = getPositionCount(positionCounts.orgChild2Map, orgChild2.id);
return {
departmentName: orgChild2.orgChild2Name,
deptID: orgChild2.id,
type: 3,
totalPositionCount: counts.totalCount,
totalPositionVacant: isDraft ? counts.nextVacantCount : counts.currentVacantCount,
children: this.buildOrgChild3s(orgChild2.orgChild3s, positionCounts, isDraft),
};
});
}
/**
* Helper: Build orgChild3s children array with pre-fetched counts
*/
private buildOrgChild3s(
orgChild3s: OrgChild3[],
positionCounts: PositionCountsByNode,
isDraft: boolean,
) {
if (!orgChild3s) return [];
return orgChild3s
.sort((a, b) => a.orgChild3Order - b.orgChild3Order)
.map((orgChild3) => {
const counts = getPositionCount(positionCounts.orgChild3Map, orgChild3.id);
return {
departmentName: orgChild3.orgChild3Name,
deptID: orgChild3.id,
type: 4,
totalPositionCount: counts.totalCount,
totalPositionVacant: isDraft ? counts.nextVacantCount : counts.currentVacantCount,
children: this.buildOrgChild4s(orgChild3.orgChild4s, positionCounts, isDraft),
};
});
}
/**
* Helper: Build orgChild4s children array with pre-fetched counts (leaf nodes)
*/
private buildOrgChild4s(
orgChild4s: OrgChild4[],
positionCounts: PositionCountsByNode,
isDraft: boolean,
) {
if (!orgChild4s) return [];
return orgChild4s
.sort((a, b) => a.orgChild4Order - b.orgChild4Order)
.map((orgChild4) => {
const counts = getPositionCount(positionCounts.orgChild4Map, orgChild4.id);
return {
departmentName: orgChild4.orgChild4Name,
deptID: orgChild4.id,
type: 5,
totalPositionCount: counts.totalCount,
totalPositionVacant: isDraft ? counts.nextVacantCount : counts.currentVacantCount,
};
});
}
}