Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 54s

* develop:
  fix
  #1888
  fix script: retire remove from org
  fix: script create keycloak
  fix: send token in keycloak function & change script fix retire
  fix
  fix
  update validate privilege (#201)
  แก้ค้นหาชื่อลูกจ้าง (#199)
  update validate สิทธิ์จัดการโครงสร้างในเมนูโครงสร้างอัตตรากำลัง
  Fix #1836 (#197)
  update privilage validate (NORMAL) and update calRetireLaw
  update privilege validate (OWNER)
This commit is contained in:
Warunee Tamkoo 2025-10-22 11:07:53 +07:00
commit d3f2377898
8 changed files with 578 additions and 235 deletions

View file

@ -1954,27 +1954,71 @@ export class CommandController extends Controller {
]; ];
} }
const orgLeave = _OrgLeave.filter((x: any) => x !== undefined && x !== null).join("\n"); 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 { return {
no: Extension.ToThaiNumber((idx + 1).toString()), no: Extension.ToThaiNumber((idx + 1).toString()),
org: profile?.isLeave == false org: commandCode != "C-PM-21"
? (_child4 == null ? "" : _child4 + "\n") + ? profile?.isLeave == false
(_child3 == null ? "" : _child3 + "\n") + ? (_child4 == null ? "" : _child4 + "\n") +
(_child2 == null ? "" : _child2 + "\n") + (_child3 == null ? "" : _child3 + "\n") +
(_child1 == null ? "" : _child1 + "\n") + (_child2 == null ? "" : _child2 + "\n") +
(_root == null ? "" : _root) (_child1 == null ? "" : _child1 + "\n") +
: orgLeave, (_root == null ? "" : _root)
: orgLeave
: profileTemp.org,
fullName: `${x.prefix}${x.firstName} ${x.lastName}`, fullName: `${x.prefix}${x.firstName} ${x.lastName}`,
citizenId: Extension.ToThaiNumber(x.citizenId), citizenId: Extension.ToThaiNumber(x.citizenId),
position: profile?.position ? profile?.position : "-", position: commandCode != "C-PM-21"
posLevel: ? profile?.position
profile?.posType && profile?.posLevel ? profile?.position
: "-"
: profileTemp.position,
posLevel: commandCode != "C-PM-21"
? profile?.posType && profile?.posLevel
? Extension.ToThaiNumber( ? Extension.ToThaiNumber(
`${profile?.posType.posTypeShortName} ${profile?.posLevel.posLevelName}`, `${profile?.posType.posTypeShortName} ${profile?.posLevel.posLevelName}`,
) )
: "-", : "-"
posNo: shortName : Extension.ToThaiNumber(profileTemp.posLevel),
? Extension.ToThaiNumber(shortName) posNo: commandCode != "C-PM-21"
: "-", ? shortName
? Extension.ToThaiNumber(shortName)
: "-"
: Extension.ToThaiNumber(profileTemp.posNo),
amount: x.amount ? Extension.ToThaiNumber(x.amount.toLocaleString()) : "-", amount: x.amount ? Extension.ToThaiNumber(x.amount.toLocaleString()) : "-",
dateRetire: profile?.dateRetire dateRetire: profile?.dateRetire
? Extension.ToThaiNumber(Extension.ToThaiShortDate_monthYear(profile?.dateRetire)) ? Extension.ToThaiNumber(Extension.ToThaiShortDate_monthYear(profile?.dateRetire))

View file

@ -1,3 +1,4 @@
import { RoleKeycloak } from "./../entities/RoleKeycloak";
import { ProfileEmployee } from "./../entities/ProfileEmployee"; import { ProfileEmployee } from "./../entities/ProfileEmployee";
import { EmployeePosition } from "./../entities/EmployeePosition"; import { EmployeePosition } from "./../entities/EmployeePosition";
import { EmployeePosMaster } from "./../entities/EmployeePosMaster"; import { EmployeePosMaster } from "./../entities/EmployeePosMaster";
@ -37,7 +38,14 @@ import { sendToQueueOrg, sendToQueueOrgDraft } from "../services/rabbitmq";
import { PosType } from "../entities/PosType"; import { PosType } from "../entities/PosType";
import { PosLevel } from "../entities/PosLevel"; import { PosLevel } from "../entities/PosLevel";
import { PermissionOrg } from "../entities/PermissionOrg"; import { PermissionOrg } from "../entities/PermissionOrg";
import { deleteUser, getToken } from "../keycloak"; import {
deleteUser,
getToken,
createUser,
getUserByUsername,
getRoles,
addUserRoles,
} from "../keycloak";
import { import {
CreatePosMasterHistoryEmployee, CreatePosMasterHistoryEmployee,
CreatePosMasterHistoryOfficer, CreatePosMasterHistoryOfficer,
@ -69,6 +77,8 @@ export class OrganizationController extends Controller {
private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee); private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee);
private employeePosMasterRepository = AppDataSource.getRepository(EmployeePosMaster); private employeePosMasterRepository = AppDataSource.getRepository(EmployeePosMaster);
private employeePositionRepository = AppDataSource.getRepository(EmployeePosition); private employeePositionRepository = AppDataSource.getRepository(EmployeePosition);
private roleKeycloakRepo = AppDataSource.getRepository(RoleKeycloak);
/** /**
* API * API
* *
@ -1973,6 +1983,7 @@ export class OrganizationController extends Controller {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล"); throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
} }
let _privilege = await new permission().PermissionOrgList(request, "SYS_ORG"); let _privilege = await new permission().PermissionOrgList(request, "SYS_ORG");
const attrOwnership = _privilege.root === null ? true : false; const attrOwnership = _privilege.root === null ? true : false;
const profile = await this.profileRepo.findOne({ const profile = await this.profileRepo.findOne({
@ -1987,14 +1998,43 @@ export class OrganizationController extends Controller {
?.posMasterAssigns.find((x) => x.assignId === "SYS_ORG"); ?.posMasterAssigns.find((x) => x.assignId === "SYS_ORG");
if (orgRevision.orgRevisionIsDraft && !orgRevision.orgRevisionIsCurrent && !attrOwnership) { 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; const isCurrentActive = !orgRevision.orgRevisionIsDraft && orgRevision.orgRevisionIsCurrent;
if (isCurrentActive) { if (isCurrentActive) {
if (profileAssign) { if (profileAssign && _privilege.privilege !== "OWNER") {
_data.root = [profile.current_holders.find((x) => x.orgRevisionId === id)?.orgRootId]; 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 { } else {
if (!attrOwnership) _data = _privilege; if (!attrOwnership) _data = _privilege;
} }
@ -7281,61 +7321,96 @@ export class OrganizationController extends Controller {
} }
/** /**
* API * API
* *
* @summary - (ADMIN) * @summary - (ADMIN)
* *
*/ */
@Get("delete/profile/org/{orgRevisionId}") @Get("delete/profile-officer/org/{orgRevisionId}")
async deleteRetireInOrg(@Path() orgRevisionId: string, @Request() request: RequestWithUser) { async deleteOfficerRetireInOrg(
// const posMasters = await this.posMasterRepository.find({ @Path() orgRevisionId: string,
// where: { @Request() request: RequestWithUser,
// orgRevisionId: orgRevisionId, ) {
// current_holder: { const posMasters = await this.posMasterRepository.find({
// 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({
where: { where: {
orgRevisionId: orgRevisionId, orgRevisionId,
current_holderId: Not(IsNull()),
current_holder: { current_holder: {
isLeave: true, 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( await Promise.all(
posMastersEmployee.map(async (posMaster) => { posMastersEmployee.map(async (posMaster) => {
posMaster.current_holderId = null; posMaster.current_holderId = null;
posMaster.isSit = false;
if (posMaster.positions) { if (posMaster.positions) {
for (const position of posMaster.positions) { for (const position of posMaster.positions) {
position.positionIsSelected = false; position.positionIsSelected = false;
await this.employeePositionRepository.save(position); await this.employeePositionRepository.save(position);
check += 1; checkEmployee += 1;
} }
} }
await this.employeePosMasterRepository.save(posMaster); await this.employeePosMasterRepository.save(posMaster);
await CreatePosMasterHistoryEmployee(posMaster.id, null); await CreatePosMasterHistoryEmployee(posMaster.id, null);
check += 1;
}), }),
); );
// จำนวนคนที่ถูกลบออกจากโครงสร้าง
const total = posMastersEmployee.length; return new HttpSuccess({
return new HttpSuccess({ total, successAmount: check }); totalEmployee: posMastersEmployee.length,
employeeSuccessAmount: checkEmployee,
});
} }
/** /**
@ -7346,75 +7421,78 @@ export class OrganizationController extends Controller {
*/ */
@Get("save/profile/position-history") @Get("save/profile/position-history")
async saveRetireToPositionHistory(@Request() request: RequestWithUser) { async saveRetireToPositionHistory(@Request() request: RequestWithUser) {
// const profileLeave = await this.profileRepo.find({ const [profileLeave, profileEmployeeLeave] = await Promise.all([
// where: { this.profileRepo.find({
// isLeave: true, where: {
// leaveType: "RETIRE", isLeave: true,
// }, isRetirement: true,
// }); leaveType: IsNull(),
},
}),
this.profileEmployeeRepo.find({
where: {
isLeave: true,
isRetirement: true,
leaveType: IsNull(),
},
}),
]);
// 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);
// check += 1;
// }),
// );
const profileLeave = await this.profileEmployeeRepo.find({
where: {
isLeave: true,
leaveType: "RETIRE",
},
});
let check: number = 0;
await Promise.all( await Promise.all(
profileLeave.map(async (profile: any) => { 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({ const dest_item = await this.profileSalaryRepository.findOne({
where: { profileEmployeeId: profile.id }, where: { profileEmployeeId: profile.id },
order: { order: "DESC" }, order: { order: "DESC" },
@ -7460,13 +7538,20 @@ export class OrganizationController extends Controller {
history.profileSalaryId = savedData.id; history.profileSalaryId = savedData.id;
await this.salaryHistoryRepo.save(history); 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") @Get("update/profile/leave-reason")
async updateRetireReason() { async updateRetireReason() {
// const profileLeave = await this.profileRepo.find({ const [profileLeave, profileEmployeeLeave, token] = await Promise.all([
// where: { this.profileRepo.find({
// isLeave: true, where: {
// leaveType: "RETIRE", isLeave: true,
// }, isRetirement: true,
// }); leaveType: IsNull(),
},
// 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([
this.profileEmployeeRepo.find({ this.profileEmployeeRepo.find({
where: { where: {
isLeave: true, isLeave: true,
leaveType: "RETIRE", isRetirement: true,
leaveType: IsNull(),
}, },
}), }),
getToken(), getToken(),
@ -7520,77 +7583,272 @@ export class OrganizationController extends Controller {
if (!token) if (!token)
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถเชื่อมต่อ Keycloak"); throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถเชื่อมต่อ Keycloak");
let check: number = 0; let checkOfficer: number = 0;
let notDelete: string[] = []; 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( await Promise.all(
posMasters.map(async (posMaster) => { profileLeave.map(async (profile) => {
if (posMaster.positions && posMaster.positions.length > 0) { profile.leaveReason = "เกษียณอายุราชการ";
for (const position of posMaster.positions) { profile.leaveType = "RETIRE";
position.positionIsSelected = false; profile.isActive = false;
await this.positionRepository.save(position);
check += 1; 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);
}), }),
); );
// จำนวนคนที่ถูกลบออกจากโครงสร้าง let checkEmployee: number = 0;
const total = posMasters.length; 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 }); return new HttpSuccess({ total, successAmount: check });
} }
} }

View file

@ -282,7 +282,6 @@ export class OrganizationDotnetController extends Controller {
}), }),
) )
.andWhere(condition, conditionParams) .andWhere(condition, conditionParams)
.orderBy("profileSalary.order", "DESC")
.select([ .select([
"profile.id", "profile.id",
"profile.citizenId", "profile.citizenId",
@ -4390,7 +4389,7 @@ export class OrganizationDotnetController extends Controller {
}, },
) { ) {
let typeCondition: any = {}; let typeCondition: any = {};
if (body.role === "CHILD" || body.role === "PARENT" || body.role === "ROOT") { if (body.role === "CHILD" || body.role === "PARENT") {
switch (body.node) { switch (body.node) {
case 0: case 0:
typeCondition = { typeCondition = {
@ -4431,7 +4430,7 @@ export class OrganizationDotnetController extends Controller {
typeCondition = {}; typeCondition = {};
break; break;
} }
} else if (body.role === "OWNER") { } else if (body.role === "OWNER" || body.role === "ROOT") {
switch (body.reqNode) { switch (body.reqNode) {
case 0: case 0:
typeCondition = { typeCondition = {
@ -4985,7 +4984,7 @@ export class OrganizationDotnetController extends Controller {
}, },
) { ) {
let typeCondition: any = {}; let typeCondition: any = {};
if (body.role === "CHILD" || body.role === "PARENT" || body.role === "ROOT") { if (body.role === "CHILD" || body.role === "PARENT") {
switch (body.node) { switch (body.node) {
case 0: case 0:
typeCondition = { typeCondition = {
@ -5029,7 +5028,7 @@ export class OrganizationDotnetController extends Controller {
typeCondition = {}; typeCondition = {};
break; break;
} }
} else if (body.role === "OWNER") { } else if (body.role === "OWNER" || body.role === "ROOT") {
switch (body.reqNode) { switch (body.reqNode) {
case 0: case 0:
typeCondition = { typeCondition = {

View file

@ -2134,7 +2134,6 @@ export class PositionController extends Controller {
orgChild1Id: IsNull(), orgChild1Id: IsNull(),
}; };
searchShortName = `CONCAT(orgRoot.orgRootShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`; searchShortName = `CONCAT(orgRoot.orgRootShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`;
} else {
} }
} else if (body.type === 1) { } else if (body.type === 1) {
typeCondition = { typeCondition = {
@ -2145,7 +2144,6 @@ export class PositionController extends Controller {
orgChild2Id: IsNull(), orgChild2Id: IsNull(),
}; };
searchShortName = `CONCAT(orgChild1.orgChild1ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`; searchShortName = `CONCAT(orgChild1.orgChild1ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`;
} else {
} }
} else if (body.type === 2) { } else if (body.type === 2) {
typeCondition = { typeCondition = {
@ -2156,7 +2154,6 @@ export class PositionController extends Controller {
orgChild3Id: IsNull(), orgChild3Id: IsNull(),
}; };
searchShortName = `CONCAT(orgChild2.orgChild2ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`; searchShortName = `CONCAT(orgChild2.orgChild2ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`;
} else {
} }
} else if (body.type === 3) { } else if (body.type === 3) {
typeCondition = { typeCondition = {
@ -2167,7 +2164,6 @@ export class PositionController extends Controller {
orgChild4Id: IsNull(), orgChild4Id: IsNull(),
}; };
searchShortName = `CONCAT(orgChild3.orgChild3ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`; searchShortName = `CONCAT(orgChild3.orgChild3ShortName," ",posMaster.posMasterNo) like '%${body.keyword}%'`;
} else {
} }
} else if (body.type === 4) { } else if (body.type === 4) {
typeCondition = { 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 }); return new HttpSuccess({ data: formattedData, total });
} }

View file

@ -5262,6 +5262,7 @@ export class ProfileController extends Controller {
if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลโปรไฟล์นี้"); if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลโปรไฟล์นี้");
Object.assign(record, body); Object.assign(record, body);
record.dateRetireLaw = calculateRetireLaw(record.birthDate);
record.prefixMain = record.prefix; record.prefixMain = record.prefix;
record.prefix = record.rank && record.rank.length > 0 ? record.rank : record.prefixMain; record.prefix = record.rank && record.rank.length > 0 ? record.rank : record.prefixMain;
record.createdUserId = request.user.sub; record.createdUserId = request.user.sub;

View file

@ -2002,6 +2002,7 @@ export class ProfileEmployeeController extends Controller {
} }
Object.assign(record, body); Object.assign(record, body);
record.dateRetireLaw = calculateRetireLaw(record.birthDate);
record.prefixMain = record.prefix; record.prefixMain = record.prefix;
record.prefix = record.rank && record.rank.length > 0 ? record.rank : record.prefixMain; record.prefix = record.rank && record.rank.length > 0 ? record.rank : record.prefixMain;
record.createdUserId = request.user.sub; record.createdUserId = request.user.sub;

View file

@ -994,6 +994,7 @@ export class ProfileEmployeeTempController extends Controller {
} }
Object.assign(record, body); Object.assign(record, body);
record.dateRetireLaw = calculateRetireLaw(record.birthDate);
record.prefixMain = record.prefix; record.prefixMain = record.prefix;
record.createdUserId = request.user.sub; record.createdUserId = request.user.sub;
record.createdFullName = request.user.name; record.createdFullName = request.user.name;

View file

@ -67,11 +67,16 @@ export async function getToken() {
* *
* @returns user uuid or true if success, false otherwise. * @returns user uuid or true if success, false otherwise.
*/ */
export async function createUser(username: string, password: string, opts?: Record<string, any>) { export async function createUser(
username: string,
password: string,
opts?: Record<string, any>,
token?: string,
) {
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users`, { const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users`, {
// prettier-ignore // prettier-ignore
headers: { headers: {
"authorization": `Bearer ${await getToken()}`, "authorization": `Bearer ${token || await getToken()}`,
"content-type": `application/json`, "content-type": `application/json`,
}, },
method: "POST", method: "POST",
@ -101,11 +106,11 @@ export async function createUser(username: string, password: string, opts?: Reco
* *
* @returns user if success, false otherwise. * @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}`, { const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users/${userId}`, {
// prettier-ignore // prettier-ignore
headers: { headers: {
"authorization": `Bearer ${await getToken()}`, "authorization": `Bearer ${token || await getToken()}`,
"content-type": `application/json`, "content-type": `application/json`,
}, },
}).catch((e) => console.log("Keycloak Error: ", e)); }).catch((e) => console.log("Keycloak Error: ", e));
@ -123,11 +128,11 @@ export async function getUser(userId: string) {
* *
* @returns user if success, false otherwise. * @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}`, { const res = await fetch(`${KC_URL}/admin/realms/${KC_REALMS}/users?username=${citizenId}`, {
// prettier-ignore // prettier-ignore
headers: { headers: {
"authorization": `Bearer ${await getToken()}`, "authorization": `Bearer ${token || await getToken()}`,
"content-type": `application/json`, "content-type": `application/json`,
}, },
}).catch((e) => console.log("Keycloak Error: ", e)); }).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. * @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( const res = await fetch(
`${KC_URL}/admin/realms/${KC_REALMS}/roles`.concat((name && `/${name}`) || ""), `${KC_URL}/admin/realms/${KC_REALMS}/roles`.concat((name && `/${name}`) || ""),
{ {
// prettier-ignore // prettier-ignore
headers: { headers: {
"authorization": `Bearer ${await getToken()}`, "authorization": `Bearer ${token || await getToken()}`,
}, },
}, },
).catch((e) => console.log(e)); ).catch((e) => console.log(e));
@ -491,13 +496,17 @@ export async function getUserRoles(userId: string) {
* *
* @returns true if success, false otherwise. * @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( const res = await fetch(
`${KC_URL}/admin/realms/${KC_REALMS}/users/${userId}/role-mappings/realm`, `${KC_URL}/admin/realms/${KC_REALMS}/users/${userId}/role-mappings/realm`,
{ {
// prettier-ignore // prettier-ignore
headers: { headers: {
"authorization": `Bearer ${await getToken()}`, "authorization": `Bearer ${token || await getToken()}`,
"content-type": `application/json`, "content-type": `application/json`,
}, },
method: "POST", method: "POST",