diff --git a/src/controllers/ProfileEmployeeController.ts b/src/controllers/ProfileEmployeeController.ts index b217b3b3..89b6644d 100644 --- a/src/controllers/ProfileEmployeeController.ts +++ b/src/controllers/ProfileEmployeeController.ts @@ -13,6 +13,7 @@ import { Response, Get, Query, + Example, } from "tsoa"; import { AppDataSource } from "../database/data-source"; import HttpSuccess from "../interfaces/http-success"; @@ -79,6 +80,7 @@ import { ProfileChangeName } from "../entities/ProfileChangeName"; import { ProfileChildren } from "../entities/ProfileChildren"; import { ProfileDuty } from "../entities/ProfileDuty"; import { getTopDegrees } from "../services/PositionService"; +import { ProfileLeaveService } from "../services/ProfileLeaveService"; @Route("api/v1/org/profile-employee") @Tags("ProfileEmployee") @Security("bearerAuth") @@ -131,6 +133,9 @@ export class ProfileEmployeeController extends Controller { private profileAbilityRepo = AppDataSource.getRepository(ProfileAbility); private profileAssistanceRepository = AppDataSource.getRepository(ProfileAssistance); + // Services + private profileLeaveService = new ProfileLeaveService(); + /** * report ประวัติแบบย่อ ลูกจ้าง * @@ -2629,6 +2634,29 @@ export class ProfileEmployeeController extends Controller { * */ @Get("profileLeave") + @Example({ + status: 200, + message: "สำเร็จ", + result: { + data: [ + { + page: 1, + pageSize: 12, + posLevel: "บ 1", + posType: "บริการพื้นฐาน", + isProbation: false, + isRetire: true, + node: 0, + nodeId: "8349b6b6-d005-4eb7-9960-ceb5b96e1962", + isAll: true, + sortBy: "profile.dateAppoint", + sort: "DESC", + retireType: "RETIRE_DECEASED", + }, + ], + total: 1, + }, + }) async listProfileLeave( @Request() request: RequestWithUser, @Query("page") page: number = 1, @@ -2638,443 +2666,31 @@ export class ProfileEmployeeController extends Controller { @Query() searchKeyword: string = "", @Query() posType?: string, @Query() posLevel?: string, - @Query() yearLeave?: number, @Query() isProbation?: boolean, - // @Query() isRetire?: boolean, - @Query() type?: string, @Query() node?: number, @Query() nodeId?: string, @Query() isAll?: boolean, @Query() retireType?: string, - @Query() sortBy: string = "current_holders.posMasterNo", - @Query() sort: "ASC" | "DESC" = "ASC", + @Query() sortBy: string = "profileEmployee.dateLeave", + @Query() sort: "ASC" | "DESC" = "DESC", ) { - let _data = await new permission().PermissionOrgList(request, "SYS_REGISTRY_EMP"); - let queryLike = - "CONCAT(profileEmployee.prefix, profileEmployee.firstName, ' ', profileEmployee.lastName) LIKE :keyword"; - if (searchField == "citizenId") { - queryLike = "profileEmployee.citizenId LIKE :keyword"; - } else if (searchField == "position") { - queryLike = "profileEmployee.position LIKE :keyword"; - } - // else if (searchField == "posNo") { - // queryLike = ` - // CASE - // WHEN current_holders.orgChild4Id IS NOT NULL THEN CONCAT(orgChild4.orgChild4ShortName, current_holders.posMasterNo) - // WHEN current_holders.orgChild3Id IS NOT NULL THEN CONCAT(orgChild3.orgChild3ShortName, current_holders.posMasterNo) - // WHEN current_holders.orgChild2Id IS NOT NULL THEN CONCAT(orgChild2.orgChild2ShortName, current_holders.posMasterNo) - // WHEN current_holders.orgChild1Id IS NOT NULL THEN CONCAT(orgChild1.orgChild1ShortName, current_holders.posMasterNo) - // ELSE CONCAT(orgRoot.orgRootShortName, current_holders.posMasterNo) - // END LIKE :keyword - // `; - // } - else if (searchField == "posNo") { - queryLike = ` - CONCAT(profileSalary.posNoAbb, profileSalary.posNo) LIKE :keyword - OR CONCAT(profileSalary.posNoAbb, " ", profileSalary.posNo) LIKE :keyword - OR profileSalary.posNo LIKE :keyword - `; - } - let nodeCondition = "1=1"; - let nodeAll = ""; - let orgRoot = null; - let orgChild1 = null; - let orgChild2 = null; - let orgChild3 = null; - let orgChild4 = null; + const { data, total } = await this.profileLeaveService.getLeaveEmployees(request, { + page, + pageSize, + searchField, + searchKeyword, + posType, + posLevel, + isProbation, + node, + nodeId, + isAll, + retireType, + sortBy, + sort, + }); - let pmsCondition = "1=1"; - let orgRootPms = null; - let orgChild1Pms = null; - let orgChild2Pms = null; - let orgChild3Pms = null; - let orgChild4Pms = null; - - if (node === 0 && nodeId) { - orgRoot = await this.orgRootRepository.findOne({ where: { id: nodeId } }); - if (orgRoot) { - nodeCondition = "profileSalary.orgRoot = :orgRoot"; - } - if (isAll == false) nodeAll = " AND profileSalary.orgChild1 IS NULL"; - } else if (node === 1 && nodeId) { - orgChild1 = await this.child1Repository.findOne({ where: { id: nodeId } }); - if (orgChild1) { - nodeCondition = "profileSalary.orgChild1 = :orgChild1"; - } - if (isAll == false) nodeAll = " AND profileSalary.orgChild2 IS NULL"; - } else if (node === 2 && nodeId) { - orgChild2 = await this.child2Repository.findOne({ where: { id: nodeId } }); - if (orgChild2) { - nodeCondition = "profileSalary.orgChild2 = :orgChild2"; - } - if (isAll == false) nodeAll = " AND profileSalary.orgChild3 IS NULL"; - } else if (node === 3 && nodeId) { - orgChild3 = await this.child3Repository.findOne({ where: { id: nodeId } }); - if (orgChild3) { - nodeCondition = "profileSalary.orgChild3 = :orgChild3"; - } - if (isAll == false) nodeAll = " AND profileSalary.orgChild4 IS NULL"; - } else if (node === 4 && nodeId) { - orgChild4 = await this.child4Repository.findOne({ where: { id: nodeId } }); - if (orgChild4) { - nodeCondition = "profileSalary.orgChild4 = :orgChild4"; - } - } - nodeCondition = nodeCondition + nodeAll; - - if (_data.root) { - orgRootPms = await this.orgRootRepository.findOne({ where: { id: _data.root } }); - if (orgRootPms) { - pmsCondition = "profileSalary.orgRoot = :orgRootPms"; - } - if (isAll == false) nodeAll = " AND profileSalary.orgChild1 IS NULL"; - } else if (_data.child1) { - orgChild1Pms = await this.child1Repository.findOne({ where: { id: _data.child1 } }); - if (orgChild1Pms) { - pmsCondition = "profileSalary.orgChild1 = :orgChild1Pms"; - } - if (isAll == false) nodeAll = " AND profileSalary.orgChild2 IS NULL"; - } else if (_data.child2) { - orgChild2Pms = await this.child2Repository.findOne({ where: { id: _data.child2 } }); - if (orgChild2Pms) { - pmsCondition = "profileSalary.orgChild2 = :orgChild2Pms"; - } - if (isAll == false) nodeAll = " AND profileSalary.orgChild3 IS NULL"; - } else if (_data.child3) { - orgChild3Pms = await this.child3Repository.findOne({ where: { id: _data.child3 } }); - if (orgChild3Pms) { - pmsCondition = "profileSalary.orgChild3 = :orgChild3Pms"; - } - if (isAll == false) nodeAll = " AND profileSalary.orgChild4 IS NULL"; - } else if (_data.child4) { - orgChild4Pms = await this.child4Repository.findOne({ where: { id: _data.child4 } }); - if (orgChild4Pms) { - pmsCondition = "profileSalary.orgChild4 = :orgChild4Pms"; - } - } - pmsCondition = pmsCondition + nodeAll; - // const findRevision = await this.orgRevisionRepo.findOne({ - // where: { orgRevisionIsCurrent: true }, - // }); - // if (!findRevision) { - // throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision"); - // } - const [record, total] = await this.profileRepo - .createQueryBuilder("profileEmployee") - .leftJoinAndSelect("profileEmployee.posLevel", "posLevel") - .leftJoinAndSelect("profileEmployee.posType", "posType") - // .leftJoinAndSelect("profileEmployee.current_holders", "current_holders") - .leftJoinAndSelect("profileEmployee.profileEmployeeEmployment", "profileEmployeeEmployment") - // .leftJoinAndSelect("current_holders.positions", "positions") - .leftJoinAndSelect("profileEmployee.profileSalary", "profileSalary") - // .leftJoinAndSelect("current_holders.orgRevision", "orgRevision") - // .leftJoinAndSelect("current_holders.orgRoot", "orgRoot") - // .leftJoinAndSelect("current_holders.orgChild1", "orgChild1") - // .leftJoinAndSelect("current_holders.orgChild2", "orgChild2") - // .leftJoinAndSelect("current_holders.orgChild3", "orgChild3") - // .leftJoinAndSelect("current_holders.orgChild4", "orgChild4") - // .where(node && nodeId ? "current_holders.orgRevisionId = :orgRevisionId" : "1=1", { - // orgRevisionId: node && nodeId ? findRevision.id : undefined, - // }) - .where( - new Brackets((qb) => { - qb.where("profileEmployee.isLeave = :isLeave", { isLeave: true }).orWhere( - "profileEmployee.isRetirement = :isRetirement", - { isRetirement: true }, - ); - }), - ) - // .andWhere("profileEmployee.leaveCommandId Is NOT NULL") - .andWhere( - "profileSalary.order = (SELECT MAX(ps.order) FROM profileSalary ps WHERE ps.profileEmployeeId = profileEmployee.id and ps.positionName != 'เกษียณอายุราชการ')", - ) - - // .andWhere( - // _data.root != undefined && _data.root != null - // ? _data.root[0] != null - // ? `current_holders.orgRootId IN (:...root)` - // : `current_holders.orgRootId is null` - // : "1=1", - // { - // root: _data.root, - // }, - // ) - // .andWhere( - // _data.child1 != undefined && _data.child1 != null - // ? _data.child1[0] != null - // ? `current_holders.orgChild1Id IN (:...child1)` - // : `current_holders.orgChild1Id is null` - // : "1=1", - // { - // child1: _data.child1, - // }, - // ) - // .andWhere( - // _data.child2 != undefined && _data.child2 != null - // ? _data.child2[0] != null - // ? `current_holders.orgChild2Id IN (:...child2)` - // : `current_holders.orgChild2Id is null` - // : "1=1", - // { - // child2: _data.child2, - // }, - // ) - // .andWhere( - // _data.child3 != undefined && _data.child3 != null - // ? _data.child3[0] != null - // ? `current_holders.orgChild3Id IN (:...child3)` - // : `current_holders.orgChild3Id is null` - // : "1=1", - // { - // child3: _data.child3, - // }, - // ) - // .andWhere( - // _data.child4 != undefined && _data.child4 != null - // ? _data.child4[0] != null - // ? `current_holders.orgChild4Id IN (:...child4)` - // : `current_holders.orgChild4Id is null` - // : "1=1", - // { - // child4: _data.child4, - // }, - // ) - .andWhere( - posType != undefined && posType != null && posType != "" - ? "posType.posTypeName LIKE :keyword1" - : "1=1", - { - keyword1: `${posType}`, - }, - ) - .andWhere( - posLevel != undefined && posLevel != null && posLevel != "" - ? `CONCAT(posType.posTypeShortName,' ',posLevel.posLevelName) LIKE :keyword2` - : "1=1", - { - keyword2: `${posLevel}`, - }, - ) - .andWhere( - isProbation != undefined && isProbation != null - ? `profileEmployee.isProbation = ${isProbation}` - : "1=1", - ) - .andWhere( - retireType != undefined && retireType != null - ? `profileEmployee.leaveType = :retireType` - : "1=1", - { retireType: retireType }, - ) - .andWhere("profileEmployee.employeeClass LIKE :type", { - type: "PERM", - }) - .andWhere( - searchKeyword != undefined && searchKeyword != null && searchKeyword != "" - ? queryLike - : "1=1", - { - keyword: `%${searchKeyword}%`, - }, - ) - .andWhere(pmsCondition, { - orgRootPms: orgRootPms ? orgRootPms.orgRootName : "", - orgChild1Pms: orgChild1Pms ? orgChild1Pms.orgChild1Name : "", - orgChild2Pms: orgChild2Pms ? orgChild2Pms.orgChild2Name : "", - orgChild3Pms: orgChild3Pms ? orgChild3Pms.orgChild3Name : "", - orgChild4Pms: orgChild4Pms ? orgChild4Pms.orgChild4Name : "", - }) - - .andWhere(nodeCondition, { - orgRoot: orgRoot ? orgRoot.orgRootName : "", - orgChild1: orgChild1 ? orgChild1.orgChild1Name : "", - orgChild2: orgChild2 ? orgChild2.orgChild2Name : "", - orgChild3: orgChild3 ? orgChild3.orgChild3Name : "", - orgChild4: orgChild4 ? orgChild4.orgChild4Name : "", - }) - // .andWhere(`current_holders.orgRevisionId LIKE :orgRevisionId`, { - // orgRevisionId: findRevision.id, - // }) - // .orderBy("current_holders.posMasterNo", "ASC") - // .orderBy(`${sortBy}`, sort) - .skip((page - 1) * pageSize) - .take(pageSize) - .getManyAndCount(); - const data = await Promise.all( - record.map((_data) => { - // const shortName = - // _data.current_holders.length == 0 - // ? null - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4 != - // null - // ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4.orgChild4ShortName}${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) - // ?.orgChild3 != null - // ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3.orgChild3ShortName}${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) - // ?.orgChild2 != null - // ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild2.orgChild2ShortName}${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) - // ?.orgChild1 != null - // ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild1.orgChild1ShortName}${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != - // null && - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) - // ?.orgRoot != null - // ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot.orgRootShortName}${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` - // : null; - const dateEmployment = - _data.profileEmployeeEmployment.length == 0 - ? null - : _data.profileEmployeeEmployment.reduce((latest, current) => { - return latest.date > current.date ? latest : current; - }).date; - // const root = - // _data.current_holders.length == 0 || - // (_data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot == null) - // ? null - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot; - - // const child1 = - // _data.current_holders == null || - // _data.current_holders.length == 0 || - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null - // ? null - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild1; - - // const child2 = - // _data.current_holders == null || - // _data.current_holders.length == 0 || - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null - // ? null - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild2; - - // const child3 = - // _data.current_holders == null || - // _data.current_holders.length == 0 || - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null - // ? null - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3; - - // const child4 = - // _data.current_holders == null || - // _data.current_holders.length == 0 || - // _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null - // ? null - // : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4; - - // let _child1 = child1?.orgChild1Name; - // let _child2 = child2?.orgChild2Name; - // let _child3 = child3?.orgChild3Name; - // let _child4 = child4?.orgChild4Name; - return { - id: _data.id, - avatar: _data.avatar, - avatarName: _data.avatarName, - prefix: _data.prefix, - rank: _data.rank, - firstName: _data.firstName, - lastName: _data.lastName, - citizenId: _data.citizenId, - posLevel: _data.posLevel == null ? null : _data.posLevel.posLevelName, - posType: _data.posType == null ? null : _data.posType.posTypeName, - posTypeShortName: _data.posType == null ? null : _data.posType.posTypeShortName, - posLevelId: _data.posLevel == null ? null : _data.posLevel.id, - posTypeId: _data.posType == null ? null : _data.posType.id, - positionId: _data.positionIdTemp, - posmasterId: _data.posmasterIdTemp, - position: _data.position, - posNo: - _data.profileSalary[0].posNoAbb && _data.profileSalary[0].posNo - ? `${_data.profileSalary[0].posNoAbb} ${_data.profileSalary[0].posNo}` - : _data.profileSalary[0].posNo || "", - employeeClass: _data.employeeClass == null ? null : _data.employeeClass, - govAge: Extension.CalculateGovAge(_data.dateAppoint, 0, 0), - age: Extension.CalculateAgeStrV2(_data.birthDate, 0, 0, "GET"), - dateEmployment: dateEmployment, - dateAppoint: _data.dateAppoint, - dateStart: _data.dateStart, - createdAt: _data.createdAt, - dateRetireLaw: _data.dateRetireLaw, - draftOrganizationOrganization: - _data.nodeTemp == "0" - ? _data.rootTemp - : _data.nodeTemp == "1" - ? _data.child1Temp - : _data.nodeTemp == "2" - ? _data.child2Temp - : _data.nodeTemp == "3" - ? _data.child3Temp - : _data.nodeTemp == "4" - ? _data.child4Temp - : null, - draftPositionEmployee: _data.positionTemp, - draftOrgEmployeeStatus: _data.statusTemp, - node: _data.nodeTemp, - nodeId: _data.nodeIdTemp, - nodeName: - _data.nodeTemp == "0" - ? _data.rootTemp - : _data.nodeTemp == "1" - ? _data.child1Temp - : _data.nodeTemp == "2" - ? _data.child2Temp - : _data.nodeTemp == "3" - ? _data.child3Temp - : _data.nodeTemp == "4" - ? _data.child4Temp - : null, - nodeShortName: - _data.nodeTemp == "0" - ? _data.rootShortNameTemp - : _data.nodeTemp == "1" - ? _data.child1ShortNameTemp - : _data.nodeTemp == "2" - ? _data.child1ShortNameTemp - : _data.nodeTemp == "3" - ? _data.child3ShortNameTemp - : _data.nodeTemp == "4" - ? _data.child4ShortNameTemp - : null, - root: _data.rootTemp ? _data.rootTemp : null, - rootId: _data.rootIdTemp ? _data.rootIdTemp : null, - rootShortName: _data.rootShortNameTemp ? _data.rootShortNameTemp : null, - child1: _data.child1Temp ? _data.child1Temp : null, - child1Id: _data.child1IdTemp ? _data.child1IdTemp : null, - child1ShortName: _data.child1ShortNameTemp ? _data.child1ShortNameTemp : null, - child2: _data.child2Temp ? _data.child2Temp : null, - child2Id: _data.child2IdTemp ? _data.child2IdTemp : null, - child2ShortName: _data.child2ShortNameTemp ? _data.child2ShortNameTemp : null, - child3: _data.child3Temp ? _data.child3Temp : null, - child3Id: _data.child3IdTemp ? _data.child3IdTemp : null, - child3ShortName: _data.child3ShortNameTemp ? _data.child3ShortNameTemp : null, - child4: _data.child4Temp ? _data.child4Temp : null, - child4Id: _data.child4IdTemp ? _data.child4IdTemp : null, - child4ShortName: _data.child4ShortNameTemp ? _data.child4ShortNameTemp : null, - org: - (_data.profileSalary[0].orgChild4 == null - ? "" - : _data.profileSalary[0].orgChild4 + "\n") + - (_data.profileSalary[0].orgChild3 == null - ? "" - : _data.profileSalary[0].orgChild3 + "\n") + - (_data.profileSalary[0].orgChild2 == null - ? "" - : _data.profileSalary[0].orgChild2 + "\n") + - (_data.profileSalary[0].orgChild1 == null - ? "" - : _data.profileSalary[0].orgChild1 + "\n") + - (_data.profileSalary[0].orgRoot == null ? "" : _data.profileSalary[0].orgRoot), - }; - }), - ); - - return new HttpSuccess({ data: data, total }); + return new HttpSuccess({ data, total }); } /** @@ -3137,15 +2753,13 @@ export class ProfileEmployeeController extends Controller { @Query() searchKeyword: string = "", @Query() posType?: string, @Query() posLevel?: string, - @Query() yearLeave?: number, @Query() isProbation?: boolean, @Query() isRetire?: boolean, - @Query() type?: string, @Query() node?: number, @Query() nodeId?: string, @Query() isAll?: boolean, @Query() retireType?: string, - @Query() sortBy: string = "current_holders.posMasterNo", + @Query() sortBy?: string, @Query() sort: "ASC" | "DESC" = "ASC", ) { let _data = await new permission().PermissionOrgList(request, "SYS_REGISTRY_EMP"); @@ -3300,13 +2914,8 @@ export class ProfileEmployeeController extends Controller { .andWhere(nodeCondition, { nodeId: nodeId, }) - // .andWhere(`current_holders.orgRevisionId LIKE :orgRevisionId`, { - // orgRevisionId: findRevision.id, - // }) - // .orderBy("current_holders.posMasterNo", "ASC") - // .orderBy(`${sortBy}`, sort) .addSelect("CASE WHEN current_holders.posMasterNo IS NULL THEN 1 ELSE 0 END", "sort_order") - .orderBy("sort_order", "ASC") + .orderBy(`${sortBy ? sortBy : "sort_order"}`, `${sort}`) .addOrderBy("orgRoot.orgRootOrder", sort) .addOrderBy("orgChild1.orgChild1Order", sort) .addOrderBy("orgChild2.orgChild2Order", sort) @@ -5123,34 +4732,28 @@ export class ProfileEmployeeController extends Controller { }, ); }), - ) + ); if (body.sortBy) { - if(body.sortBy === "posType"){ - query = query.orderBy( - `posType.posTypeName`, - body.descending ? "DESC" : "ASC" - ); - }else if(body.sortBy === "posLevel"){ + if (body.sortBy === "posType") { + query = query.orderBy(`posType.posTypeName`, body.descending ? "DESC" : "ASC"); + } else if (body.sortBy === "posLevel") { query = query - .orderBy(`posType.posTypeShortName`,body.descending ? "DESC" : "ASC") - .addOrderBy(`posLevel.posLevelName`,body.descending ? "DESC" : "ASC"); - }else if(body.sortBy === "orgShortName" || body.sortBy === "posMasterNo"){ + .orderBy(`posType.posTypeShortName`, body.descending ? "DESC" : "ASC") + .addOrderBy(`posLevel.posLevelName`, body.descending ? "DESC" : "ASC"); + } else if (body.sortBy === "orgShortName" || body.sortBy === "posMasterNo") { query = query - .orderBy(`orgRoot.orgRootShortName`,body.descending ? "DESC" : "ASC") - .addOrderBy(`orgChild1.orgChild1ShortName`,body.descending ? "DESC" : "ASC") - .addOrderBy(`orgChild2.orgChild2ShortName`,body.descending ? "DESC" : "ASC") - .addOrderBy(`orgChild3.orgChild3ShortName`,body.descending ? "DESC" : "ASC") - .addOrderBy(`orgChild4.orgChild4ShortName`,body.descending ? "DESC" : "ASC") - .addOrderBy(`employeePosMaster.posMasterNo`,body.descending ? "DESC" : "ASC") - }else{ - query = query.orderBy( - `current_holder.${body.sortBy}`, - body.descending ? "DESC" : "ASC" - ); + .orderBy(`orgRoot.orgRootShortName`, body.descending ? "DESC" : "ASC") + .addOrderBy(`orgChild1.orgChild1ShortName`, body.descending ? "DESC" : "ASC") + .addOrderBy(`orgChild2.orgChild2ShortName`, body.descending ? "DESC" : "ASC") + .addOrderBy(`orgChild3.orgChild3ShortName`, body.descending ? "DESC" : "ASC") + .addOrderBy(`orgChild4.orgChild4ShortName`, body.descending ? "DESC" : "ASC") + .addOrderBy(`employeePosMaster.posMasterNo`, body.descending ? "DESC" : "ASC"); + } else { + query = query.orderBy(`current_holder.${body.sortBy}`, body.descending ? "DESC" : "ASC"); } - }else{ - query = query.orderBy("current_holder.citizenId", "ASC") + } else { + query = query.orderBy("current_holder.citizenId", "ASC"); } const [findPosMaster, total] = await query diff --git a/src/services/ProfileLeaveService.ts b/src/services/ProfileLeaveService.ts new file mode 100644 index 00000000..f187675d --- /dev/null +++ b/src/services/ProfileLeaveService.ts @@ -0,0 +1,433 @@ +import { AppDataSource } from "../database/data-source"; +import { ProfileEmployee } from "../entities/ProfileEmployee"; +import { OrgRoot } from "../entities/OrgRoot"; +import { OrgChild1 } from "../entities/OrgChild1"; +import { OrgChild2 } from "../entities/OrgChild2"; +import { OrgChild3 } from "../entities/OrgChild3"; +import { OrgChild4 } from "../entities/OrgChild4"; +import { Brackets, Repository } from "typeorm"; +import Extension from "../interfaces/extension"; +import permission from "../interfaces/permission"; +import { RequestWithUser } from "../middlewares/user"; + +export interface LeaveEmployeeFilter { + page: number; + pageSize: number; + searchField?: "firstName" | "lastName" | "fullName" | "citizenId" | "position" | "posNo"; + searchKeyword?: string; + posType?: string; + posLevel?: string; + isProbation?: boolean; + node?: number; + nodeId?: string; + isAll?: boolean; + retireType?: string; + sortBy?: string; + sort: "ASC" | "DESC"; +} + +export interface OrganizationCondition { + condition: string; + params: Record; +} + +export class ProfileLeaveService { + private profileRepo: Repository; + private orgRootRepository: Repository; + private child1Repository: Repository; + private child2Repository: Repository; + private child3Repository: Repository; + private child4Repository: Repository; + + constructor() { + this.profileRepo = AppDataSource.getRepository(ProfileEmployee); + this.orgRootRepository = AppDataSource.getRepository(OrgRoot); + this.child1Repository = AppDataSource.getRepository(OrgChild1); + this.child2Repository = AppDataSource.getRepository(OrgChild2); + this.child3Repository = AppDataSource.getRepository(OrgChild3); + this.child4Repository = AppDataSource.getRepository(OrgChild4); + } + + /** + * สร้าง query สำหรับการค้นหาตามฟิลด์ต่างๆ + */ + buildSearchQuery(searchField?: string): string { + switch (searchField) { + case "citizenId": + return "profileEmployee.citizenId LIKE :keyword"; + case "position": + return "profileEmployee.position LIKE :keyword"; + case "posNo": + return ` + (profileSalary.posNoAbb IS NOT NULL AND CONCAT(profileSalary.posNoAbb, profileSalary.posNo) LIKE :keyword) + OR (profileSalary.posNoAbb IS NOT NULL AND CONCAT(profileSalary.posNoAbb, " ", profileSalary.posNo) LIKE :keyword) + OR (profileSalary.posNo IS NOT NULL AND profileSalary.posNo LIKE :keyword) + `; + default: + return "CONCAT(profileEmployee.prefix, profileEmployee.firstName, ' ', profileEmployee.lastName) LIKE :keyword"; + } + } + + /** + * สร้างเงื่อนไขการค้นหาตาม node และ nodeId + */ + async buildNodeCondition( + node?: number, + nodeId?: string, + isAll?: boolean, + ): Promise { + let condition = "1=1"; + let nodeAll = ""; + const params: Record = {}; + + if (!node || !nodeId) { + return { condition, params }; + } + + // สร้าง nodeAll condition - เพิ่มการตรวจสอบ IS NULL + if (isAll === false && node < 4) { + const nextLevels = ["orgChild1", "orgChild2", "orgChild3", "orgChild4"]; + nodeAll = ` AND (profileSalary.${nextLevels[node]} IS NULL OR profileSalary.id IS NULL)`; + } + + try { + switch (node) { + case 0: { + const orgRoot = await this.orgRootRepository.findOne({ where: { id: nodeId } }); + if (orgRoot) { + condition = "(profileSalary.orgRoot = :orgRoot OR profileSalary.id IS NULL)"; + params.orgRoot = orgRoot.orgRootName; + } + break; + } + case 1: { + const orgChild1 = await this.child1Repository.findOne({ where: { id: nodeId } }); + if (orgChild1) { + condition = "(profileSalary.orgChild1 = :orgChild1 OR profileSalary.id IS NULL)"; + params.orgChild1 = orgChild1.orgChild1Name; + } + break; + } + case 2: { + const orgChild2 = await this.child2Repository.findOne({ where: { id: nodeId } }); + if (orgChild2) { + condition = "(profileSalary.orgChild2 = :orgChild2 OR profileSalary.id IS NULL)"; + params.orgChild2 = orgChild2.orgChild2Name; + } + break; + } + case 3: { + const orgChild3 = await this.child3Repository.findOne({ where: { id: nodeId } }); + if (orgChild3) { + condition = "(profileSalary.orgChild3 = :orgChild3 OR profileSalary.id IS NULL)"; + params.orgChild3 = orgChild3.orgChild3Name; + } + break; + } + case 4: { + const orgChild4 = await this.child4Repository.findOne({ where: { id: nodeId } }); + if (orgChild4) { + condition = "(profileSalary.orgChild4 = :orgChild4 OR profileSalary.id IS NULL)"; + params.orgChild4 = orgChild4.orgChild4Name; + } + break; + } + } + } catch (error) { + console.error("Error building node condition:", error); + } + + return { condition: condition + nodeAll, params }; + } + + /** + * สร้างเงื่อนไขการค้นหาตาม permission + */ + async buildPermissionCondition( + request: RequestWithUser, + isAll?: boolean, + ): Promise { + const _data = await new permission().PermissionOrgList(request, "SYS_REGISTRY_EMP"); + let condition = "1=1"; + let nodeAll = ""; + const params: Record = {}; + + try { + if (_data.root) { + const orgRootPms = await this.orgRootRepository.findOne({ where: { id: _data.root } }); + if (orgRootPms) { + condition = "(profileSalary.orgRoot = :orgRootPms OR profileSalary.id IS NULL)"; + params.orgRootPms = orgRootPms.orgRootName; + } + if (isAll === false) + nodeAll = " AND (profileSalary.orgChild1 IS NULL OR profileSalary.id IS NULL)"; + } else if (_data.child1) { + const orgChild1Pms = await this.child1Repository.findOne({ where: { id: _data.child1 } }); + if (orgChild1Pms) { + condition = "(profileSalary.orgChild1 = :orgChild1Pms OR profileSalary.id IS NULL)"; + params.orgChild1Pms = orgChild1Pms.orgChild1Name; + } + if (isAll === false) + nodeAll = " AND (profileSalary.orgChild2 IS NULL OR profileSalary.id IS NULL)"; + } else if (_data.child2) { + const orgChild2Pms = await this.child2Repository.findOne({ where: { id: _data.child2 } }); + if (orgChild2Pms) { + condition = "(profileSalary.orgChild2 = :orgChild2Pms OR profileSalary.id IS NULL)"; + params.orgChild2Pms = orgChild2Pms.orgChild2Name; + } + if (isAll === false) + nodeAll = " AND (profileSalary.orgChild3 IS NULL OR profileSalary.id IS NULL)"; + } else if (_data.child3) { + const orgChild3Pms = await this.child3Repository.findOne({ where: { id: _data.child3 } }); + if (orgChild3Pms) { + condition = "(profileSalary.orgChild3 = :orgChild3Pms OR profileSalary.id IS NULL)"; + params.orgChild3Pms = orgChild3Pms.orgChild3Name; + } + if (isAll === false) + nodeAll = " AND (profileSalary.orgChild4 IS NULL OR profileSalary.id IS NULL)"; + } else if (_data.child4) { + const orgChild4Pms = await this.child4Repository.findOne({ where: { id: _data.child4 } }); + if (orgChild4Pms) { + condition = "(profileSalary.orgChild4 = :orgChild4Pms OR profileSalary.id IS NULL)"; + params.orgChild4Pms = orgChild4Pms.orgChild4Name; + } + } + } catch (error) { + console.error("Error building permission condition:", error); + } + + return { condition: condition + nodeAll, params }; + } + + /** + * แปลงข้อมูลพนักงานเป็น format ที่ต้องการ + */ + transformEmployeeData(employee: ProfileEmployee): any { + const dateEmployment = + employee.profileEmployeeEmployment?.length === 0 || !employee.profileEmployeeEmployment + ? null + : employee.profileEmployeeEmployment.reduce((latest, current) => { + return latest.date > current.date ? latest : current; + }).date; + + // ตรวจสอบว่า profileSalary มีข้อมูลหรือไม่ + const salary = + employee.profileSalary && employee.profileSalary.length > 0 + ? employee.profileSalary[0] + : null; + + const posNo = + salary?.posNoAbb && salary?.posNo + ? `${salary.posNoAbb} ${salary.posNo}` + : salary?.posNo || ""; + + // สร้าง organization hierarchy - ใช้ข้อมูลจาก temp fields ถ้า salary ไม่มี + const org = salary + ? [salary.orgChild4, salary.orgChild3, salary.orgChild2, salary.orgChild1, salary.orgRoot] + .filter(Boolean) + .join("\n") + : [ + employee.child4Temp, + employee.child3Temp, + employee.child2Temp, + employee.child1Temp, + employee.rootTemp, + ] + .filter(Boolean) + .join("\n"); + + // สร้าง node information + const getNodeInfo = (nodeTemp: string) => { + switch (nodeTemp) { + case "0": + return { + name: employee.rootTemp, + shortName: employee.rootShortNameTemp, + }; + case "1": + return { + name: employee.child1Temp, + shortName: employee.child1ShortNameTemp, + }; + case "2": + return { + name: employee.child2Temp, + shortName: employee.child2ShortNameTemp, + }; + case "3": + return { + name: employee.child3Temp, + shortName: employee.child3ShortNameTemp, + }; + case "4": + return { + name: employee.child4Temp, + shortName: employee.child4ShortNameTemp, + }; + default: + return { name: null, shortName: null }; + } + }; + + const nodeInfo = getNodeInfo(employee.nodeTemp || "0"); + + return { + id: employee.id, + avatar: employee.avatar, + avatarName: employee.avatarName, + prefix: employee.prefix, + rank: employee.rank, + firstName: employee.firstName, + lastName: employee.lastName, + citizenId: employee.citizenId, + posLevel: employee.posLevel?.posLevelName || null, + posType: employee.posType?.posTypeName || null, + posTypeShortName: employee.posType?.posTypeShortName || null, + posLevelId: employee.posLevel?.id || null, + posTypeId: employee.posType?.id || null, + positionId: employee.positionIdTemp, + posmasterId: employee.posmasterIdTemp, + position: employee.position, + posNo, + employeeClass: employee.employeeClass, + govAge: Extension.CalculateGovAge(employee.dateAppoint, 0, 0), + age: Extension.CalculateAgeStrV2(employee.birthDate, 0, 0, "GET"), + dateEmployment, + dateAppoint: employee.dateAppoint, + dateStart: employee.dateStart, + createdAt: employee.createdAt, + dateRetireLaw: employee.dateRetireLaw, + draftOrganizationOrganization: nodeInfo.name, + draftPositionEmployee: employee.positionTemp, + draftOrgEmployeeStatus: employee.statusTemp, + node: employee.nodeTemp, + nodeId: employee.nodeIdTemp, + nodeName: nodeInfo.name, + nodeShortName: nodeInfo.shortName, + root: employee.rootTemp || null, + rootId: employee.rootIdTemp || null, + rootShortName: employee.rootShortNameTemp || null, + child1: employee.child1Temp || null, + child1Id: employee.child1IdTemp || null, + child1ShortName: employee.child1ShortNameTemp || null, + child2: employee.child2Temp || null, + child2Id: employee.child2IdTemp || null, + child2ShortName: employee.child2ShortNameTemp || null, + child3: employee.child3Temp || null, + child3Id: employee.child3IdTemp || null, + child3ShortName: employee.child3ShortNameTemp || null, + child4: employee.child4Temp || null, + child4Id: employee.child4IdTemp || null, + child4ShortName: employee.child4ShortNameTemp || null, + org, + }; + } + + /** + * ค้นหาพนักงานที่พ้นจากราชการ + */ + async getLeaveEmployees( + request: RequestWithUser, + filter: LeaveEmployeeFilter, + ): Promise<{ data: any[]; total: number }> { + const { + page, + pageSize, + searchField, + searchKeyword = "", + posType, + posLevel, + isProbation, + node, + nodeId, + isAll, + retireType, + sortBy = "profileEmployee.dateLeave", + sort, + } = filter; + + // สร้าง query conditions แบบ parallel + const [nodeCondition, permissionCondition] = await Promise.all([ + this.buildNodeCondition(node, nodeId, isAll), + this.buildPermissionCondition(request, isAll), + ]); + + const searchQuery = this.buildSearchQuery(searchField); + + // สร้าง main query - เปลี่ยนจาก leftJoinAndSelect เป็น leftJoin สำหรับ profileSalary + const queryBuilder = this.profileRepo + .createQueryBuilder("profileEmployee") + .leftJoinAndSelect("profileEmployee.posLevel", "posLevel") + .leftJoinAndSelect("profileEmployee.posType", "posType") + .leftJoinAndSelect("profileEmployee.profileEmployeeEmployment", "profileEmployeeEmployment") + .leftJoin( + "profileEmployee.profileSalary", + "profileSalary", + "profileSalary.order = (SELECT MAX(ps.order) FROM profileSalary ps WHERE ps.profileEmployeeId = profileEmployee.id and ps.positionName != 'เกษียณอายุราชการ')", + ) + .addSelect([ + "profileSalary.id", + "profileSalary.order", + "profileSalary.posNo", + "profileSalary.posNoAbb", + "profileSalary.orgRoot", + "profileSalary.orgChild1", + "profileSalary.orgChild2", + "profileSalary.orgChild3", + "profileSalary.orgChild4", + ]) + .where( + new Brackets((qb) => { + qb.where("profileEmployee.isLeave = :isLeave", { isLeave: true }).orWhere( + "profileEmployee.isRetirement = :isRetirement", + { isRetirement: true }, + ); + }), + ) + .andWhere("profileEmployee.employeeClass LIKE :type", { type: "PERM" }); + + // เพิ่มเงื่อนไขการค้นหา + if (posType) { + queryBuilder.andWhere("posType.posTypeName LIKE :keyword1", { keyword1: `${posType}` }); + } + + if (posLevel) { + queryBuilder.andWhere( + "CONCAT(posType.posTypeShortName,' ',posLevel.posLevelName) LIKE :keyword2", + { keyword2: `${posLevel}` }, + ); + } + + if (isProbation !== undefined && isProbation !== null) { + queryBuilder.andWhere(`profileEmployee.isProbation = ${isProbation}`); + } + + if (retireType) { + queryBuilder.andWhere("profileEmployee.leaveType = :retireType", { retireType }); + } + + if (searchKeyword) { + queryBuilder.andWhere(searchQuery, { keyword: `%${searchKeyword}%` }); + } + + // เพิ่ม permission และ node conditions + queryBuilder + .andWhere(permissionCondition.condition, permissionCondition.params) + .andWhere(nodeCondition.condition, nodeCondition.params); + + // เพิ่ม sorting และ pagination + queryBuilder + .orderBy(sortBy, sort) + .skip((page - 1) * pageSize) + .take(pageSize); + + const [records, total] = await queryBuilder.getManyAndCount(); + + // แปลงข้อมูลแบบ parallel + const data = await Promise.all( + records.map((record) => Promise.resolve(this.transformEmployeeData(record))), + ); + + return { data, total }; + } +}