Linear Flow (PlacementService) #224
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m10s
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m10s
This commit is contained in:
parent
2f17c10050
commit
616ccf9e64
6 changed files with 1160 additions and 777 deletions
|
|
@ -104,7 +104,10 @@ import { LeaveType } from "../entities/LeaveType";
|
||||||
import { KeycloakAttributeService } from "../services/KeycloakAttributeService";
|
import { KeycloakAttributeService } from "../services/KeycloakAttributeService";
|
||||||
import { reOrderCommandRecivesAndDelete } from "../services/CommandService";
|
import { reOrderCommandRecivesAndDelete } from "../services/CommandService";
|
||||||
import { RetirementService } from "../services/RetirementService";
|
import { RetirementService } from "../services/RetirementService";
|
||||||
import { OfficerProfileService } from "../services/OfficerProfileService";
|
import { ExecuteOfficerProfileService } from "../services/ExecuteOfficerProfileService";
|
||||||
|
import { ExecuteSalaryService } from "../services/ExecuteSalaryService";
|
||||||
|
import { ExecuteSalaryCurrentService } from "../services/ExecuteSalaryCurrentService";
|
||||||
|
import { ExecuteSalaryEmployeeCurrentService } from "../services/ExecuteSalaryEmployeeCurrentService";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
const REDIS_HOST = process.env.REDIS_HOST;
|
const REDIS_HOST = process.env.REDIS_HOST;
|
||||||
const REDIS_PORT = process.env.REDIS_PORT;
|
const REDIS_PORT = process.env.REDIS_PORT;
|
||||||
|
|
@ -3648,6 +3651,14 @@ export class CommandController extends Controller {
|
||||||
return new HttpSuccess();
|
return new HttpSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API สร้าง ProfileSalary ข้าราชการ + อัปเดตตำแหน่งปัจจุบัน (เปลี่ยนตำแหน่ง)
|
||||||
|
*
|
||||||
|
* Thin wrapper — เรียก ExecuteSalaryCurrentService (C-PM-03, 04, 05, 06, 07, 39, 47)
|
||||||
|
* ทั้ง endpoint นี้และ consumer ใน rabbitmq ใช้ service ตัวเดียวกัน (Linear Flow)
|
||||||
|
*
|
||||||
|
* @summary API สร้าง ProfileSalary ข้าราชการ + เปลี่ยนตำแหน่ง
|
||||||
|
*/
|
||||||
@Post("excexute/salary-current")
|
@Post("excexute/salary-current")
|
||||||
public async newSalaryAndUpdateCurrent(
|
public async newSalaryAndUpdateCurrent(
|
||||||
@Request() req: RequestWithUser,
|
@Request() req: RequestWithUser,
|
||||||
|
|
@ -3689,326 +3700,10 @@ export class CommandController extends Controller {
|
||||||
}[];
|
}[];
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
let _posNumCodeSit: string = "";
|
await new ExecuteSalaryCurrentService().executeSalaryCurrent(body.data, {
|
||||||
let _posNumCodeSitAbb: string = "";
|
user: { sub: req.user.sub, name: req.user.name },
|
||||||
const _command = await this.commandRepository.findOne({
|
req,
|
||||||
where: { id: body.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 ?? "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Promise.all(
|
|
||||||
body.data.map(async (item) => {
|
|
||||||
const profile: any = await this.profileRepository.findOneBy({ id: item.profileId });
|
|
||||||
if (!profile) {
|
|
||||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");
|
|
||||||
}
|
|
||||||
let _null: any = null;
|
|
||||||
const dest_item = await this.salaryRepo.findOne({
|
|
||||||
where: { profileId: item.profileId },
|
|
||||||
order: { order: "DESC" },
|
|
||||||
});
|
|
||||||
const before = null;
|
|
||||||
const data = new ProfileSalary();
|
|
||||||
|
|
||||||
const meta = {
|
|
||||||
order: dest_item == null ? 1 : dest_item.order + 1,
|
|
||||||
createdUserId: req.user.sub,
|
|
||||||
createdFullName: req.user.name,
|
|
||||||
lastUpdateUserId: req.user.sub,
|
|
||||||
lastUpdateFullName: req.user.name,
|
|
||||||
createdAt: new Date(),
|
|
||||||
lastUpdatedAt: new Date(),
|
|
||||||
};
|
|
||||||
data.posNumCodeSit = _posNumCodeSit;
|
|
||||||
data.posNumCodeSitAbb = _posNumCodeSitAbb;
|
|
||||||
Object.assign(data, { ...item, ...meta });
|
|
||||||
const history = new ProfileSalaryHistory();
|
|
||||||
Object.assign(history, { ...data, id: undefined });
|
|
||||||
await this.salaryRepo.save(data, { data: req });
|
|
||||||
setLogDataDiff(req, { before, after: data });
|
|
||||||
history.commandId = item.commandId ?? _null;
|
|
||||||
history.profileSalaryId = data.id;
|
|
||||||
await this.salaryHistoryRepo.save(history, { data: req });
|
|
||||||
|
|
||||||
// STEP 1: หา posMaster ที่จะใช้งานตาม id ที่ส่งมา
|
|
||||||
let posMaster = await this.posMasterRepository.findOne({
|
|
||||||
where: { id: item.posmasterId },
|
|
||||||
relations: {
|
|
||||||
orgRevision: true,
|
|
||||||
orgRoot: true,
|
|
||||||
orgChild1: true,
|
|
||||||
orgChild2: true,
|
|
||||||
orgChild3: true,
|
|
||||||
orgChild4: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// เช็คว่า posMaster ที่หามาอยู่ในโครงสร้างปัจจุบันหรือไม่
|
|
||||||
const isCurrent =
|
|
||||||
posMaster?.orgRevision?.orgRevisionIsCurrent === true &&
|
|
||||||
posMaster?.orgRevision?.orgRevisionIsDraft === false;
|
|
||||||
|
|
||||||
// ถ้าไม่อยู่ในโครงสร้างปัจจุบัน ให้หาตัวใหม่จาก ancestorDNA
|
|
||||||
if (!isCurrent && posMaster?.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,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (posMaster == null) {
|
|
||||||
console.error(
|
|
||||||
`[CommandController] PosMaster not found - posMasterId: ${item.posmasterId}, `
|
|
||||||
);
|
|
||||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
|
|
||||||
}
|
|
||||||
|
|
||||||
const posMasterOld = await this.posMasterRepository.findOne({
|
|
||||||
where: {
|
|
||||||
current_holderId: item.profileId,
|
|
||||||
orgRevisionId: posMaster.orgRevisionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (posMasterOld != null) {
|
|
||||||
posMasterOld.current_holderId = null;
|
|
||||||
posMasterOld.lastUpdatedAt = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
const positionOld = await this.positionRepository.findOne({
|
|
||||||
where: {
|
|
||||||
posMasterId: posMasterOld?.id,
|
|
||||||
positionIsSelected: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (positionOld != null) {
|
|
||||||
logPositionIsSelectedChange(positionOld.id, positionOld.positionIsSelected, false, {
|
|
||||||
posMasterId: posMasterOld?.id,
|
|
||||||
userId: req.user.sub,
|
|
||||||
endpoint: "updateMaster",
|
|
||||||
action: "command_change_reset_old_position",
|
|
||||||
});
|
|
||||||
|
|
||||||
positionOld.positionIsSelected = false;
|
|
||||||
await this.positionRepository.save(positionOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkPosition = await this.positionRepository.find({
|
|
||||||
where: {
|
|
||||||
posMasterId: posMaster!.id, // ใช้ posMaster ตัวใหม่ (ที่อาจจะเปลี่ยนจาก ancestorDNA)
|
|
||||||
positionIsSelected: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (checkPosition.length > 0) {
|
|
||||||
console.log(
|
|
||||||
`[positionIsSelected-DEBUG] Command change: clearing ${checkPosition.length} positions (posMasterId: ${posMaster!.id}, userId: ${req.user.sub}, endpoint: updateMaster)`
|
|
||||||
);
|
|
||||||
|
|
||||||
const clearPosition = checkPosition.map((positions) => {
|
|
||||||
logPositionIsSelectedChange(positions.id, positions.positionIsSelected, false, {
|
|
||||||
posMasterId: posMaster!.id,
|
|
||||||
userId: req.user.sub,
|
|
||||||
endpoint: "updateMaster",
|
|
||||||
action: "command_change_clear_positions",
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...positions,
|
|
||||||
positionIsSelected: false,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
await this.positionRepository.save(clearPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
posMaster.current_holderId = item.profileId;
|
|
||||||
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);
|
|
||||||
|
|
||||||
// STEP 2: กำหนด position ใหม่
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Resolve ID: ใช้ positionTypeId/positionLevelId ก่อน ถ้าไม่มี fallback เป็น positionType/positionLevel
|
|
||||||
const posTypeId = item.positionTypeId || item.positionType;
|
|
||||||
const posLevelId = item.positionLevelId || item.positionLevel;
|
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
|
||||||
// CONDITION 1: เช็คจาก positionId ตรง
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
|
||||||
if (item.positionId) {
|
|
||||||
const positionById = await this.positionRepository.findOne({
|
|
||||||
where: {
|
|
||||||
id: item.positionId,
|
|
||||||
posMasterId: posMaster.id, // ต้องอยู่ใน posMaster ที่ถูกต้อง
|
|
||||||
},
|
|
||||||
relations: ["posExecutive"],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (positionById) {
|
|
||||||
positionNew = positionById;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
|
||||||
// CONDITION 2: Match 7 ฟิลด์ (ถ้า Condition 1 ไม่ match)
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
|
||||||
if (!positionNew && item.positionName && posTypeId && posLevelId) {
|
|
||||||
// สร้าง where clause แบบ dynamic - ใส่เฉพาะฟิลด์ที่มีค่า
|
|
||||||
const whereCondition: any = {
|
|
||||||
posMasterId: posMaster.id,
|
|
||||||
positionName: item.positionName,
|
|
||||||
posTypeId: posTypeId,
|
|
||||||
posLevelId: posLevelId,
|
|
||||||
};
|
|
||||||
|
|
||||||
// เพิ่มเฉพาะฟิลด์ที่มีค่า (ไม่ใช่ null, undefined, หรือ string ว่าง)
|
|
||||||
if (item.positionField) {
|
|
||||||
whereCondition.positionField = item.positionField;
|
|
||||||
}
|
|
||||||
if (item.posExecutiveId) {
|
|
||||||
whereCondition.posExecutiveId = item.posExecutiveId;
|
|
||||||
}
|
|
||||||
if (item.positionExecutiveField) {
|
|
||||||
whereCondition.positionExecutiveField = item.positionExecutiveField;
|
|
||||||
}
|
|
||||||
if (item.positionArea) {
|
|
||||||
whereCondition.positionArea = item.positionArea;
|
|
||||||
}
|
|
||||||
|
|
||||||
const positionBy7Fields = await this.positionRepository.findOne({
|
|
||||||
where: whereCondition,
|
|
||||||
relations: ["posExecutive"],
|
|
||||||
order: { orderNo: "ASC" }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (positionBy7Fields) {
|
|
||||||
positionNew = positionBy7Fields;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
|
||||||
// CONDITION 3: Match 3 ฟิลด์ (ถ้า Condition 2 ไม่ match)
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
|
||||||
if (!positionNew && item.positionName && posTypeId && posLevelId) {
|
|
||||||
const positionBy3Fields = await this.positionRepository.findOne({
|
|
||||||
where: {
|
|
||||||
posMasterId: posMaster.id,
|
|
||||||
positionName: item.positionName,
|
|
||||||
posTypeId: posTypeId,
|
|
||||||
posLevelId: posLevelId,
|
|
||||||
},
|
|
||||||
relations: ["posExecutive"],
|
|
||||||
order: { orderNo: "ASC" }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (positionBy3Fields) {
|
|
||||||
positionNew = positionBy3Fields;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// // ═══════════════════════════════════════════════════════════
|
|
||||||
// // 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];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
|
|
||||||
if (positionNew != null) {
|
|
||||||
positionNew.positionIsSelected = true;
|
|
||||||
// อัพเดท org และ posMasterNo ตลอดไม่ต้องดัก isSit
|
|
||||||
profile.posMasterNo = getPosMasterNo(posMaster);
|
|
||||||
profile.org = getOrgFullName(posMaster);
|
|
||||||
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.amount = item.amount ?? null;
|
|
||||||
profile.amountSpecial = item.amountSpecial ?? null;
|
|
||||||
await this.profileRepository.save(profile);
|
|
||||||
await this.positionRepository.save(positionNew);
|
|
||||||
}
|
|
||||||
await CreatePosMasterHistoryOfficer(posMaster.id, req);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return new HttpSuccess();
|
return new HttpSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4046,162 +3741,10 @@ export class CommandController extends Controller {
|
||||||
}[];
|
}[];
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
let _posNumCodeSit: string = "";
|
await new ExecuteSalaryEmployeeCurrentService().executeSalaryEmployeeCurrent(body.data, {
|
||||||
let _posNumCodeSitAbb: string = "";
|
user: { sub: req.user.sub, name: req.user.name },
|
||||||
const _command = await this.commandRepository.findOne({
|
req,
|
||||||
where: { id: body.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 ?? "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Promise.all(
|
|
||||||
body.data.map(async (item) => {
|
|
||||||
const profile: any = await this.profileEmployeeRepository.findOneBy({ id: item.profileId });
|
|
||||||
if (!profile) {
|
|
||||||
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
|
|
||||||
}
|
|
||||||
|
|
||||||
const dest_item = await this.salaryRepo.findOne({
|
|
||||||
where: { profileEmployeeId: item.profileId },
|
|
||||||
order: { order: "DESC" },
|
|
||||||
});
|
|
||||||
const before = null;
|
|
||||||
const data = new ProfileSalary();
|
|
||||||
data.posNumCodeSit = _posNumCodeSit;
|
|
||||||
data.posNumCodeSitAbb = _posNumCodeSitAbb;
|
|
||||||
const meta = {
|
|
||||||
order: dest_item == null ? 1 : dest_item.order + 1,
|
|
||||||
createdUserId: req.user.sub,
|
|
||||||
createdFullName: req.user.name,
|
|
||||||
lastUpdateUserId: req.user.sub,
|
|
||||||
lastUpdateFullName: req.user.name,
|
|
||||||
createdAt: new Date(),
|
|
||||||
lastUpdatedAt: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.assign(data, {
|
|
||||||
...item,
|
|
||||||
...meta,
|
|
||||||
profileEmployeeId: item.profileId,
|
|
||||||
profileId: undefined,
|
|
||||||
});
|
|
||||||
const history = new ProfileSalaryHistory();
|
|
||||||
Object.assign(history, { ...data, id: undefined });
|
|
||||||
|
|
||||||
await this.salaryRepo.save(data, { data: req });
|
|
||||||
setLogDataDiff(req, { before, after: data });
|
|
||||||
history.profileSalaryId = data.id;
|
|
||||||
await this.salaryHistoryRepo.save(history, { data: req });
|
|
||||||
|
|
||||||
const posMaster = await this.employeePosMasterRepository.findOne({
|
|
||||||
where: { id: item.posmasterId },
|
|
||||||
relations: ["orgRoot"],
|
|
||||||
});
|
|
||||||
if (posMaster == null)
|
|
||||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
|
|
||||||
|
|
||||||
const posMasterOld = await this.employeePosMasterRepository.findOne({
|
|
||||||
where: {
|
|
||||||
current_holderId: item.profileId,
|
|
||||||
orgRevisionId: posMaster.orgRevisionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (posMasterOld != null) {
|
|
||||||
posMasterOld.current_holderId = null;
|
|
||||||
posMasterOld.lastUpdatedAt = new Date();
|
|
||||||
}
|
|
||||||
// if (posMasterOld != null) posMasterOld.next_holderId = null;
|
|
||||||
|
|
||||||
const positionOld = await this.employeePositionRepository.findOne({
|
|
||||||
where: {
|
|
||||||
posMasterId: posMasterOld?.id,
|
|
||||||
positionIsSelected: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (positionOld != null) {
|
|
||||||
positionOld.positionIsSelected = false;
|
|
||||||
await this.employeePositionRepository.save(positionOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkPosition = await this.employeePositionRepository.find({
|
|
||||||
where: {
|
|
||||||
posMasterId: item.posmasterId,
|
|
||||||
positionIsSelected: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (checkPosition.length > 0) {
|
|
||||||
const clearPosition = checkPosition.map((positions) => ({
|
|
||||||
...positions,
|
|
||||||
positionIsSelected: false,
|
|
||||||
}));
|
|
||||||
await this.employeePositionRepository.save(clearPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
posMaster.current_holderId = item.profileId;
|
|
||||||
posMaster.lastUpdatedAt = new Date();
|
|
||||||
posMaster.next_holderId = null;
|
|
||||||
if (posMasterOld != null) {
|
|
||||||
await this.employeePosMasterRepository.save(posMasterOld);
|
|
||||||
await CreatePosMasterHistoryEmployee(posMasterOld.id, req);
|
|
||||||
}
|
|
||||||
await this.employeePosMasterRepository.save(posMaster);
|
|
||||||
const positionNew = await this.employeePositionRepository.findOne({
|
|
||||||
where: {
|
|
||||||
id: item.positionId,
|
|
||||||
posMasterId: item.posmasterId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (positionNew != null) {
|
|
||||||
positionNew.positionIsSelected = true;
|
|
||||||
profile.posLevelId = positionNew.posLevelId;
|
|
||||||
profile.posTypeId = positionNew.posTypeId;
|
|
||||||
profile.position = positionNew.positionName;
|
|
||||||
profile.employeeOc = posMaster?.orgRoot?.orgRootName ?? null;
|
|
||||||
profile.positionEmployeePositionId = positionNew.positionName;
|
|
||||||
profile.amount = item.amount ?? null;
|
|
||||||
profile.amountSpecial = item.amountSpecial ?? null;
|
|
||||||
await this.profileEmployeeRepository.save(profile);
|
|
||||||
await this.employeePositionRepository.save(positionNew);
|
|
||||||
}
|
|
||||||
await CreatePosMasterHistoryEmployee(posMaster.id, req);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return new HttpSuccess();
|
return new HttpSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5003,6 +4546,14 @@ export class CommandController extends Controller {
|
||||||
return new HttpSuccess();
|
return new HttpSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API สร้าง ProfileSalary ข้าราชการ + handle leave/ออกจากราชการ/ช่วยราชการ
|
||||||
|
*
|
||||||
|
* Thin wrapper — เรียก ExecuteSalaryService (C-PM-13, 15, 16)
|
||||||
|
* ทั้ง endpoint นี้และ consumer ใน rabbitmq ใช้ service ตัวเดียวกัน (Linear Flow)
|
||||||
|
*
|
||||||
|
* @summary API สร้าง ProfileSalary ข้าราชการ (leave/โอน/ช่วยราชการ)
|
||||||
|
*/
|
||||||
@Post("excexute/salary")
|
@Post("excexute/salary")
|
||||||
public async newSalaryAndUpdate(
|
public async newSalaryAndUpdate(
|
||||||
@Request() req: RequestWithUser,
|
@Request() req: RequestWithUser,
|
||||||
|
|
@ -5045,221 +4596,10 @@ export class CommandController extends Controller {
|
||||||
}[];
|
}[];
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
let _posNumCodeSit: string = "";
|
await new ExecuteSalaryService().executeSalary(body.data, {
|
||||||
let _posNumCodeSitAbb: string = "";
|
user: { sub: req.user.sub, name: req.user.name },
|
||||||
const _command = await this.commandRepository.findOne({
|
req,
|
||||||
relations: ["commandType"],
|
|
||||||
where: { id: body.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 ?? "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Promise.all(
|
|
||||||
body.data.map(async (item) => {
|
|
||||||
const profile: any = await this.profileRepository.findOne({
|
|
||||||
where: { id: item.profileId },
|
|
||||||
// relations: ["roleKeycloaks"],
|
|
||||||
relations: {
|
|
||||||
roleKeycloaks: true,
|
|
||||||
posType: true,
|
|
||||||
posLevel: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!profile) {
|
|
||||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");
|
|
||||||
}
|
|
||||||
const posMaster: any = await this.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)) {
|
|
||||||
removePostMasterAct(profile.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let _commandYear = item.commandYear;
|
|
||||||
if (item.commandYear) {
|
|
||||||
_commandYear = item.commandYear > 2500 ? item.commandYear : item.commandYear + 543;
|
|
||||||
}
|
|
||||||
const dest_item = await this.salaryRepo.findOne({
|
|
||||||
where: { profileId: item.profileId },
|
|
||||||
order: { order: "DESC" },
|
|
||||||
});
|
|
||||||
const before = null;
|
|
||||||
const data = new ProfileSalary();
|
|
||||||
data.posNumCodeSit = _posNumCodeSit;
|
|
||||||
data.posNumCodeSitAbb = _posNumCodeSitAbb;
|
|
||||||
const meta = {
|
|
||||||
order: dest_item == null ? 1 : dest_item.order + 1,
|
|
||||||
createdUserId: req.user.sub,
|
|
||||||
createdFullName: req.user.name,
|
|
||||||
lastUpdateUserId: req.user.sub,
|
|
||||||
lastUpdateFullName: req.user.name,
|
|
||||||
createdAt: new Date(),
|
|
||||||
lastUpdatedAt: new Date(),
|
|
||||||
};
|
|
||||||
if (item.isLeave != undefined && item.isLeave == true) {
|
|
||||||
await CreatePosMasterHistoryOfficer(orgRevisionRef, req, "DELETE");
|
|
||||||
await removeProfileInOrganize(profile.id, "OFFICER");
|
|
||||||
}
|
|
||||||
const clearProfile = await checkCommandType(String(item.commandId));
|
|
||||||
const _null: any = null;
|
|
||||||
if (clearProfile.status) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 this.profileRepository.save(profile, { data: req });
|
|
||||||
|
|
||||||
// if (profile.id) {
|
|
||||||
// await this.keycloakAttributeService.clearOrgDnaAttributes(
|
|
||||||
// [profile.id],
|
|
||||||
// "PROFILE",
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
Object.assign(data, { ...item, ...meta });
|
|
||||||
const history = new ProfileSalaryHistory();
|
|
||||||
Object.assign(history, { ...data, id: undefined });
|
|
||||||
|
|
||||||
await this.salaryRepo.save(data, { data: req });
|
|
||||||
setLogDataDiff(req, { before, after: data });
|
|
||||||
history.profileSalaryId = data.id;
|
|
||||||
await this.salaryHistoryRepo.save(history, { data: req });
|
|
||||||
|
|
||||||
if (_command) {
|
|
||||||
/*
|
|
||||||
const command = await this.commandRepository.findOne({
|
|
||||||
where: { id: item.commandId },
|
|
||||||
relations: ["commandType"],
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
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,
|
|
||||||
createdUserId: req.user.sub,
|
|
||||||
createdFullName: req.user.name,
|
|
||||||
lastUpdateUserId: req.user.sub,
|
|
||||||
lastUpdateFullName: req.user.name,
|
|
||||||
createdAt: new Date(),
|
|
||||||
lastUpdatedAt: new Date(),
|
|
||||||
status: _command.commandType.code == "C-PM-15" ? "PENDING" : "DONE",
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.assign(dataAssis, metaAssis);
|
|
||||||
const historyAssis = new ProfileAssistanceHistory();
|
|
||||||
Object.assign(historyAssis, { ...dataAssis, id: undefined });
|
|
||||||
|
|
||||||
await this.assistanceRepository.save(dataAssis);
|
|
||||||
historyAssis.profileAssistanceId = dataAssis.id;
|
|
||||||
await this.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(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return new HttpSuccess();
|
return new HttpSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6712,7 +6052,7 @@ export class CommandController extends Controller {
|
||||||
}[];
|
}[];
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
await new OfficerProfileService().executeCreateOfficerProfile(body.data, {
|
await new ExecuteOfficerProfileService().executeCreateOfficerProfile(body.data, {
|
||||||
user: { sub: req.user.sub, name: req.user.name },
|
user: { sub: req.user.sub, name: req.user.name },
|
||||||
req,
|
req,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ export interface ExecutionContext {
|
||||||
*
|
*
|
||||||
* Behavior ทั้งหมด preserve จาก CommandController.CreateOfficeProfileExcecute ต้นฉบับ
|
* Behavior ทั้งหมด preserve จาก CommandController.CreateOfficeProfileExcecute ต้นฉบับ
|
||||||
*/
|
*/
|
||||||
export class OfficerProfileService {
|
export class ExecuteOfficerProfileService {
|
||||||
private commandRepository = AppDataSource.getRepository(Command);
|
private commandRepository = AppDataSource.getRepository(Command);
|
||||||
private profileRepository = AppDataSource.getRepository(Profile);
|
private profileRepository = AppDataSource.getRepository(Profile);
|
||||||
private profileEmployeeRepository = AppDataSource.getRepository(ProfileEmployee);
|
private profileEmployeeRepository = AppDataSource.getRepository(ProfileEmployee);
|
||||||
|
|
@ -177,8 +177,8 @@ export class OfficerProfileService {
|
||||||
data: OfficerProfileItem[],
|
data: OfficerProfileItem[],
|
||||||
ctx: ExecutionContext,
|
ctx: ExecutionContext,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
console.log("[OfficerProfileService] Starting executeCreateOfficerProfile");
|
console.log("[ExecuteOfficerProfileService] Starting executeCreateOfficerProfile");
|
||||||
console.log("[OfficerProfileService] Request body count:", data?.length);
|
console.log("[ExecuteOfficerProfileService] Request body count:", data?.length);
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
// Normalize date fields
|
// Normalize date fields
|
||||||
|
|
@ -224,35 +224,35 @@ export class OfficerProfileService {
|
||||||
const roleKeycloak = await this.roleKeycloakRepo.findOne({
|
const roleKeycloak = await this.roleKeycloakRepo.findOne({
|
||||||
where: { name: Like("USER") },
|
where: { name: Like("USER") },
|
||||||
});
|
});
|
||||||
console.log("[OfficerProfileService] roleKeycloak found:", !!roleKeycloak);
|
console.log("[ExecuteOfficerProfileService] roleKeycloak found:", !!roleKeycloak);
|
||||||
const list = await getRoles();
|
const list = await getRoles();
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Roles list retrieved, length:",
|
"[ExecuteOfficerProfileService] Roles list retrieved, length:",
|
||||||
Array.isArray(list) ? list.length : "not array",
|
Array.isArray(list) ? list.length : "not array",
|
||||||
);
|
);
|
||||||
if (!Array.isArray(list)) {
|
if (!Array.isArray(list)) {
|
||||||
console.error(
|
console.error(
|
||||||
"[OfficerProfileService] Failed - Cannot get role(s) data from the server",
|
"[ExecuteOfficerProfileService] Failed - Cannot get role(s) data from the server",
|
||||||
);
|
);
|
||||||
throw new Error("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 _posNumCodeSit: string = "";
|
||||||
let _posNumCodeSitAbb: string = "";
|
let _posNumCodeSitAbb: string = "";
|
||||||
console.log("[OfficerProfileService] Getting command data");
|
console.log("[ExecuteOfficerProfileService] Getting command data");
|
||||||
const _command = await this.commandRepository.findOne({
|
const _command = await this.commandRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: data.find((x) => x.bodySalarys?.commandId)?.bodySalarys?.commandId ?? "",
|
id: data.find((x) => x.bodySalarys?.commandId)?.bodySalarys?.commandId ?? "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Command found:",
|
"[ExecuteOfficerProfileService] Command found:",
|
||||||
!!_command,
|
!!_command,
|
||||||
"isBangkok:",
|
"isBangkok:",
|
||||||
_command?.isBangkok,
|
_command?.isBangkok,
|
||||||
);
|
);
|
||||||
if (_command) {
|
if (_command) {
|
||||||
if (_command?.isBangkok?.toLocaleUpperCase() == "OFFICE") {
|
if (_command?.isBangkok?.toLocaleUpperCase() == "OFFICE") {
|
||||||
console.log("[OfficerProfileService] Setting position codes for OFFICE");
|
console.log("[ExecuteOfficerProfileService] Setting position codes for OFFICE");
|
||||||
const orgRootDeputy = await this.orgRootRepository.findOne({
|
const orgRootDeputy = await this.orgRootRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
isDeputy: true,
|
isDeputy: true,
|
||||||
|
|
@ -268,21 +268,21 @@ export class OfficerProfileService {
|
||||||
: "สำนักปลัดกรุงเทพมหานคร";
|
: "สำนักปลัดกรุงเทพมหานคร";
|
||||||
_posNumCodeSitAbb = orgRootDeputy ? orgRootDeputy?.orgRootShortName : "สนป.";
|
_posNumCodeSitAbb = orgRootDeputy ? orgRootDeputy?.orgRootShortName : "สนป.";
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] OFFICE position codes set:",
|
"[ExecuteOfficerProfileService] OFFICE position codes set:",
|
||||||
_posNumCodeSit,
|
_posNumCodeSit,
|
||||||
_posNumCodeSitAbb,
|
_posNumCodeSitAbb,
|
||||||
);
|
);
|
||||||
} else if (_command?.isBangkok?.toLocaleUpperCase() == "BANGKOK") {
|
} else if (_command?.isBangkok?.toLocaleUpperCase() == "BANGKOK") {
|
||||||
console.log("[OfficerProfileService] Setting position codes for BANGKOK");
|
console.log("[ExecuteOfficerProfileService] Setting position codes for BANGKOK");
|
||||||
_posNumCodeSit = "กรุงเทพมหานคร";
|
_posNumCodeSit = "กรุงเทพมหานคร";
|
||||||
_posNumCodeSitAbb = "กทม.";
|
_posNumCodeSitAbb = "กทม.";
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] BANGKOK position codes set:",
|
"[ExecuteOfficerProfileService] BANGKOK position codes set:",
|
||||||
_posNumCodeSit,
|
_posNumCodeSit,
|
||||||
_posNumCodeSitAbb,
|
_posNumCodeSitAbb,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log("[OfficerProfileService] Setting position codes from admin profile");
|
console.log("[ExecuteOfficerProfileService] Setting position codes from admin profile");
|
||||||
let _profileAdmin = await this.profileRepository.findOne({
|
let _profileAdmin = await this.profileRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
keycloak: _command?.createdUserId.toString(),
|
keycloak: _command?.createdUserId.toString(),
|
||||||
|
|
@ -306,7 +306,7 @@ export class OfficerProfileService {
|
||||||
_profileAdmin?.current_holders.find((x) => x.orgRoot.orgRootShortName)?.orgRoot
|
_profileAdmin?.current_holders.find((x) => x.orgRoot.orgRootShortName)?.orgRoot
|
||||||
.orgRootShortName ?? "";
|
.orgRootShortName ?? "";
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Admin profile position codes set:",
|
"[ExecuteOfficerProfileService] Admin profile position codes set:",
|
||||||
_posNumCodeSit,
|
_posNumCodeSit,
|
||||||
_posNumCodeSitAbb,
|
_posNumCodeSitAbb,
|
||||||
);
|
);
|
||||||
|
|
@ -322,14 +322,14 @@ export class OfficerProfileService {
|
||||||
lastUpdatedAt: new Date(),
|
lastUpdatedAt: new Date(),
|
||||||
};
|
};
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Starting to process",
|
"[ExecuteOfficerProfileService] Starting to process",
|
||||||
data.length,
|
data.length,
|
||||||
"profile(s)",
|
"profile(s)",
|
||||||
);
|
);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
data.map(async (item, index) => {
|
data.map(async (item, index) => {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Processing item",
|
"[ExecuteOfficerProfileService] Processing item",
|
||||||
index + 1,
|
index + 1,
|
||||||
"of",
|
"of",
|
||||||
data.length,
|
data.length,
|
||||||
|
|
@ -342,7 +342,7 @@ export class OfficerProfileService {
|
||||||
!(await this.posLevelRepo.findOneBy({ id: item.bodyProfile.posLevelId }))
|
!(await this.posLevelRepo.findOneBy({ id: item.bodyProfile.posLevelId }))
|
||||||
) {
|
) {
|
||||||
console.error(
|
console.error(
|
||||||
"[OfficerProfileService] ไม่พบข้อมูลระดับตำแหน่งนี้ posLevelId:",
|
"[ExecuteOfficerProfileService] ไม่พบข้อมูลระดับตำแหน่งนี้ posLevelId:",
|
||||||
item.bodyProfile.posLevelId,
|
item.bodyProfile.posLevelId,
|
||||||
);
|
);
|
||||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลระดับตำแหน่งนี้");
|
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลระดับตำแหน่งนี้");
|
||||||
|
|
@ -352,14 +352,14 @@ export class OfficerProfileService {
|
||||||
!(await this.posTypeRepo.findOneBy({ id: item.bodyProfile.posTypeId }))
|
!(await this.posTypeRepo.findOneBy({ id: item.bodyProfile.posTypeId }))
|
||||||
) {
|
) {
|
||||||
console.error(
|
console.error(
|
||||||
"[OfficerProfileService] ไม่พบข้อมูลประเภทตำแหน่งนี้ posTypeId:",
|
"[ExecuteOfficerProfileService] ไม่พบข้อมูลประเภทตำแหน่งนี้ posTypeId:",
|
||||||
item.bodyProfile.posTypeId,
|
item.bodyProfile.posTypeId,
|
||||||
);
|
);
|
||||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้");
|
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Processing citizenId:",
|
"[ExecuteOfficerProfileService] Processing citizenId:",
|
||||||
item.bodyProfile.citizenId,
|
item.bodyProfile.citizenId,
|
||||||
);
|
);
|
||||||
let registrationProvinceId = await this.provinceRepo.findOneBy({
|
let registrationProvinceId = await this.provinceRepo.findOneBy({
|
||||||
|
|
@ -380,7 +380,7 @@ export class OfficerProfileService {
|
||||||
let currentSubDistrictId = await this.subDistrictRepo.findOneBy({
|
let currentSubDistrictId = await this.subDistrictRepo.findOneBy({
|
||||||
id: item.bodyProfile.currentSubDistrictId ?? "",
|
id: item.bodyProfile.currentSubDistrictId ?? "",
|
||||||
});
|
});
|
||||||
console.log("[OfficerProfileService] Address validation completed");
|
console.log("[ExecuteOfficerProfileService] Address validation completed");
|
||||||
|
|
||||||
let _dateRetire =
|
let _dateRetire =
|
||||||
item.bodyProfile.birthDate == null
|
item.bodyProfile.birthDate == null
|
||||||
|
|
@ -394,16 +394,16 @@ export class OfficerProfileService {
|
||||||
let userKeycloakId: any;
|
let userKeycloakId: any;
|
||||||
let result: any;
|
let result: any;
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Checking Keycloak user for citizenId:",
|
"[ExecuteOfficerProfileService] Checking Keycloak user for citizenId:",
|
||||||
item.bodyProfile.citizenId,
|
item.bodyProfile.citizenId,
|
||||||
);
|
);
|
||||||
const checkUser = await getUserByUsername(item.bodyProfile.citizenId);
|
const checkUser = await getUserByUsername(item.bodyProfile.citizenId);
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Keycloak user exists:",
|
"[ExecuteOfficerProfileService] Keycloak user exists:",
|
||||||
checkUser.length > 0,
|
checkUser.length > 0,
|
||||||
);
|
);
|
||||||
if (checkUser.length == 0) {
|
if (checkUser.length == 0) {
|
||||||
console.log("[OfficerProfileService] Creating new Keycloak user");
|
console.log("[ExecuteOfficerProfileService] Creating new Keycloak user");
|
||||||
let password = item.bodyProfile.citizenId;
|
let password = item.bodyProfile.citizenId;
|
||||||
if (item.bodyProfile.birthDate != null) {
|
if (item.bodyProfile.birthDate != null) {
|
||||||
const _date = new Date(item.bodyProfile.birthDate.toDateString())
|
const _date = new Date(item.bodyProfile.birthDate.toDateString())
|
||||||
|
|
@ -419,11 +419,11 @@ export class OfficerProfileService {
|
||||||
password = `${_date}${_month}${_year}`;
|
password = `${_date}${_month}${_year}`;
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Calling createUser for:",
|
"[ExecuteOfficerProfileService] Calling createUser for:",
|
||||||
item.bodyProfile.citizenId,
|
item.bodyProfile.citizenId,
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] createUser data - firstName:",
|
"[ExecuteOfficerProfileService] createUser data - firstName:",
|
||||||
item.bodyProfile.firstName,
|
item.bodyProfile.firstName,
|
||||||
"lastName:",
|
"lastName:",
|
||||||
item.bodyProfile.lastName,
|
item.bodyProfile.lastName,
|
||||||
|
|
@ -440,7 +440,7 @@ export class OfficerProfileService {
|
||||||
userKeycloakId.errorMessage
|
userKeycloakId.errorMessage
|
||||||
) {
|
) {
|
||||||
console.error(
|
console.error(
|
||||||
"[OfficerProfileService] createUser FAILED - field:",
|
"[ExecuteOfficerProfileService] createUser FAILED - field:",
|
||||||
userKeycloakId.field,
|
userKeycloakId.field,
|
||||||
"errorMessage:",
|
"errorMessage:",
|
||||||
userKeycloakId.errorMessage,
|
userKeycloakId.errorMessage,
|
||||||
|
|
@ -453,7 +453,7 @@ export class OfficerProfileService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] User created in Keycloak, userKeycloakId:",
|
"[ExecuteOfficerProfileService] User created in Keycloak, userKeycloakId:",
|
||||||
userKeycloakId,
|
userKeycloakId,
|
||||||
);
|
);
|
||||||
result = await addUserRoles(
|
result = await addUserRoles(
|
||||||
|
|
@ -466,14 +466,14 @@ export class OfficerProfileService {
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] USER role assigned to new user, result:",
|
"[ExecuteOfficerProfileService] USER role assigned to new user, result:",
|
||||||
result,
|
result,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log("[OfficerProfileService] Updating existing Keycloak user");
|
console.log("[ExecuteOfficerProfileService] Updating existing Keycloak user");
|
||||||
userKeycloakId = checkUser[0].id;
|
userKeycloakId = checkUser[0].id;
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Existing userKeycloakId:",
|
"[ExecuteOfficerProfileService] Existing userKeycloakId:",
|
||||||
userKeycloakId,
|
userKeycloakId,
|
||||||
);
|
);
|
||||||
const rolesData = await getRoleMappings(userKeycloakId);
|
const rolesData = await getRoleMappings(userKeycloakId);
|
||||||
|
|
@ -483,7 +483,7 @@ export class OfficerProfileService {
|
||||||
name: x.name,
|
name: x.name,
|
||||||
}));
|
}));
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Removing old roles:",
|
"[ExecuteOfficerProfileService] Removing old roles:",
|
||||||
_delRole.length,
|
_delRole.length,
|
||||||
);
|
);
|
||||||
await removeUserRoles(userKeycloakId, _delRole);
|
await removeUserRoles(userKeycloakId, _delRole);
|
||||||
|
|
@ -498,7 +498,7 @@ export class OfficerProfileService {
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] USER role assigned to existing user",
|
"[ExecuteOfficerProfileService] USER role assigned to existing user",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,7 +507,7 @@ export class OfficerProfileService {
|
||||||
relations: ["roleKeycloaks", "profileInsignias", "profileAvatars"],
|
relations: ["roleKeycloaks", "profileInsignias", "profileAvatars"],
|
||||||
});
|
});
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Profile found:",
|
"[ExecuteOfficerProfileService] Profile found:",
|
||||||
!!profile,
|
!!profile,
|
||||||
"for citizenId:",
|
"for citizenId:",
|
||||||
item.bodyProfile.citizenId,
|
item.bodyProfile.citizenId,
|
||||||
|
|
@ -517,7 +517,7 @@ export class OfficerProfileService {
|
||||||
//ลูกจ้างประจำ หรือ บุคคลภายนอก
|
//ลูกจ้างประจำ หรือ บุคคลภายนอก
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] No existing profile found, creating new profile",
|
"[ExecuteOfficerProfileService] No existing profile found, creating new profile",
|
||||||
);
|
);
|
||||||
//กรณีลูกจ้างประจำมาสอบเป็นข้าราชการ ต้อง update สถานะโปรไฟล์เดิม
|
//กรณีลูกจ้างประจำมาสอบเป็นข้าราชการ ต้อง update สถานะโปรไฟล์เดิม
|
||||||
let profileEmployee: any = await this.profileEmployeeRepository.findOne({
|
let profileEmployee: any = await this.profileEmployeeRepository.findOne({
|
||||||
|
|
@ -525,12 +525,12 @@ export class OfficerProfileService {
|
||||||
relations: ["profileInsignias", "roleKeycloaks"],
|
relations: ["profileInsignias", "roleKeycloaks"],
|
||||||
});
|
});
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Employee profile found:",
|
"[ExecuteOfficerProfileService] Employee profile found:",
|
||||||
!!profileEmployee,
|
!!profileEmployee,
|
||||||
);
|
);
|
||||||
if (profileEmployee) {
|
if (profileEmployee) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Converting employee profile to officer profile",
|
"[ExecuteOfficerProfileService] Converting employee profile to officer profile",
|
||||||
);
|
);
|
||||||
const _order = await this.salaryRepo.findOne({
|
const _order = await this.salaryRepo.findOne({
|
||||||
where: { profileEmployeeId: profileEmployee.id },
|
where: { profileEmployeeId: profileEmployee.id },
|
||||||
|
|
@ -618,10 +618,10 @@ export class OfficerProfileService {
|
||||||
profile.bloodGroup = item.bodyProfile.bloodGroup ?? null;
|
profile.bloodGroup = item.bodyProfile.bloodGroup ?? null;
|
||||||
profile.phone = item.bodyProfile.phone ?? null;
|
profile.phone = item.bodyProfile.phone ?? null;
|
||||||
|
|
||||||
console.log("[OfficerProfileService] Saving new profile");
|
console.log("[ExecuteOfficerProfileService] Saving new profile");
|
||||||
await this.profileRepository.save(profile);
|
await this.profileRepository.save(profile);
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] New profile saved, profileId:",
|
"[ExecuteOfficerProfileService] New profile saved, profileId:",
|
||||||
profile.id,
|
profile.id,
|
||||||
);
|
);
|
||||||
// update user attribute in keycloak
|
// update user attribute in keycloak
|
||||||
|
|
@ -629,13 +629,13 @@ export class OfficerProfileService {
|
||||||
profileId: [profile.id],
|
profileId: [profile.id],
|
||||||
prefix: [profile.prefix || ""],
|
prefix: [profile.prefix || ""],
|
||||||
});
|
});
|
||||||
console.log("[OfficerProfileService] Keycloak attributes updated");
|
console.log("[ExecuteOfficerProfileService] Keycloak attributes updated");
|
||||||
setLogDataDiff(req, { before, after: profile });
|
setLogDataDiff(req, { before, after: profile });
|
||||||
}
|
}
|
||||||
//ขรก.ในระบบ หรือ ขรก.ในระบบที่สถานะพ้นจากราชการ
|
//ขรก.ในระบบ หรือ ขรก.ในระบบที่สถานะพ้นจากราชการ
|
||||||
else {
|
else {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Existing profile found, isLeave:",
|
"[ExecuteOfficerProfileService] Existing profile found, isLeave:",
|
||||||
profile.isLeave,
|
profile.isLeave,
|
||||||
"leaveType:",
|
"leaveType:",
|
||||||
profile.leaveType,
|
profile.leaveType,
|
||||||
|
|
@ -646,7 +646,7 @@ export class OfficerProfileService {
|
||||||
["PLACEMENT_TRANSFER", "RETIRE_RESIGN"].includes(profile.leaveType)
|
["PLACEMENT_TRANSFER", "RETIRE_RESIGN"].includes(profile.leaveType)
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Profile is leaving with eligible leave type, creating new profile record",
|
"[ExecuteOfficerProfileService] Profile is leaving with eligible leave type, creating new profile record",
|
||||||
);
|
);
|
||||||
//ดึง profileSalary เดิม
|
//ดึง profileSalary เดิม
|
||||||
_oldSalaries = await this.salaryRepo.find({
|
_oldSalaries = await this.salaryRepo.find({
|
||||||
|
|
@ -698,13 +698,13 @@ export class OfficerProfileService {
|
||||||
profile.phone = item.bodyProfile.phone ?? null;
|
profile.phone = item.bodyProfile.phone ?? null;
|
||||||
await this.profileRepository.save(profile);
|
await this.profileRepository.save(profile);
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] New profile record saved for leaving officer, profileId:",
|
"[ExecuteOfficerProfileService] New profile record saved for leaving officer, profileId:",
|
||||||
profile.id,
|
profile.id,
|
||||||
);
|
);
|
||||||
setLogDataDiff(req, { before, after: profile });
|
setLogDataDiff(req, { before, after: profile });
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Updating existing active profile",
|
"[ExecuteOfficerProfileService] Updating existing active profile",
|
||||||
);
|
);
|
||||||
profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : [];
|
profile.roleKeycloaks = result && roleKeycloak ? [roleKeycloak] : [];
|
||||||
profile.keycloak =
|
profile.keycloak =
|
||||||
|
|
@ -793,7 +793,7 @@ export class OfficerProfileService {
|
||||||
: profile.phone;
|
: profile.phone;
|
||||||
await this.profileRepository.save(profile);
|
await this.profileRepository.save(profile);
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Existing active profile updated, profileId:",
|
"[ExecuteOfficerProfileService] Existing active profile updated, profileId:",
|
||||||
profile.id,
|
profile.id,
|
||||||
);
|
);
|
||||||
setLogDataDiff(req, { before, after: profile });
|
setLogDataDiff(req, { before, after: profile });
|
||||||
|
|
@ -802,13 +802,13 @@ export class OfficerProfileService {
|
||||||
|
|
||||||
if (profile && profile.id) {
|
if (profile && profile.id) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Processing additional data for profileId:",
|
"[ExecuteOfficerProfileService] Processing additional data for profileId:",
|
||||||
profile.id,
|
profile.id,
|
||||||
);
|
);
|
||||||
//Educations
|
//Educations
|
||||||
if (item.bodyEducations && item.bodyEducations.length > 0) {
|
if (item.bodyEducations && item.bodyEducations.length > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Processing educations, count:",
|
"[ExecuteOfficerProfileService] Processing educations, count:",
|
||||||
item.bodyEducations.length,
|
item.bodyEducations.length,
|
||||||
);
|
);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|
@ -834,7 +834,7 @@ export class OfficerProfileService {
|
||||||
//Certificates
|
//Certificates
|
||||||
if (item.bodyCertificates && item.bodyCertificates.length > 0) {
|
if (item.bodyCertificates && item.bodyCertificates.length > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Processing certificates, count:",
|
"[ExecuteOfficerProfileService] Processing certificates, count:",
|
||||||
item.bodyCertificates.length,
|
item.bodyCertificates.length,
|
||||||
);
|
);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|
@ -853,7 +853,7 @@ export class OfficerProfileService {
|
||||||
}
|
}
|
||||||
//FamilyCouple
|
//FamilyCouple
|
||||||
if (item.bodyMarry != null) {
|
if (item.bodyMarry != null) {
|
||||||
console.log("[OfficerProfileService] Processing couple/marry data");
|
console.log("[ExecuteOfficerProfileService] Processing couple/marry data");
|
||||||
const profileCouple = new ProfileFamilyCouple();
|
const profileCouple = new ProfileFamilyCouple();
|
||||||
const data = {
|
const data = {
|
||||||
profileId: profile.id,
|
profileId: profile.id,
|
||||||
|
|
@ -875,7 +875,7 @@ export class OfficerProfileService {
|
||||||
}
|
}
|
||||||
//FamilyFather
|
//FamilyFather
|
||||||
if (item.bodyFather != null) {
|
if (item.bodyFather != null) {
|
||||||
console.log("[OfficerProfileService] Processing father data");
|
console.log("[ExecuteOfficerProfileService] Processing father data");
|
||||||
const profileFather = new ProfileFamilyFather();
|
const profileFather = new ProfileFamilyFather();
|
||||||
const data = {
|
const data = {
|
||||||
profileId: profile.id,
|
profileId: profile.id,
|
||||||
|
|
@ -896,7 +896,7 @@ export class OfficerProfileService {
|
||||||
}
|
}
|
||||||
//FamilyMother
|
//FamilyMother
|
||||||
if (item.bodyMother != null) {
|
if (item.bodyMother != null) {
|
||||||
console.log("[OfficerProfileService] Processing mother data");
|
console.log("[ExecuteOfficerProfileService] Processing mother data");
|
||||||
const profileMother = new ProfileFamilyMother();
|
const profileMother = new ProfileFamilyMother();
|
||||||
const data = {
|
const data = {
|
||||||
profileId: profile.id,
|
profileId: profile.id,
|
||||||
|
|
@ -919,7 +919,7 @@ export class OfficerProfileService {
|
||||||
//insert profileSalary อันเก่า กรณีพ้นราชการแล้วกลับมาบรรจุ
|
//insert profileSalary อันเก่า กรณีพ้นราชการแล้วกลับมาบรรจุ
|
||||||
if (_oldSalaries.length > 0) {
|
if (_oldSalaries.length > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Restoring old salaries, count:",
|
"[ExecuteOfficerProfileService] Restoring old salaries, count:",
|
||||||
_oldSalaries.length,
|
_oldSalaries.length,
|
||||||
);
|
);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|
@ -938,7 +938,7 @@ export class OfficerProfileService {
|
||||||
}
|
}
|
||||||
//insert item.bodySalarys ต่อจากที่ insert เดิมไปแล้ว
|
//insert item.bodySalarys ต่อจากที่ insert เดิมไปแล้ว
|
||||||
if (item.bodySalarys && item.bodySalarys != null) {
|
if (item.bodySalarys && item.bodySalarys != null) {
|
||||||
console.log("[OfficerProfileService] Processing new salary data");
|
console.log("[ExecuteOfficerProfileService] Processing new salary data");
|
||||||
const dest_item = await this.salaryRepo.findOne({
|
const dest_item = await this.salaryRepo.findOne({
|
||||||
where: { profileId: profile.id },
|
where: { profileId: profile.id },
|
||||||
order: { order: "DESC" },
|
order: { order: "DESC" },
|
||||||
|
|
@ -963,10 +963,10 @@ export class OfficerProfileService {
|
||||||
}
|
}
|
||||||
//Position
|
//Position
|
||||||
if (item.bodyPosition && item.bodyPosition != null) {
|
if (item.bodyPosition && item.bodyPosition != null) {
|
||||||
console.log("[OfficerProfileService] Processing position assignment");
|
console.log("[ExecuteOfficerProfileService] Processing position assignment");
|
||||||
// STEP 1: หา posMaster ที่จะใช้งานตาม id ที่ส่งมา (อาจเป็นตำแหน่งเก่าหรือใหม่ก็ได้)
|
// STEP 1: หา posMaster ที่จะใช้งานตาม id ที่ส่งมา (อาจเป็นตำแหน่งเก่าหรือใหม่ก็ได้)
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] STEP 1: Finding posMaster, posmasterId:",
|
"[ExecuteOfficerProfileService] STEP 1: Finding posMaster, posmasterId:",
|
||||||
item.bodyPosition.posmasterId,
|
item.bodyPosition.posmasterId,
|
||||||
);
|
);
|
||||||
let posMaster = await this.posMasterRepository.findOne({
|
let posMaster = await this.posMasterRepository.findOne({
|
||||||
|
|
@ -982,18 +982,18 @@ export class OfficerProfileService {
|
||||||
orgChild4: true,
|
orgChild4: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log("[OfficerProfileService] posMaster found:", !!posMaster);
|
console.log("[ExecuteOfficerProfileService] posMaster found:", !!posMaster);
|
||||||
|
|
||||||
// เช็คว่า posMaster ที่หามาอยู่ในโครงสร้างปัจจุบันหรือไม่
|
// เช็คว่า posMaster ที่หามาอยู่ในโครงสร้างปัจจุบันหรือไม่
|
||||||
const isCurrent =
|
const isCurrent =
|
||||||
posMaster?.orgRevision?.orgRevisionIsCurrent === true &&
|
posMaster?.orgRevision?.orgRevisionIsCurrent === true &&
|
||||||
posMaster?.orgRevision?.orgRevisionIsDraft === false;
|
posMaster?.orgRevision?.orgRevisionIsDraft === false;
|
||||||
console.log("[OfficerProfileService] posMaster isCurrent:", isCurrent);
|
console.log("[ExecuteOfficerProfileService] posMaster isCurrent:", isCurrent);
|
||||||
|
|
||||||
// ถ้าไม่อยู่ในโครงสร้างปัจจุบัน ให้หาตัวใหม่จาก ancestorDNA
|
// ถ้าไม่อยู่ในโครงสร้างปัจจุบัน ให้หาตัวใหม่จาก ancestorDNA
|
||||||
if (!isCurrent && posMaster?.ancestorDNA) {
|
if (!isCurrent && posMaster?.ancestorDNA) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Finding current posMaster from ancestorDNA",
|
"[ExecuteOfficerProfileService] Finding current posMaster from ancestorDNA",
|
||||||
);
|
);
|
||||||
posMaster = await this.posMasterRepository.findOne({
|
posMaster = await this.posMasterRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
|
|
@ -1013,20 +1013,20 @@ export class OfficerProfileService {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Current posMaster from ancestorDNA found:",
|
"[ExecuteOfficerProfileService] Current posMaster from ancestorDNA found:",
|
||||||
!!posMaster,
|
!!posMaster,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (posMaster == null) {
|
if (posMaster == null) {
|
||||||
console.error(
|
console.error(
|
||||||
`[OfficerProfileService] not found posMasterId: ${item.bodyPosition.posmasterId}`,
|
`[ExecuteOfficerProfileService] not found posMasterId: ${item.bodyPosition.posmasterId}`,
|
||||||
);
|
);
|
||||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
|
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 2: เคลียร์ข้อมูลตำแหน่งเก่าที่ครองอยู่ ในโครงสร้างปัจจุบัน
|
// STEP 2: เคลียร์ข้อมูลตำแหน่งเก่าที่ครองอยู่ ในโครงสร้างปัจจุบัน
|
||||||
console.log("[OfficerProfileService] STEP 2: Clearing old position data");
|
console.log("[ExecuteOfficerProfileService] STEP 2: Clearing old position data");
|
||||||
const posMasterOld = await this.posMasterRepository.findOne({
|
const posMasterOld = await this.posMasterRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
current_holderId: profile.id,
|
current_holderId: profile.id,
|
||||||
|
|
@ -1053,7 +1053,7 @@ export class OfficerProfileService {
|
||||||
|
|
||||||
// STEP 3: เคลียร์ position ที่เลือกไว้อื่นๆ ใน posMaster ตัวใหม่
|
// STEP 3: เคลียร์ position ที่เลือกไว้อื่นๆ ใน posMaster ตัวใหม่
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] STEP 3: Clearing other selected positions in new posMaster",
|
"[ExecuteOfficerProfileService] STEP 3: Clearing other selected positions in new posMaster",
|
||||||
);
|
);
|
||||||
const checkPosition = await this.positionRepository.find({
|
const checkPosition = await this.positionRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
|
@ -1071,7 +1071,7 @@ export class OfficerProfileService {
|
||||||
|
|
||||||
// STEP 4: กำหนดคนครองใหม่ให้กับ posMaster
|
// STEP 4: กำหนดคนครองใหม่ให้กับ posMaster
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] STEP 4: Assigning new holder to posMaster",
|
"[ExecuteOfficerProfileService] STEP 4: Assigning new holder to posMaster",
|
||||||
);
|
);
|
||||||
posMaster.current_holderId = profile.id;
|
posMaster.current_holderId = profile.id;
|
||||||
posMaster.lastUpdatedAt = new Date();
|
posMaster.lastUpdatedAt = new Date();
|
||||||
|
|
@ -1082,11 +1082,11 @@ export class OfficerProfileService {
|
||||||
await CreatePosMasterHistoryOfficer(posMasterOld.id, req);
|
await CreatePosMasterHistoryOfficer(posMasterOld.id, req);
|
||||||
}
|
}
|
||||||
await this.posMasterRepository.save(posMaster);
|
await this.posMasterRepository.save(posMaster);
|
||||||
console.log("[OfficerProfileService] posMaster saved with new holder");
|
console.log("[ExecuteOfficerProfileService] posMaster saved with new holder");
|
||||||
|
|
||||||
// STEP 5: กำหนด position ใหม่
|
// STEP 5: กำหนด position ใหม่
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] STEP 5: Determining position to assign",
|
"[ExecuteOfficerProfileService] STEP 5: Determining position to assign",
|
||||||
);
|
);
|
||||||
// Match position ตามลำดับ priority:
|
// Match position ตามลำดับ priority:
|
||||||
// Condition 1: match จาก positionId
|
// Condition 1: match จาก positionId
|
||||||
|
|
@ -1100,7 +1100,7 @@ export class OfficerProfileService {
|
||||||
// CONDITION 1: เช็คจาก positionId ตรง
|
// CONDITION 1: เช็คจาก positionId ตรง
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] CONDITION 1: Checking by positionId:",
|
"[ExecuteOfficerProfileService] CONDITION 1: Checking by positionId:",
|
||||||
item.bodyPosition?.positionId,
|
item.bodyPosition?.positionId,
|
||||||
);
|
);
|
||||||
if (item.bodyPosition?.positionId) {
|
if (item.bodyPosition?.positionId) {
|
||||||
|
|
@ -1115,7 +1115,7 @@ export class OfficerProfileService {
|
||||||
if (positionById) {
|
if (positionById) {
|
||||||
positionNew = positionById;
|
positionNew = positionById;
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] CONDITION 1 matched, positionId:",
|
"[ExecuteOfficerProfileService] CONDITION 1 matched, positionId:",
|
||||||
positionById.id,
|
positionById.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1126,7 +1126,7 @@ export class OfficerProfileService {
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
if (!positionNew && item.bodyPosition) {
|
if (!positionNew && item.bodyPosition) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] CONDITION 1 not matched, trying CONDITION 2: Match 7 fields",
|
"[ExecuteOfficerProfileService] CONDITION 1 not matched, trying CONDITION 2: Match 7 fields",
|
||||||
);
|
);
|
||||||
// สร้าง where clause แบบ dynamic - ใส่เฉพาะฟิลด์ที่ไม่ใช่ null
|
// สร้าง where clause แบบ dynamic - ใส่เฉพาะฟิลด์ที่ไม่ใช่ null
|
||||||
const whereCondition: any = {
|
const whereCondition: any = {
|
||||||
|
|
@ -1158,7 +1158,7 @@ export class OfficerProfileService {
|
||||||
if (positionBy7Fields) {
|
if (positionBy7Fields) {
|
||||||
positionNew = positionBy7Fields;
|
positionNew = positionBy7Fields;
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] CONDITION 2 matched with 7 fields, positionId:",
|
"[ExecuteOfficerProfileService] CONDITION 2 matched with 7 fields, positionId:",
|
||||||
positionBy7Fields.id,
|
positionBy7Fields.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1169,7 +1169,7 @@ export class OfficerProfileService {
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
if (!positionNew && item.bodyPosition) {
|
if (!positionNew && item.bodyPosition) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] CONDITION 2 not matched, trying CONDITION 3: Match 3 fields",
|
"[ExecuteOfficerProfileService] CONDITION 2 not matched, trying CONDITION 3: Match 3 fields",
|
||||||
);
|
);
|
||||||
const positionBy3Fields = await this.positionRepository.findOne({
|
const positionBy3Fields = await this.positionRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
|
|
@ -1185,12 +1185,12 @@ export class OfficerProfileService {
|
||||||
if (positionBy3Fields) {
|
if (positionBy3Fields) {
|
||||||
positionNew = positionBy3Fields;
|
positionNew = positionBy3Fields;
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] CONDITION 3 matched with 3 fields, positionId:",
|
"[ExecuteOfficerProfileService] CONDITION 3 matched with 3 fields, positionId:",
|
||||||
positionBy3Fields.id,
|
positionBy3Fields.id,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] No position matched for profileId:",
|
"[ExecuteOfficerProfileService] No position matched for profileId:",
|
||||||
profile.id,
|
profile.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1222,7 +1222,7 @@ export class OfficerProfileService {
|
||||||
// ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
|
// ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
|
||||||
if (positionNew != null) {
|
if (positionNew != null) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Final position assignment, isSit:",
|
"[ExecuteOfficerProfileService] Final position assignment, isSit:",
|
||||||
posMaster.isSit,
|
posMaster.isSit,
|
||||||
"positionId:",
|
"positionId:",
|
||||||
positionNew.id,
|
positionNew.id,
|
||||||
|
|
@ -1242,7 +1242,7 @@ export class OfficerProfileService {
|
||||||
} else if (!posMaster.isSit) {
|
} else if (!posMaster.isSit) {
|
||||||
// fallback: ตำแหน่งในโครงสร้างถูกแก้ไข ใช้ข้อมูลตำแหน่งที่สมัครสอบมา
|
// fallback: ตำแหน่งในโครงสร้างถูกแก้ไข ใช้ข้อมูลตำแหน่งที่สมัครสอบมา
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] positionNew is null, using bodyPosition data as fallback",
|
"[ExecuteOfficerProfileService] positionNew is null, using bodyPosition data as fallback",
|
||||||
);
|
);
|
||||||
profile.position = item.bodyPosition.positionName ?? null;
|
profile.position = item.bodyPosition.positionName ?? null;
|
||||||
profile.posTypeId = item.bodyPosition.posTypeId ?? null;
|
profile.posTypeId = item.bodyPosition.posTypeId ?? null;
|
||||||
|
|
@ -1261,7 +1261,7 @@ export class OfficerProfileService {
|
||||||
// Insignia
|
// Insignia
|
||||||
if (_oldInsigniaIds.length > 0) {
|
if (_oldInsigniaIds.length > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Processing old insignias, count:",
|
"[ExecuteOfficerProfileService] Processing old insignias, count:",
|
||||||
_oldInsigniaIds.length,
|
_oldInsigniaIds.length,
|
||||||
);
|
);
|
||||||
const _insignias = await this.insigniaRepo.find({
|
const _insignias = await this.insigniaRepo.find({
|
||||||
|
|
@ -1299,7 +1299,7 @@ export class OfficerProfileService {
|
||||||
// เพิ่มรูปภาพโปรไฟล์
|
// เพิ่มรูปภาพโปรไฟล์
|
||||||
if (item.bodyProfile.objectRefId) {
|
if (item.bodyProfile.objectRefId) {
|
||||||
console.log(
|
console.log(
|
||||||
"[OfficerProfileService] Processing profile avatar image, objectRefId:",
|
"[ExecuteOfficerProfileService] Processing profile avatar image, objectRefId:",
|
||||||
item.bodyProfile.objectRefId,
|
item.bodyProfile.objectRefId,
|
||||||
);
|
);
|
||||||
const _profileAvatar = new ProfileAvatar();
|
const _profileAvatar = new ProfileAvatar();
|
||||||
|
|
@ -1345,6 +1345,6 @@ export class OfficerProfileService {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
console.log("[OfficerProfileService] executeCreateOfficerProfile completed successfully");
|
console.log("[ExecuteOfficerProfileService] executeCreateOfficerProfile completed successfully");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
431
src/services/ExecuteSalaryCurrentService.ts
Normal file
431
src/services/ExecuteSalaryCurrentService.ts
Normal file
|
|
@ -0,0 +1,431 @@
|
||||||
|
import { Double } from "typeorm";
|
||||||
|
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 { OrgRoot } from "../entities/OrgRoot";
|
||||||
|
import { PosMaster } from "../entities/PosMaster";
|
||||||
|
import { Position } from "../entities/Position";
|
||||||
|
import { Command } from "../entities/Command";
|
||||||
|
import { getOrgFullName, getPosMasterNo } from "../utils/org-formatting";
|
||||||
|
import { logPositionIsSelectedChange, setLogDataDiff } from "../interfaces/utils";
|
||||||
|
import { CreatePosMasterHistoryOfficer } from "./PositionService";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input: ข้อมูล 1 คนสำหรับ endpoint excexute/salary-current
|
||||||
|
* (C-PM-03, 04, 05, 06, 07, 39, 47 — เปลี่ยนตำแหน่งปัจจุบันของข้าราชการ + salary ใหม่)
|
||||||
|
*/
|
||||||
|
export interface SalaryCurrentItem {
|
||||||
|
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;
|
||||||
|
positionTypeId?: string | null;
|
||||||
|
positionLevelId?: string | null;
|
||||||
|
posmasterId: string;
|
||||||
|
positionId: string;
|
||||||
|
posExecutiveId?: string | null;
|
||||||
|
positionField?: string | null;
|
||||||
|
commandId?: string | null;
|
||||||
|
orgRoot?: string | null;
|
||||||
|
orgChild1?: string | null;
|
||||||
|
orgChild2?: string | null;
|
||||||
|
orgChild3?: string | null;
|
||||||
|
orgChild4?: 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context สำหรับ audit/log
|
||||||
|
*/
|
||||||
|
export interface SalaryCurrentExecutionContext {
|
||||||
|
user: { sub: string; name: string };
|
||||||
|
req?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service สำหรับสร้าง ProfileSalary ของข้าราชการ + อัปเดตตำแหน่งปัจจุบัน (เปลี่ยนตำแหน่ง)
|
||||||
|
*
|
||||||
|
* ใช้กับ commandType: C-PM-03, 04, 05, 06, 07, 39, 47
|
||||||
|
*
|
||||||
|
* - endpoint /org/command/excexute/salary-current เรียกผ่าน service นี้ (thin wrapper)
|
||||||
|
* - consumer ใน rabbitmq handler เรียกผ่าน service นี้โดยตรง (Linear Flow)
|
||||||
|
*
|
||||||
|
* Behavior ทั้งหมด preserve จาก CommandController.newSalaryAndUpdateCurrent ต้นฉบับ
|
||||||
|
*/
|
||||||
|
export class ExecuteSalaryCurrentService {
|
||||||
|
private commandRepository = AppDataSource.getRepository(Command);
|
||||||
|
private profileRepository = AppDataSource.getRepository(Profile);
|
||||||
|
private salaryRepo = AppDataSource.getRepository(ProfileSalary);
|
||||||
|
private salaryHistoryRepo = AppDataSource.getRepository(ProfileSalaryHistory);
|
||||||
|
private posMasterRepository = AppDataSource.getRepository(PosMaster);
|
||||||
|
private positionRepository = AppDataSource.getRepository(Position);
|
||||||
|
private orgRootRepository = AppDataSource.getRepository(OrgRoot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ประมวลผลสร้าง ProfileSalary + อัปเดตตำแหน่งปัจจุบันของข้าราชการ
|
||||||
|
*/
|
||||||
|
async executeSalaryCurrent(
|
||||||
|
data: SalaryCurrentItem[],
|
||||||
|
ctx: SalaryCurrentExecutionContext,
|
||||||
|
): Promise<void> {
|
||||||
|
console.log("[ExecuteSalaryCurrentService] Starting executeSalaryCurrent");
|
||||||
|
console.log("[ExecuteSalaryCurrentService] Request body count:", data?.length);
|
||||||
|
|
||||||
|
const req = ctx.req;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// 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.commandDateAffect = toDate(it.commandDateAffect);
|
||||||
|
it.commandDateSign = toDate(it.commandDateSign);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _posNumCodeSit: string = "";
|
||||||
|
let _posNumCodeSitAbb: string = "";
|
||||||
|
const _command = await this.commandRepository.findOne({
|
||||||
|
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 ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all(
|
||||||
|
data.map(async (item) => {
|
||||||
|
const profile: any = await this.profileRepository.findOneBy({ id: item.profileId });
|
||||||
|
if (!profile) {
|
||||||
|
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");
|
||||||
|
}
|
||||||
|
let _null: any = null;
|
||||||
|
const dest_item = await this.salaryRepo.findOne({
|
||||||
|
where: { profileId: item.profileId },
|
||||||
|
order: { order: "DESC" },
|
||||||
|
});
|
||||||
|
const before = null;
|
||||||
|
const dataSalary = new ProfileSalary();
|
||||||
|
|
||||||
|
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(),
|
||||||
|
};
|
||||||
|
dataSalary.posNumCodeSit = _posNumCodeSit;
|
||||||
|
dataSalary.posNumCodeSitAbb = _posNumCodeSitAbb;
|
||||||
|
Object.assign(dataSalary, { ...item, ...meta });
|
||||||
|
const history = new ProfileSalaryHistory();
|
||||||
|
Object.assign(history, { ...dataSalary, id: undefined });
|
||||||
|
await this.salaryRepo.save(dataSalary, { data: req });
|
||||||
|
setLogDataDiff(req, { before, after: dataSalary });
|
||||||
|
history.commandId = item.commandId ?? _null;
|
||||||
|
history.profileSalaryId = dataSalary.id;
|
||||||
|
await this.salaryHistoryRepo.save(history, { data: req });
|
||||||
|
|
||||||
|
// STEP 1: หา posMaster ที่จะใช้งานตาม id ที่ส่งมา
|
||||||
|
let posMaster = await this.posMasterRepository.findOne({
|
||||||
|
where: { id: item.posmasterId },
|
||||||
|
relations: {
|
||||||
|
orgRevision: true,
|
||||||
|
orgRoot: true,
|
||||||
|
orgChild1: true,
|
||||||
|
orgChild2: true,
|
||||||
|
orgChild3: true,
|
||||||
|
orgChild4: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// เช็คว่า posMaster ที่หามาอยู่ในโครงสร้างปัจจุบันหรือไม่
|
||||||
|
const isCurrent =
|
||||||
|
posMaster?.orgRevision?.orgRevisionIsCurrent === true &&
|
||||||
|
posMaster?.orgRevision?.orgRevisionIsDraft === false;
|
||||||
|
|
||||||
|
// ถ้าไม่อยู่ในโครงสร้างปัจจุบัน ให้หาตัวใหม่จาก ancestorDNA
|
||||||
|
if (!isCurrent && posMaster?.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,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posMaster == null) {
|
||||||
|
console.error(
|
||||||
|
`[ExecuteSalaryCurrentService] PosMaster not found - posMasterId: ${item.posmasterId}, `,
|
||||||
|
);
|
||||||
|
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
|
||||||
|
}
|
||||||
|
|
||||||
|
const posMasterOld = await this.posMasterRepository.findOne({
|
||||||
|
where: {
|
||||||
|
current_holderId: item.profileId,
|
||||||
|
orgRevisionId: posMaster.orgRevisionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (posMasterOld != null) {
|
||||||
|
posMasterOld.current_holderId = null;
|
||||||
|
posMasterOld.lastUpdatedAt = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
const positionOld = await this.positionRepository.findOne({
|
||||||
|
where: {
|
||||||
|
posMasterId: posMasterOld?.id,
|
||||||
|
positionIsSelected: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (positionOld != null) {
|
||||||
|
logPositionIsSelectedChange(positionOld.id, positionOld.positionIsSelected, false, {
|
||||||
|
posMasterId: posMasterOld?.id,
|
||||||
|
userId: ctx.user.sub,
|
||||||
|
endpoint: "updateMaster",
|
||||||
|
action: "command_change_reset_old_position",
|
||||||
|
});
|
||||||
|
|
||||||
|
positionOld.positionIsSelected = false;
|
||||||
|
await this.positionRepository.save(positionOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkPosition = await this.positionRepository.find({
|
||||||
|
where: {
|
||||||
|
posMasterId: posMaster!.id, // ใช้ posMaster ตัวใหม่ (ที่อาจจะเปลี่ยนจาก ancestorDNA)
|
||||||
|
positionIsSelected: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (checkPosition.length > 0) {
|
||||||
|
console.log(
|
||||||
|
`[positionIsSelected-DEBUG] Command change: clearing ${checkPosition.length} positions (posMasterId: ${posMaster!.id}, userId: ${ctx.user.sub}, endpoint: updateMaster)`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const clearPosition = checkPosition.map((positions) => {
|
||||||
|
logPositionIsSelectedChange(positions.id, positions.positionIsSelected, false, {
|
||||||
|
posMasterId: posMaster!.id,
|
||||||
|
userId: ctx.user.sub,
|
||||||
|
endpoint: "updateMaster",
|
||||||
|
action: "command_change_clear_positions",
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...positions,
|
||||||
|
positionIsSelected: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
await this.positionRepository.save(clearPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
posMaster.current_holderId = item.profileId;
|
||||||
|
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);
|
||||||
|
|
||||||
|
// STEP 2: กำหนด position ใหม่
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Resolve ID: ใช้ positionTypeId/positionLevelId ก่อน ถ้าไม่มี fallback เป็น positionType/positionLevel
|
||||||
|
const posTypeId = item.positionTypeId || item.positionType;
|
||||||
|
const posLevelId = item.positionLevelId || item.positionLevel;
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// CONDITION 1: เช็คจาก positionId ตรง
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
if (item.positionId) {
|
||||||
|
const positionById = await this.positionRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id: item.positionId,
|
||||||
|
posMasterId: posMaster.id, // ต้องอยู่ใน posMaster ที่ถูกต้อง
|
||||||
|
},
|
||||||
|
relations: ["posExecutive"],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (positionById) {
|
||||||
|
positionNew = positionById;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// CONDITION 2: Match 7 ฟิลด์ (ถ้า Condition 1 ไม่ match)
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
if (!positionNew && item.positionName && posTypeId && posLevelId) {
|
||||||
|
// สร้าง where clause แบบ dynamic - ใส่เฉพาะฟิลด์ที่มีค่า
|
||||||
|
const whereCondition: any = {
|
||||||
|
posMasterId: posMaster.id,
|
||||||
|
positionName: item.positionName,
|
||||||
|
posTypeId: posTypeId,
|
||||||
|
posLevelId: posLevelId,
|
||||||
|
};
|
||||||
|
|
||||||
|
// เพิ่มเฉพาะฟิลด์ที่มีค่า (ไม่ใช่ null, undefined, หรือ string ว่าง)
|
||||||
|
if (item.positionField) {
|
||||||
|
whereCondition.positionField = item.positionField;
|
||||||
|
}
|
||||||
|
if (item.posExecutiveId) {
|
||||||
|
whereCondition.posExecutiveId = item.posExecutiveId;
|
||||||
|
}
|
||||||
|
if (item.positionExecutiveField) {
|
||||||
|
whereCondition.positionExecutiveField = item.positionExecutiveField;
|
||||||
|
}
|
||||||
|
if (item.positionArea) {
|
||||||
|
whereCondition.positionArea = item.positionArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
const positionBy7Fields = await this.positionRepository.findOne({
|
||||||
|
where: whereCondition,
|
||||||
|
relations: ["posExecutive"],
|
||||||
|
order: { orderNo: "ASC" },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (positionBy7Fields) {
|
||||||
|
positionNew = positionBy7Fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// CONDITION 3: Match 3 ฟิลด์ (ถ้า Condition 2 ไม่ match)
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
if (!positionNew && item.positionName && posTypeId && posLevelId) {
|
||||||
|
const positionBy3Fields = await this.positionRepository.findOne({
|
||||||
|
where: {
|
||||||
|
posMasterId: posMaster.id,
|
||||||
|
positionName: item.positionName,
|
||||||
|
posTypeId: posTypeId,
|
||||||
|
posLevelId: posLevelId,
|
||||||
|
},
|
||||||
|
relations: ["posExecutive"],
|
||||||
|
order: { orderNo: "ASC" },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (positionBy3Fields) {
|
||||||
|
positionNew = positionBy3Fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // ═══════════════════════════════════════════════════════════
|
||||||
|
// // 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];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
|
||||||
|
if (positionNew != null) {
|
||||||
|
positionNew.positionIsSelected = true;
|
||||||
|
// อัพเดท org และ posMasterNo ตลอดไม่ต้องดัก isSit
|
||||||
|
profile.posMasterNo = getPosMasterNo(posMaster);
|
||||||
|
profile.org = getOrgFullName(posMaster);
|
||||||
|
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.amount = item.amount ?? null;
|
||||||
|
profile.amountSpecial = item.amountSpecial ?? null;
|
||||||
|
await this.profileRepository.save(profile);
|
||||||
|
await this.positionRepository.save(positionNew);
|
||||||
|
}
|
||||||
|
await CreatePosMasterHistoryOfficer(posMaster.id, req);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("[ExecuteSalaryCurrentService] executeSalaryCurrent completed successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
262
src/services/ExecuteSalaryEmployeeCurrentService.ts
Normal file
262
src/services/ExecuteSalaryEmployeeCurrentService.ts
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
import { Double } from "typeorm";
|
||||||
|
import { AppDataSource } from "../database/data-source";
|
||||||
|
import HttpError from "../interfaces/http-error";
|
||||||
|
import HttpStatusCode from "../interfaces/http-status";
|
||||||
|
import HttpStatus from "../interfaces/http-status";
|
||||||
|
import { Profile } from "../entities/Profile";
|
||||||
|
import { ProfileEmployee } from "../entities/ProfileEmployee";
|
||||||
|
import { ProfileSalary } from "../entities/ProfileSalary";
|
||||||
|
import { ProfileSalaryHistory } from "../entities/ProfileSalaryHistory";
|
||||||
|
import { OrgRoot } from "../entities/OrgRoot";
|
||||||
|
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
|
||||||
|
import { EmployeePosition } from "../entities/EmployeePosition";
|
||||||
|
import { Command } from "../entities/Command";
|
||||||
|
import { setLogDataDiff } from "../interfaces/utils";
|
||||||
|
import { CreatePosMasterHistoryEmployee } from "./PositionService";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input: ข้อมูล 1 คนสำหรับ endpoint excexute/salary-employee-current
|
||||||
|
* (C-PM-22, 24 — เปลี่ยนตำแหน่งปัจจุบันของลูกจ้าง + salary ใหม่)
|
||||||
|
*/
|
||||||
|
export interface SalaryEmployeeCurrentItem {
|
||||||
|
profileId: string;
|
||||||
|
amount?: Double | null;
|
||||||
|
amountSpecial?: Double | null;
|
||||||
|
positionSalaryAmount?: Double | null;
|
||||||
|
mouthSalaryAmount?: Double | null;
|
||||||
|
positionType: string | null;
|
||||||
|
positionLevel: string | null;
|
||||||
|
posmasterId: string;
|
||||||
|
positionId: string;
|
||||||
|
commandId?: string | null;
|
||||||
|
orgRoot?: string | null;
|
||||||
|
orgChild1?: string | null;
|
||||||
|
orgChild2?: string | null;
|
||||||
|
orgChild3?: string | null;
|
||||||
|
orgChild4?: 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context สำหรับ audit/log
|
||||||
|
*/
|
||||||
|
export interface SalaryEmployeeCurrentExecutionContext {
|
||||||
|
user: { sub: string; name: string };
|
||||||
|
req?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service สำหรับสร้าง ProfileSalary ของลูกจ้าง + อัปเดตตำแหน่งปัจจุบัน (เปลี่ยนตำแหน่ง)
|
||||||
|
*
|
||||||
|
* ใช้กับ commandType: C-PM-22, 24
|
||||||
|
*
|
||||||
|
* - endpoint /org/command/excexute/salary-employee-current เรียกผ่าน service นี้ (thin wrapper)
|
||||||
|
* - consumer ใน rabbitmq handler เรียกผ่าน service นี้โดยตรง (Linear Flow)
|
||||||
|
*
|
||||||
|
* Behavior ทั้งหมด preserve จาก CommandController.newSalaryEmployeeAndUpdateCurrent ต้นฉบับ
|
||||||
|
*/
|
||||||
|
export class ExecuteSalaryEmployeeCurrentService {
|
||||||
|
private commandRepository = AppDataSource.getRepository(Command);
|
||||||
|
private profileRepository = AppDataSource.getRepository(Profile);
|
||||||
|
private profileEmployeeRepository = AppDataSource.getRepository(ProfileEmployee);
|
||||||
|
private salaryRepo = AppDataSource.getRepository(ProfileSalary);
|
||||||
|
private salaryHistoryRepo = AppDataSource.getRepository(ProfileSalaryHistory);
|
||||||
|
private employeePosMasterRepository = AppDataSource.getRepository(EmployeePosMaster);
|
||||||
|
private employeePositionRepository = AppDataSource.getRepository(EmployeePosition);
|
||||||
|
private orgRootRepository = AppDataSource.getRepository(OrgRoot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ประมวลผลสร้าง ProfileSalary + อัปเดตตำแหน่งปัจจุบันของลูกจ้าง
|
||||||
|
*/
|
||||||
|
async executeSalaryEmployeeCurrent(
|
||||||
|
data: SalaryEmployeeCurrentItem[],
|
||||||
|
ctx: SalaryEmployeeCurrentExecutionContext,
|
||||||
|
): Promise<void> {
|
||||||
|
console.log("[ExecuteSalaryEmployeeCurrentService] Starting executeSalaryEmployeeCurrent");
|
||||||
|
console.log("[ExecuteSalaryEmployeeCurrentService] Request body count:", data?.length);
|
||||||
|
|
||||||
|
const req = ctx.req;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// 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.commandDateAffect = toDate(it.commandDateAffect);
|
||||||
|
it.commandDateSign = toDate(it.commandDateSign);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _posNumCodeSit: string = "";
|
||||||
|
let _posNumCodeSitAbb: string = "";
|
||||||
|
const _command = await this.commandRepository.findOne({
|
||||||
|
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 ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all(
|
||||||
|
data.map(async (item) => {
|
||||||
|
const profile: any = await this.profileEmployeeRepository.findOneBy({ id: item.profileId });
|
||||||
|
if (!profile) {
|
||||||
|
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
|
||||||
|
}
|
||||||
|
|
||||||
|
const dest_item = await this.salaryRepo.findOne({
|
||||||
|
where: { profileEmployeeId: 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(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(dataSalary, {
|
||||||
|
...item,
|
||||||
|
...meta,
|
||||||
|
profileEmployeeId: item.profileId,
|
||||||
|
profileId: undefined,
|
||||||
|
});
|
||||||
|
const history = new ProfileSalaryHistory();
|
||||||
|
Object.assign(history, { ...dataSalary, id: undefined });
|
||||||
|
|
||||||
|
await this.salaryRepo.save(dataSalary, { data: req });
|
||||||
|
setLogDataDiff(req, { before, after: dataSalary });
|
||||||
|
history.profileSalaryId = dataSalary.id;
|
||||||
|
await this.salaryHistoryRepo.save(history, { data: req });
|
||||||
|
|
||||||
|
const posMaster = await this.employeePosMasterRepository.findOne({
|
||||||
|
where: { id: item.posmasterId },
|
||||||
|
relations: ["orgRoot"],
|
||||||
|
});
|
||||||
|
if (posMaster == null)
|
||||||
|
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
|
||||||
|
|
||||||
|
const posMasterOld = await this.employeePosMasterRepository.findOne({
|
||||||
|
where: {
|
||||||
|
current_holderId: item.profileId,
|
||||||
|
orgRevisionId: posMaster.orgRevisionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (posMasterOld != null) {
|
||||||
|
posMasterOld.current_holderId = null;
|
||||||
|
posMasterOld.lastUpdatedAt = new Date();
|
||||||
|
}
|
||||||
|
// if (posMasterOld != null) posMasterOld.next_holderId = null;
|
||||||
|
|
||||||
|
const positionOld = await this.employeePositionRepository.findOne({
|
||||||
|
where: {
|
||||||
|
posMasterId: posMasterOld?.id,
|
||||||
|
positionIsSelected: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (positionOld != null) {
|
||||||
|
positionOld.positionIsSelected = false;
|
||||||
|
await this.employeePositionRepository.save(positionOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkPosition = await this.employeePositionRepository.find({
|
||||||
|
where: {
|
||||||
|
posMasterId: item.posmasterId,
|
||||||
|
positionIsSelected: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (checkPosition.length > 0) {
|
||||||
|
const clearPosition = checkPosition.map((positions) => ({
|
||||||
|
...positions,
|
||||||
|
positionIsSelected: false,
|
||||||
|
}));
|
||||||
|
await this.employeePositionRepository.save(clearPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
posMaster.current_holderId = item.profileId;
|
||||||
|
posMaster.lastUpdatedAt = new Date();
|
||||||
|
posMaster.next_holderId = null;
|
||||||
|
if (posMasterOld != null) {
|
||||||
|
await this.employeePosMasterRepository.save(posMasterOld);
|
||||||
|
await CreatePosMasterHistoryEmployee(posMasterOld.id, req);
|
||||||
|
}
|
||||||
|
await this.employeePosMasterRepository.save(posMaster);
|
||||||
|
const positionNew = await this.employeePositionRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id: item.positionId,
|
||||||
|
posMasterId: item.posmasterId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (positionNew != null) {
|
||||||
|
positionNew.positionIsSelected = true;
|
||||||
|
profile.posLevelId = positionNew.posLevelId;
|
||||||
|
profile.posTypeId = positionNew.posTypeId;
|
||||||
|
profile.position = positionNew.positionName;
|
||||||
|
profile.employeeOc = posMaster?.orgRoot?.orgRootName ?? null;
|
||||||
|
profile.positionEmployeePositionId = positionNew.positionName;
|
||||||
|
profile.amount = item.amount ?? null;
|
||||||
|
profile.amountSpecial = item.amountSpecial ?? null;
|
||||||
|
await this.profileEmployeeRepository.save(profile);
|
||||||
|
await this.employeePositionRepository.save(positionNew);
|
||||||
|
}
|
||||||
|
await CreatePosMasterHistoryEmployee(posMaster.id, req);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("[ExecuteSalaryEmployeeCurrentService] executeSalaryEmployeeCurrent completed successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
327
src/services/ExecuteSalaryService.ts
Normal file
327
src/services/ExecuteSalaryService.ts
Normal file
|
|
@ -0,0 +1,327 @@
|
||||||
|
import { Double } from "typeorm";
|
||||||
|
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 ต้นฉบับ
|
||||||
|
*/
|
||||||
|
export class ExecuteSalaryService {
|
||||||
|
private commandRepository = AppDataSource.getRepository(Command);
|
||||||
|
private profileRepository = AppDataSource.getRepository(Profile);
|
||||||
|
private salaryRepo = AppDataSource.getRepository(ProfileSalary);
|
||||||
|
private salaryHistoryRepo = AppDataSource.getRepository(ProfileSalaryHistory);
|
||||||
|
private posMasterRepository = AppDataSource.getRepository(PosMaster);
|
||||||
|
private orgRootRepository = AppDataSource.getRepository(OrgRoot);
|
||||||
|
private assistanceRepository = AppDataSource.getRepository(ProfileAssistance);
|
||||||
|
private assistanceHistoryRepository = AppDataSource.getRepository(ProfileAssistanceHistory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ประมวลผลสร้าง ProfileSalary + handle leave/assistance
|
||||||
|
*/
|
||||||
|
async executeSalary(data: SalaryItem[], ctx: SalaryExecutionContext): Promise<void> {
|
||||||
|
console.log("[ExecuteSalaryService] Starting executeSalary");
|
||||||
|
console.log("[ExecuteSalaryService] Request body count:", data?.length);
|
||||||
|
|
||||||
|
const req = ctx.req;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// 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 ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all(
|
||||||
|
data.map(async (item) => {
|
||||||
|
const profile: any = await this.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 this.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)) {
|
||||||
|
removePostMasterAct(profile.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _commandYear = item.commandYear;
|
||||||
|
if (item.commandYear) {
|
||||||
|
_commandYear = item.commandYear > 2500 ? item.commandYear : item.commandYear + 543;
|
||||||
|
}
|
||||||
|
const dest_item = await this.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) {
|
||||||
|
await CreatePosMasterHistoryOfficer(orgRevisionRef, req, "DELETE");
|
||||||
|
await removeProfileInOrganize(profile.id, "OFFICER");
|
||||||
|
}
|
||||||
|
const clearProfile = await checkCommandType(String(item.commandId));
|
||||||
|
const _null: any = null;
|
||||||
|
if (clearProfile.status) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 this.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 this.salaryRepo.save(dataSalary, { data: req });
|
||||||
|
setLogDataDiff(req, { before, after: dataSalary });
|
||||||
|
history.profileSalaryId = dataSalary.id;
|
||||||
|
await this.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,
|
||||||
|
createdUserId: ctx.user.sub,
|
||||||
|
createdFullName: ctx.user.name,
|
||||||
|
lastUpdateUserId: ctx.user.sub,
|
||||||
|
lastUpdateFullName: ctx.user.name,
|
||||||
|
createdAt: new Date(),
|
||||||
|
lastUpdatedAt: new Date(),
|
||||||
|
status: _command.commandType.code == "C-PM-15" ? "PENDING" : "DONE",
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(dataAssis, metaAssis);
|
||||||
|
const historyAssis = new ProfileAssistanceHistory();
|
||||||
|
Object.assign(historyAssis, { ...dataAssis, id: undefined });
|
||||||
|
|
||||||
|
await this.assistanceRepository.save(dataAssis);
|
||||||
|
historyAssis.profileAssistanceId = dataAssis.id;
|
||||||
|
await this.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(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("[ExecuteSalaryService] executeSalary completed successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,7 +29,10 @@ import { sendWebSocket } from "./webSocket";
|
||||||
import { PayloadSendNoti } from "../interfaces/utils";
|
import { PayloadSendNoti } from "../interfaces/utils";
|
||||||
import { PermissionProfile } from "../entities/PermissionProfile";
|
import { PermissionProfile } from "../entities/PermissionProfile";
|
||||||
import { PosMasterHistory } from "../entities/PosMasterHistory";
|
import { PosMasterHistory } from "../entities/PosMasterHistory";
|
||||||
import { OfficerProfileService } from "./OfficerProfileService";
|
import { ExecuteOfficerProfileService } from "./ExecuteOfficerProfileService";
|
||||||
|
import { ExecuteSalaryService } from "./ExecuteSalaryService";
|
||||||
|
import { ExecuteSalaryCurrentService } from "./ExecuteSalaryCurrentService";
|
||||||
|
import { ExecuteSalaryEmployeeCurrentService } from "./ExecuteSalaryEmployeeCurrentService";
|
||||||
|
|
||||||
const redis = require("redis");
|
const redis = require("redis");
|
||||||
const REDIS_HOST = process.env.REDIS_HOST;
|
const REDIS_HOST = process.env.REDIS_HOST;
|
||||||
|
|
@ -323,13 +326,22 @@ async function handler(msg: amqp.ConsumeMessage): Promise<boolean> {
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
// Linear Flow
|
// Linear Flow
|
||||||
// ทดสอบคำสั่ง "C-PM-01", "C-PM-02", "C-PM-14"
|
// รับ resultData จาก .NET แล้วเรียก Service ตรงๆ ตาม commandType (ไม่ผ่าน HTTP loopback)
|
||||||
// รับ resultData จาก .NET แล้วเรียก OfficerProfileService ตรงๆ ไม่ผ่าน HTTP loopback
|
// - ExecuteOfficerProfileService : C-PM-01, 02, 14 (บรรจุ/รับโอน)
|
||||||
|
// - ExecuteSalaryCurrentService : C-PM-03, 04, 05, 06, 07, 39, 47 (แต่งตั้ง-เลื่อน-ย้าย)
|
||||||
|
// - ExecuteSalaryEmployeeCurrent : C-PM-22, 24 (ลูกจ้าง ปรับระดับชั้นงาน-ย้าย)
|
||||||
|
// - ExecuteSalaryService : C-PM-13, 15, 16 (ให้โอน/ให้ช่วยราชการ/ให้กลับเข้าราชการ)
|
||||||
|
// - คำสั่งอื่น ยังใช้ Circular Flow เดิม
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
const isLinearFlow = ["C-PM-01", "C-PM-02", "C-PM-14"].includes(command.commandType?.code);
|
const code = command.commandType?.code;
|
||||||
|
const isOfficerProfile = ["C-PM-01", "C-PM-02", "C-PM-14"].includes(code);
|
||||||
|
const isSalaryCurrent = ["C-PM-03", "C-PM-04", "C-PM-05", "C-PM-06", "C-PM-07", "C-PM-39", "C-PM-47"].includes(code);
|
||||||
|
const isSalaryEmployeeCurrent = ["C-PM-22", "C-PM-24"].includes(code);
|
||||||
|
const isSalary = ["C-PM-13", "C-PM-15", "C-PM-16"].includes(code);
|
||||||
|
const isLinearFlow = isOfficerProfile || isSalaryCurrent || isSalaryEmployeeCurrent || isSalary;
|
||||||
|
|
||||||
if (isLinearFlow) {
|
if (isLinearFlow) {
|
||||||
console.log(`[AMQ] Linear Flow`);
|
console.log(`[AMQ] Linear Flow (${code})`);
|
||||||
let resultData: any[] = [];
|
let resultData: any[] = [];
|
||||||
|
|
||||||
for (const chunk of chunks) {
|
for (const chunk of chunks) {
|
||||||
|
|
@ -346,9 +358,9 @@ async function handler(msg: amqp.ConsumeMessage): Promise<boolean> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[AMQ] Received ${resultData.length} profiles from .NET (${command.commandType?.code})`);
|
console.log(`[AMQ] Received ${resultData.length} profiles from .NET (${code})`);
|
||||||
|
|
||||||
// เรียก OfficerProfileService
|
// Route ไป service ที่ถูกต้องตาม commandType
|
||||||
if (resultData.length > 0) {
|
if (resultData.length > 0) {
|
||||||
// สร้าง pseudo-req สำหรับ setLogDataDiff/save({data: req})
|
// สร้าง pseudo-req สำหรับ setLogDataDiff/save({data: req})
|
||||||
const pseudoReq = {
|
const pseudoReq = {
|
||||||
|
|
@ -360,11 +372,22 @@ async function handler(msg: amqp.ConsumeMessage): Promise<boolean> {
|
||||||
req: pseudoReq,
|
req: pseudoReq,
|
||||||
};
|
};
|
||||||
|
|
||||||
await new OfficerProfileService().executeCreateOfficerProfile(resultData, ctx);
|
if (isOfficerProfile) {
|
||||||
console.log(`[AMQ] Processed ${resultData.length} profiles via OfficerProfileService`);
|
await new ExecuteOfficerProfileService().executeCreateOfficerProfile(resultData, ctx);
|
||||||
|
console.log(`[AMQ] Processed ${resultData.length} profiles via ExecuteOfficerProfileService`);
|
||||||
|
} else if (isSalaryCurrent) {
|
||||||
|
await new ExecuteSalaryCurrentService().executeSalaryCurrent(resultData, ctx);
|
||||||
|
console.log(`[AMQ] Processed ${resultData.length} profiles via ExecuteSalaryCurrentService`);
|
||||||
|
} else if (isSalaryEmployeeCurrent) {
|
||||||
|
await new ExecuteSalaryEmployeeCurrentService().executeSalaryEmployeeCurrent(resultData, ctx);
|
||||||
|
console.log(`[AMQ] Processed ${resultData.length} profiles via ExecuteSalaryEmployeeCurrentService`);
|
||||||
|
} else if (isSalary) {
|
||||||
|
await new ExecuteSalaryService().executeSalary(resultData, ctx);
|
||||||
|
console.log(`[AMQ] Processed ${resultData.length} profiles via ExecuteSalaryService`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(`[AMQ] Circular Flow`);
|
console.log(`[AMQ] Circular Flow (${code})`);
|
||||||
for (const chunk of chunks) {
|
for (const chunk of chunks) {
|
||||||
await new CallAPI().PostData(
|
await new CallAPI().PostData(
|
||||||
{ headers: { authorization: token } },
|
{ headers: { authorization: token } },
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue