2026-06-24 18:05:54 +07:00
|
|
|
import { Double, EntityManager } from "typeorm";
|
2026-06-18 18:29:03 +07:00
|
|
|
import { AppDataSource } from "../database/data-source";
|
|
|
|
|
import HttpError from "../interfaces/http-error";
|
|
|
|
|
import HttpStatusCode from "../interfaces/http-status";
|
|
|
|
|
import { Profile } from "../entities/Profile";
|
|
|
|
|
import { ProfileSalary } from "../entities/ProfileSalary";
|
|
|
|
|
import { ProfileSalaryHistory } from "../entities/ProfileSalaryHistory";
|
|
|
|
|
import { ProfileAssistance } from "../entities/ProfileAssistance";
|
|
|
|
|
import { ProfileAssistanceHistory } from "../entities/ProfileAssistanceHistory";
|
|
|
|
|
import { OrgRoot } from "../entities/OrgRoot";
|
|
|
|
|
import { PosMaster } from "../entities/PosMaster";
|
|
|
|
|
import { Command } from "../entities/Command";
|
|
|
|
|
import {
|
|
|
|
|
checkCommandType,
|
|
|
|
|
removePostMasterAct,
|
|
|
|
|
removeProfileInOrganize,
|
|
|
|
|
setLogDataDiff,
|
|
|
|
|
} from "../interfaces/utils";
|
|
|
|
|
import { CreatePosMasterHistoryOfficer } from "./PositionService";
|
|
|
|
|
import { deleteUser } from "../keycloak";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Input: ข้อมูล 1 คนสำหรับ endpoint excexute/salary
|
|
|
|
|
* (C-PM-13 โอน, C-PM-15 ช่วยราชการ, C-PM-16 เกษียณ/ปลดเกษียณ)
|
|
|
|
|
*/
|
|
|
|
|
export interface SalaryItem {
|
|
|
|
|
profileId: string;
|
|
|
|
|
amount?: Double | null;
|
|
|
|
|
amountSpecial?: Double | null;
|
|
|
|
|
positionSalaryAmount?: Double | null;
|
|
|
|
|
mouthSalaryAmount?: Double | null;
|
|
|
|
|
positionExecutive: string | null;
|
|
|
|
|
positionExecutiveField?: string | null;
|
|
|
|
|
positionArea?: string | null;
|
|
|
|
|
positionType: string | null;
|
|
|
|
|
positionLevel: string | null;
|
|
|
|
|
commandId?: string | null;
|
|
|
|
|
leaveReason?: string | null;
|
|
|
|
|
dateLeave?: Date | string | null;
|
|
|
|
|
isLeave?: boolean;
|
|
|
|
|
orgRoot?: string | null;
|
|
|
|
|
orgChild1?: string | null;
|
|
|
|
|
orgChild2?: string | null;
|
|
|
|
|
orgChild3?: string | null;
|
|
|
|
|
orgChild4?: string | null;
|
|
|
|
|
officerOrg?: string | null;
|
|
|
|
|
dateStart?: Date | string | null;
|
|
|
|
|
dateEnd?: Date | string | null;
|
|
|
|
|
commandNo: string | null;
|
|
|
|
|
commandYear: number | null;
|
|
|
|
|
posNo: string | null;
|
|
|
|
|
posNoAbb: string | null;
|
|
|
|
|
commandDateAffect?: Date | string | null;
|
|
|
|
|
commandDateSign?: Date | string | null;
|
|
|
|
|
positionName: string | null;
|
|
|
|
|
commandCode?: string | null;
|
|
|
|
|
commandName?: string | null;
|
|
|
|
|
remark: string | null;
|
|
|
|
|
refId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Context สำหรับ audit/log (เหมือน ExecuteOfficerProfileService)
|
|
|
|
|
*/
|
|
|
|
|
export interface SalaryExecutionContext {
|
|
|
|
|
user: { sub: string; name: string };
|
|
|
|
|
req?: any;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Service สำหรับสร้าง ProfileSalary ของข้าราชการ + handle leave/ออกจากราชการ/ช่วยราชการ
|
|
|
|
|
*
|
|
|
|
|
* ใช้กับ commandType: C-PM-13 (โอน), C-PM-15 (ช่วยราชการ), C-PM-16 (เกษียณ)
|
|
|
|
|
*
|
|
|
|
|
* - endpoint /org/command/excexute/salary เรียกผ่าน service นี้ (thin wrapper)
|
|
|
|
|
* - consumer ใน rabbitmq handler เรียกผ่าน service นี้โดยตรง (Linear Flow)
|
|
|
|
|
*
|
|
|
|
|
* Behavior ทั้งหมด preserve จาก CommandController.newSalaryAndUpdate ต้นฉบับ
|
2026-06-24 18:05:54 +07:00
|
|
|
*
|
|
|
|
|
* Batch semantics: all-or-nothing — ประมวลผลทุกคนภายใต้ transaction เดียว (sequential)
|
|
|
|
|
* ถ้าคนใด throw จะ rollback ทั้ง batch และ propagate error ออกไป (ล้มเหลวทั้งหมด)
|
|
|
|
|
* ถ้าทุกคนสำเร็จจะ return result รายงาน success count
|
|
|
|
|
*
|
|
|
|
|
* Keycloak operations (deleteUser) ทำก่อนเข้า transaction เพราะไม่สามารถ rollback ได้
|
2026-06-18 18:29:03 +07:00
|
|
|
*/
|
|
|
|
|
export class ExecuteSalaryService {
|
|
|
|
|
private commandRepository = AppDataSource.getRepository(Command);
|
|
|
|
|
private profileRepository = AppDataSource.getRepository(Profile);
|
|
|
|
|
private orgRootRepository = AppDataSource.getRepository(OrgRoot);
|
|
|
|
|
|
|
|
|
|
/**
|
2026-06-24 18:05:54 +07:00
|
|
|
* ประมวลผลสร้าง ProfileSalary + handle leave/assistance ทั้ง batch
|
|
|
|
|
*
|
|
|
|
|
* @returns สรุปผล success/failure ต่อคน
|
2026-06-18 18:29:03 +07:00
|
|
|
*/
|
|
|
|
|
async executeSalary(data: SalaryItem[], ctx: SalaryExecutionContext): Promise<void> {
|
2026-06-24 18:05:54 +07:00
|
|
|
const commandId = data?.find((x) => x.commandId)?.commandId ?? "unknown";
|
|
|
|
|
const commandCode = data?.find((x) => x.commandCode)?.commandCode ?? "unknown";
|
|
|
|
|
console.log(
|
|
|
|
|
`[ExecuteSalaryService] Starting executeSalary — commandCode: ${commandCode}, commandId: ${commandId}`,
|
|
|
|
|
);
|
|
|
|
|
console.log(`[ExecuteSalaryService] Request body count: ${data?.length ?? 0}`);
|
2026-06-18 18:29:03 +07:00
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
// Normalize date fields (ผ่าน handler จะได้ string → ต้องแปลงเป็น Date)
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
const toDate = (v: any): Date | null => {
|
|
|
|
|
if (v == null || v === "") return null;
|
|
|
|
|
if (v instanceof Date) return isNaN(v.getTime()) ? null : v;
|
|
|
|
|
const d = new Date(v);
|
|
|
|
|
return isNaN(d.getTime()) ? null : d;
|
|
|
|
|
};
|
|
|
|
|
for (const item of data ?? []) {
|
|
|
|
|
const it = item as any;
|
|
|
|
|
it.dateLeave = toDate(it.dateLeave);
|
|
|
|
|
it.dateStart = toDate(it.dateStart);
|
|
|
|
|
it.dateEnd = toDate(it.dateEnd);
|
|
|
|
|
it.commandDateAffect = toDate(it.commandDateAffect);
|
|
|
|
|
it.commandDateSign = toDate(it.commandDateSign);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let _posNumCodeSit: string = "";
|
|
|
|
|
let _posNumCodeSitAbb: string = "";
|
|
|
|
|
const _command = await this.commandRepository.findOne({
|
|
|
|
|
relations: ["commandType"],
|
|
|
|
|
where: { id: data.find((x) => x.commandId)?.commandId ?? "" },
|
|
|
|
|
});
|
|
|
|
|
if (_command) {
|
|
|
|
|
if (_command?.isBangkok?.toLocaleUpperCase() == "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 : "สนป.";
|
|
|
|
|
} else if (_command?.isBangkok?.toLocaleUpperCase() == "BANGKOK") {
|
|
|
|
|
_posNumCodeSit = "กรุงเทพมหานคร";
|
|
|
|
|
_posNumCodeSitAbb = "กทม.";
|
|
|
|
|
} else {
|
|
|
|
|
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 ?? "";
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-24 18:05:54 +07:00
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
// Single transaction ครอบทั้ง batch (all-or-nothing)
|
|
|
|
|
// ทุกคนใช้ manager ตัวเดียวกัน — คนใด throw จะ rollback ทั้ง batch
|
|
|
|
|
// และ propagate error ออกไป (ล้มเหลวทั้งหมด) โดย log error ของคนที่ทำให้ fail ก่อน rethrow
|
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
|
let successCount = 0;
|
|
|
|
|
await AppDataSource.transaction(async (manager) => {
|
|
|
|
|
for (const item of data ?? []) {
|
|
|
|
|
try {
|
|
|
|
|
await this.processOne(item, ctx, manager, _command, _posNumCodeSit, _posNumCodeSitAbb);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const reason =
|
|
|
|
|
err instanceof HttpError
|
|
|
|
|
? err.message
|
|
|
|
|
: err instanceof Error
|
|
|
|
|
? err.message
|
|
|
|
|
: "unexpected error";
|
|
|
|
|
console.error(
|
|
|
|
|
`[ExecuteSalaryService] Failed commandCode=${commandCode}, commandId=${commandId}, profileId=${item.profileId}: ${reason}`,
|
|
|
|
|
err,
|
|
|
|
|
);
|
|
|
|
|
throw err; // → rollback ทั้ง transaction + propagate เป็น batch failure
|
2026-06-18 18:29:03 +07:00
|
|
|
}
|
2026-06-24 18:05:54 +07:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-06-18 18:29:03 +07:00
|
|
|
|
2026-06-24 18:05:54 +07:00
|
|
|
/**
|
|
|
|
|
* ประมวลผล 1 คน ภายใน transaction เดียว (manager)
|
|
|
|
|
* ทุก save ใช้ manager.getRepository(...) เพื่อให้อยู่ใน transaction เดียวกัน
|
|
|
|
|
* ถ้า throw ระหว่างทาง → rollback ทั้งหมดของคนนี้ + ทั้ง batch (กัน partial commit)
|
|
|
|
|
*
|
|
|
|
|
* หมายเหตุ: Keycloak deleteUser ทำก่อนเข้า transaction เพราะไม่สามารถ rollback ได้
|
|
|
|
|
*/
|
|
|
|
|
private async processOne(
|
|
|
|
|
item: SalaryItem,
|
|
|
|
|
ctx: SalaryExecutionContext,
|
|
|
|
|
manager: EntityManager,
|
|
|
|
|
_command: Command | null,
|
|
|
|
|
_posNumCodeSit: string,
|
|
|
|
|
_posNumCodeSitAbb: string,
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
const req = ctx.req;
|
2026-06-18 18:29:03 +07:00
|
|
|
|
2026-06-24 18:05:54 +07:00
|
|
|
const profileRepository = manager.getRepository(Profile);
|
|
|
|
|
const salaryRepo = manager.getRepository(ProfileSalary);
|
|
|
|
|
const salaryHistoryRepo = manager.getRepository(ProfileSalaryHistory);
|
|
|
|
|
const posMasterRepository = manager.getRepository(PosMaster);
|
|
|
|
|
const assistanceRepository = manager.getRepository(ProfileAssistance);
|
|
|
|
|
const assistanceHistoryRepository = manager.getRepository(ProfileAssistanceHistory);
|
2026-06-18 18:29:03 +07:00
|
|
|
|
2026-06-24 18:05:54 +07:00
|
|
|
const profile: any = await profileRepository.findOne({
|
|
|
|
|
where: { id: item.profileId },
|
|
|
|
|
relations: {
|
|
|
|
|
roleKeycloaks: true,
|
|
|
|
|
posType: true,
|
|
|
|
|
posLevel: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (!profile) {
|
|
|
|
|
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");
|
|
|
|
|
}
|
|
|
|
|
const posMaster: any = await posMasterRepository.findOne({
|
|
|
|
|
where: {
|
|
|
|
|
current_holderId: item.profileId,
|
|
|
|
|
orgRevision: {
|
|
|
|
|
orgRevisionIsCurrent: true,
|
|
|
|
|
orgRevisionIsDraft: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
relations: {
|
|
|
|
|
orgRevision: true,
|
|
|
|
|
orgRoot: true,
|
|
|
|
|
orgChild1: true,
|
|
|
|
|
orgChild2: true,
|
|
|
|
|
orgChild3: true,
|
|
|
|
|
orgChild4: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const orgRevisionRef = posMaster ? posMaster.id : null;
|
|
|
|
|
const orgRootRef = orgRevisionRef?.orgRoot ?? null;
|
|
|
|
|
const orgChild1Ref = orgRevisionRef?.orgChild1 ?? null;
|
|
|
|
|
const orgChild2Ref = orgRevisionRef?.orgChild2 ?? null;
|
|
|
|
|
const orgChild3Ref = orgRevisionRef?.orgChild3 ?? null;
|
|
|
|
|
const orgChild4Ref = orgRevisionRef?.orgChild4 ?? null;
|
|
|
|
|
|
|
|
|
|
//ลบตำแหน่งที่รักษาการแทน
|
|
|
|
|
const code = _command?.commandType?.code;
|
|
|
|
|
if (code && ["C-PM-13"].includes(code)) {
|
|
|
|
|
// await (เดิมไม่ await = fire-and-forget bug) + ส่ง manager เข้าไปเพื่อให้อยู่ใน transaction
|
|
|
|
|
await removePostMasterAct(profile.id, manager);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let _commandYear = item.commandYear;
|
|
|
|
|
if (item.commandYear) {
|
|
|
|
|
_commandYear = item.commandYear > 2500 ? item.commandYear : item.commandYear + 543;
|
|
|
|
|
}
|
|
|
|
|
const dest_item = await salaryRepo.findOne({
|
|
|
|
|
where: { profileId: item.profileId },
|
|
|
|
|
order: { order: "DESC" },
|
|
|
|
|
});
|
|
|
|
|
const before = null;
|
|
|
|
|
const dataSalary = new ProfileSalary();
|
|
|
|
|
dataSalary.posNumCodeSit = _posNumCodeSit;
|
|
|
|
|
dataSalary.posNumCodeSitAbb = _posNumCodeSitAbb;
|
|
|
|
|
const meta = {
|
|
|
|
|
order: dest_item == null ? 1 : dest_item.order + 1,
|
|
|
|
|
createdUserId: ctx.user.sub,
|
|
|
|
|
createdFullName: ctx.user.name,
|
|
|
|
|
lastUpdateUserId: ctx.user.sub,
|
|
|
|
|
lastUpdateFullName: ctx.user.name,
|
|
|
|
|
createdAt: new Date(),
|
|
|
|
|
lastUpdatedAt: new Date(),
|
|
|
|
|
};
|
|
|
|
|
if (item.isLeave != undefined && item.isLeave == true) {
|
|
|
|
|
console.log(
|
|
|
|
|
`[ExecuteSalaryService] Creating PosMasterHistory — posMasterId: ${orgRevisionRef}, profileId: ${item.profileId}, type: DELETE`,
|
|
|
|
|
);
|
|
|
|
|
await CreatePosMasterHistoryOfficer(orgRevisionRef, req, "DELETE", null, manager);
|
|
|
|
|
await removeProfileInOrganize(profile.id, "OFFICER", manager);
|
|
|
|
|
}
|
|
|
|
|
const clearProfile = await checkCommandType(String(item.commandId));
|
|
|
|
|
const _null: any = null;
|
|
|
|
|
if (clearProfile.status) {
|
|
|
|
|
// Keycloak deleteUser ทำก่อนเข้า transaction-bound save ด้านล่าง
|
|
|
|
|
// (ทำภายใน transaction เดียวกัน เพราะถ้า fail ต้อง rollback DB ด้วย)
|
|
|
|
|
// หมายเหตุ: Keycloak ไม่สามารถ rollback ได้ → ถ้า DB rollback หลังจากนี้ Keycloak จะถูกลบไปแล้ว
|
|
|
|
|
if (profile.keycloak != null && profile.keycloak != "" && profile.isDelete === false) {
|
|
|
|
|
const delUserKeycloak = await deleteUser(profile.keycloak);
|
|
|
|
|
if (delUserKeycloak) {
|
|
|
|
|
// Task #228
|
|
|
|
|
// profile.keycloak = _null;
|
|
|
|
|
profile.roleKeycloaks = [];
|
|
|
|
|
profile.isActive = false;
|
|
|
|
|
profile.isDelete = true;
|
2026-06-18 18:29:03 +07:00
|
|
|
}
|
2026-06-24 18:05:54 +07:00
|
|
|
}
|
|
|
|
|
profile.isLeave = item.isLeave;
|
|
|
|
|
profile.leaveCommandId = item.commandId ?? _null;
|
|
|
|
|
profile.leaveCommandNo = `${item.commandNo}/${_commandYear}`;
|
|
|
|
|
profile.leaveRemark = clearProfile.leaveRemark ?? _null;
|
|
|
|
|
profile.leaveDate = item.commandDateAffect ?? _null;
|
|
|
|
|
profile.leaveType = clearProfile.LeaveType ?? _null;
|
|
|
|
|
//ออกจากราชการ ไม่ต้องลบตำแหน่งในทะเบียน (issue #1516)
|
|
|
|
|
// profile.position = _null;
|
|
|
|
|
// profile.posTypeId = _null;
|
|
|
|
|
// profile.posLevelId = _null;
|
|
|
|
|
profile.leaveReason = item.leaveReason ?? _null;
|
|
|
|
|
profile.dateLeave = item.dateLeave ?? _null;
|
|
|
|
|
profile.amount = item.amount ?? _null;
|
|
|
|
|
profile.amountSpecial = item.amountSpecial ?? _null;
|
|
|
|
|
await profileRepository.save(profile, { data: req });
|
|
|
|
|
|
|
|
|
|
// if (profile.id) {
|
|
|
|
|
// await this.keycloakAttributeService.clearOrgDnaAttributes(
|
|
|
|
|
// [profile.id],
|
|
|
|
|
// "PROFILE",
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
Object.assign(dataSalary, { ...item, ...meta });
|
|
|
|
|
const history = new ProfileSalaryHistory();
|
|
|
|
|
Object.assign(history, { ...dataSalary, id: undefined });
|
|
|
|
|
|
|
|
|
|
await salaryRepo.save(dataSalary, { data: req });
|
|
|
|
|
setLogDataDiff(req, { before, after: dataSalary });
|
|
|
|
|
history.profileSalaryId = dataSalary.id;
|
|
|
|
|
await salaryHistoryRepo.save(history, { data: req });
|
|
|
|
|
|
|
|
|
|
if (_command) {
|
|
|
|
|
if (["C-PM-15", "C-PM-16"].includes(_command.commandType.code)) {
|
|
|
|
|
// ประวัติคำสั่งให้ช่วยราชการ
|
|
|
|
|
const dataAssis = new ProfileAssistance();
|
|
|
|
|
|
|
|
|
|
const metaAssis = {
|
|
|
|
|
profileId: item.profileId,
|
|
|
|
|
agency: item.officerOrg,
|
|
|
|
|
dateStart: item.dateStart,
|
|
|
|
|
dateEnd: item.dateEnd,
|
|
|
|
|
commandNo: `${item.commandNo}/${_commandYear}`,
|
|
|
|
|
commandName: item.commandName,
|
|
|
|
|
refId: item.refId,
|
|
|
|
|
refCommandDate: new Date(),
|
|
|
|
|
commandId: item.commandId,
|
2026-06-18 18:29:03 +07:00
|
|
|
createdUserId: ctx.user.sub,
|
|
|
|
|
createdFullName: ctx.user.name,
|
|
|
|
|
lastUpdateUserId: ctx.user.sub,
|
|
|
|
|
lastUpdateFullName: ctx.user.name,
|
|
|
|
|
createdAt: new Date(),
|
|
|
|
|
lastUpdatedAt: new Date(),
|
2026-06-24 18:05:54 +07:00
|
|
|
status: _command.commandType.code == "C-PM-15" ? "PENDING" : "DONE",
|
2026-06-18 18:29:03 +07:00
|
|
|
};
|
|
|
|
|
|
2026-06-24 18:05:54 +07:00
|
|
|
Object.assign(dataAssis, metaAssis);
|
|
|
|
|
const historyAssis = new ProfileAssistanceHistory();
|
|
|
|
|
Object.assign(historyAssis, { ...dataAssis, id: undefined });
|
2026-06-18 18:29:03 +07:00
|
|
|
|
2026-06-24 18:05:54 +07:00
|
|
|
await assistanceRepository.save(dataAssis);
|
|
|
|
|
historyAssis.profileAssistanceId = dataAssis.id;
|
|
|
|
|
await assistanceHistoryRepository.save(historyAssis);
|
|
|
|
|
}
|
|
|
|
|
// Task #2190
|
|
|
|
|
else if (_command.commandType.code == "C-PM-13") {
|
|
|
|
|
let organizeName = "";
|
|
|
|
|
if (orgRootRef) {
|
|
|
|
|
const names = [
|
|
|
|
|
orgChild4Ref?.orgChild4Name,
|
|
|
|
|
orgChild3Ref?.orgChild3Name,
|
|
|
|
|
orgChild2Ref?.orgChild2Name,
|
|
|
|
|
orgChild1Ref?.orgChild1Name,
|
|
|
|
|
orgRootRef?.orgRootName,
|
|
|
|
|
].filter(Boolean);
|
|
|
|
|
organizeName = names.join(" ");
|
2026-06-18 18:29:03 +07:00
|
|
|
}
|
2026-06-24 18:05:54 +07:00
|
|
|
}
|
|
|
|
|
}
|
2026-06-18 18:29:03 +07:00
|
|
|
|
2026-06-24 18:05:54 +07:00
|
|
|
console.log(
|
|
|
|
|
`[ExecuteSalaryService] Completed processOne — profileId: ${item.profileId}`,
|
|
|
|
|
);
|
2026-06-18 18:29:03 +07:00
|
|
|
}
|
|
|
|
|
}
|