Linear Flow (ทดสอบเฉพาะคำสั่ง C-PM-01) #224
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m7s

This commit is contained in:
harid 2026-06-18 11:48:46 +07:00
parent 9f7803cc74
commit c26fb19c1c
3 changed files with 1368 additions and 953 deletions

View file

@ -104,6 +104,7 @@ import { LeaveType } from "../entities/LeaveType";
import { KeycloakAttributeService } from "../services/KeycloakAttributeService";
import { reOrderCommandRecivesAndDelete } from "../services/CommandService";
import { RetirementService } from "../services/RetirementService";
import { OfficerProfileService } from "../services/OfficerProfileService";
import { promisify } from "util";
const REDIS_HOST = process.env.REDIS_HOST;
const REDIS_PORT = process.env.REDIS_PORT;
@ -6661,6 +6662,10 @@ export class CommandController extends Controller {
return new HttpSuccess();
}
/**
* API
* @summary API
*/
@Post("excexute/create-officer-profile")
public async CreateOfficeProfileExcecute(
@Request() req: RequestWithUser,
@ -6707,953 +6712,10 @@ export class CommandController extends Controller {
}[];
},
) {
console.log("[Excexute/CreateOfficerProfile] Starting CreateOfficeProfileExcecute");
console.log("[Excexute/CreateOfficerProfile] Request body count:", body.data?.length);
const roleKeycloak = await this.roleKeycloakRepo.findOne({
where: { name: Like("USER") },
await new OfficerProfileService().executeCreateOfficerProfile(body.data, {
user: { sub: req.user.sub, name: req.user.name },
req,
});
console.log("[Excexute/CreateOfficerProfile] roleKeycloak found:", !!roleKeycloak);
const list = await getRoles();
console.log("[Excexute/CreateOfficerProfile] Roles list retrieved, length:", Array.isArray(list) ? list.length : "not array");
if (!Array.isArray(list)) {
console.error("[Excexute/CreateOfficerProfile] Failed - Cannot get role(s) data from the server");
throw new Error("Failed. Cannot get role(s) data from the server.");
}
let _posNumCodeSit: string = "";
let _posNumCodeSitAbb: string = "";
console.log("[Excexute/CreateOfficerProfile] Getting command data");
const _command = await this.commandRepository.findOne({
where: { id: body.data.find((x) => x.bodySalarys?.commandId)?.bodySalarys?.commandId ?? "" },
});
console.log("[Excexute/CreateOfficerProfile] Command found:", !!_command, "isBangkok:", _command?.isBangkok);
if (_command) {
if (_command?.isBangkok?.toLocaleUpperCase() == "OFFICE") {
console.log("[Excexute/CreateOfficerProfile] Setting position codes for OFFICE");
const orgRootDeputy = await this.orgRootRepository.findOne({
where: {
isDeputy: true,
orgRevision: {
orgRevisionIsCurrent: true,
orgRevisionIsDraft: false,
},
},
relations: ["orgRevision"],
});
_posNumCodeSit = orgRootDeputy ? orgRootDeputy?.orgRootName : "สำนักปลัดกรุงเทพมหานคร";
_posNumCodeSitAbb = orgRootDeputy ? orgRootDeputy?.orgRootShortName : "สนป.";
console.log("[Excexute/CreateOfficerProfile] OFFICE position codes set:", _posNumCodeSit, _posNumCodeSitAbb);
} else if (_command?.isBangkok?.toLocaleUpperCase() == "BANGKOK") {
console.log("[Excexute/CreateOfficerProfile] Setting position codes for BANGKOK");
_posNumCodeSit = "กรุงเทพมหานคร";
_posNumCodeSitAbb = "กทม.";
console.log("[Excexute/CreateOfficerProfile] BANGKOK position codes set:", _posNumCodeSit, _posNumCodeSitAbb);
} else {
console.log("[Excexute/CreateOfficerProfile] Setting position codes from admin profile");
let _profileAdmin = await this.profileRepository.findOne({
where: {
keycloak: _command?.createdUserId.toString(),
current_holders: {
orgRevision: {
orgRevisionIsCurrent: true,
orgRevisionIsDraft: false,
},
},
},
relations: ["current_holders", "current_holders.orgRevision", "current_holders.orgRoot"],
});
_posNumCodeSit =
_profileAdmin?.current_holders.find((x) => x.orgRoot.orgRootName)?.orgRoot.orgRootName ??
"";
_posNumCodeSitAbb =
_profileAdmin?.current_holders.find((x) => x.orgRoot.orgRootShortName)?.orgRoot
.orgRootShortName ?? "";
console.log("[Excexute/CreateOfficerProfile] Admin profile position codes set:", _posNumCodeSit, _posNumCodeSitAbb);
}
}
const before = null;
const meta = {
createdUserId: req.user.sub,
createdFullName: req.user.name,
lastUpdateUserId: req.user.sub,
lastUpdateFullName: req.user.name,
createdAt: new Date(),
lastUpdatedAt: new Date(),
};
console.log("[Excexute/CreateOfficerProfile] Starting to process", body.data.length, "profile(s)");
await Promise.all(
body.data.map(async (item, index) => {
console.log("[Excexute/CreateOfficerProfile] Processing item", index + 1, "of", body.data.length);
const _null: any = null;
if (item.bodyProfile.posLevelId === "") item.bodyProfile.posLevelId = null;
if (item.bodyProfile.posTypeId === "") item.bodyProfile.posTypeId = null;
if (
item.bodyProfile.posLevelId &&
!(await this.posLevelRepo.findOneBy({ id: item.bodyProfile.posLevelId }))
) {
console.error("[Excexute/CreateOfficerProfile] ไม่พบข้อมูลระดับตำแหน่งนี้ posLevelId:", item.bodyProfile.posLevelId);
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลระดับตำแหน่งนี้");
}
if (
item.bodyProfile.posTypeId &&
!(await this.posTypeRepo.findOneBy({ id: item.bodyProfile.posTypeId }))
) {
console.error("[Excexute/CreateOfficerProfile] ไม่พบข้อมูลประเภทตำแหน่งนี้ posTypeId:", item.bodyProfile.posTypeId);
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้");
}
console.log("[Excexute/CreateOfficerProfile] Processing citizenId:", item.bodyProfile.citizenId);
let registrationProvinceId = await this.provinceRepo.findOneBy({
id: item.bodyProfile.registrationProvinceId ?? "",
});
let registrationDistrictId = await this.districtRepo.findOneBy({
id: item.bodyProfile.registrationDistrictId ?? "",
});
let registrationSubDistrictId = await this.subDistrictRepo.findOneBy({
id: item.bodyProfile.registrationSubDistrictId ?? "",
});
let currentProvinceId = await this.provinceRepo.findOneBy({
id: item.bodyProfile.currentProvinceId ?? "",
});
let currentDistrictId = await this.districtRepo.findOneBy({
id: item.bodyProfile.currentDistrictId ?? "",
});
let currentSubDistrictId = await this.subDistrictRepo.findOneBy({
id: item.bodyProfile.currentSubDistrictId ?? "",
});
console.log("[Excexute/CreateOfficerProfile] Address validation completed");
let _dateRetire =
item.bodyProfile.birthDate == null
? _null
: calculateRetireDate(item.bodyProfile.birthDate);
let _dateRetireLaw =
item.bodyProfile.birthDate == null
? _null
: calculateRetireLaw(item.bodyProfile.birthDate);
let userKeycloakId: any;
let result: any;
console.log("[Excexute/CreateOfficerProfile] Checking Keycloak user for citizenId:", item.bodyProfile.citizenId);
const checkUser = await getUserByUsername(item.bodyProfile.citizenId);
console.log("[Excexute/CreateOfficerProfile] Keycloak user exists:", checkUser.length > 0);
if (checkUser.length == 0) {
console.log("[Excexute/CreateOfficerProfile] Creating new Keycloak user");
let password = item.bodyProfile.citizenId;
if (item.bodyProfile.birthDate != null) {
const _date = new Date(item.bodyProfile.birthDate.toDateString())
.getDate()
.toString()
.padStart(2, "0");
const _month = (new Date(item.bodyProfile.birthDate.toDateString()).getMonth() + 1)
.toString()
.padStart(2, "0");
const _year = new Date(item.bodyProfile.birthDate.toDateString()).getFullYear() + 543;
password = `${_date}${_month}${_year}`;
}
console.log("[Excexute/CreateOfficerProfile] Calling createUser for:", item.bodyProfile.citizenId);
console.log("[Excexute/CreateOfficerProfile] createUser data - firstName:", item.bodyProfile.firstName, "lastName:", item.bodyProfile.lastName);
// กรอง "." ออกจาก firstName ก่อนส่งไป keycloak (ป้องกัน . หรืออักขระอื่นๆ)
const sanitizedFirstName = item.bodyProfile.firstName?.replace(/\./g, "") ?? "";
userKeycloakId = await createUser(item.bodyProfile.citizenId, password, {
firstName: sanitizedFirstName,
lastName: item.bodyProfile.lastName,
});
if (userKeycloakId && typeof userKeycloakId === "object" && userKeycloakId.errorMessage) {
console.error("[Excexute/CreateOfficerProfile] createUser FAILED - field:", userKeycloakId.field, "errorMessage:", userKeycloakId.errorMessage, "params:", userKeycloakId.params);
throw new HttpError(HttpStatus.BAD_REQUEST, `Keycloak validation failed: ${userKeycloakId.field} - ${userKeycloakId.errorMessage}`);
}
console.log("[Excexute/CreateOfficerProfile] User created in Keycloak, userKeycloakId:", userKeycloakId);
result = await addUserRoles(
userKeycloakId,
list
.filter((v) => v.name === "USER")
.map((x) => ({
id: x.id,
name: x.name,
})),
);
console.log("[Excexute/CreateOfficerProfile] USER role assigned to new user, result:", result);
} else {
console.log("[Excexute/CreateOfficerProfile] Updating existing Keycloak user");
userKeycloakId = checkUser[0].id;
console.log("[Excexute/CreateOfficerProfile] Existing userKeycloakId:", userKeycloakId);
const rolesData = await getRoleMappings(userKeycloakId);
if (rolesData) {
const _delRole = rolesData.map((x: any) => ({
id: x.id,
name: x.name,
}));
console.log("[Excexute/CreateOfficerProfile] Removing old roles:", _delRole.length);
await removeUserRoles(userKeycloakId, _delRole);
}
result = await addUserRoles(
userKeycloakId,
list
.filter((v) => v.name === "USER")
.map((x) => ({
id: x.id,
name: x.name,
})),
);
console.log("[Excexute/CreateOfficerProfile] USER role assigned to existing user");
}
let profile: any = await this.profileRepository.findOne({
where: { citizenId: item.bodyProfile.citizenId /*, isActive: true */ },
relations: ["roleKeycloaks", "profileInsignias", "profileAvatars"],
});
console.log("[Excexute/CreateOfficerProfile] Profile found:", !!profile, "for citizenId:", item.bodyProfile.citizenId);
let _oldInsigniaIds: string[] = [];
let _oldSalaries: any[] = [];
//ลูกจ้างประจำ หรือ บุคคลภายนอก
if (!profile) {
console.log("[Excexute/CreateOfficerProfile] No existing profile found, creating new profile");
//กรณีลูกจ้างประจำมาสอบเป็นข้าราชการ ต้อง update สถานะโปรไฟล์เดิม
let profileEmployee: any = await this.profileEmployeeRepository.findOne({
where: { citizenId: item.bodyProfile.citizenId },
relations: ["profileInsignias", "roleKeycloaks"],
});
console.log("[Excexute/CreateOfficerProfile] Employee profile found:", !!profileEmployee);
if (profileEmployee) {
console.log("[Excexute/CreateOfficerProfile] Converting employee profile to officer profile");
const _order = await this.salaryRepo.findOne({
where: { profileEmployeeId: profileEmployee.id },
order: { order: "DESC" },
});
const profileEmpSalary = new ProfileSalary();
profileEmpSalary.posNumCodeSit = _posNumCodeSit;
profileEmpSalary.posNumCodeSitAbb = _posNumCodeSitAbb;
profileEmpSalary.order = _order == null ? 1 : _order.order + 1;
Object.assign(profileEmpSalary, {
...item.bodySalarys,
...meta,
profileEmployeeId: profileEmployee.id,
profileId: undefined,
});
const history = new ProfileSalaryHistory();
Object.assign(history, { ...profileEmpSalary, id: undefined });
profileEmpSalary.dateGovernment = item.bodySalarys?.commandDateAffect ?? meta.createdAt;
(profileEmpSalary.profileId = _null),
await this.salaryRepo.save(profileEmpSalary, { data: req });
setLogDataDiff(req, { before, after: profileEmpSalary });
history.profileSalaryId = profileEmpSalary.id;
await this.salaryHistoryRepo.save(history, { data: req });
if (profileEmployee.profileInsignias.length > 0) {
_oldInsigniaIds = profileEmployee.profileInsignias?.map((x: any) => x.id) ?? [];
}
await removeProfileInOrganize(profileEmployee.id, "EMPLOYEE");
if (profileEmployee.keycloak != null) {
// const delUserKeycloak = await deleteUser(profileEmployee.keycloak);
// if (delUserKeycloak) {
// Task #228
// profileEmployee.keycloak = _null;
profileEmployee.roleKeycloaks = [];
profileEmployee.isActive = false;
// }
}
profileEmployee.isLeave = true;
profileEmployee.leaveReason = "บรรจุข้าราชการ";
profileEmployee.lastUpdateUserId = req.user.sub;
profileEmployee.lastUpdateFullName = req.user.name;
profileEmployee.lastUpdatedAt = new Date();
await this.profileEmployeeRepository.save(profileEmployee);
setLogDataDiff(req, { before, after: profileEmployee });
}
profile = Object.assign({ ...item.bodyProfile, ...meta });
profile.dateRetire = _dateRetire;
profile.dateRetireLaw = _dateRetireLaw;
profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : [];
profile.keycloak =
userKeycloakId && typeof userKeycloakId === "string" ? userKeycloakId : "";
profile.registrationAddress = item.bodyProfile.registrationAddress;
profile.registrationProvinceId = registrationProvinceId
? registrationProvinceId.id
: _null;
profile.registrationDistrictId = registrationDistrictId
? registrationDistrictId.id
: _null;
profile.registrationSubDistrictId = registrationSubDistrictId
? registrationSubDistrictId.id
: _null;
profile.registrationZipCode = item.bodyProfile.registrationZipCode;
profile.currentAddress = item.bodyProfile.currentAddress;
profile.currentProvinceId = currentProvinceId ? currentProvinceId.id : _null;
profile.currentDistrictId = currentDistrictId ? currentDistrictId.id : _null;
profile.currentSubDistrictId = currentSubDistrictId ? currentSubDistrictId.id : _null;
profile.currentZipCode = item.bodyProfile.currentZipCode;
profile.email = item.bodyProfile.email;
profile.dateStart = item.bodyProfile.dateStart;
profile.amount = item.bodyProfile.amount ?? null;
profile.amountSpecial = item.bodyProfile.amountSpecial ?? null;
profile.isProbation = item.bodyProfile.isProbation;
//เพิ่มใหม่จากรับโอน
profile.rank = item?.bodyProfile?.rank || null;
profile.prefix = item?.bodyProfile?.rank || item?.bodyProfile?.prefix || null;
profile.prefixMain = item?.bodyProfile?.prefix ?? null;
profile.firstName = item.bodyProfile.firstName ?? null;
profile.lastName = item.bodyProfile.lastName ?? null;
profile.birthDate = item.bodyProfile.birthDate ?? null;
profile.gender = item.bodyProfile.gender ?? null;
profile.relationship = item.bodyProfile.relationship ?? null;
profile.religion = item.bodyProfile.religion ?? null;
profile.ethnicity = item.bodyProfile.ethnicity;
profile.nationality = item.bodyProfile.nationality ?? null;
profile.bloodGroup = item.bodyProfile.bloodGroup ?? null;
profile.phone = item.bodyProfile.phone ?? null;
console.log("[Excexute/CreateOfficerProfile] Saving new profile");
await this.profileRepository.save(profile);
console.log("[Excexute/CreateOfficerProfile] New profile saved, profileId:", profile.id);
// update user attribute in keycloak
await updateUserAttributes(profile.keycloak ?? "", {
profileId: [profile.id],
prefix: [profile.prefix || ""],
});
console.log("[Excexute/CreateOfficerProfile] Keycloak attributes updated");
setLogDataDiff(req, { before, after: profile });
}
//ขรก.ในระบบ หรือ ขรก.ในระบบที่สถานะพ้นจากราชการ
else {
console.log("[Excexute/CreateOfficerProfile] Existing profile found, isLeave:", profile.isLeave, "leaveType:", profile.leaveType);
//สร้างโปรไฟล์ใหม่ ถ้าสถานะพ้นราชการ คำสั่งโอนออกหรือคำสั่งขอลาออก
if (
profile.isLeave &&
["PLACEMENT_TRANSFER", "RETIRE_RESIGN"].includes(profile.leaveType)
) {
console.log("[Excexute/CreateOfficerProfile] Profile is leaving with eligible leave type, creating new profile record");
//ดึง profileSalary เดิม
_oldSalaries = await this.salaryRepo.find({
where: { profileId: profile.id },
order: { order: "ASC" },
});
if (profile.profileInsignias.length > 0) {
_oldInsigniaIds = profile.profileInsignias?.map((x: any) => x.id) ?? [];
}
profile = Object.assign({ ...item.bodyProfile, ...meta });
profile.dateRetire = _dateRetire;
profile.dateRetireLaw = _dateRetireLaw;
profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : [];
profile.keycloak =
userKeycloakId && typeof userKeycloakId === "string" ? userKeycloakId : "";
profile.registrationAddress = item.bodyProfile.registrationAddress;
profile.registrationProvinceId = registrationProvinceId
? registrationProvinceId.id
: _null;
profile.registrationDistrictId = registrationDistrictId
? registrationDistrictId.id
: _null;
profile.registrationSubDistrictId = registrationSubDistrictId
? registrationSubDistrictId.id
: _null;
profile.registrationZipCode = item.bodyProfile.registrationZipCode;
profile.currentAddress = item.bodyProfile.currentAddress;
profile.currentProvinceId = currentProvinceId ? currentProvinceId.id : _null;
profile.currentDistrictId = currentDistrictId ? currentDistrictId.id : _null;
profile.currentSubDistrictId = currentSubDistrictId ? currentSubDistrictId.id : _null;
profile.currentZipCode = item.bodyProfile.currentZipCode;
profile.email = item.bodyProfile.email;
profile.dateStart = item.bodyProfile.dateStart;
profile.amount = item.bodyProfile.amount ?? null;
profile.amountSpecial = item.bodyProfile.amountSpecial ?? null;
profile.isProbation = item.bodyProfile.isProbation;
profile.rank = item?.bodyProfile?.rank || null;
profile.prefix = item?.bodyProfile?.rank || item?.bodyProfile?.prefix || null;
profile.prefixMain = item?.bodyProfile?.prefix ?? null;
profile.firstName = item.bodyProfile.firstName ?? null;
profile.lastName = item.bodyProfile.lastName ?? null;
profile.birthDate = item.bodyProfile.birthDate ?? null;
profile.gender = item.bodyProfile.gender ?? null;
profile.relationship = item.bodyProfile.relationship ?? null;
profile.religion = item.bodyProfile.religion ?? null;
profile.ethnicity = item.bodyProfile.ethnicity;
profile.nationality = item.bodyProfile.nationality ?? null;
profile.bloodGroup = item.bodyProfile.bloodGroup ?? null;
profile.phone = item.bodyProfile.phone ?? null;
await this.profileRepository.save(profile);
console.log("[Excexute/CreateOfficerProfile] New profile record saved for leaving officer, profileId:", profile.id);
setLogDataDiff(req, { before, after: profile });
} else {
console.log("[Excexute/CreateOfficerProfile] Updating existing active profile");
profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : [];
profile.keycloak =
userKeycloakId && typeof userKeycloakId === "string" ? userKeycloakId : "";
profile.isProbation = item.bodyProfile.isProbation;
profile.isLeave = item.bodyProfile.isLeave;
profile.isRetirement = false;
profile.isActive = true;
profile.isDelete = false;
profile.dateLeave = _null;
profile.dateRetire = _dateRetire;
profile.dateRetireLaw = _dateRetireLaw;
profile.registrationAddress = item.bodyProfile.registrationAddress;
profile.registrationProvinceId = registrationProvinceId
? registrationProvinceId.id
: _null;
profile.registrationDistrictId = registrationDistrictId
? registrationDistrictId.id
: _null;
profile.registrationSubDistrictId = registrationSubDistrictId
? registrationSubDistrictId.id
: _null;
profile.registrationZipCode = item.bodyProfile.registrationZipCode;
profile.currentAddress = item.bodyProfile.currentAddress;
profile.currentProvinceId = currentProvinceId ? currentProvinceId.id : _null;
profile.currentDistrictId = currentDistrictId ? currentDistrictId.id : _null;
profile.currentSubDistrictId = currentSubDistrictId ? currentSubDistrictId.id : _null;
profile.currentZipCode = item.bodyProfile.currentZipCode;
profile.email = item.bodyProfile.email;
profile.telephoneNumber = item.bodyProfile.telephoneNumber;
profile.phone = item.bodyProfile.phone;
profile.dateStart = item.bodyProfile.dateStart;
profile.amount = item.bodyProfile.amount ?? null;
profile.amountSpecial = item.bodyProfile.amountSpecial ?? null;
profile.leaveCommandId = _null;
profile.leaveCommandNo = _null;
profile.leaveRemark = _null;
profile.leaveDate = _null;
profile.leaveType = _null;
profile.leaveReason = _null;
profile.lastUpdateUserId = req.user.sub;
profile.lastUpdateFullName = req.user.name;
profile.lastUpdatedAt = new Date();
//เพิ่มใหม่จากรับโอน
profile.rank = item?.bodyProfile?.rank || null;
profile.prefix = item?.bodyProfile?.rank || item?.bodyProfile?.prefix || null;
profile.prefixMain = item?.bodyProfile?.prefix ?? null;
profile.firstName =
item.bodyProfile.firstName && item.bodyProfile.firstName != ""
? item.bodyProfile.firstName
: profile.firstName;
profile.lastName =
item.bodyProfile.lastName && item.bodyProfile.lastName != ""
? item.bodyProfile.lastName
: profile.lastName;
profile.birthDate = item.bodyProfile.birthDate
? item.bodyProfile.birthDate
: profile.birthDate;
profile.gender =
item.bodyProfile.gender && item.bodyProfile.gender != ""
? item.bodyProfile.gender
: profile.gender;
profile.relationship =
item.bodyProfile.relationship && item.bodyProfile.relationship != ""
? item.bodyProfile.relationship
: profile.relationship;
profile.religion =
item.bodyProfile.religion && item.bodyProfile.religion != ""
? item.bodyProfile.religion
: profile.religion;
profile.ethnicity =
item.bodyProfile.ethnicity && item.bodyProfile.ethnicity != ""
? item.bodyProfile.ethnicity
: profile.ethnicity;
profile.nationality =
item.bodyProfile.nationality && item.bodyProfile.nationality != ""
? item.bodyProfile.nationality
: profile.nationality;
profile.bloodGroup =
item.bodyProfile.bloodGroup && item.bodyProfile.bloodGroup != ""
? item.bodyProfile.bloodGroup
: profile.bloodGroup;
profile.phone =
item.bodyProfile.phone && item.bodyProfile.phone != ""
? item.bodyProfile.phone
: profile.phone;
await this.profileRepository.save(profile);
console.log("[Excexute/CreateOfficerProfile] Existing active profile updated, profileId:", profile.id);
setLogDataDiff(req, { before, after: profile });
}
}
if (profile && profile.id) {
console.log("[Excexute/CreateOfficerProfile] Processing additional data for profileId:", profile.id);
//Educations
if (item.bodyEducations && item.bodyEducations.length > 0) {
console.log("[Excexute/CreateOfficerProfile] Processing educations, count:", item.bodyEducations.length);
await Promise.all(
item.bodyEducations.map(async (education) => {
const profileEdu = new ProfileEducation();
Object.assign(profileEdu, { ...education, ...meta });
const eduHistory = new ProfileEducationHistory();
Object.assign(eduHistory, { ...profileEdu, id: undefined });
profileEdu.profileId = profile.id;
const educationLevel = await this.profileEducationRepo.findOne({
select: ["id", "level", "profileId"],
where: { profileId: profile.id, isDeleted: false },
order: { level: "DESC" },
});
profileEdu.level = educationLevel == null ? 1 : educationLevel.level + 1;
await this.profileEducationRepo.save(profileEdu, { data: req });
setLogDataDiff(req, { before, after: profileEdu });
eduHistory.profileEducationId = profileEdu.id;
await this.profileEducationHistoryRepo.save(eduHistory, { data: req });
}),
);
}
//Certificates
if (item.bodyCertificates && item.bodyCertificates.length > 0) {
console.log("[Excexute/CreateOfficerProfile] Processing certificates, count:", item.bodyCertificates.length);
await Promise.all(
item.bodyCertificates.map(async (cer) => {
const profileCer = new ProfileCertificate();
Object.assign(profileCer, { ...cer, ...meta });
const cerHistory = new ProfileCertificateHistory();
Object.assign(cerHistory, { ...profileCer, id: undefined });
profileCer.profileId = profile.id;
await this.certificateRepo.save(profileCer, { data: req });
setLogDataDiff(req, { before, after: profileCer });
cerHistory.profileCertificateId = profileCer.id;
await this.certificateHistoryRepo.save(cerHistory, { data: req });
}),
);
}
//FamilyCouple
if (item.bodyMarry != null) {
console.log("[Excexute/CreateOfficerProfile] Processing couple/marry data");
const profileCouple = new ProfileFamilyCouple();
const data = {
profileId: profile.id,
couple: item.bodyMarry.marry,
couplePrefix: item.bodyMarry.marryPrefix,
coupleFirstName: item.bodyMarry.marryFirstName,
coupleLastName: item.bodyMarry.marryLastName,
coupleCareer: item.bodyMarry.marryOccupation,
coupleLive: true,
};
Object.assign(profileCouple, { ...data, ...meta });
const coupleHistory = new ProfileFamilyCoupleHistory();
Object.assign(coupleHistory, { ...profileCouple, id: undefined });
profileCouple.profileId = profile.id;
await this.profileFamilyCoupleRepo.save(profileCouple, { data: req });
setLogDataDiff(req, { before, after: profileCouple });
coupleHistory.profileFamilyCoupleId = profileCouple.id;
await this.profileFamilyCoupleHistoryRepo.save(coupleHistory, { data: req });
}
//FamilyFather
if (item.bodyFather != null) {
console.log("[Excexute/CreateOfficerProfile] Processing father data");
const profileFather = new ProfileFamilyFather();
const data = {
profileId: profile.id,
fatherPrefix: item.bodyFather.fatherPrefix,
fatherFirstName: item.bodyFather.fatherFirstName,
fatherLastName: item.bodyFather.fatherLastName,
fatherCareer: item.bodyFather.fatherOccupation,
fatherLive: true,
};
Object.assign(profileFather, { ...data, ...meta });
const fatherHistory = new ProfileFamilyFatherHistory();
Object.assign(fatherHistory, { ...profileFather, id: undefined });
profileFather.profileId = profile.id;
await this.profileFamilyFatherRepo.save(profileFather, { data: req });
setLogDataDiff(req, { before, after: profileFather });
fatherHistory.profileFamilyFatherId = profileFather.id;
await this.profileFamilyFatherHistoryRepo.save(fatherHistory, { data: req });
}
//FamilyMother
if (item.bodyMother != null) {
console.log("[Excexute/CreateOfficerProfile] Processing mother data");
const profileMother = new ProfileFamilyMother();
const data = {
profileId: profile.id,
motherPrefix: item.bodyMother.motherPrefix,
motherFirstName: item.bodyMother.motherFirstName,
motherLastName: item.bodyMother.motherLastName,
motherCareer: item.bodyMother.motherOccupation,
motherLive: true,
};
Object.assign(profileMother, { ...data, ...meta });
const motherHistory = new ProfileFamilyMotherHistory();
Object.assign(motherHistory, { ...profileMother, id: undefined });
profileMother.profileId = profile.id;
await this.profileFamilyMotherRepo.save(profileMother, { data: req });
setLogDataDiff(req, { before, after: profileMother });
motherHistory.profileFamilyMotherId = profileMother.id;
await this.profileFamilyMotherHistoryRepo.save(motherHistory, { data: req });
}
//Salary
//insert profileSalary อันเก่า กรณีพ้นราชการแล้วกลับมาบรรจุ
if (_oldSalaries.length > 0) {
console.log("[Excexute/CreateOfficerProfile] Restoring old salaries, count:", _oldSalaries.length);
await Promise.all(
_oldSalaries.map(async (oldSal) => {
const profileSal: any = new ProfileSalary();
Object.assign(profileSal, { ...oldSal, ...meta });
const salaryHistory = new ProfileSalaryHistory();
Object.assign(salaryHistory, { ...profileSal, id: undefined });
profileSal.profileId = profile.id;
await this.salaryRepo.save(profileSal, { data: req });
setLogDataDiff(req, { before, after: profileSal });
salaryHistory.profileSalaryId = profileSal.id;
await this.salaryHistoryRepo.save(salaryHistory, { data: req });
}),
);
}
//insert item.bodySalarys ต่อจากที่ insert เดิมไปแล้ว
if (item.bodySalarys && item.bodySalarys != null) {
console.log("[Excexute/CreateOfficerProfile] Processing new salary data");
const dest_item = await this.salaryRepo.findOne({
where: { profileId: profile.id },
order: { order: "DESC" },
});
const profileSal: any = new ProfileSalary();
profileSal.posNumCodeSit = _posNumCodeSit;
profileSal.posNumCodeSitAbb = _posNumCodeSitAbb;
Object.assign(profileSal, { ...item.bodySalarys, ...meta });
const salaryHistory = new ProfileSalaryHistory();
Object.assign(salaryHistory, { ...profileSal, id: undefined });
profileSal.order = dest_item == null ? 1 : dest_item.order + 1;
profileSal.profileId = profile.id;
profileSal.dateGovernment = item.bodySalarys.commandDateAffect ?? meta.createdAt;
profileSal.amount = item.bodySalarys.amount ?? null;
profileSal.amountSpecial = item.bodySalarys.amountSpecial ?? null;
profileSal.positionSalaryAmount = item.bodySalarys.positionSalaryAmount ?? null;
profileSal.mouthSalaryAmount = item.bodySalarys.mouthSalaryAmount ?? null;
await this.salaryRepo.save(profileSal, { data: req });
setLogDataDiff(req, { before, after: profileSal });
salaryHistory.profileSalaryId = profileSal.id;
await this.salaryHistoryRepo.save(salaryHistory, { data: req });
}
//Position
if (item.bodyPosition && item.bodyPosition != null) {
console.log("[Excexute/CreateOfficerProfile] Processing position assignment");
// STEP 1: หา posMaster ที่จะใช้งานตาม id ที่ส่งมา (อาจเป็นตำแหน่งเก่าหรือใหม่ก็ได้)
console.log("[Excexute/CreateOfficerProfile] STEP 1: Finding posMaster, posmasterId:", item.bodyPosition.posmasterId);
let posMaster = await this.posMasterRepository.findOne({
where: {
id: item.bodyPosition.posmasterId,
},
relations: {
orgRevision: true,
orgRoot: true,
orgChild1: true,
orgChild2: true,
orgChild3: true,
orgChild4: true,
},
});
console.log("[Excexute/CreateOfficerProfile] posMaster found:", !!posMaster);
// เช็คว่า posMaster ที่หามาอยู่ในโครงสร้างปัจจุบันหรือไม่
const isCurrent =
posMaster?.orgRevision?.orgRevisionIsCurrent === true &&
posMaster?.orgRevision?.orgRevisionIsDraft === false;
console.log("[Excexute/CreateOfficerProfile] posMaster isCurrent:", isCurrent);
// ถ้าไม่อยู่ในโครงสร้างปัจจุบัน ให้หาตัวใหม่จาก ancestorDNA
if (!isCurrent && posMaster?.ancestorDNA) {
console.log("[Excexute/CreateOfficerProfile] Finding current posMaster from ancestorDNA");
posMaster = await this.posMasterRepository.findOne({
where: {
ancestorDNA: posMaster.ancestorDNA,
orgRevision: {
orgRevisionIsCurrent: true,
orgRevisionIsDraft: false,
},
},
relations: {
orgRevision: true,
orgRoot: true,
orgChild1: true,
orgChild2: true,
orgChild3: true,
orgChild4: true,
},
});
console.log("[Excexute/CreateOfficerProfile] Current posMaster from ancestorDNA found:", !!posMaster);
}
if (posMaster == null) {
console.error(
`[Excexute/CreateOfficerProfile] not found posMasterId: ${item.bodyPosition.posmasterId}`
);
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
}
// STEP 2: เคลียร์ข้อมูลตำแหน่งเก่าที่ครองอยู่ ในโครงสร้างปัจจุบัน
console.log("[Excexute/CreateOfficerProfile] STEP 2: Clearing old position data");
const posMasterOld = await this.posMasterRepository.findOne({
where: {
current_holderId: profile.id,
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) {
// เคลียร์คนครองเก่าออกจากตำแหน่งเดิม
posMasterOld.current_holderId = null;
posMasterOld.lastUpdatedAt = new Date();
}
// หา position เก่าที่เลือกไว้ แล้วเคลียร์การเลือก
const positionOld = await this.positionRepository.findOne({
where: {
posMasterId: posMasterOld?.id,
positionIsSelected: true,
},
});
if (positionOld != null) {
positionOld.positionIsSelected = false;
await this.positionRepository.save(positionOld);
}
// STEP 3: เคลียร์ position ที่เลือกไว้อื่นๆ ใน posMaster ตัวใหม่
console.log("[Excexute/CreateOfficerProfile] STEP 3: Clearing other selected positions in new posMaster");
const checkPosition = await this.positionRepository.find({
where: {
posMasterId: posMaster.id,
positionIsSelected: true,
},
});
if (checkPosition.length > 0) {
const clearPosition = checkPosition.map((positions) => ({
...positions,
positionIsSelected: false,
}));
await this.positionRepository.save(clearPosition);
}
// STEP 4: กำหนดคนครองใหม่ให้กับ posMaster
console.log("[Excexute/CreateOfficerProfile] STEP 4: Assigning new holder to posMaster");
posMaster.current_holderId = profile.id;
posMaster.lastUpdatedAt = new Date();
// posMaster.conditionReason = _null;
// posMaster.isCondition = false;
if (posMasterOld != null) {
await this.posMasterRepository.save(posMasterOld);
await CreatePosMasterHistoryOfficer(posMasterOld.id, req);
}
await this.posMasterRepository.save(posMaster);
console.log("[Excexute/CreateOfficerProfile] posMaster saved with new holder");
// STEP 5: กำหนด position ใหม่
console.log("[Excexute/CreateOfficerProfile] STEP 5: Determining position to assign");
// Match position ตามลำดับ priority:
// Condition 1: match จาก positionId
// Condition 2: match 7 ฟิลด์ (positionName, posTypeId, posLevelId, positionField, positionArea, positionExecutiveField, posExecutiveId)
// Condition 3: match 3 ฟิลด์ (positionName, posTypeId, posLevelId)
// Fallback: เลือก position แรกใน posMaster
let positionNew: Position | null = null;
// ═══════════════════════════════════════════════════════════
// CONDITION 1: เช็คจาก positionId ตรง
// ═══════════════════════════════════════════════════════════
console.log("[Excexute/CreateOfficerProfile] CONDITION 1: Checking by positionId:", item.bodyPosition?.positionId);
if (item.bodyPosition?.positionId) {
const positionById = await this.positionRepository.findOne({
where: {
id: item.bodyPosition.positionId,
posMasterId: posMaster.id, // ต้องอยู่ใน posMaster ที่ถูกต้อง
},
relations: ["posExecutive"],
});
if (positionById) {
positionNew = positionById;
console.log("[Excexute/CreateOfficerProfile] CONDITION 1 matched, positionId:", positionById.id);
}
}
// ═══════════════════════════════════════════════════════════
// CONDITION 2: Match 7 ฟิลด์ (ถ้า Condition 1 ไม่ match)
// ═══════════════════════════════════════════════════════════
if (!positionNew && item.bodyPosition) {
console.log("[Excexute/CreateOfficerProfile] CONDITION 1 not matched, trying CONDITION 2: Match 7 fields");
// สร้าง where clause แบบ dynamic - ใส่เฉพาะฟิลด์ที่ไม่ใช่ null
const whereCondition: any = {
posMasterId: posMaster.id,
positionName: item.bodyPosition.positionName,
posTypeId: item.bodyPosition.posTypeId,
posLevelId: item.bodyPosition.posLevelId,
};
if (item.bodyPosition.positionField) {
whereCondition.positionField = item.bodyPosition.positionField;
}
if (item.bodyPosition.posExecutiveId) {
whereCondition.posExecutiveId = item.bodyPosition.posExecutiveId;
}
if (item.bodyPosition.positionExecutiveField) {
whereCondition.positionExecutiveField = item.bodyPosition.positionExecutiveField;
}
if (item.bodyPosition.positionArea) {
whereCondition.positionArea = item.bodyPosition.positionArea;
}
const positionBy7Fields = await this.positionRepository.findOne({
where: whereCondition,
relations: ["posExecutive"],
order: { orderNo: "ASC" }
});
if (positionBy7Fields) {
positionNew = positionBy7Fields;
console.log("[Excexute/CreateOfficerProfile] CONDITION 2 matched with 7 fields, positionId:", positionBy7Fields.id);
}
}
// ═══════════════════════════════════════════════════════════
// CONDITION 3: Match 3 ฟิลด์ (ถ้า Condition 2 ไม่ match)
// ═══════════════════════════════════════════════════════════
if (!positionNew && item.bodyPosition) {
console.log("[Excexute/CreateOfficerProfile] CONDITION 2 not matched, trying CONDITION 3: Match 3 fields");
const positionBy3Fields = await this.positionRepository.findOne({
where: {
posMasterId: posMaster.id,
positionName: item.bodyPosition.positionName,
posTypeId: item.bodyPosition.posTypeId,
posLevelId: item.bodyPosition.posLevelId,
},
relations: ["posExecutive"],
order: { orderNo: "ASC" }
});
if (positionBy3Fields) {
positionNew = positionBy3Fields;
console.log("[Excexute/CreateOfficerProfile] CONDITION 3 matched with 3 fields, positionId:", positionBy3Fields.id);
} else {
console.log("[Excexute/CreateOfficerProfile] No position matched for profileId:", profile.id);
}
}
// // ═══════════════════════════════════════════════════════════
// // FALLBACK: ถ้าทั้ง 3 ไม่ match ให้เลือก position แรกใน posMaster
// // ═══════════════════════════════════════════════════════════
// if (!positionNew) {
// const fallbackPositions = await this.positionRepository.find({
// where: {
// posMasterId: posMaster.id,
// },
// relations: ["posExecutive"],
// order: {
// orderNo: "ASC",
// },
// take: 1,
// });
// if (fallbackPositions.length > 0) {
// positionNew = fallbackPositions[0];
// }
// }
// อัพเดท org และ posMasterNo ตลอดไม่ต้องดัก isSit
profile.posMasterNo = getPosMasterNo(posMaster);
profile.org = getOrgFullName(posMaster);
// ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
if (positionNew != null) {
console.log("[Excexute/CreateOfficerProfile] Final position assignment, isSit:", posMaster.isSit, "positionId:", positionNew.id);
positionNew.positionIsSelected = true;
if (!posMaster.isSit) {
profile.posLevelId = positionNew.posLevelId;
profile.posTypeId = positionNew.posTypeId;
profile.position = positionNew.positionName;
profile.positionField = positionNew.positionField ?? null;
profile.posExecutive = positionNew.posExecutive?.posExecutiveName ?? null;
profile.positionArea = positionNew.positionArea ?? null;
profile.positionExecutiveField = positionNew.positionExecutiveField ?? null;
// profile.dateStart = new Date();
}
await this.positionRepository.save(positionNew, { data: req });
} else if (!posMaster.isSit) {
// fallback: ตำแหน่งในโครงสร้างถูกแก้ไข ใช้ข้อมูลตำแหน่งที่สมัครสอบมา
console.log("[Excexute/CreateOfficerProfile] positionNew is null, using bodyPosition data as fallback");
profile.position = item.bodyPosition.positionName ?? null;
profile.posTypeId = item.bodyPosition.posTypeId ?? null;
profile.posLevelId = item.bodyPosition.posLevelId ?? null;
profile.positionField = item.bodyPosition.positionField ?? null;
profile.positionArea = item.bodyPosition.positionArea ?? null;
profile.positionExecutiveField = item.bodyPosition.positionExecutiveField ?? null;
}
await this.profileRepository.save(profile, { data: req });
setLogDataDiff(req, { before, after: profile });
// await CreatePosMasterHistoryOfficer(posMaster.id, req);
await CreatePosMasterHistoryOfficer(posMaster.id, req, null, {
positionId: positionNew?.id,
});
}
// Insignia
if (_oldInsigniaIds.length > 0) {
console.log("[Excexute/CreateOfficerProfile] Processing old insignias, count:", _oldInsigniaIds.length);
const _insignias = await this.insigniaRepo.find({
where: { id: In(_oldInsigniaIds), isDeleted: false },
order: { createdAt: "ASC" },
});
for (const oldInsignia of _insignias) {
const newInsigniaData: CreateProfileInsignia = {
profileId: profile.id,
year: oldInsignia.year,
no: oldInsignia.no,
volume: oldInsignia.volume,
section: oldInsignia.section,
page: oldInsignia.page,
receiveDate: oldInsignia.receiveDate,
insigniaId: oldInsignia.insigniaId,
dateAnnounce: oldInsignia.dateAnnounce,
issue: oldInsignia.issue,
volumeNo: oldInsignia.volumeNo,
refCommandDate: oldInsignia.refCommandDate,
refCommandNo: oldInsignia.refCommandNo,
note: oldInsignia.note,
isUpload: oldInsignia.isUpload,
};
const insignia = new ProfileInsignia();
Object.assign(insignia, { ...newInsigniaData, ...meta });
const history = new ProfileInsigniaHistory();
Object.assign(history, { ...insignia, id: undefined });
await this.insigniaRepo.save(insignia, { data: req });
setLogDataDiff(req, { before, after: insignia });
history.profileInsigniaId = insignia.id;
await this.insigniaHistoryRepo.save(history, { data: req });
}
}
// เพิ่มรูปภาพโปรไฟล์
if (item.bodyProfile.objectRefId) {
console.log("[Excexute/CreateOfficerProfile] Processing profile avatar image, objectRefId:", item.bodyProfile.objectRefId);
const _profileAvatar = new ProfileAvatar();
Object.assign(_profileAvatar, {
...meta,
profileId: profile.id,
profileEmployeeId: undefined,
});
if (profile.profileAvatars && profile.profileAvatars.length > 0) {
await Promise.all(
profile.profileAvatars.map(async (item: any) => {
item.isActive = false;
await this.avatarRepository.save(item);
}),
);
}
await this.avatarRepository.save(_profileAvatar);
let avatar = `ทะเบียนประวัติ/โปรไฟล์/${profile.id}`;
let fileName = `profile-${_profileAvatar.id}`;
_profileAvatar.isActive = true;
_profileAvatar.avatar = avatar;
_profileAvatar.avatarName = fileName;
await this.avatarRepository.save(_profileAvatar, { data: req });
profile.avatar = avatar;
profile.avatarName = fileName;
await this.profileRepository.save(profile, { data: req });
const checkAvatar = await this.avatarRepository.findOne({
where: { avatar: avatar, avatarName: fileName },
});
if (checkAvatar && checkAvatar.profileId == null) {
checkAvatar.profileId = profile.id;
await this.avatarRepository.save(checkAvatar);
}
//duplicate รูปภาพโปรไฟล์โดยอิงจากรูปภาพเดิม
await new CallAPI()
.PostData(req, `/salary/file/avatar/${item.bodyProfile.objectRefId}`, {
prefix: avatar,
fileName: fileName,
})
.then(() => {})
.catch(() => {});
}
}
}),
);
console.log("[Excexute/CreateOfficerProfile] CreateOfficeProfileExcecute completed successfully");
return new HttpSuccess();
}

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@ import { sendWebSocket } from "./webSocket";
import { PayloadSendNoti } from "../interfaces/utils";
import { PermissionProfile } from "../entities/PermissionProfile";
import { PosMasterHistory } from "../entities/PosMasterHistory";
import { OfficerProfileService } from "./OfficerProfileService";
const redis = require("redis");
const REDIS_HOST = process.env.REDIS_HOST;
@ -320,13 +321,55 @@ async function handler(msg: amqp.ConsumeMessage): Promise<boolean> {
20,
);
for (const chunk of chunks) {
await new CallAPI().PostData(
{ headers: { authorization: token } },
path + "/excecute",
{ refIds: chunk },
false,
);
// ─────────────────────────────────────────────────────────────
// Linear Flow
// ทดสอบเฉพาะ C-PM-01 รับ resultData จาก .NET แล้วเรียก OfficerProfileService ตรงๆ ไม่ผ่าน HTTP loopback
// ─────────────────────────────────────────────────────────────
const isLinearFlow = command.commandType?.code === "C-PM-01";
if (isLinearFlow) {
let resultData: any[] = [];
for (const chunk of chunks) {
const res = await new CallAPI().PostData(
{ headers: { authorization: token } },
path + "/excecute",
{ refIds: chunk },
false,
);
// CallAPI.PostData คืน response.data.result (ตาม call-api.ts)
if (res?.result && Array.isArray(res.result)) {
resultData.push(...res.result);
}
}
console.log(`[AMQ] Received ${resultData.length} profiles from .NET (C-PM-01)`);
// เรียก OfficerProfileService
if (resultData.length > 0) {
// สร้าง pseudo-req สำหรับ setLogDataDiff/save({data: req})
const pseudoReq = {
headers: { authorization: token },
user,
};
const ctx = {
user: { sub: user?.sub ?? "system", name: user?.name ?? "System" },
req: pseudoReq,
};
await new OfficerProfileService().executeCreateOfficerProfile(resultData, ctx);
console.log(`[AMQ] Processed ${resultData.length} profiles via OfficerProfileService`);
}
} else {
// Flow เดิม
for (const chunk of chunks) {
await new CallAPI().PostData(
{ headers: { authorization: token } },
path + "/excecute",
{ refIds: chunk },
false,
);
}
}
Object.assign(command, { status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt });