diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 7cce510c..c9302286 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -1954,27 +1954,71 @@ export class CommandController extends Controller { ]; } const orgLeave = _OrgLeave.filter((x: any) => x !== undefined && x !== null).join("\n"); + let profileTemp = { + org: "-", + position: "-", + posLevel: "-", + posNo: "-", + }; + if (commandCode == "C-PM-21") { + profileTemp.position = profile?.positionTemp ?? "-"; + profileTemp.posLevel = profile?.posLevelNameTemp ?? "-"; + profileTemp.org = (profile?.child4Temp == null ? "" : profile?.child4Temp + "\n") + + (profile?.child3Temp == null ? "" : profile?.child3Temp + "\n") + + (profile?.child2Temp == null ? "" : profile?.child2Temp + "\n") + + (profile?.child1Temp == null ? "" : profile?.child1Temp + "\n") + + (profile?.rootTemp == null ? "" : profile?.rootTemp) + if (profile?.nodeTemp) { + switch (profile?.nodeTemp) { + case "4": + profileTemp.posNo = `${profile.child4ShortNameTemp} ${profile?.posMasterNoTemp}`; + break + case "3": + profileTemp.posNo = `${profile.child3ShortNameTemp} ${profile?.posMasterNoTemp}`; + break + case "2": + profileTemp.posNo = `${profile.child2ShortNameTemp} ${profile?.posMasterNoTemp}`; + break + case "1": + profileTemp.posNo = `${profile.child1ShortNameTemp} ${profile?.posMasterNoTemp}`; + break + case "0": + profileTemp.posNo = `${profile.rootShortNameTemp} ${profile?.posMasterNoTemp}`; + break + default: break; + } + } + } return { no: Extension.ToThaiNumber((idx + 1).toString()), - org: profile?.isLeave == false - ? (_child4 == null ? "" : _child4 + "\n") + - (_child3 == null ? "" : _child3 + "\n") + - (_child2 == null ? "" : _child2 + "\n") + - (_child1 == null ? "" : _child1 + "\n") + - (_root == null ? "" : _root) - : orgLeave, + org: commandCode != "C-PM-21" + ? profile?.isLeave == false + ? (_child4 == null ? "" : _child4 + "\n") + + (_child3 == null ? "" : _child3 + "\n") + + (_child2 == null ? "" : _child2 + "\n") + + (_child1 == null ? "" : _child1 + "\n") + + (_root == null ? "" : _root) + : orgLeave + : profileTemp.org, fullName: `${x.prefix}${x.firstName} ${x.lastName}`, citizenId: Extension.ToThaiNumber(x.citizenId), - position: profile?.position ? profile?.position : "-", - posLevel: - profile?.posType && profile?.posLevel + position: commandCode != "C-PM-21" + ? profile?.position + ? profile?.position + : "-" + : profileTemp.position, + posLevel: commandCode != "C-PM-21" + ? profile?.posType && profile?.posLevel ? Extension.ToThaiNumber( `${profile?.posType.posTypeShortName} ${profile?.posLevel.posLevelName}`, ) - : "-", - posNo: shortName - ? Extension.ToThaiNumber(shortName) - : "-", + : "-" + : Extension.ToThaiNumber(profileTemp.posLevel), + posNo: commandCode != "C-PM-21" + ? shortName + ? Extension.ToThaiNumber(shortName) + : "-" + : Extension.ToThaiNumber(profileTemp.posNo), amount: x.amount ? Extension.ToThaiNumber(x.amount.toLocaleString()) : "-", dateRetire: profile?.dateRetire ? Extension.ToThaiNumber(Extension.ToThaiShortDate_monthYear(profile?.dateRetire)) diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index 18a65e8d..8544c1f3 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -1,3 +1,4 @@ +import { RoleKeycloak } from "./../entities/RoleKeycloak"; import { ProfileEmployee } from "./../entities/ProfileEmployee"; import { EmployeePosition } from "./../entities/EmployeePosition"; import { EmployeePosMaster } from "./../entities/EmployeePosMaster"; @@ -37,7 +38,14 @@ import { sendToQueueOrg, sendToQueueOrgDraft } from "../services/rabbitmq"; import { PosType } from "../entities/PosType"; import { PosLevel } from "../entities/PosLevel"; import { PermissionOrg } from "../entities/PermissionOrg"; -import { deleteUser, getToken } from "../keycloak"; +import { + deleteUser, + getToken, + createUser, + getUserByUsername, + getRoles, + addUserRoles, +} from "../keycloak"; import { CreatePosMasterHistoryEmployee, CreatePosMasterHistoryOfficer, @@ -69,6 +77,8 @@ export class OrganizationController extends Controller { private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee); private employeePosMasterRepository = AppDataSource.getRepository(EmployeePosMaster); private employeePositionRepository = AppDataSource.getRepository(EmployeePosition); + private roleKeycloakRepo = AppDataSource.getRepository(RoleKeycloak); + /** * API ล้างข้อมูล * @@ -1973,6 +1983,7 @@ export class OrganizationController extends Controller { 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({ @@ -1987,14 +1998,43 @@ export class OrganizationController extends Controller { ?.posMasterAssigns.find((x) => x.assignId === "SYS_ORG"); if (orgRevision.orgRevisionIsDraft && !orgRevision.orgRevisionIsCurrent && !attrOwnership) { - _data.root = profile.permissionProfiles.map((x) => x.orgRootId); + 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) { - _data.root = [profile.current_holders.find((x) => x.orgRevisionId === id)?.orgRootId]; + if (profileAssign && _privilege.privilege !== "OWNER") { + 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") { + 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; } @@ -7281,61 +7321,96 @@ export class OrganizationController extends Controller { } /** - * API ลบคนในโครงสร้าง + * API ลบข้าราชการในโครงสร้าง * - * @summary - ลบคนในโครงสร้าง (ADMIN) + * @summary - ลบข้าราชการในโครงสร้าง (ADMIN) * */ - @Get("delete/profile/org/{orgRevisionId}") - async deleteRetireInOrg(@Path() orgRevisionId: string, @Request() request: RequestWithUser) { - // const posMasters = await this.posMasterRepository.find({ - // where: { - // orgRevisionId: orgRevisionId, - // current_holder: { - // isLeave: true, - // }, - // }, - // }); - - // let check = 0; - // await Promise.all( - // posMasters.map(async (posMaster) => { - // posMaster.current_holderId = null; - // await this.posMasterRepository.save(posMaster); - // check += 1; - // }), - // ); - - const posMastersEmployee = await this.employeePosMasterRepository.find({ + @Get("delete/profile-officer/org/{orgRevisionId}") + async deleteOfficerRetireInOrg( + @Path() orgRevisionId: string, + @Request() request: RequestWithUser, + ) { + const posMasters = await this.posMasterRepository.find({ where: { - orgRevisionId: orgRevisionId, + orgRevisionId, + current_holderId: Not(IsNull()), current_holder: { isLeave: true, - leaveType: "RETIRE", + isRetirement: true, }, - positions: { positionIsSelected: true }, + // positions: { positionIsSelected: true }, }, + relations: ["positions"], }); - let check = 0; + 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); - check += 1; + checkEmployee += 1; } } await this.employeePosMasterRepository.save(posMaster); await CreatePosMasterHistoryEmployee(posMaster.id, null); - check += 1; }), ); - // จำนวนคนที่ถูกลบออกจากโครงสร้าง - const total = posMastersEmployee.length; - return new HttpSuccess({ total, successAmount: check }); + + return new HttpSuccess({ + totalEmployee: posMastersEmployee.length, + employeeSuccessAmount: checkEmployee, + }); } /** @@ -7346,75 +7421,78 @@ export class OrganizationController extends Controller { */ @Get("save/profile/position-history") async saveRetireToPositionHistory(@Request() request: RequestWithUser) { - // const profileLeave = await this.profileRepo.find({ - // where: { - // isLeave: true, - // leaveType: "RETIRE", - // }, - // }); + 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 check: 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); - - // check += 1; - // }), - // ); - - const profileLeave = await this.profileEmployeeRepo.find({ - where: { - isLeave: true, - leaveType: "RETIRE", - }, - }); - - let check: number = 0; + 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" }, @@ -7460,13 +7538,20 @@ export class OrganizationController extends Controller { history.profileSalaryId = savedData.id; await this.salaryHistoryRepo.save(history); - check += 1; + checkEmployee += 1; }), ); + // จำนวนคนที่บันทึกลงประวัติตำแหน่ง - const total = profileLeave.length; + const totalOfficer = profileLeave.length; + const totalEmployee = profileEmployeeLeave.length; // จำนวนคนที่ถูกบันทึกลงประวัติตำแหน่งสำเร็จ - return new HttpSuccess({ total, successAmount: check }); + return new HttpSuccess({ + totalOfficer, + totalEmployee, + officerSuccessAmount: checkOfficer, + successEmployeeAmount: checkEmployee, + }); } /** @@ -7477,41 +7562,19 @@ export class OrganizationController extends Controller { */ @Get("update/profile/leave-reason") async updateRetireReason() { - // const profileLeave = await this.profileRepo.find({ - // where: { - // isLeave: true, - // leaveType: "RETIRE", - // }, - // }); - - // let check: number = 0; - // let notDelete: string[] = []; - // await Promise.all( - // profileLeave.map(async (profile) => { - // profile.leaveReason = "เกษียณอายุราชการ"; - // profile.isActive = false; - - // if (profile.keycloak != null && profile.keycloak != "") { - // const delUserKeycloak = await deleteUser(profile.keycloak); - // if (delUserKeycloak) { - // profile.keycloak = ""; - // profile.roleKeycloaks = []; - // check += 1; - // } else { - // // push array not delete - // notDelete.push(profile.keycloak); - // } - // } - - // await this.profileRepo.save(profile); - // }), - // ); - - const [profileLeave, token] = await Promise.all([ + const [profileLeave, profileEmployeeLeave, token] = await Promise.all([ + this.profileRepo.find({ + where: { + isLeave: true, + isRetirement: true, + leaveType: IsNull(), + }, + }), this.profileEmployeeRepo.find({ where: { isLeave: true, - leaveType: "RETIRE", + isRetirement: true, + leaveType: IsNull(), }, }), getToken(), @@ -7520,77 +7583,272 @@ export class OrganizationController extends Controller { if (!token) throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถเชื่อมต่อ Keycloak"); - let check: number = 0; - let notDelete: string[] = []; + let checkOfficer: number = 0; + let notDeleteOfficer: string[] = []; - // 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, successAmount: check, notDelete }); - } - - /** - * API ลบตำแหน่งที่ครองอยู่ของข้าราชการที่รันเกษียณไปแล้ว - * - * @summary - ลบตำแหน่งที่ครองอยู่ของข้าราชการที่รันเกษียณไปแล้ว (ADMIN) - * - */ - @Get("update/org/position/remove-select/{orgRevisionId}") - async updatePositionSelectOrg( - @Path() orgRevisionId: string, - @Request() request: RequestWithUser, - ) { - const posMasters = await this.posMasterRepository.find({ - where: { - orgRevisionId: orgRevisionId, - current_holderId: IsNull(), - positions: { positionIsSelected: true }, - }, - relations: ["positions"], - }); - - // update position positionIsSelected = 0 - let check = 0; await Promise.all( - posMasters.map(async (posMaster) => { - if (posMaster.positions && posMaster.positions.length > 0) { - for (const position of posMaster.positions) { - position.positionIsSelected = false; - await this.positionRepository.save(position); - check += 1; + profileLeave.map(async (profile) => { + profile.leaveReason = "เกษียณอายุราชการ"; + profile.leaveType = "RETIRE"; + profile.isActive = false; + + if (profile.keycloak != null && profile.keycloak != "") { + const delUserKeycloak = await deleteUser(profile.keycloak, token); + if (delUserKeycloak) { + profile.keycloak = ""; + profile.roleKeycloaks = []; + checkOfficer += 1; + } else { + // push array not delete + notDeleteOfficer.push(profile.keycloak); } - await CreatePosMasterHistoryOfficer(posMaster.id, null); } + + await this.profileRepo.save(profile); }), ); - // จำนวนคนที่ถูกลบออกจากโครงสร้าง - const total = posMasters.length; + 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 != "") { + const delUserKeycloak = await deleteUser(profileEmp.keycloak, token); + if (delUserKeycloak) { + profileEmp.keycloak = ""; + 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; + await this.profileEmployeeRepo.save(_item); + } + } catch (error) { + console.error(`Error processing ${_item.citizenId}:`, error); + } + }), + ); + } + const total = profiles.length; return new HttpSuccess({ total, successAmount: check }); } } diff --git a/src/controllers/OrganizationDotnetController.ts b/src/controllers/OrganizationDotnetController.ts index 84d88bbc..52acf7f0 100644 --- a/src/controllers/OrganizationDotnetController.ts +++ b/src/controllers/OrganizationDotnetController.ts @@ -282,7 +282,6 @@ export class OrganizationDotnetController extends Controller { }), ) .andWhere(condition, conditionParams) - .orderBy("profileSalary.order", "DESC") .select([ "profile.id", "profile.citizenId", @@ -4390,7 +4389,7 @@ export class OrganizationDotnetController extends Controller { }, ) { let typeCondition: any = {}; - if (body.role === "CHILD" || body.role === "PARENT" || body.role === "ROOT") { + if (body.role === "CHILD" || body.role === "PARENT") { switch (body.node) { case 0: typeCondition = { @@ -4431,7 +4430,7 @@ export class OrganizationDotnetController extends Controller { typeCondition = {}; break; } - } else if (body.role === "OWNER") { + } else if (body.role === "OWNER" || body.role === "ROOT") { switch (body.reqNode) { case 0: typeCondition = { @@ -4985,7 +4984,7 @@ export class OrganizationDotnetController extends Controller { }, ) { let typeCondition: any = {}; - if (body.role === "CHILD" || body.role === "PARENT" || body.role === "ROOT") { + if (body.role === "CHILD" || body.role === "PARENT") { switch (body.node) { case 0: typeCondition = { @@ -5029,7 +5028,7 @@ export class OrganizationDotnetController extends Controller { typeCondition = {}; break; } - } else if (body.role === "OWNER") { + } else if (body.role === "OWNER" || body.role === "ROOT") { switch (body.reqNode) { case 0: typeCondition = { diff --git a/src/controllers/PositionController.ts b/src/controllers/PositionController.ts index 4deffbaa..e9f8d99e 100644 --- a/src/controllers/PositionController.ts +++ b/src/controllers/PositionController.ts @@ -2134,7 +2134,6 @@ export class PositionController extends Controller { orgChild1Id: IsNull(), }; searchShortName = `CONCAT(orgRoot.orgRootShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`; - } else { } } else if (body.type === 1) { typeCondition = { @@ -2145,7 +2144,6 @@ export class PositionController extends Controller { orgChild2Id: IsNull(), }; searchShortName = `CONCAT(orgChild1.orgChild1ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`; - } else { } } else if (body.type === 2) { typeCondition = { @@ -2156,7 +2154,6 @@ export class PositionController extends Controller { orgChild3Id: IsNull(), }; searchShortName = `CONCAT(orgChild2.orgChild2ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`; - } else { } } else if (body.type === 3) { typeCondition = { @@ -2167,7 +2164,6 @@ export class PositionController extends Controller { orgChild4Id: IsNull(), }; searchShortName = `CONCAT(orgChild3.orgChild3ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`; - } else { } } else if (body.type === 4) { typeCondition = { @@ -2524,6 +2520,40 @@ export class PositionController extends Controller { }; }), ); + + if(_data.privilege === 'NORMAL'|| _data.privilege === 'PARENT'|| _data.privilege === 'CHILD'){ //PARENT จะไม่มีทางเห็น ROOT , CHILD ยึดจาก CHILD ที่อยู่ลงไปข้างล่างและจะไม่เห็น CHILD ที่อยู่เหนือกว่า + const nextChildMap:any = { //เอาไวเช็ค CHILD ถัดไป + 0: _data.child1, + 1: _data.child2, + 2: _data.child3, + 3: _data.child4, + }; + const childValue = nextChildMap[body.type]; + if(_data.privilege === 'NORMAL'){ + if (Array.isArray(childValue) && childValue.some(item => item != null)) { + return new HttpSuccess({ data: [], total: 0 }); + } + }else if(_data.privilege === 'PARENT'){ + if (body.type == 0){ + return new HttpSuccess({ data: [], total: 0 }); + } + } else if (_data.privilege === 'CHILD') { + const higherChildChecks = [ + { type: [0], child: _data.child1, next: _data.child2 }, + { type: [0, 1], child: _data.child2, next: _data.child3 }, + { type: [0, 1, 2], child: _data.child3, next: _data.child4 }, + { type: [0, 1, 2, 3], child: _data.child4, next: true }, + ]; + + for (const check of higherChildChecks) { + if (Array.isArray(check.child) && check.next == null) { + if (check.type.includes(body.type)) { + return new HttpSuccess({ data: [], total: 0 }); + } + } + } + } + } return new HttpSuccess({ data: formattedData, total }); } diff --git a/src/controllers/ProfileController.ts b/src/controllers/ProfileController.ts index d4e65f29..aebd8fa6 100644 --- a/src/controllers/ProfileController.ts +++ b/src/controllers/ProfileController.ts @@ -5262,6 +5262,7 @@ export class ProfileController extends Controller { if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลโปรไฟล์นี้"); Object.assign(record, body); + record.dateRetireLaw = calculateRetireLaw(record.birthDate); record.prefixMain = record.prefix; record.prefix = record.rank && record.rank.length > 0 ? record.rank : record.prefixMain; record.createdUserId = request.user.sub; diff --git a/src/controllers/ProfileEmployeeController.ts b/src/controllers/ProfileEmployeeController.ts index a7d905ad..52de0922 100644 --- a/src/controllers/ProfileEmployeeController.ts +++ b/src/controllers/ProfileEmployeeController.ts @@ -2002,6 +2002,7 @@ export class ProfileEmployeeController extends Controller { } Object.assign(record, body); + record.dateRetireLaw = calculateRetireLaw(record.birthDate); record.prefixMain = record.prefix; record.prefix = record.rank && record.rank.length > 0 ? record.rank : record.prefixMain; record.createdUserId = request.user.sub; diff --git a/src/controllers/ProfileEmployeeTempController.ts b/src/controllers/ProfileEmployeeTempController.ts index 46ef525b..6dc49b1a 100644 --- a/src/controllers/ProfileEmployeeTempController.ts +++ b/src/controllers/ProfileEmployeeTempController.ts @@ -994,6 +994,7 @@ export class ProfileEmployeeTempController extends Controller { } Object.assign(record, body); + record.dateRetireLaw = calculateRetireLaw(record.birthDate); record.prefixMain = record.prefix; record.createdUserId = request.user.sub; record.createdFullName = request.user.name; diff --git a/src/keycloak/index.ts b/src/keycloak/index.ts index c14a6b62..a81e2af9 100644 --- a/src/keycloak/index.ts +++ b/src/keycloak/index.ts @@ -67,11 +67,16 @@ export async function getToken() { * * @returns user uuid or true if success, false otherwise. */ -export async function createUser(username: string, password: string, opts?: Record) { +export async function createUser( + username: string, + password: string, + opts?: Record, + token?: string, +) { const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users`, { // prettier-ignore headers: { - "authorization": `Bearer ${await getToken()}`, + "authorization": `Bearer ${token || await getToken()}`, "content-type": `application/json`, }, method: "POST", @@ -101,11 +106,11 @@ export async function createUser(username: string, password: string, opts?: Reco * * @returns user if success, false otherwise. */ -export async function getUser(userId: string) { +export async function getUser(userId: string, token?: string) { const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users/${userId}`, { // prettier-ignore headers: { - "authorization": `Bearer ${await getToken()}`, + "authorization": `Bearer ${token || await getToken()}`, "content-type": `application/json`, }, }).catch((e) => console.log("Keycloak Error: ", e)); @@ -123,11 +128,11 @@ export async function getUser(userId: string) { * * @returns user if success, false otherwise. */ -export async function getUserByUsername(citizenId: string) { +export async function getUserByUsername(citizenId: string, token?: string) { const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users?username=${citizenId}`, { // prettier-ignore headers: { - "authorization": `Bearer ${await getToken()}`, + "authorization": `Bearer ${token || await getToken()}`, "content-type": `application/json`, }, }).catch((e) => console.log("Keycloak Error: ", e)); @@ -409,13 +414,13 @@ export async function getRoleMappings(userId: string) { * * @returns role's info (array if not specify name) if success, null if not found, false otherwise. */ -export async function getRoles(name?: string) { +export async function getRoles(name?: string, token?: string) { const res = await fetch( `${KC_URL}/admin/realms/${KC_REALMS}/roles`.concat((name && `/${name}`) || ""), { // prettier-ignore headers: { - "authorization": `Bearer ${await getToken()}`, + "authorization": `Bearer ${token || await getToken()}`, }, }, ).catch((e) => console.log(e)); @@ -491,13 +496,17 @@ export async function getUserRoles(userId: string) { * * @returns true if success, false otherwise. */ -export async function addUserRoles(userId: string, roles: { id: string; name: string }[]) { +export async function addUserRoles( + userId: string, + roles: { id: string; name: string }[], + token?: string, +) { const res = await fetch( `${KC_URL}/admin/realms/${KC_REALMS}/users/${userId}/role-mappings/realm`, { // prettier-ignore headers: { - "authorization": `Bearer ${await getToken()}`, + "authorization": `Bearer ${token || await getToken()}`, "content-type": `application/json`, }, method: "POST",