diff --git a/src/app.ts b/src/app.ts index 565cb46f..236fb105 100644 --- a/src/app.ts +++ b/src/app.ts @@ -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); } diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 5dfcf45d..c1e98a6c 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -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: { diff --git a/src/controllers/EmployeePositionController.ts b/src/controllers/EmployeePositionController.ts index 6ef4ffaa..632261e0 100644 --- a/src/controllers/EmployeePositionController.ts +++ b/src/controllers/EmployeePositionController.ts @@ -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); + } } diff --git a/src/controllers/EmployeeTempPositionController.ts b/src/controllers/EmployeeTempPositionController.ts index 7ad6b9c7..5d304de0 100644 --- a/src/controllers/EmployeeTempPositionController.ts +++ b/src/controllers/EmployeeTempPositionController.ts @@ -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); + } } diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index cd400837..37663cc2 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -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; } } diff --git a/src/controllers/OrganizationDotnetController.ts b/src/controllers/OrganizationDotnetController.ts index f6e926c3..01cec5dd 100644 --- a/src/controllers/OrganizationDotnetController.ts +++ b/src/controllers/OrganizationDotnetController.ts @@ -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 }, }); diff --git a/src/controllers/PositionController.ts b/src/controllers/PositionController.ts index b233b631..6ffa9708 100644 --- a/src/controllers/PositionController.ts +++ b/src/controllers/PositionController.ts @@ -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); + } } diff --git a/src/controllers/ProfileController.ts b/src/controllers/ProfileController.ts index 5d1bf77c..1cfa4565 100644 --- a/src/controllers/ProfileController.ts +++ b/src/controllers/ProfileController.ts @@ -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, diff --git a/src/controllers/ProfileInsigniaController.ts b/src/controllers/ProfileInsigniaController.ts index 4ed9c189..93c792f5 100644 --- a/src/controllers/ProfileInsigniaController.ts +++ b/src/controllers/ProfileInsigniaController.ts @@ -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 }) { @@ -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); + } } diff --git a/src/controllers/ProfileSalaryController.ts b/src/controllers/ProfileSalaryController.ts index f99c96bd..6809f326 100644 --- a/src/controllers/ProfileSalaryController.ts +++ b/src/controllers/ProfileSalaryController.ts @@ -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 }) { const profile = await this.profileRepo.findOneBy({ keycloak: request.user.sub }); diff --git a/src/controllers/ReportController.ts b/src/controllers/ReportController.ts index cedd3105..d3f947f7 100644 --- a/src/controllers/ReportController.ts +++ b/src/controllers/ReportController.ts @@ -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, diff --git a/src/entities/PosMasterEmployeeHistory.ts b/src/entities/PosMasterEmployeeHistory.ts new file mode 100644 index 00000000..7dfa3b0c --- /dev/null +++ b/src/entities/PosMasterEmployeeHistory.ts @@ -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; +} diff --git a/src/entities/PosMasterEmployeeTempHistory.ts b/src/entities/PosMasterEmployeeTempHistory.ts new file mode 100644 index 00000000..c664959d --- /dev/null +++ b/src/entities/PosMasterEmployeeTempHistory.ts @@ -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; +} diff --git a/src/entities/PosMasterHistory.ts b/src/entities/PosMasterHistory.ts new file mode 100644 index 00000000..4360cf1e --- /dev/null +++ b/src/entities/PosMasterHistory.ts @@ -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; +} diff --git a/src/entities/Registry.ts b/src/entities/Registry.ts new file mode 100644 index 00000000..95a4d63e --- /dev/null +++ b/src/entities/Registry.ts @@ -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; +} \ No newline at end of file diff --git a/src/entities/RegistryEmployee.ts b/src/entities/RegistryEmployee.ts new file mode 100644 index 00000000..31d0a8b2 --- /dev/null +++ b/src/entities/RegistryEmployee.ts @@ -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; +} \ No newline at end of file diff --git a/src/entities/view/viewRegistryEmployee.ts b/src/entities/view/viewRegistryEmployee.ts index a26e20f0..807d08bc 100644 --- a/src/entities/view/viewRegistryEmployee.ts +++ b/src/entities/view/viewRegistryEmployee.ts @@ -298,4 +298,7 @@ export class viewRegistryEmployee { @ViewColumn() fields: string; + + @ViewColumn() + employeeClass: string; } diff --git a/src/interfaces/utils.ts b/src/interfaces/utils.ts index 69b31e58..cf86f369 100644 --- a/src/interfaces/utils.ts +++ b/src/interfaces/utils.ts @@ -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": diff --git a/src/migration/1756282384029-create_table_registry_.ts b/src/migration/1756282384029-create_table_registry_.ts new file mode 100644 index 00000000..fe3b8d02 --- /dev/null +++ b/src/migration/1756282384029-create_table_registry_.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class CreateTableRegistry_1756282384029 implements MigrationInterface { + name = 'CreateTableRegistry_1756282384029' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE \`registryEmployee\` (\`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL COMMENT 'สร้างข้อมูลเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`createdUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่สร้างข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`lastUpdatedAt\` datetime(6) NOT NULL COMMENT 'แก้ไขข้อมูลล่าสุดเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`lastUpdateUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่แก้ไขข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`createdFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่สร้างข้อมูล' DEFAULT 'System Administrator', \`lastUpdateFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่แก้ไขข้อมูลล่าสุด' DEFAULT 'System Administrator', \`profileEmployeeId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง profileEmployee', \`citizenId\` varchar(13) NULL COMMENT 'เลขประจำตัวประชาชน', \`prefix\` varchar(20) NULL COMMENT 'คำนำหน้าชื่อ เช่น นาย นาง นางสาว', \`firstName\` varchar(255) NULL COMMENT 'ชื่อ', \`lastName\` varchar(255) NULL COMMENT 'นามสกุล', \`isProbation\` tinyint NOT NULL COMMENT 'ทดลองปฏิบัติหน้าที่' DEFAULT 0, \`isLeave\` tinyint NOT NULL COMMENT 'พ้นราชการ' DEFAULT 0, \`isRetirement\` tinyint NOT NULL COMMENT 'เกษียณ' DEFAULT 0, \`leaveType\` varchar(255) NULL COMMENT 'ประเภทพ้นคำสั่งพ้นจากราชการ', \`posMasterNo\` varchar(255) NULL COMMENT 'เลขที่ตำแหน่ง เป็นตัวเลข', \`orgRootId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgRoot', \`orgChild1Id\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgChild1', \`orgChild2Id\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgChild2', \`orgChild3Id\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgChild3', \`orgChild4Id\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgChild4', \`orgRootName\` varchar(255) NULL COMMENT 'ชื่อหน่วยงาน', \`orgChild1Name\` varchar(255) NULL COMMENT 'ชื่อส่วนราชการ Child1', \`orgChild2Name\` varchar(255) NULL COMMENT 'ชื่อส่วนราชการ Child2', \`orgChild3Name\` varchar(255) NULL COMMENT 'ชื่อส่วนราชการ Child3', \`orgChild4Name\` varchar(255) NULL COMMENT 'ชื่อส่วนราชการ Child4', \`org\` varchar(255) NULL COMMENT 'สังกัด', \`searchShortName\` varchar(255) NULL COMMENT 'เลขที่ตำแหน่ง', \`position\` varchar(255) NULL COMMENT 'ชื่อตำแหน่งในสายงาน', \`posTypeName\` varchar(255) NULL COMMENT 'ประเภทตำแหน่ง', \`posLevelName\` varchar(255) NULL COMMENT 'ระดับตำแหน่ง', \`gender\` varchar(40) NULL COMMENT 'เพศ', \`relationship\` varchar(40) NULL COMMENT 'ความสัมพันธ์', \`dateAppoint\` datetime NULL COMMENT 'วันที่บรรจุ', \`dateRetire\` datetime NULL COMMENT 'วันครบเกษียณอายุ', \`dateRetireLaw\` datetime NULL COMMENT 'วันที่เกษียณอายุราชการตามกฏหมาย', \`birthdate\` datetime NULL COMMENT 'วันเกิด', \`degrees\` varchar(255) NULL COMMENT 'วุฒิการศึกษา', \`age\` int NULL COMMENT 'อายุ', \`Years\` int NULL COMMENT 'จำนวนปีระยะเวลาดำรงตำแหน่งในสายงาน', \`Months\` int NULL COMMENT 'จำนวนเดือนระยะเวลาดำรงตำแหน่งในสายงาน', \`Days\` int NULL COMMENT 'จำนวนวันระยะเวลาดำรงตำแหน่งในสายงาน', \`levelYears\` int NULL COMMENT 'จำนวนปีระยะเวลาดำรงตำแหน่งตามระดับ', \`levelMonths\` int NULL COMMENT 'จำนวนเดือนระยะเวลาดำรงตำแหน่งตามระดับ', \`levelDays\` int NULL COMMENT 'จำนวนวันระยะเวลาดำรงตำแหน่งตามระดับ', \`Educations\` text NULL COMMENT 'วุฒิการศึกษา', \`educationLevels\` varchar(255) NULL COMMENT 'ระดับศึกษา', \`fields\` varchar(255) NULL COMMENT 'สาขาวิชา/ทาง', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`CREATE TABLE \`registry\` (\`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL COMMENT 'สร้างข้อมูลเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`createdUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่สร้างข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`lastUpdatedAt\` datetime(6) NOT NULL COMMENT 'แก้ไขข้อมูลล่าสุดเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`lastUpdateUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่แก้ไขข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`createdFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่สร้างข้อมูล' DEFAULT 'System Administrator', \`lastUpdateFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่แก้ไขข้อมูลล่าสุด' DEFAULT 'System Administrator', \`profileId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง profile', \`citizenId\` varchar(13) NULL COMMENT 'เลขประจำตัวประชาชน', \`prefix\` varchar(20) NULL COMMENT 'คำนำหน้าชื่อ เช่น นาย นาง นางสาว', \`firstName\` varchar(255) NULL COMMENT 'ชื่อ', \`lastName\` varchar(255) NULL COMMENT 'นามสกุล', \`isProbation\` tinyint NOT NULL COMMENT 'ทดลองปฏิบัติหน้าที่' DEFAULT 0, \`isLeave\` tinyint NOT NULL COMMENT 'พ้นราชการ' DEFAULT 0, \`isRetirement\` tinyint NOT NULL COMMENT 'เกษียณ' DEFAULT 0, \`leaveType\` varchar(255) NULL COMMENT 'ประเภทพ้นคำสั่งพ้นจากราชการ', \`posMasterNo\` varchar(255) NULL COMMENT 'เลขที่ตำแหน่ง เป็นตัวเลข', \`orgRootId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgRoot', \`orgChild1Id\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgChild1', \`orgChild2Id\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgChild2', \`orgChild3Id\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgChild3', \`orgChild4Id\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง orgChild4', \`orgRootName\` varchar(255) NULL COMMENT 'ชื่อหน่วยงาน', \`orgChild1Name\` varchar(255) NULL COMMENT 'ชื่อส่วนราชการ Child1', \`orgChild2Name\` varchar(255) NULL COMMENT 'ชื่อส่วนราชการ Child2', \`orgChild3Name\` varchar(255) NULL COMMENT 'ชื่อส่วนราชการ Child3', \`orgChild4Name\` varchar(255) NULL COMMENT 'ชื่อส่วนราชการ Child4', \`org\` varchar(255) NULL COMMENT 'สังกัด', \`searchShortName\` varchar(255) NULL COMMENT 'เลขที่ตำแหน่ง', \`posExecutiveName\` varchar(255) NULL COMMENT 'ชื่อตำแหน่งทางการบริหาร', \`position\` varchar(255) NULL COMMENT 'ชื่อตำแหน่งในสายงาน', \`posTypeName\` varchar(255) NULL COMMENT 'ประเภทตำแหน่ง', \`posLevelName\` varchar(255) NULL COMMENT 'ระดับตำแหน่ง', \`gender\` varchar(40) NULL COMMENT 'เพศ', \`relationship\` varchar(40) NULL COMMENT 'ความสัมพันธ์', \`dateAppoint\` datetime NULL COMMENT 'วันที่บรรจุ', \`dateRetire\` datetime NULL COMMENT 'วันครบเกษียณอายุ', \`dateRetireLaw\` datetime NULL COMMENT 'วันที่เกษียณอายุราชการตามกฏหมาย', \`birthdate\` datetime NULL COMMENT 'วันเกิด', \`degrees\` varchar(255) NULL COMMENT 'วุฒิการศึกษา', \`age\` int NULL COMMENT 'อายุ', \`Years\` int NULL COMMENT 'จำนวนปีระยะเวลาดำรงตำแหน่งในสายงาน', \`Months\` int NULL COMMENT 'จำนวนเดือนระยะเวลาดำรงตำแหน่งในสายงาน', \`Days\` int NULL COMMENT 'จำนวนวันระยะเวลาดำรงตำแหน่งในสายงาน', \`levelYears\` int NULL COMMENT 'จำนวนปีระยะเวลาดำรงตำแหน่งตามระดับ', \`levelMonths\` int NULL COMMENT 'จำนวนเดือนระยะเวลาดำรงตำแหน่งตามระดับ', \`levelDays\` int NULL COMMENT 'จำนวนวันระยะเวลาดำรงตำแหน่งตามระดับ', \`posExecutiveYears\` int NULL COMMENT 'จำนวนปีระยะเวลาดำรงตำแหน่งทางการบริหาร', \`posExecutiveMonths\` int NULL COMMENT 'จำนวนเดือนระยะเวลาดำรงตำแหน่งทางการบริหาร', \`posExecutiveDays\` int NULL COMMENT 'จำนวนวันระยะเวลาดำรงตำแหน่งทางการบริหาร', \`positionArea\` varchar(255) NULL COMMENT 'ด้าน/สาขา', \`Educations\` text NULL COMMENT 'วุฒิการศึกษา', \`educationLevels\` varchar(255) NULL COMMENT 'ระดับศึกษา', \`fields\` varchar(255) NULL COMMENT 'สาขาวิชา/ทาง', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE \`registry\``); + await queryRunner.query(`DROP TABLE \`registryEmployee\``); + } + +} diff --git a/src/migration/1756357065498-update_registry_fix_length_prefix.ts b/src/migration/1756357065498-update_registry_fix_length_prefix.ts new file mode 100644 index 00000000..564e3329 --- /dev/null +++ b/src/migration/1756357065498-update_registry_fix_length_prefix.ts @@ -0,0 +1,20 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class UpdateRegistryFixLengthPrefix1756357065498 implements MigrationInterface { + name = 'UpdateRegistryFixLengthPrefix1756357065498' + + public async up(queryRunner: QueryRunner): Promise { + 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 { + 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 'คำนำหน้าชื่อ เช่น นาย นาง นางสาว'`); + } + +} diff --git a/src/migration/1756364862810-update_registrymployere_add_field_employeeClass.ts b/src/migration/1756364862810-update_registrymployere_add_field_employeeClass.ts new file mode 100644 index 00000000..997ad8c5 --- /dev/null +++ b/src/migration/1756364862810-update_registrymployere_add_field_employeeClass.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class UpdateRegistrymployereAddFieldEmployeeClass1756364862810 implements MigrationInterface { + name = 'UpdateRegistrymployereAddFieldEmployeeClass1756364862810' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`registryEmployee\` ADD \`employeeClass\` varchar(40) NULL COMMENT 'ประเภทลูกจ้าง (perm->ลูกจ้างประจำ temp->ลูกจ้างชั่วคราว)'`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`registryEmployee\` DROP COLUMN \`employeeClass\``); + } + +} diff --git a/src/services/PositionService.ts b/src/services/PositionService.ts new file mode 100644 index 00000000..cbf842bb --- /dev/null +++ b/src/services/PositionService.ts @@ -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 { + 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 { + 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 { + 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; + } +} diff --git a/src/services/rabbitmq.ts b/src/services/rabbitmq.ts index 183a0e94..d55667a6 100644 --- a/src/services/rabbitmq.ts +++ b/src/services/rabbitmq.ts @@ -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 })) : []; + 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 subject: `${command.issue}`, body: `${command.issue}`, receiverUserIds: profilesSend, - payload: "", // แนบไฟล์ (ถ้าจำเป็น) + payload: payloadStr, // แนบไฟล์ (ถ้าจำเป็น) }, false, ) @@ -580,6 +581,7 @@ async function handler_org(msg: amqp.ConsumeMessage): Promise { 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