Merge branch 'develop'

This commit is contained in:
Warunee Tamkoo 2025-09-01 16:48:38 +07:00
commit 8cc31d45e4
23 changed files with 1802 additions and 119 deletions

View file

@ -81,6 +81,8 @@ async function main() {
await profileSalaryController.cronjobTenureExecutivePositionOfficer();
await profileSalaryController.cronjobTenurePositionEmployee();
await profileSalaryController.cronjobTenureLevelEmployee();
await profileSalaryController.Registry();
await profileSalaryController.RegistryEmployee();
} catch (error) {
console.error("Error executing function from controller:", error);
}

View file

@ -59,7 +59,6 @@ import {
createUser,
getRoles,
deleteUser,
enableStatus,
getUserByUsername,
getRoleMappings,
removeUserRoles,
@ -92,6 +91,10 @@ import { ProfileInsignia, CreateProfileInsignia } from "../entities/ProfileInsig
import { ProfileInsigniaHistory } from "../entities/ProfileInsigniaHistory";
import { Gender } from "../entities/Gender";
import { ProfileAvatar } from "../entities/ProfileAvatar";
import {
CreatePosMasterHistoryEmployee,
CreatePosMasterHistoryOfficer,
} from "../services/PositionService";
@Route("api/v1/org/command")
@Tags("Command")
@Security("bearerAuth")
@ -2166,7 +2169,16 @@ export class CommandController extends Controller {
command.detailFooter = commandType.detailFooter;
command.isAttachment = commandType.isAttachment;
command.isUploadAttachment = commandType.isUploadAttachment;
command.status = "NEW";
// ถ้าเป็นคำสั่งโปรดเกล้าฯ "C-PM-47" ให้เปิดถึงรออัปโหลดไฟล์ #1780
if (commandCode === "C-PM-47") {
command.isSignature = true;
command.isDraft = true;
command.isSign = true;
command.status = "PENDING";
}
else {
command.status = "NEW";
}
command.issue = commandType.name;
(command.commandAffectDate = requestBody.commandAffectDate
? new Date(requestBody.commandAffectDate)
@ -3154,8 +3166,12 @@ export class CommandController extends Controller {
posMaster.lastUpdatedAt = new Date();
posMaster.conditionReason = _null;
posMaster.isCondition = false;
if (posMasterOld != null) await this.posMasterRepository.save(posMasterOld);
if (posMasterOld != null) {
await this.posMasterRepository.save(posMasterOld);
await CreatePosMasterHistoryOfficer(posMasterOld.id, req);
}
await this.posMasterRepository.save(posMaster);
await CreatePosMasterHistoryOfficer(posMaster.id, req);
const positionNew = await this.positionRepository.findOne({
where: {
@ -3342,8 +3358,12 @@ export class CommandController extends Controller {
posMaster.current_holderId = item.profileId;
posMaster.lastUpdatedAt = new Date();
posMaster.next_holderId = null;
if (posMasterOld != null) await this.employeePosMasterRepository.save(posMasterOld);
if (posMasterOld != null) {
await this.employeePosMasterRepository.save(posMasterOld);
await CreatePosMasterHistoryEmployee(posMasterOld.id, req);
}
await this.employeePosMasterRepository.save(posMaster);
await CreatePosMasterHistoryEmployee(posMaster.id, req);
const positionNew = await this.employeePositionRepository.findOne({
where: {
@ -3573,6 +3593,7 @@ export class CommandController extends Controller {
posMaster.conditionReason = _null;
posMaster.isCondition = false;
await this.posMasterRepository.save(posMaster);
await CreatePosMasterHistoryOfficer(posMaster.id, req);
const positionNew = await this.positionRepository.findOne({
where: {
posMasterId: posMaster.id,
@ -6030,8 +6051,12 @@ export class CommandController extends Controller {
posMaster.lastUpdatedAt = new Date();
posMaster.conditionReason = _null;
posMaster.isCondition = false;
if (posMasterOld != null) await this.posMasterRepository.save(posMasterOld);
if (posMasterOld != null) {
await this.posMasterRepository.save(posMasterOld);
await CreatePosMasterHistoryOfficer(posMasterOld.id, req);
}
await this.posMasterRepository.save(posMaster);
await CreatePosMasterHistoryOfficer(posMaster.id, req);
const positionNew = await this.positionRepository.findOne({
where: {
@ -6411,8 +6436,12 @@ export class CommandController extends Controller {
posMaster.current_holderId = profile.id;
posMaster.lastUpdatedAt = new Date();
posMaster.next_holderId = null;
if (posMasterOld != null) await this.employeePosMasterRepository.save(posMasterOld);
if (posMasterOld != null) {
await this.employeePosMasterRepository.save(posMasterOld);
await CreatePosMasterHistoryEmployee(posMasterOld.id, req);
}
await this.employeePosMasterRepository.save(posMaster);
await CreatePosMasterHistoryEmployee(posMaster.id, req);
const clsTempPosmaster = await this.employeeTempPosMasterRepository.find({
where: {

View file

@ -38,6 +38,11 @@ import { AuthRole } from "../entities/AuthRole";
import { RequestWithUser } from "../middlewares/user";
import permission from "../interfaces/permission";
import { setLogDataDiff } from "../interfaces/utils";
import {
CreatePosMasterHistoryOfficer,
CreatePosMasterHistoryEmployee,
} from "../services/PositionService";
import { PosMasterEmployeeHistory } from "../entities/PosMasterEmployeeHistory";
@Route("api/v1/org/employee/pos")
@Tags("Employee")
@Security("bearerAuth")
@ -50,6 +55,7 @@ export class EmployeePositionController extends Controller {
private employeePosTypeRepository = AppDataSource.getRepository(EmployeePosType);
private employeePosLevelRepository = AppDataSource.getRepository(EmployeePosLevel);
private employeePosMasterRepository = AppDataSource.getRepository(EmployeePosMaster);
private posMasterHistoryRepository = AppDataSource.getRepository(PosMasterEmployeeHistory);
private employeePositionRepository = AppDataSource.getRepository(EmployeePosition);
private profileRepository = AppDataSource.getRepository(ProfileEmployee);
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
@ -2265,6 +2271,7 @@ export class EmployeePositionController extends Controller {
dataMaster.lastUpdatedAt = new Date();
// dataMaster.next_holderId = requestBody.profileId;
await this.employeePosMasterRepository.save(dataMaster);
await CreatePosMasterHistoryEmployee(dataMaster.id, request);
return new HttpSuccess();
}
@ -2439,8 +2446,12 @@ export class EmployeePositionController extends Controller {
posMaster.current_holderId = body.profileId;
posMaster.lastUpdatedAt = new Date();
// posMaster.next_holderId = body.profileId;
if (posMasterOld != null) await this.employeePosMasterRepository.save(posMasterOld);
if (posMasterOld != null) {
await this.employeePosMasterRepository.save(posMasterOld);
await CreatePosMasterHistoryEmployee(posMasterOld.id, request);
}
await this.employeePosMasterRepository.save(posMaster);
await CreatePosMasterHistoryEmployee(posMaster.id, request);
const positionNew = await this.employeePositionRepository.findOne({
where: {
@ -2463,4 +2474,20 @@ export class EmployeePositionController extends Controller {
}
return new HttpSuccess();
}
/**
* API
*
* @summary (ADMIN)
*
*/
@Get("history-update/{id}")
async listPosMasterHistory(@Path() id: string, @Request() request: RequestWithUser) {
const posMasterHistory = await this.posMasterHistoryRepository.find({
where: { ancestorDNA: id },
order: { createdAt: "DESC" },
});
return new HttpSuccess(posMasterHistory);
}
}

View file

@ -41,6 +41,8 @@ import { AuthRole } from "../entities/AuthRole";
import { RequestWithUser } from "../middlewares/user";
import permission from "../interfaces/permission";
import { setLogDataDiff } from "../interfaces/utils";
import { CreatePosMasterHistoryEmployeeTemp } from "../services/PositionService";
import { PosMasterEmployeeTempHistory } from "../entities/PosMasterEmployeeTempHistory";
@Route("api/v1/org/employee-temp/pos")
@Tags("Employee")
@Security("bearerAuth")
@ -53,6 +55,7 @@ export class EmployeeTempPositionController extends Controller {
private employeePosTypeRepository = AppDataSource.getRepository(EmployeePosType);
private employeePosLevelRepository = AppDataSource.getRepository(EmployeePosLevel);
private employeeTempPosMasterRepository = AppDataSource.getRepository(EmployeeTempPosMaster);
private posMasterHistoryRepository = AppDataSource.getRepository(PosMasterEmployeeTempHistory);
private employeePositionRepository = AppDataSource.getRepository(EmployeePosition);
private profileRepository = AppDataSource.getRepository(ProfileEmployee);
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
@ -2004,6 +2007,7 @@ export class EmployeeTempPositionController extends Controller {
dataMaster.lastUpdatedAt = new Date();
// dataMaster.next_holderId = requestBody.profileId;
await this.employeeTempPosMasterRepository.save(dataMaster);
await CreatePosMasterHistoryEmployeeTemp(dataMaster.id, request);
return new HttpSuccess();
}
@ -2178,8 +2182,12 @@ export class EmployeeTempPositionController extends Controller {
posMaster.current_holderId = body.profileId;
posMaster.lastUpdatedAt = new Date();
// posMaster.next_holderId = body.profileId;
if (posMasterOld != null) await this.employeeTempPosMasterRepository.save(posMasterOld);
if (posMasterOld != null) {
await this.employeeTempPosMasterRepository.save(posMasterOld);
await CreatePosMasterHistoryEmployeeTemp(posMasterOld.id, request);
}
await this.employeeTempPosMasterRepository.save(posMaster);
await CreatePosMasterHistoryEmployeeTemp(posMaster.id, request);
const positionNew = await this.employeePositionRepository.findOne({
where: {
@ -2202,4 +2210,20 @@ export class EmployeeTempPositionController extends Controller {
}
return new HttpSuccess();
}
/**
* API
*
* @summary (ADMIN)
*
*/
@Get("history-update/{id}")
async listPosMasterHistory(@Path() id: string, @Request() request: RequestWithUser) {
const posMasterHistory = await this.posMasterHistoryRepository.find({
where: { ancestorDNA: id },
order: { createdAt: "DESC" },
});
return new HttpSuccess(posMasterHistory);
}
}

View file

@ -124,20 +124,20 @@ export class OrganizationController extends Controller {
@Request() request: RequestWithUser,
) {
try {
// // CheckQueueInProgress
// const [isBusyDraft, isBusyPublish] = await Promise.all([
// checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG_DRAFT}`),
// checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG}`),
// ]);
// // console.log("✅ ตรวจสอบแล้ว Draft Busy:", isBusyDraft);
// // console.log("✅ ตรวจสอบแล้ว Publish Busy:", isBusyPublish);
// if (isBusyDraft || isBusyPublish) {
// // console.log("🚫 พบว่ามีงานอยู่ในคิว — error")
// throw new HttpError(
// HttpStatusCode.CONFLICT,
// "ไม่สามารถดำเนินการได้ หากกำลังเผยแพร่หรือสร้างแบบร่างโครงสร้างหน่วยงาน",
// );
// }
// CheckQueueInProgress
const [isBusyDraft, isBusyPublish] = await Promise.all([
checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG_DRAFT}`),
checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG}`),
]);
// console.log("✅ ตรวจสอบแล้ว Draft Busy:", isBusyDraft);
// console.log("✅ ตรวจสอบแล้ว Publish Busy:", isBusyPublish);
if (isBusyDraft || isBusyPublish) {
// console.log("🚫 พบว่ามีงานอยู่ในคิว — error")
throw new HttpError(
HttpStatusCode.CONFLICT,
"ไม่สามารถดำเนินการได้ หากกำลังเผยแพร่หรือสร้างแบบร่างโครงสร้างหน่วยงาน",
);
}
//new main revision
const before = null;
const revision = Object.assign(new OrgRevision(), requestBody) as OrgRevision;
@ -163,13 +163,7 @@ export class OrganizationController extends Controller {
await sendToQueueOrgDraft(msg);
return new HttpSuccess("Draft is being created... Processing in the background.");
} catch (error: any) {
if (error?.status && error?.message) {
return error;
}
return new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
"Failed to process the draft. Please try again later.",
);
throw error;
}
}
@ -3209,19 +3203,19 @@ export class OrganizationController extends Controller {
try {
// CheckQueueInProgress
// console.log("🚀 ตรวจสอบว่ามีงานอยู่ในคิว");
// const [isBusyDraft, isBusyPublish] = await Promise.all([
// checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG_DRAFT}`),
// checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG}`),
// ]);
// // console.log("✅ ตรวจสอบแล้ว Draft Busy:", isBusyDraft);
// // console.log("✅ ตรวจสอบแล้ว Publish Busy:", isBusyPublish);
// if (isBusyDraft || isBusyPublish) {
// // console.log("🚫 พบว่ามีงานอยู่ในคิว — error")
// throw new HttpError(
// HttpStatusCode.CONFLICT,
// "ไม่สามารถดำเนินการได้ หากกำลังเผยแพร่หรือสร้างแบบร่างโครงสร้างหน่วยงาน",
// );
// }
const [isBusyDraft, isBusyPublish] = await Promise.all([
checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG_DRAFT}`),
checkQueueInProgress(`${process.env.AMQ_QUEUE_ORG}`),
]);
// console.log("✅ ตรวจสอบแล้ว Draft Busy:", isBusyDraft);
// console.log("✅ ตรวจสอบแล้ว Publish Busy:", isBusyPublish);
if (isBusyDraft || isBusyPublish) {
// console.log("🚫 พบว่ามีงานอยู่ในคิว — error")
throw new HttpError(
HttpStatusCode.CONFLICT,
"ไม่สามารถดำเนินการได้ หากกำลังเผยแพร่หรือสร้างแบบร่างโครงสร้างหน่วยงาน",
);
}
const today = new Date();
today.setHours(0, 0, 0, 0); // Set time to the beginning of the day
@ -3258,13 +3252,7 @@ export class OrganizationController extends Controller {
await sendToQueueOrg(msg);
return new HttpSuccess();
} catch (error: any) {
if (error?.status && error?.message) {
return error;
}
return new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
"Failed to process the publish. Please try again later.",
);
throw error;
}
}

View file

@ -4050,33 +4050,33 @@ export class OrganizationDotnetController extends Controller {
},
) {
let typeCondition: any = {};
if (body.isAll == false) {
if (body.node === 0) {
typeCondition = {
orgRootId: body.nodeId,
orgChild1Id: IsNull(),
};
} else if (body.node === 1) {
typeCondition = {
orgChild1Id: body.nodeId,
orgChild2Id: IsNull(),
};
} else if (body.node === 2) {
typeCondition = {
orgChild2Id: body.nodeId,
orgChild3Id: IsNull(),
};
} else if (body.node === 3) {
typeCondition = {
orgChild3Id: body.nodeId,
orgChild4Id: IsNull(),
};
} else if (body.node === 4) {
typeCondition = {
orgChild4Id: body.nodeId,
};
}
} else {
// if (body.isAll == false) {
// if (body.node === 0) {
// typeCondition = {
// orgRootId: body.nodeId,
// orgChild1Id: IsNull(),
// };
// } else if (body.node === 1) {
// typeCondition = {
// orgChild1Id: body.nodeId,
// orgChild2Id: IsNull(),
// };
// } else if (body.node === 2) {
// typeCondition = {
// orgChild2Id: body.nodeId,
// orgChild3Id: IsNull(),
// };
// } else if (body.node === 3) {
// typeCondition = {
// orgChild3Id: body.nodeId,
// orgChild4Id: IsNull(),
// };
// } else if (body.node === 4) {
// typeCondition = {
// orgChild4Id: body.nodeId,
// };
// }
// } else {
if (body.node === 0) {
typeCondition = {
orgRootId: body.nodeId,
@ -4098,7 +4098,7 @@ export class OrganizationDotnetController extends Controller {
orgChild4Id: body.nodeId,
};
}
}
// }
let profile = await this.profileRepo.find({
where: { keycloak: Not(IsNull()) || Not(""), isLeave: false, current_holders: typeCondition },
relations: [
@ -4112,7 +4112,10 @@ export class OrganizationDotnetController extends Controller {
"current_holders.orgChild4",
],
});
const startDate = new Date().getFullYear();
const endDate = new Date().getFullYear();
const startOfYear = new Date(startDate, 0, 1); // 1 ม.ค. ปีนี้
const endOfYear = new Date(endDate, 11, 31, 23, 59, 59, 999); // 31 ธ.ค. ปีนี้
if (body.isRetirement) {
profile = await this.profileRepo.find({
where: {
@ -4122,7 +4125,7 @@ export class OrganizationDotnetController extends Controller {
// isRetirement: true,
dateRetire: And(
Not(IsNull()),
Between(body.startDate, body.endDate)
Between(startOfYear, endOfYear)
)
},
relations: [
@ -4137,6 +4140,7 @@ export class OrganizationDotnetController extends Controller {
],
});
}
let findRevision = await this.orgRevisionRepo.findOne({
where: { orgRevisionIsCurrent: true },
});

View file

@ -42,6 +42,8 @@ import { setLogDataDiff } from "../interfaces/utils";
import { PosMasterAssign } from "../entities/PosMasterAssign";
import { Assign } from "../entities/Assign";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import { PosMasterHistory } from "../entities/PosMasterHistory";
import { CreatePosMasterHistoryOfficer } from "../services/PositionService";
@Route("api/v1/org/pos")
@Tags("Position")
@Security("bearerAuth")
@ -57,6 +59,7 @@ export class PositionController extends Controller {
private posLevelEmployeeRepository = AppDataSource.getRepository(EmployeePosLevel);
private posDictRepository = AppDataSource.getRepository(PosDict);
private posMasterRepository = AppDataSource.getRepository(PosMaster);
private posMasterHistoryRepository = AppDataSource.getRepository(PosMasterHistory);
private employeePosMasterRepository = AppDataSource.getRepository(EmployeePosMaster);
private positionRepository = AppDataSource.getRepository(Position);
private profileRepository = AppDataSource.getRepository(Profile);
@ -1541,7 +1544,7 @@ export class PositionController extends Controller {
// posLevelRank: "ASC",
// },
orderNo: "ASC",
createdAt: "ASC"
createdAt: "ASC",
},
});
const formattedData = {
@ -2381,7 +2384,7 @@ export class PositionController extends Controller {
// posType: { posTypeRank: "ASC" },
// posLevel: { posLevelRank: "ASC" },
orderNo: "ASC",
createdAt: "ASC"
createdAt: "ASC",
},
});
@ -2455,6 +2458,7 @@ export class PositionController extends Controller {
return {
id: posMaster.id,
ancestorDNA: posMaster.ancestorDNA,
current_holderId: posMaster.current_holderId,
next_holderId: posMaster.next_holderId,
isDirector: posMaster.isDirector,
@ -3654,6 +3658,7 @@ export class PositionController extends Controller {
dataMaster.current_holderId = _null;
}
await this.posMasterRepository.save(dataMaster, { data: request });
await CreatePosMasterHistoryOfficer(dataMaster.id, request);
setLogDataDiff(request, { before, after: dataMaster });
return new HttpSuccess();
@ -4071,21 +4076,53 @@ export class PositionController extends Controller {
},
) {
let typeCondition: any = {};
let conditionA: any = null;
let conditionA: any = "1=1";
let params: any = {};
let posType: any = {};
let posLevel: any = {};
let posType = await this.posTypeRepository.findOne({
where: { id: String(body.posType) },
});
let posLevel = await this.posLevelRepository.findOne({
where: { id: String(body.posLevel) },
});
if (body.typeCommand === "ROYAL") {
posType = await this.posTypeRepository.find({
where: { posTypeName: In(["วิชาการ", "บริหาร"]) },
});
posLevel = await this.posLevelRepository.find({
where: {
posTypeId: In(posType.map((x: any) => x.id)),
posLevelName: In(["ทรงคุณวุฒิ", "สูง"])
},
});
conditionA = "positions.posTypeId IN (:...posTypeIds) AND positions.posLevelId IN (:...posLevelIds)";
params = {
posTypeIds: posType.map((x: any) => x.id),
posLevelIds: posLevel.map((x: any) => x.id),
};
}
else {
posType = await this.posTypeRepository.findOne({
where: { id: String(body.posType) },
});
posLevel = await this.posLevelRepository.findOne({
where: { id: String(body.posLevel) },
});
if (body.typeCommand == "APPOINTED" || body.typeCommand == "MOVE") {
conditionA = "positions.posTypeId LIKE :posType AND positions.posLevelId LIKE :posLevel";
} else if (body.typeCommand == "APPOINT") {
conditionA = "posType.posTypeRank > :posTypeRank";
} else if (body.typeCommand == "SLIP") {
conditionA = "positions.posTypeId LIKE :posType AND posLevel.posLevelRank > :posLevelRank";
if (body.typeCommand == "APPOINTED" || body.typeCommand == "MOVE") {
conditionA = "positions.posTypeId LIKE :posType AND positions.posLevelId LIKE :posLevel";
params = {
posType: posType?.id,
posLevel: posLevel?.id,
};
} else if (body.typeCommand == "APPOINT") {
conditionA = "posType.posTypeRank > :posTypeRank";
params = {
posTypeRank: posType?.posTypeRank ?? 0,
};
} else if (body.typeCommand == "SLIP") {
conditionA = "positions.posTypeId LIKE :posType AND posLevel.posLevelRank > :posLevelRank";
params = {
posType: posType?.id,
posLevelRank: posLevel?.posLevelRank ?? 0,
};
}
}
if (body.isAll == false) {
@ -4157,12 +4194,14 @@ export class PositionController extends Controller {
.andWhere("posMaster.next_holderId IS NULL")
.andWhere(
new Brackets((qb) => {
qb.andWhere(typeCondition).andWhere(conditionA == null ? "1=1" : conditionA, {
posType: posType == null ? `%%` : `${posType.id}`,
posLevel: posLevel == null ? `%%` : `${posLevel.id}`,
posTypeRank: posType == null ? 0 : posType.posTypeRank,
posLevelRank: posLevel == null ? 0 : posLevel.posLevelRank,
});
qb.andWhere(typeCondition)
// .andWhere(conditionA == null ? "1=1" : conditionA, {
// posType: posType == null ? `%%` : `${posType.id}`,
// posLevel: posLevel == null ? `%%` : `${posLevel.id}`,
// posTypeRank: posType == null ? 0 : posType.posTypeRank,
// posLevelRank: posLevel == null ? 0 : posLevel.posLevelRank,
// });
.andWhere(conditionA, params);
}),
)
.orderBy("orgRoot.orgRootOrder", "ASC")
@ -4826,6 +4865,7 @@ export class PositionController extends Controller {
positionId: string;
profileId: string;
},
@Request() request: RequestWithUser,
) {
const posMaster = await this.posMasterRepository.findOne({
where: { id: body.posmasterId },
@ -4879,8 +4919,12 @@ export class PositionController extends Controller {
const _null: any = null;
posMaster.conditionReason = _null;
posMaster.isCondition = false;
if (posMasterOld != null) await this.posMasterRepository.save(posMasterOld);
if (posMasterOld != null) {
await this.posMasterRepository.save(posMasterOld);
await CreatePosMasterHistoryOfficer(posMasterOld.id, request);
}
await this.posMasterRepository.save(posMaster);
await CreatePosMasterHistoryOfficer(posMaster.id, request);
const positionNew = await this.positionRepository.findOne({
where: {
@ -5432,7 +5476,6 @@ export class PositionController extends Controller {
posMaster.lastUpdatedAt = new Date();
posMaster.lastUpdateUserId = request.user.sub;
posMaster.lastUpdateFullName = request.user.name;
posMaster.lastUpdatedAt = new Date();
await this.posMasterRepository.save(posMaster);
return new HttpSuccess();
}
@ -5617,4 +5660,20 @@ export class PositionController extends Controller {
}
return new HttpSuccess();
}
/**
* API
*
* @summary (ADMIN)
*
*/
@Get("history-update/{id}")
async listPosMasterHistory(@Path() id: string, @Request() request: RequestWithUser) {
const posMasterHistory = await this.posMasterHistoryRepository.find({
where: { ancestorDNA: id },
order: { createdAt: "DESC" },
});
return new HttpSuccess(posMasterHistory);
}
}

View file

@ -6268,6 +6268,7 @@ export class ProfileController extends Controller {
"current_holders.orgRevisionId",
"current_holders.posMasterNo",
"orgRoot.id",
"orgRoot.ancestorDNA",
"orgRoot.orgRootName",
"orgRoot.orgRootShortName",
"orgRoot.orgRootOrder",
@ -6414,6 +6415,7 @@ export class ProfileController extends Controller {
posNo: shortName ?? null,
rootId: holder?.orgRoot?.id ?? null,
root: holder?.orgRoot?.orgRootName ?? null,
rootDnaId: holder?.orgRoot == null ? null : holder?.orgRoot?.ancestorDNA,
orgRootShortName: holder?.orgRoot?.orgRootShortName ?? null,
orgRevisionId: holder?.orgRoot?.orgRevisionId ?? null,
org,

View file

@ -26,6 +26,8 @@ import { Profile } from "../entities/Profile";
import { Insignia } from "../entities/Insignia";
import permission from "../interfaces/permission";
import { setLogDataDiff } from "../interfaces/utils";
import { ProfileSalary } from "../entities/ProfileSalary";
import { In, IsNull } from "typeorm";
@Route("api/v1/org/profile/insignia")
@Tags("ProfileInsignia")
@Security("bearerAuth")
@ -34,6 +36,7 @@ export class ProfileInsigniaController extends Controller {
private insigniaRepo = AppDataSource.getRepository(ProfileInsignia);
private insigniaHistoryRepo = AppDataSource.getRepository(ProfileInsigniaHistory);
private insigniaMetaRepo = AppDataSource.getRepository(Insignia);
private profileSalaryRepo = AppDataSource.getRepository(ProfileSalary);
@Get("user")
public async getInsigniaUser(@Request() request: { user: Record<string, any> }) {
@ -258,4 +261,74 @@ export class ProfileInsigniaController extends Controller {
return new HttpSuccess();
}
/**
* @summary ()
*/
@Post("position")
public async GetPprofileSalarys(
@Request() req: RequestWithUser,
@Body() body: { profileId: string },
) {
const profile = await this.profileRepo.findOneBy({ id: body.profileId });
if (!profile) {
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
}
const profileSalarys = await this.profileSalaryRepo.find({
where: [
{
profileId: body.profileId,
commandCode: In([
"0",
"9",
"1",
"2",
"3",
"4",
"8",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
]),
},
{ profileId: body.profileId, commandCode: IsNull() },
],
order: { order: "ASC" },
});
if (!profileSalarys) {
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบข้อมูลตำแหน่งและเงินเดือน");
}
const birth = new Date(profile.birthDate);
const mapData = profileSalarys.map(x => {
// คำนวณอายุ
let age = null;
if (x.commandDateAffect && profile.birthDate) {
const affect = new Date(x.commandDateAffect);
age = affect.getFullYear() - birth.getFullYear();
// เช็คเดือน/วัน ถ้าวันเกิดยังไม่มาถึงในปีนั้น ให้ลบ 1
const monthDiff = affect.getMonth() - birth.getMonth();
const dayDiff = affect.getDate() - birth.getDate();
if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
age--;
}
}
return {
dateAffect: x.commandDateAffect,
position: x.positionName,
root: x.orgRoot,
child1: x.orgChild1,
child2: x.orgChild2,
child3: x.orgChild3,
child4: x.orgChild4,
age: age,
amount: x.amount,
remark: x.remark
};
});
return new HttpSuccess(mapData);
}
}

View file

@ -33,7 +33,10 @@ import { OrgRoot } from "../entities/OrgRoot";
import { OrgRevision } from "../entities/OrgRevision";
import { Position } from "../entities/Position";
import Extension from "../interfaces/extension";
import { viewRegistryOfficer } from "../entities/view/viewRegistryOfficer";
import { viewRegistryEmployee } from "../entities/view/viewRegistryEmployee";
import { Registry } from "../entities/Registry";
import { RegistryEmployee } from "../entities/RegistryEmployee";
@Route("api/v1/org/profile/salary")
@Tags("ProfileSalary")
@Security("bearerAuth")
@ -51,7 +54,9 @@ export class ProfileSalaryController extends Controller {
private orgRootRepository = AppDataSource.getRepository(OrgRoot);
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
private positionRepo = AppDataSource.getRepository(Position);
private registryRepo = AppDataSource.getRepository(Registry);
private registryEmployeeRepo = AppDataSource.getRepository(RegistryEmployee);
@Get("TenurePositionOfficer")
public async cronjobTenurePositionOfficer() {
let data: any = [];
@ -88,9 +93,12 @@ export class ProfileSalaryController extends Controller {
profileId: x.id,
positionName: calDayDiff.positionName,
days_diff: calDayDiff.days_diff,
Years: (calDayDiff.days_diff / 365.2524).toFixed(4),
Months: ((calDayDiff.days_diff / 30.4375) % 12).toFixed(4),
Days: (calDayDiff.days_diff % 30.4375).toFixed(4),
// Years: (calDayDiff.days_diff / 365.2524).toFixed(4),
// Months: ((calDayDiff.days_diff / 30.4375) % 12).toFixed(4),
// Days: (calDayDiff.days_diff % 30.4375).toFixed(4),
Years: Math.floor(calDayDiff.days_diff / 365.2524),
Months: Math.floor((calDayDiff.days_diff / 30.4375) % 12),
Days: Math.floor(calDayDiff.days_diff % 30.4375),
};
// data.push(_mapData);
await this.positionOfficerRepo.save(mapData);
@ -138,9 +146,12 @@ export class ProfileSalaryController extends Controller {
profileEmployeeId: x.id,
positionName: calDayDiff.positionName,
days_diff: calDayDiff.days_diff,
Years: (calDayDiff.days_diff / 365.2524).toFixed(4),
Months: ((calDayDiff.days_diff / 30.4375) % 12).toFixed(4),
Days: (calDayDiff.days_diff % 30.4375).toFixed(4),
// Years: (calDayDiff.days_diff / 365.2524).toFixed(4),
// Months: ((calDayDiff.days_diff / 30.4375) % 12).toFixed(4),
// Days: (calDayDiff.days_diff % 30.4375).toFixed(4),
Years: Math.floor(calDayDiff.days_diff / 365.2524),
Months: Math.floor((calDayDiff.days_diff / 30.4375) % 12),
Days: Math.floor(calDayDiff.days_diff % 30.4375),
};
// data.push(_mapData);
await this.positionEmployeeRepo.save(mapData);
@ -332,6 +343,50 @@ export class ProfileSalaryController extends Controller {
return new HttpSuccess();
}
@Get("Registry")
public async Registry() {
await this.registryRepo.clear();
const allRegis = await AppDataSource.getRepository(viewRegistryOfficer)
.createQueryBuilder("registryOfficer")
.getMany();
const profileIds = new Set((await this.profileRepo.find()).map(p => p.id));
const mapData = allRegis
.filter(x => profileIds.has(x.profileId))
.map(x => ({
...x,
isProbation: Boolean(x.isProbation),
isLeave: Boolean(x.isLeave),
isRetirement: Boolean(x.isRetirement),
Educations: x.Educations ? JSON.stringify(x.Educations) : "",
}));
if (mapData.length > 0) {
await this.registryRepo.save(mapData);
}
return new HttpSuccess();
}
@Get("RegistryEmployee")
public async RegistryEmployee() {
await this.registryEmployeeRepo.clear();
const allRegis = await AppDataSource.getRepository(viewRegistryEmployee)
.createQueryBuilder("registryEmployee")
.getMany();
const profileEmpIds = new Set((await this.profileEmployeeRepo.find()).map(p => p.id));
const mapData = allRegis
.filter(x => profileEmpIds.has(x.profileEmployeeId))
.map(x => ({
...x,
isProbation: Boolean(x.isProbation),
isLeave: Boolean(x.isLeave),
isRetirement: Boolean(x.isRetirement),
Educations: x.Educations ? JSON.stringify(x.Educations) : "",
}));
if (mapData.length > 0) {
await this.registryEmployeeRepo.save(mapData);
}
return new HttpSuccess();
}
@Get("user")
public async getSalaryUser(@Request() request: { user: Record<string, any> }) {
const profile = await this.profileRepo.findOneBy({ keycloak: request.user.sub });

View file

@ -32,7 +32,8 @@ import { viewRegistryOfficer } from "../entities/view/viewRegistryOfficer";
import { viewRegistryEmployee } from "../entities/view/viewRegistryEmployee";
import { EmployeeTempPosMaster } from "../entities/EmployeeTempPosMaster";
// import { sendWebSocket } from "../services/webSocket";
import { Registry } from "../entities/Registry";
import { RegistryEmployee } from "../entities/RegistryEmployee";
@Route("api/v1/org/report")
@Tags("Report")
@Security("bearerAuth")
@ -153,8 +154,9 @@ export class ReportController extends Controller {
} else if (tenureType != "" && tenureType == "posExecutive") {
tenureTypeCondition = "registryOfficer.posExecutiveYears BETWEEN :tenureMin AND :tenureMax";
}
const [lists, total] = await AppDataSource.getRepository(viewRegistryOfficer)
// ดึงผ่าน Table แทน View
// const [lists, total] = await AppDataSource.getRepository(viewRegistryOfficer)
const [lists, total] = await AppDataSource.getRepository(Registry)
.createQueryBuilder("registryOfficer")
.where(nodeCondition, {
nodeId: nodeId,
@ -493,8 +495,9 @@ export class ReportController extends Controller {
retireLawCondition =
"DATE(registryEmployee.dateRetireLaw) >= :startDateRetireLaw AND DATE(registryEmployee.dateRetireLaw) <= :endDateRetireLaw";
}
const [lists, total] = await AppDataSource.getRepository(viewRegistryEmployee)
// ดึงผ่าน Table แทน View
// const [lists, total] = await AppDataSource.getRepository(viewRegistryEmployee)
const [lists, total] = await AppDataSource.getRepository(RegistryEmployee)
.createQueryBuilder("registryEmployee")
.where(nodeCondition, {
nodeId: nodeId,

View file

@ -0,0 +1,101 @@
import { Entity, Column } from "typeorm";
import { EntityBase } from "./base/Base";
@Entity("posMasterEmployeeHistory")
export class PosMasterEmployeeHistory extends EntityBase {
@Column({
nullable: true,
comment: "คำนำหน้า",
length: 255,
default: null,
})
prefix: string;
@Column({
nullable: true,
comment: "ชื่อ",
length: 255,
default: null,
})
firstName: string;
@Column({
nullable: true,
comment: "สกุล",
length: 255,
default: null,
})
lastName: string;
@Column({
nullable: true,
comment: "อักษรย่อ",
length: 16,
default: null,
})
shortName: string;
@Column({
nullable: true,
comment: "Prefix นำหน้าเลขที่ตำแหน่ง เป็น Optional (ไม่ใช่อักษรย่อของหน่วยงาน/ส่วนราชการ)",
length: 16,
default: null,
})
posMasterNoPrefix: string;
@Column({
nullable: true,
comment: "เลขที่ตำแหน่ง เป็นตัวเลข",
default: null,
})
posMasterNo: number;
@Column({
nullable: true,
comment: "Suffix หลังเลขที่ตำแหน่ง เช่น ช.",
length: 16,
default: null,
})
posMasterNoSuffix: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่ง",
length: 255,
default: null,
})
position: string;
@Column({
nullable: true,
comment: "ชื่อประเภทตำแหน่ง",
length: 255,
default: null,
})
posType: string;
@Column({
nullable: true,
comment: "ชื่อระดับตำแหน่ง",
length: 255,
default: null,
})
posLevel: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่งทางการบริหาร",
length: 255,
default: null,
})
posExecutive: string;
@Column({
nullable: true,
comment:
"รหัส DNA ใช้ในกรณีที่มีการทำสำเนาโครงสร้างและตำแหน่ง ตำแหน่งที่ทำสำเนามากับตำแหน่งเก่าจะต้องมี DNA เดียวกัน เพื่อให้ track ประวัติการแก้ไขตำแหน่งย้อนหลังได้",
length: 40,
default: null,
})
ancestorDNA: string;
}

View file

@ -0,0 +1,101 @@
import { Entity, Column } from "typeorm";
import { EntityBase } from "./base/Base";
@Entity("posMasterEmployeeTempHistory")
export class PosMasterEmployeeTempHistory extends EntityBase {
@Column({
nullable: true,
comment: "คำนำหน้า",
length: 255,
default: null,
})
prefix: string;
@Column({
nullable: true,
comment: "ชื่อ",
length: 255,
default: null,
})
firstName: string;
@Column({
nullable: true,
comment: "สกุล",
length: 255,
default: null,
})
lastName: string;
@Column({
nullable: true,
comment: "อักษรย่อ",
length: 16,
default: null,
})
shortName: string;
@Column({
nullable: true,
comment: "Prefix นำหน้าเลขที่ตำแหน่ง เป็น Optional (ไม่ใช่อักษรย่อของหน่วยงาน/ส่วนราชการ)",
length: 16,
default: null,
})
posMasterNoPrefix: string;
@Column({
nullable: true,
comment: "เลขที่ตำแหน่ง เป็นตัวเลข",
default: null,
})
posMasterNo: number;
@Column({
nullable: true,
comment: "Suffix หลังเลขที่ตำแหน่ง เช่น ช.",
length: 16,
default: null,
})
posMasterNoSuffix: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่ง",
length: 255,
default: null,
})
position: string;
@Column({
nullable: true,
comment: "ชื่อประเภทตำแหน่ง",
length: 255,
default: null,
})
posType: string;
@Column({
nullable: true,
comment: "ชื่อระดับตำแหน่ง",
length: 255,
default: null,
})
posLevel: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่งทางการบริหาร",
length: 255,
default: null,
})
posExecutive: string;
@Column({
nullable: true,
comment:
"รหัส DNA ใช้ในกรณีที่มีการทำสำเนาโครงสร้างและตำแหน่ง ตำแหน่งที่ทำสำเนามากับตำแหน่งเก่าจะต้องมี DNA เดียวกัน เพื่อให้ track ประวัติการแก้ไขตำแหน่งย้อนหลังได้",
length: 40,
default: null,
})
ancestorDNA: string;
}

View file

@ -0,0 +1,101 @@
import { Entity, Column } from "typeorm";
import { EntityBase } from "./base/Base";
@Entity("posMasterHistory")
export class PosMasterHistory extends EntityBase {
@Column({
nullable: true,
comment: "คำนำหน้า",
length: 255,
default: null,
})
prefix: string;
@Column({
nullable: true,
comment: "ชื่อ",
length: 255,
default: null,
})
firstName: string;
@Column({
nullable: true,
comment: "สกุล",
length: 255,
default: null,
})
lastName: string;
@Column({
nullable: true,
comment: "อักษรย่อ",
length: 16,
default: null,
})
shortName: string;
@Column({
nullable: true,
comment: "Prefix นำหน้าเลขที่ตำแหน่ง เป็น Optional (ไม่ใช่อักษรย่อของหน่วยงาน/ส่วนราชการ)",
length: 16,
default: null,
})
posMasterNoPrefix: string;
@Column({
nullable: true,
comment: "เลขที่ตำแหน่ง เป็นตัวเลข",
default: null,
})
posMasterNo: number;
@Column({
nullable: true,
comment: "Suffix หลังเลขที่ตำแหน่ง เช่น ช.",
length: 16,
default: null,
})
posMasterNoSuffix: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่ง",
length: 255,
default: null,
})
position: string;
@Column({
nullable: true,
comment: "ชื่อประเภทตำแหน่ง",
length: 255,
default: null,
})
posType: string;
@Column({
nullable: true,
comment: "ชื่อระดับตำแหน่ง",
length: 255,
default: null,
})
posLevel: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่งทางการบริหาร",
length: 255,
default: null,
})
posExecutive: string;
@Column({
nullable: true,
comment:
"รหัส DNA ใช้ในกรณีที่มีการทำสำเนาโครงสร้างและตำแหน่ง ตำแหน่งที่ทำสำเนามากับตำแหน่งเก่าจะต้องมี DNA เดียวกัน เพื่อให้ track ประวัติการแก้ไขตำแหน่งย้อนหลังได้",
length: 40,
default: null,
})
ancestorDNA: string;
}

417
src/entities/Registry.ts Normal file
View file

@ -0,0 +1,417 @@
import {
Entity,
Column
} from "typeorm";
import { EntityBase } from "./base/Base";
@Entity("registry")
export class Registry extends EntityBase {
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง profile",
default: null,
})
profileId: string;
@Column({
nullable: true,
comment: "เลขประจำตัวประชาชน",
default: null,
length: 13,
})
citizenId: string;
@Column({
nullable: true,
length: 40,
comment: "คำนำหน้าชื่อ เช่น นาย นาง นางสาว",
default: null,
})
prefix: string;
@Column({
nullable: true,
comment: "ชื่อ",
length: 255,
default: null,
})
firstName: string;
@Column({
nullable: true,
comment: "นามสกุล",
length: 255,
default: null,
})
lastName: string;
@Column({
comment: "ทดลองปฏิบัติหน้าที่",
default: false,
})
isProbation: boolean;
@Column({
comment: "พ้นราชการ",
default: false,
})
isLeave: boolean;
@Column({
comment: "เกษียณ",
default: false,
})
isRetirement: boolean;
@Column({
nullable: true,
length: 255,
comment: "ประเภทพ้นคำสั่งพ้นจากราชการ",
default: null,
})
leaveType: string;
@Column({
nullable: true,
comment: "เลขที่ตำแหน่ง เป็นตัวเลข",
default: null,
})
posMasterNo: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgRoot",
default: null,
})
orgRootId?: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgChild1",
default: null,
})
orgChild1Id?: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgChild2",
default: null,
})
orgChild2Id?: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgChild3",
default: null,
})
orgChild3Id?: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgChild4",
default: null,
})
orgChild4Id?: string;
@Column({
nullable: true,
comment: "ชื่อหน่วยงาน",
length: 255,
default: null,
})
orgRootName: string;
@Column({
nullable: true,
comment: "ชื่อส่วนราชการ Child1",
length: 255,
default: null,
})
orgChild1Name: string;
@Column({
nullable: true,
comment: "ชื่อส่วนราชการ Child2",
length: 255,
default: null,
})
orgChild2Name: string;
@Column({
nullable: true,
comment: "ชื่อส่วนราชการ Child3",
length: 255,
default: null,
})
orgChild3Name: string;
@Column({
nullable: true,
comment: "ชื่อส่วนราชการ Child4",
length: 255,
default: null,
})
orgChild4Name: string;
@Column({
nullable: true,
length: 255,
comment: "สังกัด",
default: null,
})
org: string;
@Column({
nullable: true,
length: 255,
comment: "เลขที่ตำแหน่ง",
default: null,
})
searchShortName: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่งทางการบริหาร",
length: 255,
default: null,
})
posExecutiveName: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่งในสายงาน",
length: 255,
default: null,
})
position: string;
@Column({
nullable: true,
length: 255,
comment: "ประเภทตำแหน่ง",
default: null,
})
posTypeName: string;
@Column({
nullable: true,
length: 255,
comment: "ระดับตำแหน่ง",
default: null,
})
posLevelName: string;
@Column({
nullable: true,
comment: "เพศ",
length: 40,
default: null,
})
gender: string;
@Column({
nullable: true,
comment: "ความสัมพันธ์",
length: 40,
default: null,
})
relationship: string;
@Column({
nullable: true,
type: "datetime",
comment: "วันที่บรรจุ",
default: null,
})
dateAppoint: Date;
@Column({
nullable: true,
type: "datetime",
comment: "วันครบเกษียณอายุ",
default: null,
})
dateRetire: Date;
@Column({
nullable: true,
type: "datetime",
comment: "วันที่เกษียณอายุราชการตามกฏหมาย",
default: null,
})
dateRetireLaw: Date;
@Column({
nullable: true,
type: "datetime",
comment: "วันเกิด",
default: null,
})
birthdate: Date;
@Column({
nullable: true,
comment: "วุฒิการศึกษา",
length: 255,
default: null,
})
degrees: string;
@Column({
nullable: true,
comment: "อายุ",
default: null,
})
age: number;
@Column({
nullable: true,
comment: "จำนวนปีระยะเวลาดำรงตำแหน่งในสายงาน",
default: null,
})
Years: number;
@Column({
nullable: true,
comment: "จำนวนเดือนระยะเวลาดำรงตำแหน่งในสายงาน",
default: null,
})
Months: number;
@Column({
nullable: true,
comment: "จำนวนวันระยะเวลาดำรงตำแหน่งในสายงาน",
default: null,
})
Days: number;
@Column({
nullable: true,
comment: "จำนวนปีระยะเวลาดำรงตำแหน่งตามระดับ",
default: null,
})
levelYears: number;
@Column({
nullable: true,
comment: "จำนวนเดือนระยะเวลาดำรงตำแหน่งตามระดับ",
default: null,
})
levelMonths: number;
@Column({
nullable: true,
comment: "จำนวนวันระยะเวลาดำรงตำแหน่งตามระดับ",
default: null,
})
levelDays: number;
@Column({
nullable: true,
comment: "จำนวนปีระยะเวลาดำรงตำแหน่งทางการบริหาร",
default: null,
})
posExecutiveYears: number;
@Column({
nullable: true,
comment: "จำนวนเดือนระยะเวลาดำรงตำแหน่งทางการบริหาร",
default: null,
})
posExecutiveMonths: number;
@Column({
nullable: true,
comment: "จำนวนวันระยะเวลาดำรงตำแหน่งทางการบริหาร",
default: null,
})
posExecutiveDays: number;
@Column({
nullable: true,
comment: "ด้าน/สาขา",
length: 255,
default: null,
})
positionArea: string;
@Column({
type: "text",
nullable: true,
comment: "วุฒิการศึกษา",
default: null,
})
Educations: string;
@Column({
nullable: true,
comment: "ระดับศึกษา",
length: 255,
default: null,
})
educationLevels: string;
@Column({
nullable: true,
comment: "สาขาวิชา/ทาง",
length: 255,
default: null,
})
fields: string;
}
export class RegistryCreateDto {
profileId: string;
citizenId?: string | null;
prefix?: string | null;
firstName?: string | null;
lastName?: string | null;
isProbation?: boolean | null;
isLeave?: boolean | null;
isRetirement?: boolean | null;
leaveType?: string | null;
posMasterNo?: string | null;
orgRootId?: string | null;
orgChild1Id?: string | null;
orgChild2Id?: string | null;
orgChild3Id?: string | null;
orgChild4Id?: string | null;
orgRootName?: string | null;
orgChild1Name?: string | null;
orgChild2Name?: string | null;
orgChild3Name?: string | null;
orgChild4Name?: string | null;
org?: string | null;
searchShortName?: string | null;
posExecutiveName?: string | null;
position?: string | null;
posTypeName?: string | null;
posLevelName?: string | null;
gender?: string | null;
relationship?: string | null;
dateAppoint?: Date | null;
dateRetire?: Date | null;
dateRetireLaw?: Date | null;
birthdate?: Date | null;
degrees?: string | null;
age?: number | null;
Years?: number | null;
Months?: number | null;
Days?: number | null;
levelYears?: number | null;
levelMonths?: number | null;
levelDays?: number | null;
posExecutiveYears?: number | null;
posExecutiveMonths?: number | null;
posExecutiveDays?: number | null;
positionArea?: string | null;
Educations?: string | null;
educationLevels?: string | null;
fields?: string | null;
}

View file

@ -0,0 +1,384 @@
import {
Entity,
Column
} from "typeorm";
import { EntityBase } from "./base/Base";
@Entity("registryEmployee")
export class RegistryEmployee extends EntityBase {
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง profileEmployee",
default: null,
})
profileEmployeeId: string;
@Column({
nullable: true,
comment: "เลขประจำตัวประชาชน",
default: null,
length: 13,
})
citizenId: string;
@Column({
nullable: true,
length: 40,
comment: "คำนำหน้าชื่อ เช่น นาย นาง นางสาว",
default: null,
})
prefix: string;
@Column({
nullable: true,
comment: "ชื่อ",
length: 255,
default: null,
})
firstName: string;
@Column({
nullable: true,
comment: "นามสกุล",
length: 255,
default: null,
})
lastName: string;
@Column({
comment: "ทดลองปฏิบัติหน้าที่",
default: false,
})
isProbation: boolean;
@Column({
comment: "พ้นราชการ",
default: false,
})
isLeave: boolean;
@Column({
comment: "เกษียณ",
default: false,
})
isRetirement: boolean;
@Column({
nullable: true,
length: 255,
comment: "ประเภทพ้นคำสั่งพ้นจากราชการ",
default: null,
})
leaveType: string;
@Column({
nullable: true,
comment: "เลขที่ตำแหน่ง เป็นตัวเลข",
default: null,
})
posMasterNo: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgRoot",
default: null,
})
orgRootId?: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgChild1",
default: null,
})
orgChild1Id?: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgChild2",
default: null,
})
orgChild2Id?: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgChild3",
default: null,
})
orgChild3Id?: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง orgChild4",
default: null,
})
orgChild4Id?: string;
@Column({
nullable: true,
comment: "ชื่อหน่วยงาน",
length: 255,
default: null,
})
orgRootName: string;
@Column({
nullable: true,
comment: "ชื่อส่วนราชการ Child1",
length: 255,
default: null,
})
orgChild1Name: string;
@Column({
nullable: true,
comment: "ชื่อส่วนราชการ Child2",
length: 255,
default: null,
})
orgChild2Name: string;
@Column({
nullable: true,
comment: "ชื่อส่วนราชการ Child3",
length: 255,
default: null,
})
orgChild3Name: string;
@Column({
nullable: true,
comment: "ชื่อส่วนราชการ Child4",
length: 255,
default: null,
})
orgChild4Name: string;
@Column({
nullable: true,
length: 255,
comment: "สังกัด",
default: null,
})
org: string;
@Column({
nullable: true,
length: 255,
comment: "เลขที่ตำแหน่ง",
default: null,
})
searchShortName: string;
@Column({
nullable: true,
comment: "ชื่อตำแหน่งในสายงาน",
length: 255,
default: null,
})
position: string;
@Column({
nullable: true,
length: 255,
comment: "ประเภทตำแหน่ง",
default: null,
})
posTypeName: string;
@Column({
nullable: true,
length: 255,
comment: "ระดับตำแหน่ง",
default: null,
})
posLevelName: string;
@Column({
nullable: true,
comment: "เพศ",
length: 40,
default: null,
})
gender: string;
@Column({
nullable: true,
comment: "ความสัมพันธ์",
length: 40,
default: null,
})
relationship: string;
@Column({
nullable: true,
type: "datetime",
comment: "วันที่บรรจุ",
default: null,
})
dateAppoint: Date;
@Column({
nullable: true,
type: "datetime",
comment: "วันครบเกษียณอายุ",
default: null,
})
dateRetire: Date;
@Column({
nullable: true,
type: "datetime",
comment: "วันที่เกษียณอายุราชการตามกฏหมาย",
default: null,
})
dateRetireLaw: Date;
@Column({
nullable: true,
type: "datetime",
comment: "วันเกิด",
default: null,
})
birthdate: Date;
@Column({
nullable: true,
comment: "วุฒิการศึกษา",
length: 255,
default: null,
})
degrees: string;
@Column({
nullable: true,
comment: "อายุ",
default: null,
})
age: number;
@Column({
nullable: true,
comment: "จำนวนปีระยะเวลาดำรงตำแหน่งในสายงาน",
default: null,
})
Years: number;
@Column({
nullable: true,
comment: "จำนวนเดือนระยะเวลาดำรงตำแหน่งในสายงาน",
default: null,
})
Months: number;
@Column({
nullable: true,
comment: "จำนวนวันระยะเวลาดำรงตำแหน่งในสายงาน",
default: null,
})
Days: number;
@Column({
nullable: true,
comment: "จำนวนปีระยะเวลาดำรงตำแหน่งตามระดับ",
default: null,
})
levelYears: number;
@Column({
nullable: true,
comment: "จำนวนเดือนระยะเวลาดำรงตำแหน่งตามระดับ",
default: null,
})
levelMonths: number;
@Column({
nullable: true,
comment: "จำนวนวันระยะเวลาดำรงตำแหน่งตามระดับ",
default: null,
})
levelDays: number;
@Column({
type: "text",
nullable: true,
comment: "วุฒิการศึกษา",
default: null,
})
Educations: string;
@Column({
nullable: true,
comment: "ระดับศึกษา",
length: 255,
default: null,
})
educationLevels: string;
@Column({
nullable: true,
comment: "สาขาวิชา/ทาง",
length: 255,
default: null,
})
fields: string;
@Column({
nullable: true,
comment: "ประเภทลูกจ้าง (perm->ลูกจ้างประจำ temp->ลูกจ้างชั่วคราว)",
length: 40,
default: null,
})
employeeClass: string;
}
export class RegistryEmployeeCreateDto {
profileEmployeeId: string;
citizenId?: string | null;
prefix?: string | null;
firstName?: string | null;
lastName?: string | null;
isProbation?: boolean | null;
isLeave?: boolean | null;
isRetirement?: boolean | null;
leaveType?: string | null;
posMasterNo?: string | null;
orgRootId?: string | null;
orgChild1Id?: string | null;
orgChild2Id?: string | null;
orgChild3Id?: string | null;
orgChild4Id?: string | null;
orgRootName?: string | null;
orgChild1Name?: string | null;
orgChild2Name?: string | null;
orgChild3Name?: string | null;
orgChild4Name?: string | null;
org?: string | null;
searchShortName?: string | null;
position?: string | null;
posTypeName?: string | null;
posLevelName?: string | null;
gender?: string | null;
relationship?: string | null;
dateAppoint?: Date | null;
dateRetire?: Date | null;
dateRetireLaw?: Date | null;
birthdate?: Date | null;
degrees?: string | null;
age?: number | null;
Years?: number | null;
Months?: number | null;
Days?: number | null;
levelYears?: number | null;
levelMonths?: number | null;
levelDays?: number | null;
Educations?: string | null;
educationLevels?: string | null;
fields?: string | null;
employeeClass?: string | null;
}

View file

@ -298,4 +298,7 @@ export class viewRegistryEmployee {
@ViewColumn()
fields: string;
@ViewColumn()
employeeClass: string;
}

View file

@ -561,6 +561,48 @@ export function chunkArray(array: any, size: number) {
return result;
}
export async function PayloadSendNoti(commandId: string) {
if (!commandId)
return "";
const commandRepository = AppDataSource.getRepository(Command);
const _command = await commandRepository.findOne({
where: {
id: commandId,
},
relations: ["commandType"],
});
if (!_command || !_command.commandType)
return "";
const _payload = {
name: _command && _command.commandType
? `คำสั่ง${_command.commandType.name}`
: "",
url: `${process.env.API_URL}/salary/file/ระบบออกคำสั่ง/คำสั่ง/${commandId}/คำสั่ง`,
isReport: true,
isTemplate: false,
}
let attachments = {}
if (_command.commandType.isUploadAttachment === true) {
const _payloadAtt = {
name: _command && _command.commandType
? `เอกสารแนบท้ายคำสั่ง${_command.commandType.name}`
: "",
url: `${process.env.API_URL}/salary/file/ระบบออกคำสั่ง/แนบท้าย/${commandId}/แนบท้าย`,
isReport: true,
isTemplate: false,
}
attachments = {
attachments: [_payload, _payloadAtt]
};
}
else {
attachments = {
attachments: [_payload]
};
}
return JSON.stringify(attachments);
}
export function commandTypePath(commandCode: string): string | null {
switch (commandCode) {
case "C-PM-01":

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,20 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class UpdateRegistryFixLengthPrefix1756357065498 implements MigrationInterface {
name = 'UpdateRegistryFixLengthPrefix1756357065498'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`registryEmployee\` DROP COLUMN \`prefix\``);
await queryRunner.query(`ALTER TABLE \`registryEmployee\` ADD \`prefix\` varchar(40) NULL COMMENT 'คำนำหน้าชื่อ เช่น นาย นาง นางสาว'`);
await queryRunner.query(`ALTER TABLE \`registry\` DROP COLUMN \`prefix\``);
await queryRunner.query(`ALTER TABLE \`registry\` ADD \`prefix\` varchar(40) NULL COMMENT 'คำนำหน้าชื่อ เช่น นาย นาง นางสาว'`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`registry\` DROP COLUMN \`prefix\``);
await queryRunner.query(`ALTER TABLE \`registry\` ADD \`prefix\` varchar(20) NULL COMMENT 'คำนำหน้าชื่อ เช่น นาย นาง นางสาว'`);
await queryRunner.query(`ALTER TABLE \`registryEmployee\` DROP COLUMN \`prefix\``);
await queryRunner.query(`ALTER TABLE \`registryEmployee\` ADD \`prefix\` varchar(20) NULL COMMENT 'คำนำหน้าชื่อ เช่น นาย นาง นางสาว'`);
}
}

View file

@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class UpdateRegistrymployereAddFieldEmployeeClass1756364862810 implements MigrationInterface {
name = 'UpdateRegistrymployereAddFieldEmployeeClass1756364862810'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`registryEmployee\` ADD \`employeeClass\` varchar(40) NULL COMMENT 'ประเภทลูกจ้าง (perm->ลูกจ้างประจำ temp->ลูกจ้างชั่วคราว)'`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`registryEmployee\` DROP COLUMN \`employeeClass\``);
}
}

View file

@ -0,0 +1,216 @@
import { AppDataSource } from "../database/data-source";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
import { EmployeeTempPosMaster } from "../entities/EmployeeTempPosMaster";
import { PosMaster } from "../entities/PosMaster";
import { PosMasterEmployeeHistory } from "../entities/PosMasterEmployeeHistory";
import { PosMasterEmployeeTempHistory } from "../entities/PosMasterEmployeeTempHistory";
import { PosMasterHistory } from "../entities/PosMasterHistory";
import { RequestWithUser } from "../middlewares/user";
export async function CreatePosMasterHistoryOfficer(
posMasterId: string,
request: RequestWithUser | null,
): Promise<boolean> {
try {
await AppDataSource.transaction(async (manager) => {
const repoPosmaster = manager.getRepository(PosMaster);
const repoHistory = manager.getRepository(PosMasterHistory);
const pm = await repoPosmaster.findOne({
where: { id: posMasterId },
relations: [
"positions",
"positions.posLevel",
"positions.posType",
"positions.posExecutive",
"orgRoot",
"orgChild1",
"orgChild2",
"orgChild3",
"orgChild4",
"current_holder",
],
});
if (!pm) return false;
if (!pm.ancestorDNA) return false;
const _null: any = null;
const h = new PosMasterHistory();
const selectedPosition =
pm.positions.length > 0
? pm.positions.find((p) => p.positionIsSelected === true) ?? null
: null;
h.ancestorDNA = pm.ancestorDNA;
h.prefix = pm.current_holder?.prefix || _null;
h.firstName = pm.current_holder?.firstName || _null;
h.lastName = pm.current_holder?.lastName || _null;
h.posMasterNoPrefix = pm.posMasterNoPrefix ?? _null;
h.posMasterNo = pm.posMasterNo ?? _null;
h.posMasterNoSuffix = pm.posMasterNoSuffix ?? _null;
h.position = selectedPosition?.positionName ?? _null;
h.posType = selectedPosition?.posType?.posTypeName ?? _null;
h.posLevel = selectedPosition?.posLevel?.posLevelName ?? _null;
h.posExecutive = selectedPosition?.posExecutive?.posExecutiveName ?? _null;
h.shortName =
[
pm.orgChild4?.orgChild4ShortName,
pm.orgChild3?.orgChild3ShortName,
pm.orgChild2?.orgChild2ShortName,
pm.orgChild1?.orgChild1ShortName,
pm.orgRoot?.orgRootShortName,
].find((s) => typeof s === "string" && s.trim().length > 0) ?? _null;
const userId = request?.user?.sub ?? "";
const userName = request?.user?.name ?? "system";
h.createdUserId = userId;
h.createdFullName = userName;
h.lastUpdateUserId = userId;
h.lastUpdateFullName = userName;
h.createdAt = new Date();
h.lastUpdatedAt = new Date();
await repoHistory.save(h);
});
return true;
} catch (err) {
console.error("CreatePosMasterHistoryOfficer transaction error:", err);
return false;
}
}
export async function CreatePosMasterHistoryEmployee(
posMasterId: string,
request: RequestWithUser | null,
): Promise<boolean> {
try {
await AppDataSource.transaction(async (manager) => {
const repoPosmaster = manager.getRepository(EmployeePosMaster);
const repoHistory = manager.getRepository(PosMasterEmployeeHistory);
const pm = await repoPosmaster.findOne({
where: { id: posMasterId },
relations: [
"positions",
"positions.posLevel",
"positions.posType",
"positions.posExecutive",
"orgRoot",
"orgChild1",
"orgChild2",
"orgChild3",
"orgChild4",
"current_holder",
],
});
if (!pm) return false;
if (!pm.ancestorDNA) return false;
const _null: any = null;
const h = new PosMasterEmployeeHistory();
const selectedPosition =
pm.positions.length > 0
? pm.positions.find((p) => p.positionIsSelected === true) ?? null
: null;
h.ancestorDNA = pm.ancestorDNA;
h.prefix = pm.current_holder?.prefix || _null;
h.firstName = pm.current_holder?.firstName || _null;
h.lastName = pm.current_holder?.lastName || _null;
h.posMasterNoPrefix = pm.posMasterNoPrefix ?? _null;
h.posMasterNo = pm.posMasterNo ?? _null;
h.posMasterNoSuffix = pm.posMasterNoSuffix ?? _null;
h.position = selectedPosition?.positionName ?? _null;
h.posType = selectedPosition?.posType?.posTypeName ?? _null;
h.posLevel = selectedPosition?.posLevel?.posLevelName ?? _null;
h.shortName =
[
pm.orgChild4?.orgChild4ShortName,
pm.orgChild3?.orgChild3ShortName,
pm.orgChild2?.orgChild2ShortName,
pm.orgChild1?.orgChild1ShortName,
pm.orgRoot?.orgRootShortName,
].find((s) => typeof s === "string" && s.trim().length > 0) ?? _null;
const userId = request?.user?.sub ?? "";
const userName = request?.user?.name ?? "system";
h.createdUserId = userId;
h.createdFullName = userName;
h.lastUpdateUserId = userId;
h.lastUpdateFullName = userName;
h.createdAt = new Date();
h.lastUpdatedAt = new Date();
await repoHistory.save(h);
});
return true;
} catch (err) {
console.error("CreatePosMasterHistoryEmployee transaction error:", err);
return false;
}
}
export async function CreatePosMasterHistoryEmployeeTemp(
posMasterId: string,
request: RequestWithUser | null,
): Promise<boolean> {
try {
await AppDataSource.transaction(async (manager) => {
const repoPosmaster = manager.getRepository(EmployeeTempPosMaster);
const repoHistory = manager.getRepository(PosMasterEmployeeTempHistory);
const pm = await repoPosmaster.findOne({
where: { id: posMasterId },
relations: [
"positions",
"positions.posLevel",
"positions.posType",
"positions.posExecutive",
"orgRoot",
"orgChild1",
"orgChild2",
"orgChild3",
"orgChild4",
"current_holder",
],
});
if (!pm) return false;
if (!pm.ancestorDNA) return false;
const _null: any = null;
const h = new PosMasterEmployeeTempHistory();
const selectedPosition =
pm.positions.length > 0
? pm.positions.find((p) => p.positionIsSelected === true) ?? null
: null;
h.ancestorDNA = pm.ancestorDNA;
h.prefix = pm.current_holder?.prefix || _null;
h.firstName = pm.current_holder?.firstName || _null;
h.lastName = pm.current_holder?.lastName || _null;
h.posMasterNoPrefix = pm.posMasterNoPrefix ?? _null;
h.posMasterNo = pm.posMasterNo ?? _null;
h.posMasterNoSuffix = pm.posMasterNoSuffix ?? _null;
h.position = selectedPosition?.positionName ?? _null;
h.posType = selectedPosition?.posType?.posTypeName ?? _null;
h.posLevel = selectedPosition?.posLevel?.posLevelName ?? _null;
h.shortName =
[
pm.orgChild4?.orgChild4ShortName,
pm.orgChild3?.orgChild3ShortName,
pm.orgChild2?.orgChild2ShortName,
pm.orgChild1?.orgChild1ShortName,
pm.orgRoot?.orgRootShortName,
].find((s) => typeof s === "string" && s.trim().length > 0) ?? _null;
const userId = request?.user?.sub ?? "";
const userName = request?.user?.name ?? "system";
h.createdUserId = userId;
h.createdFullName = userName;
h.lastUpdateUserId = userId;
h.lastUpdateFullName = userName;
h.createdAt = new Date();
h.lastUpdatedAt = new Date();
await repoHistory.save(h);
});
return true;
} catch (err) {
console.error("CreatePosMasterHistoryEmployeeTemp transaction error:", err);
return false;
}
}

View file

@ -5,14 +5,12 @@ import { chunkArray, commandTypePath } from "../interfaces/utils";
import CallAPI from "../interfaces/call-api";
import HttpError from "../interfaces/http-error";
import HttpStatusCode from "../interfaces/http-status";
import { RequestWithUser } from "../middlewares/user";
import { PosMaster } from "../entities/PosMaster";
import { Profile } from "../entities/Profile";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
import { EmployeeTempPosMaster } from "../entities/EmployeeTempPosMaster";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import { OrgRevision } from "../entities/OrgRevision";
import { request } from "http";
import { EmployeePosition } from "../entities/EmployeePosition";
import { OrgChild1 } from "../entities/OrgChild1";
import { OrgChild2 } from "../entities/OrgChild2";
@ -25,6 +23,8 @@ import { In, Not } from "typeorm";
import { PosMasterAct } from "../entities/PosMasterAct";
import { PermissionOrg } from "../entities/PermissionOrg";
import { sendWebSocket } from "./webSocket";
import { CreatePosMasterHistoryOfficer } from "./PositionService";
import { PayloadSendNoti } from "../interfaces/utils";
export let sendToQueue: (payload: any) => void;
export let sendToQueueOrg: (payload: any) => void;
@ -84,7 +84,7 @@ export async function init() {
console.log("[AMQ] Listening for message...");
createConsumer(queue, channel, handler), //----> (3) Process Consumer
createConsumer(queue_org, channel, handler_org);
createConsumer(queue_org, channel, handler_org);
createConsumer(queue_org_draft, channel, handler_org_draft);
createConsumer(queue_command_noti, channel, handler_command_noti);
// createConsumer(queue2, channel, handler2);
@ -446,6 +446,7 @@ async function handler_command_noti(msg: amqp.ConsumeMessage): Promise<boolean>
}))
: [];
const payloadStr = await PayloadSendNoti(command.id);
const profilesSendRequest = new CallAPI()
.PostData(
{ headers: { authorization: token } },
@ -454,7 +455,7 @@ async function handler_command_noti(msg: amqp.ConsumeMessage): Promise<boolean>
subject: `${command.issue}`,
body: `${command.issue}`,
receiverUserIds: profilesSend,
payload: "", // แนบไฟล์ (ถ้าจำเป็น)
payload: payloadStr, // แนบไฟล์ (ถ้าจำเป็น)
},
false,
)
@ -580,6 +581,7 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise<boolean> {
item.lastUpdateFullName = lastUpdateFullName;
item.lastUpdatedAt = lastUpdatedAt;
await repoPosmaster.save(item).catch((e) => console.log(e));
await CreatePosMasterHistoryOfficer(item.id, null);
}
if (orgRevisionPublish != null && orgRevisionDraft != null) {
//new main revision