diff --git a/src/controllers/OrganizationUnauthorizeController.ts b/src/controllers/OrganizationUnauthorizeController.ts index deaa1f35..c1baff3b 100644 --- a/src/controllers/OrganizationUnauthorizeController.ts +++ b/src/controllers/OrganizationUnauthorizeController.ts @@ -4,7 +4,7 @@ import { AppDataSource } from "../database/data-source"; import HttpSuccess from "../interfaces/http-success"; import HttpError from "../interfaces/http-error"; import HttpStatusCode from "../interfaces/http-status"; -import { Brackets, In, IsNull, MoreThanOrEqual, Not } from "typeorm"; +import { Brackets, In, IsNull, LessThanOrEqual, MoreThanOrEqual, Not } from "typeorm"; import { OrgRoot } from "../entities/OrgRoot"; import { PosMaster } from "../entities/PosMaster"; import { calculateRetireDate } from "../interfaces/utils"; @@ -24,6 +24,7 @@ import { viewEmployeePosMaster } from "../entities/view/viewEmployeePosMaster"; import { EmployeePosDict } from "../entities/EmployeePosDict"; import { ProfileSalary } from "../entities/ProfileSalary"; import { ProfileInsignia } from "../entities/ProfileInsignia"; +import { PosMasterHistory } from "../entities/PosMasterHistory"; @Route("api/v1/org/unauthorize") @Tags("OrganizationUnauthorize") @Response( @@ -44,6 +45,7 @@ export class OrganizationUnauthorizeController extends Controller { private posMasterRepository = AppDataSource.getRepository(PosMaster); private empPosMasterRepository = AppDataSource.getRepository(EmployeePosMaster); private salaryRepo = AppDataSource.getRepository(ProfileSalary); + private posMasterHistoryRepository = AppDataSource.getRepository(PosMasterHistory); private insigniaRepo = AppDataSource.getRepository(ProfileInsignia); @Post("user/reset-password") async forgetPassword( @@ -3107,4 +3109,327 @@ export class OrganizationUnauthorizeController extends Controller { await this.profileEmpRepo.save(profiles); return new HttpSuccess(); } + + /** + * API รายชื่อข้าราชการ (unauthorize) + * + * @summary รายชื่อข้าราชการ + * + */ + @Post("officer-list") + async officerList( + @Body() + body: { + reqNode?: number; + reqNodeId?: string; + date: Date; + }, + ) { + let typeCondition: any = {}; + + // Build typeCondition based on reqNode and reqNodeId (similar to OWNER/ROOT/PARENT logic) + switch (body.reqNode) { + case 0: + typeCondition = { + rootDnaId: body.reqNodeId, + }; + break; + case 1: + typeCondition = { + child1DnaId: body.reqNodeId, + }; + break; + case 2: + typeCondition = { + child2DnaId: body.reqNodeId, + }; + break; + case 3: + typeCondition = { + child3DnaId: body.reqNodeId, + }; + break; + case 4: + typeCondition = { + child4DnaId: body.reqNodeId, + }; + break; + default: + typeCondition = {}; + break; + } + + const date = body.date ? new Date(body.date.toISOString().slice(0, 10)) : new Date(); + // set เวลาเป็น 23:59:59 ของวันนั้น + date.setHours(23, 59, 59, 999); + + let profile = await this.posMasterHistoryRepository.find({ + where: { + ...typeCondition, + createdAt: LessThanOrEqual(date), + }, + order: { + firstName: "ASC", + lastName: "ASC", + createdAt: "DESC", + }, + }); + + // group1: group by ancestorDNA แล้วเลือก create_at ล่าสุด + const grouped1 = new Map(); + for (const item of profile) { + const key = `${item.ancestorDNA}`; + if (!grouped1.has(key)) { + grouped1.set(key, item); + } else { + const exist = grouped1.get(key); + if (exist && item.createdAt > exist.createdAt) { + grouped1.set(key, item); + } + } + } + // group2: group by shortName-posMasterNo จากค่าที่ได้จาก group1 + const grouped2 = new Map(); + for (const item of Array.from(grouped1.values())) { + const key = `${item.shortName}-${item.posMasterNo}`; + if (!grouped2.has(key)) { + grouped2.set(key, item); + } else { + const exist = grouped2.get(key); + if (exist && item.createdAt > exist.createdAt) { + grouped2.set(key, item); + } + } + } + // group3: group by firstName-lastName จากค่าที่ได้จาก group2 + const grouped3 = new Map(); + for (const item of Array.from(grouped2.values())) { + const key = `${item.firstName}-${item.lastName}`; + if (!grouped3.has(key)) { + grouped3.set(key, item); + } else { + const exist = grouped3.get(key); + if (exist && item.createdAt > exist.createdAt) { + grouped3.set(key, item); + } + } + } + + const profile_ = await Promise.all( + Array.from(grouped3.values()) + .filter((x) => x.profileId != null) + .map(async (item: PosMasterHistory) => { + let profile = await this.profileRepo.findOne({ + where: { id: item.profileId }, + }); + + return { + id: item.profileId, + prefix: item.prefix, + firstName: item.firstName, + lastName: item.lastName, + citizenId: profile?.citizenId ?? null, + dateStart: profile?.dateStart ?? null, + dateAppoint: profile?.dateAppoint ?? null, + keycloak: profile?.keycloak ?? null, + posNo: `${item.shortName} ${item.posMasterNo}`, + position: item.position, + positionLevel: item.posLevel, + positionType: item.posType, + orgRootId: item.rootDnaId, + orgChild1Id: item.child1DnaId, + orgChild2Id: item.child2DnaId, + orgChild3Id: item.child3DnaId, + orgChild4Id: item.child4DnaId, + }; + }), + ); + + return new HttpSuccess( + (profile_ ?? []).sort((a, b) => a.posNo.localeCompare(b.posNo, undefined, { numeric: true })), + ); + } + + /** + * API รายชื่อพนักงาน (unauthorize) + * + * @summary รายชื่อพนักงาน + * + */ + @Post("employee-list") + async employeeList( + @Body() + body: { + reqNode?: number; + reqNodeId?: string; + startDate?: Date; + endDate?: Date; + revisionId?: string; + }, + ) { + let typeCondition: any = {}; + + // Build typeCondition based on reqNode and reqNodeId (similar to OWNER/ROOT/PARENT logic) + switch (body.reqNode) { + case 0: + typeCondition = { + orgRoot: { + id: body.reqNodeId, + }, + }; + break; + case 1: + typeCondition = { + orgChild1: { + id: body.reqNodeId, + }, + }; + break; + case 2: + typeCondition = { + orgChild2: { + id: body.reqNodeId, + }, + }; + break; + case 3: + typeCondition = { + orgChild3: { + id: body.reqNodeId, + }, + }; + break; + case 4: + typeCondition = { + orgChild4: { + id: body.reqNodeId, + }, + }; + break; + default: + typeCondition = {}; + break; + } + + let profile = await this.profileEmpRepo.find({ + where: { isLeave: false, isRetirement: false, current_holders: typeCondition }, + relations: [ + "posType", + "posLevel", + "current_holders", + "current_holders.orgRoot", + "current_holders.orgChild1", + "current_holders.orgChild2", + "current_holders.orgChild3", + "current_holders.orgChild4", + ], + order: { + current_holders: { + orgRoot: { + orgRootOrder: "ASC", + }, + orgChild1: { + orgChild1Order: "ASC", + }, + orgChild2: { + orgChild2Order: "ASC", + }, + orgChild3: { + orgChild3Order: "ASC", + }, + orgChild4: { + orgChild4Order: "ASC", + }, + posMasterNo: "ASC", + }, + }, + }); + + let findRevision = await this.orgRevisionRepository.findOne({ + where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, + }); + + if (body.revisionId) { + findRevision = await this.orgRevisionRepository.findOne({ + where: { id: body.revisionId }, + }); + } + + const profile_ = await Promise.all( + profile.map(async (item: ProfileEmployee) => { + const shortName = + item.current_holders.length == 0 + ? null + : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null && + item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild4 != + null + ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild4.orgChild4ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}` + : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null && + item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) + ?.orgChild3 != null + ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild3.orgChild3ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}` + : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null && + item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) + ?.orgChild2 != null + ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild2.orgChild2ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}` + : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null && + item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) + ?.orgChild1 != null + ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild1.orgChild1ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}` + : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != + null && + item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) + ?.orgRoot != null + ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgRoot.orgRootShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}` + : null; + const Oc = + item.current_holders.length == 0 + ? null + : item.current_holders[0].orgChild4 != null + ? `${item.current_holders[0].orgChild4.orgChild4Name}/${item.current_holders[0].orgChild3.orgChild3Name}/${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}` + : item.current_holders[0].orgChild3 != null + ? `${item.current_holders[0].orgChild3.orgChild3Name}/${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}` + : item.current_holders[0].orgChild2 != null + ? `${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}` + : item.current_holders[0].orgChild1 != null + ? `${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}` + : item.current_holders[0].orgRoot != null + ? `${item.current_holders[0].orgRoot.orgRootName}` + : null; + + let _posMaster = await this.empPosMasterRepository.findOne({ + where: { + orgRevisionId: findRevision?.id, + current_holderId: item.id, + }, + }); + + return { + id: item.id, + prefix: item.prefix, + firstName: item.firstName, + lastName: item.lastName, + citizenId: item.citizenId, + dateStart: item.dateStart, + dateAppoint: item.dateAppoint, + keycloak: item.keycloak, + posNo: shortName, + position: item.position, + positionLevel: + item.posType?.posTypeShortName && item.posLevel?.posLevelName + ? `${item.posType?.posTypeShortName} ${item.posLevel?.posLevelName}` + : null, + positionType: item.posType?.posTypeName ?? null, + oc: Oc, + orgRootId: _posMaster?.orgRootId, + orgChild1Id: _posMaster?.orgChild1Id, + orgChild2Id: _posMaster?.orgChild2Id, + orgChild3Id: _posMaster?.orgChild3Id, + orgChild4Id: _posMaster?.orgChild4Id, + }; + }), + ); + + return new HttpSuccess(profile_); + } }