import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Route,
  Security,
  Tags,
  Body,
  Path,
  Request,
  Example,
  Response,
  Query,
} from "tsoa";
import { AppDataSource } from "../database/data-source";
import HttpSuccess from "../interfaces/http-success";
import HttpStatusCode from "../interfaces/http-status";
import { PosExecutive } from "../entities/PosExecutive";
import { PosType } from "../entities/PosType";
import { PosLevel } from "../entities/PosLevel";
import { CreatePosDict, CreatePosDictExe, PosDict, UpdatePosDict } from "../entities/PosDict";
import HttpError from "../interfaces/http-error";
import { In, IsNull, Like, Not, Brackets } from "typeorm";
import { CreatePosMaster, PosMaster } from "../entities/PosMaster";
import { OrgRevision } from "../entities/OrgRevision";
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 { Position } from "../entities/Position";
import { Profile } from "../entities/Profile";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
import { EmployeePosType } from "../entities/EmployeePosType";
import { EmployeePosLevel } from "../entities/EmployeePosLevel";
import { AuthRole } from "../entities/AuthRole";
import { RequestWithUser } from "../middlewares/user";
import permission from "../interfaces/permission";
import { resolveNodeLevel, setLogDataDiff, logPositionIsSelectedChange } from "../interfaces/utils";
import { getPosMasterNo, getOrgFullName } from "../utils/org-formatting";
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";
import { KeycloakAttributeService } from "../services/KeycloakAttributeService";
@Route("api/v1/org/pos")
@Tags("Position")
@Security("bearerAuth")
@Response(
  HttpStatusCode.INTERNAL_SERVER_ERROR,
  "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class PositionController extends Controller {
  private posExecutiveRepository = AppDataSource.getRepository(PosExecutive);
  private posTypeRepository = AppDataSource.getRepository(PosType);
  private posLevelRepository = AppDataSource.getRepository(PosLevel);
  private posTypeEmployeeRepository = AppDataSource.getRepository(EmployeePosType);
  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);
  private profileEmployeeRepository = AppDataSource.getRepository(ProfileEmployee);
  private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
  private orgRootRepository = AppDataSource.getRepository(OrgRoot);
  private child1Repository = AppDataSource.getRepository(OrgChild1);
  private child2Repository = AppDataSource.getRepository(OrgChild2);
  private child3Repository = AppDataSource.getRepository(OrgChild3);
  private child4Repository = AppDataSource.getRepository(OrgChild4);
  private authRoleRepo = AppDataSource.getRepository(AuthRole);
  private posMasterAssignRepo = AppDataSource.getRepository(PosMasterAssign);
  private assignRepo = AppDataSource.getRepository(Assign);
  private keycloakAttributeService = new KeycloakAttributeService();

  /**
   * API เพิ่มตำแหน่ง
   *
   * @summary ORG_030 - เพิ่มตำแหน่ง (ADMIN) #33
   *
   */
  @Post("position")
  @Example([
    {
      positionName: "นักบริหาร",
      positionField: "บริหาร",
      posTypeId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      posLevelId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      posExecutiveId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      positionExecutiveField: "นักบริหาร",
      positionArea: "บริหาร",
    },
  ])
  async createPosition(
    @Body()
    requestBody: CreatePosDict,
    @Request() request: RequestWithUser,
  ) {
    // await new permission().PermissionCreate(request, "SYS_ORG");
    const posDict = Object.assign(new PosDict(), requestBody);
    if (!posDict) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }

    const checkPosTypeId = await this.posTypeRepository.findOne({
      where: { id: posDict.posTypeId },
    });
    if (!checkPosTypeId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่ง");
    }

    const checkPosLevelId = await this.posLevelRepository.findOne({
      where: { id: posDict.posLevelId },
    });
    if (!checkPosLevelId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosLevelId");
    }
    const _null: any = null;
    if (posDict.posExecutiveId == "") {
      posDict.posExecutiveId = _null;
    }

    if (posDict.posExecutiveId != null) {
      const checkPosExecutiveId = await this.posExecutiveRepository.findOne({
        where: { id: posDict.posExecutiveId },
      });
      if (!checkPosExecutiveId) {
        throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosExecutiveId");
      }
    }

    const rowRepeated = await this.posDictRepository.findOne({
      where: {
        posDictName: posDict.posDictName,
        posDictField: posDict.posDictField,
        posTypeId: posDict.posTypeId,
        posLevelId: posDict.posLevelId,
        posExecutiveId: String(posDict.posExecutiveId),
        posDictExecutiveField: posDict.posDictExecutiveField,
        posDictArea: posDict.posDictArea,
        isSpecial: posDict.isSpecial,
      },
    });
    if (rowRepeated) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ข้อมูล Row นี้มีอยู่ในระบบแล้ว");
    }
    const before = null;
    posDict.createdUserId = request.user.sub;
    posDict.createdFullName = request.user.name;
    posDict.lastUpdateUserId = request.user.sub;
    posDict.lastUpdateFullName = request.user.name;
    posDict.createdAt = new Date();
    posDict.lastUpdatedAt = new Date();
    await this.posDictRepository.save(posDict, { data: request });
    setLogDataDiff(request, { before, after: posDict });
    return new HttpSuccess(posDict.id);
  }

  /**
   * API มอบหมาย
   *
   * @summary มอบหมาย
   *
   */
  @Post("assign")
  async createPositionMasterAssgin(
    @Body()
    requestBody: {
      assignIds: string[];
      posMasterId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    const posMaster = await this.posMasterRepository.findOne({
      where: { id: requestBody.posMasterId },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");
    }
    await this.posMasterAssignRepo.delete({ posMasterId: posMaster.id });

    const assigns = await this.assignRepo.find({
      where: { id: In(requestBody.assignIds) },
    });
    await Promise.all(
      await assigns.map(async (x) => {
        let _posMasterAssign = await this.posMasterAssignRepo.findOne({
          where: { posMasterId: requestBody.posMasterId, assignId: x.id },
        });
        if (_posMasterAssign == null) {
          const posMasterAssign = new PosMasterAssign();
          posMasterAssign.posMasterId = requestBody.posMasterId;
          posMasterAssign.assignId = x.id;
          posMasterAssign.createdUserId = request.user.sub;
          posMasterAssign.createdFullName = request.user.name;
          posMasterAssign.lastUpdateUserId = request.user.sub;
          posMasterAssign.lastUpdateFullName = request.user.name;
          posMasterAssign.createdAt = new Date();
          posMasterAssign.lastUpdatedAt = new Date();
          await this.posMasterAssignRepo.save(posMasterAssign);
        }
      }),
    );
    return new HttpSuccess();
  }

  /**
   * API ลบมอบหมาย
   *
   * @summary ลบมอบหมาย
   *
   * @param {string} id  Id posMaster
   */
  @Delete("assign/{id}")
  async deletePositionMasterAssgin(@Path() id: string, @Request() request: RequestWithUser) {
    const posMaster = await this.posMasterRepository.findOne({
      where: { id: id },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");
    }
    const posMasterAssigns = await this.posMasterAssignRepo.find({
      where: { posMasterId: posMaster.id },
    });
    if (posMasterAssigns.length > 0) {
      await this.posMasterAssignRepo.remove(posMasterAssigns, { data: request });
    }
    // await this.posMasterAssignRepo.delete({ posMasterId: posMaster.id });
    return new HttpSuccess();
  }

  /**
   * API เพิ่มตำแหน่ง
   *
   * @summary ORG_030 - เพิ่มตำแหน่ง (ADMIN) #33
   *
   */
  @Post("position/executive")
  @Example([
    {
      positionName: "นักบริหาร",
      positionField: "บริหาร",
      posTypeId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      posLevelId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      posExecutiveId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      positionExecutiveField: "นักบริหาร",
      positionArea: "บริหาร",
    },
  ])
  async createPositionNameExe(
    @Body()
    requestBody: CreatePosDictExe,
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionCreate(request, "SYS_ORG");
    // let posDict: PosDict;
    let posDict: any = new PosDict();
    posDict.posDictName = requestBody.posDictName;
    posDict.posDictField = requestBody.posDictField;
    posDict.posTypeId = requestBody.posTypeId;
    posDict.posLevelId = requestBody.posLevelId;
    posDict.posDictExecutiveField = requestBody.posDictExecutiveField;
    posDict.posDictArea = requestBody.posDictArea;
    posDict.isSpecial = requestBody.isSpecial;

    const checkPosTypeId = await this.posTypeRepository.findOne({
      where: { id: posDict.posTypeId },
    });
    if (!checkPosTypeId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่ง");
    }

    const checkPosLevelId = await this.posLevelRepository.findOne({
      where: { id: posDict.posLevelId },
    });
    if (!checkPosLevelId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosLevelId");
    }

    const before = null;
    let posExecutive: any = new PosExecutive();
    if (requestBody.posExecutive != null && requestBody.posExecutive != "") {
      const checkName = await this.posExecutiveRepository.findOne({
        where: { posExecutiveName: requestBody.posExecutive },
      });

      if (checkName) {
        throw new HttpError(HttpStatusCode.NOT_FOUND, "ชื่อนี้มีอยู่ในระบบแล้ว");
      }
      posExecutive.posExecutiveName = requestBody.posExecutive;
      const checkPriority = await this.posExecutiveRepository.findOne({
        select: ["posExecutivePriority"],
        where: {
          posExecutivePriority: Not(IsNull()),
        },
        order: { posExecutivePriority: "DESC" },
      });
      if (checkPriority == null) {
        posExecutive.posExecutivePriority = 1;
      } else {
        posExecutive.posExecutivePriority = checkPriority.posExecutivePriority + 1;
      }

      posExecutive.createdUserId = request.user.sub;
      posExecutive.createdFullName = request.user.name;
      posExecutive.lastUpdateUserId = request.user.sub;
      posExecutive.lastUpdateFullName = request.user.name;
      posExecutive.createdAt = new Date();
      posExecutive.lastUpdatedAt = new Date();
      await this.posExecutiveRepository.save(posExecutive, { data: request });
      setLogDataDiff(request, { before, after: posExecutive });
    }

    const rowRepeated = await this.posDictRepository.findOne({
      where: {
        posDictName: posDict.posDictName,
        posDictField: posDict.posDictField,
        posTypeId: posDict.posTypeId,
        posLevelId: posDict.posLevelId,
        posExecutiveId: posExecutive == null ? null : posExecutive.id,
        posDictExecutiveField: posDict.posDictExecutiveField,
        posDictArea: posDict.posDictArea,
        isSpecial: posDict.isSpecial,
      },
    });
    if (rowRepeated) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ข้อมูล Row นี้มีอยู่ในระบบแล้ว");
    }

    posDict.posExecutiveId = posExecutive == null ? null : posExecutive.id;
    posDict.createdUserId = request.user.sub;
    posDict.createdFullName = request.user.name;
    posDict.lastUpdateUserId = request.user.sub;
    posDict.lastUpdateFullName = request.user.name;
    posDict.createdAt = new Date();
    posDict.lastUpdatedAt = new Date();
    await this.posDictRepository.save(posDict, { data: request });
    setLogDataDiff(request, { before, after: posDict });
    return new HttpSuccess(posDict.id);
  }

  /**
   * API ค้นหารายการตำแหน่ง
   *
   * @summary ORG_029 - ค้นหารายการตำแหน่ง (ADMIN) #32
   *
   */
  @Post("position/search")
  async findPositionSearch(
    @Body()
    requestBody: {
      posLevel: string;
      posType: string;
    },
  ) {
    let findPosDict = await this.posDictRepository.find({
      relations: ["posType", "posLevel"],
      where: {
        posTypeId: requestBody.posType,
        posLevelId: requestBody.posLevel,
      },
      order: {
        posDictName: "ASC",
        createdAt: "DESC",
        posType: {
          posTypeRank: "ASC",
          createdAt: "DESC",
        },
        posLevel: {
          posLevelRank: "ASC",
          createdAt: "DESC",
        },
      },
    });

    const mapDataPosDict = await Promise.all(
      findPosDict.map(async (item: any) => {
        return {
          id: item.id,
          positionName: item.posDictName,
          positionField: item.posDictField,
          posTypeId: item.posTypeId,
          posTypeName: item.posType == null ? null : item.posType.posTypeName,
          posLevelId: item.posLevelId,
          posLevelName: item.posLevel == null ? null : item.posLevel.posLevelName,
          positionExecutiveField: item.posDictExecutiveField,
          positionArea: item.posDictArea,
          isSpecial: item.isSpecial,
          positionIsSelected: false,
          createdAt: item.createdAt,
          lastUpdatedAt: item.lastUpdatedAt,
          lastUpdateFullName: item.lastUpdateFullName,
        };
      }),
    );

    return new HttpSuccess(mapDataPosDict);
  }

  /**
   * API แก้ไขตำแหน่ง
   *
   * @summary แก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Put("position/executive/{id}")
  @Example([
    {
      positionName: "นักบริหาร",
      positionField: "บริหาร",
      posTypeId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      posLevelId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      posExecutiveId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      positionExecutiveField: "นักบริหาร",
      positionArea: "บริหาร",
    },
  ])
  async updatePositionExecutive(
    @Path() id: string,
    @Body()
    requestBody: UpdatePosDict,
    @Request() request: RequestWithUser,
  ) {
    // await new permission().PermissionUpdate(request, "SYS_ORG");
    const posDict = await this.posDictRepository.findOne({
      where: { id: id },
    });
    if (!posDict) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }

    const checkPosTypeId = await this.posTypeRepository.findOne({
      where: { id: requestBody.posTypeId },
    });
    if (!checkPosTypeId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosTypeId");
    }

    const checkPosLevelId = await this.posLevelRepository.findOne({
      where: { id: requestBody.posLevelId },
    });
    if (!checkPosLevelId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosLevelId");
    }

    const _null: any = null;
    if (requestBody.posExecutiveId == "") {
      requestBody.posExecutiveId = _null;
    }

    if (requestBody.posExecutiveId != null && requestBody.posExecutiveId != "") {
      const checkPosExecutiveId = await this.posExecutiveRepository.findOne({
        where: { id: requestBody.posExecutiveId },
      });
      if (!checkPosExecutiveId) {
        throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosExecutiveId");
      }
    }

    const rowRepeated = await this.posDictRepository.findOne({
      where: {
        id: Not(id),
        posDictName: requestBody.posDictName,
        posDictField: requestBody.posDictField,
        posTypeId: requestBody.posTypeId,
        posLevelId: requestBody.posLevelId,
        posExecutiveId: requestBody.posExecutiveId ? requestBody.posExecutiveId : "",
        posDictExecutiveField: requestBody.posDictExecutiveField
          ? requestBody.posDictExecutiveField
          : "",
        posDictArea: requestBody.posDictArea ? requestBody.posDictArea : "",
        isSpecial: requestBody.isSpecial,
      },
    });
    if (rowRepeated) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ข้อมูล Row นี้มีอยู่ในระบบแล้ว");
    }
    const before = structuredClone(posDict);
    Object.assign(posDict, requestBody);
    posDict.lastUpdateUserId = request.user.sub;
    posDict.lastUpdateFullName = request.user.name;
    posDict.lastUpdatedAt = new Date();
    posDict.posDictName = requestBody.posDictName;
    posDict.posDictField = requestBody.posDictField;
    posDict.posTypeId = requestBody.posTypeId;
    posDict.posLevelId = requestBody.posLevelId;
    posDict.posExecutiveId = requestBody.posExecutiveId ? requestBody.posExecutiveId : null;
    posDict.posDictExecutiveField = requestBody.posDictExecutiveField
      ? requestBody.posDictExecutiveField
      : "";
    posDict.posDictArea = requestBody.posDictArea ? requestBody.posDictArea : "";
    posDict.isSpecial = requestBody.isSpecial;
    // this.posDictRepository.merge(posDict, requestBody);
    await this.posDictRepository.save(posDict, { data: request });
    setLogDataDiff(request, { before, after: posDict });
    return new HttpSuccess();
  }

  /**
   * API แก้ไขตำแหน่ง
   *
   * @summary แก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Put("position/{id}")
  @Example([
    {
      positionName: "นักบริหาร",
      positionField: "บริหาร",
      posTypeId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      posLevelId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      posExecutiveId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
      positionExecutiveField: "นักบริหาร",
      positionArea: "บริหาร",
    },
  ])
  async updatePosition(
    @Path() id: string,
    @Body()
    requestBody: UpdatePosDict,
    @Request() request: RequestWithUser,
  ) {
    // await new permission().PermissionUpdate(request, "SYS_ORG");
    const posDict = await this.posDictRepository.findOne({
      where: { id: id },
    });
    if (!posDict) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }

    const checkPosTypeId = await this.posTypeRepository.findOne({
      where: { id: requestBody.posTypeId },
    });
    if (!checkPosTypeId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosTypeId");
    }

    const checkPosLevelId = await this.posLevelRepository.findOne({
      where: { id: requestBody.posLevelId },
    });
    if (!checkPosLevelId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosLevelId");
    }

    const _null: any = null;
    if (requestBody.posExecutiveId == "") {
      requestBody.posExecutiveId = _null;
    }

    if (requestBody.posExecutiveId != null && requestBody.posExecutiveId != "") {
      const checkPosExecutiveId = await this.posExecutiveRepository.findOne({
        where: { id: requestBody.posExecutiveId },
      });
      if (!checkPosExecutiveId) {
        throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล PosExecutiveId");
      }
    }

    const rowRepeated = await this.posDictRepository.findOne({
      where: {
        id: Not(id),
        posDictName: requestBody.posDictName,
        posDictField: requestBody.posDictField,
        posTypeId: requestBody.posTypeId,
        posLevelId: requestBody.posLevelId,
        posExecutiveId: requestBody.posExecutiveId ? requestBody.posExecutiveId : "",
        posDictExecutiveField: requestBody.posDictExecutiveField
          ? requestBody.posDictExecutiveField
          : "",
        posDictArea: requestBody.posDictArea ? requestBody.posDictArea : "",
        isSpecial: requestBody.isSpecial,
      },
    });
    if (rowRepeated) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ข้อมูล Row นี้มีอยู่ในระบบแล้ว");
    }
    const before = structuredClone(posDict);
    Object.assign(posDict, requestBody);
    posDict.lastUpdateUserId = request.user.sub;
    posDict.lastUpdateFullName = request.user.name;
    posDict.lastUpdatedAt = new Date();
    posDict.posDictName = requestBody.posDictName;
    posDict.posDictField = requestBody.posDictField;
    posDict.posTypeId = requestBody.posTypeId;
    posDict.posLevelId = requestBody.posLevelId;
    posDict.posExecutiveId = requestBody.posExecutiveId ? requestBody.posExecutiveId : null;
    posDict.posDictExecutiveField = requestBody.posDictExecutiveField
      ? requestBody.posDictExecutiveField
      : "";
    posDict.posDictArea = requestBody.posDictArea ? requestBody.posDictArea : "";
    posDict.isSpecial = requestBody.isSpecial;
    // this.posDictRepository.merge(posDict, requestBody);
    await this.posDictRepository.save(posDict, { data: request });
    setLogDataDiff(request, { before, after: posDict });
    return new HttpSuccess();
  }

  /**
   * API ลบตำแหน่ง
   *
   * @summary ORG_032 - ลบตำแหน่ง (ADMIN) #40
   *
   * @param {string} id  Id ตำแหน่ง
   */
  @Delete("position/{id}")
  async delete(@Path() id: string, @Request() request: RequestWithUser) {
    // await new permission().PermissionDelete(request, "SYS_ORG");
    const delPosDict = await this.posDictRepository.findOne({ where: { id } });
    if (!delPosDict) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งในสายงานนี้");
    }
    await this.posDictRepository.remove(delPosDict, { data: request });
    return new HttpSuccess();
  }

  /**
   * API ค้นหารายการตำแหน่ง
   *
   * @summary ORG_029 - ค้นหารายการตำแหน่ง (ADMIN) #32
   *
   */
  @Get("position")
  async findPosition(@Query("keyword") keyword?: string, @Query("type") type?: string) {
    let findPosDict: any;
    if (keyword && keyword?.length > 0) {
      switch (type) {
        case "positionName":
          findPosDict = await this.posDictRepository.find({
            where: { posDictName: keyword && keyword.length > 0 ? Like(`%${keyword}%`) : "1=1" },
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictName: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;

        case "positionField":
          findPosDict = await this.posDictRepository.find({
            where: { posDictField: keyword && keyword.length > 0 ? Like(`%${keyword}%`) : "1=1" },
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictField: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;

        case "positionType":
          const findTypes: PosType[] = await this.posTypeRepository.find({
            where: { posTypeName: keyword && keyword.length > 0 ? Like(`%${keyword}%`) : "1=1" },
            order: {
              // posTypeName: "ASC"
              posTypeRank: "ASC",
              createdAt: "DESC",
            },
            select: ["id"],
          });
          findPosDict = await this.posDictRepository.find({
            where: { posTypeId: In(findTypes.map((x) => x.id)) },
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictName: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;

        case "positionLevel":
          const findLevel: PosLevel[] = await this.posLevelRepository.find({
            where: { posLevelName: keyword && keyword.length > 0 ? Like(`%${keyword}%`) : "1=1" },
            order: {
              // posLevelName: "ASC"
              posLevelRank: "ASC",
              createdAt: "DESC",
            },
            select: ["id"],
          });
          findPosDict = await this.posDictRepository.find({
            where: { posLevelId: In(findLevel.map((x) => x.id)) },
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictName: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;

        case "positionExecutive":
          const findExecutive: PosExecutive[] = await this.posExecutiveRepository.find({
            where: {
              posExecutiveName: keyword && keyword.length > 0 ? Like(`%${keyword}%`) : "1=1",
            },
            select: ["id"],
          });
          findPosDict = await this.posDictRepository.find({
            where: { posExecutiveId: In(findExecutive.map((x) => x.id)) },
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictName: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;

        case "positionExecutiveField":
          findPosDict = await this.posDictRepository.find({
            where: {
              posDictExecutiveField: keyword && keyword.length > 0 ? Like(`%${keyword}%`) : "1=1",
            },
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictName: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;

        case "positionArea":
          findPosDict = await this.posDictRepository.find({
            where: { posDictArea: keyword && keyword.length > 0 ? Like(`%${keyword}%`) : "1=1" },
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictName: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;

        case "ALL":
          findPosDict = await this.posDictRepository.find({
            where: [
              { posDictName: Like(`%${keyword}%`) },
              { posDictField: Like(`%${keyword}%`) },
              {
                posTypeId: In(
                  await this.posTypeRepository
                    .find({ where: { posTypeName: Like(`%${keyword}%`) }, select: ["id"] })
                    .then((types) => types.map((type) => type.id)),
                ),
              },
              {
                posLevelId: In(
                  await this.posLevelRepository
                    .find({ where: { posLevelName: Like(`%${keyword}%`) }, select: ["id"] })
                    .then((levels) => levels.map((level) => level.id)),
                ),
              },
              {
                posExecutiveId: In(
                  await this.posExecutiveRepository
                    .find({ where: { posExecutiveName: Like(`%${keyword}%`) }, select: ["id"] })
                    .then((executives) => executives.map((exec) => exec.id)),
                ),
              },
              { posDictExecutiveField: Like(`%${keyword}%`) },
              { posDictArea: Like(`%${keyword}%`) },
            ],
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictName: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;

        default:
          findPosDict = await this.posDictRepository.find({
            relations: ["posType", "posLevel", "posExecutive"],
            order: {
              posDictName: "ASC",
              createdAt: "DESC",
              posType: {
                posTypeRank: "ASC",
                createdAt: "DESC",
              },
              posLevel: {
                posLevelRank: "ASC",
                createdAt: "DESC",
              },
              posExecutive: {
                posExecutivePriority: "ASC",
              },
            },
          });
          break;
      }
    } else {
      findPosDict = await this.posDictRepository.find({
        relations: ["posType", "posLevel", "posExecutive"],
        order: {
          posDictName: "ASC",
          createdAt: "DESC",
          posType: {
            posTypeRank: "ASC",
            createdAt: "DESC",
          },
          posLevel: {
            posLevelRank: "ASC",
            createdAt: "DESC",
          },
          posExecutive: {
            posExecutivePriority: "ASC",
          },
        },
      });
    }

    const mapDataPosDict = await Promise.all(
      findPosDict.map(async (item: any) => {
        return {
          id: item.id,
          positionName: item.posDictName,
          positionField: item.posDictField,
          posTypeId: item.posTypeId,
          posTypeName: item.posType == null ? null : item.posType.posTypeName,
          posLevelId: item.posLevelId,
          posLevelName: item.posLevel == null ? null : item.posLevel.posLevelName,
          posExecutiveId: item.posExecutiveId,
          posExecutiveName: item.posExecutive == null ? null : item.posExecutive.posExecutiveName,
          positionExecutiveField: item.posDictExecutiveField,
          positionArea: item.posDictArea,
          isSpecial: item.isSpecial,
          positionIsSelected: false,
          createdAt: item.createdAt,
          lastUpdatedAt: item.lastUpdatedAt,
          lastUpdateFullName: item.lastUpdateFullName,
        };
      }),
    );

    return new HttpSuccess(mapDataPosDict);
  }

  /**
   * API เพิ่มอัตรากำลัง
   *
   * @summary ORG_033 - เพิ่มอัตรากำลัง (ADMIN) #35
   *
   */
  @Post("master")
  @Example({
    posMasterNoPrefix: "กบ.",
    posMasterNo: 1,
    posMasterNoSuffix: "ช",
    posId: ["08db9e81-fc46-4e95-8b33-be4ca0016abf", "08db9e81-fc46-4e95-8b33-be4ca0016abf"],
    orgRootId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    orgChild1Id: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    orgChild2Id: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    orgChild3Id: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    orgChild4Id: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    reason: "บริหาร",
    positions: [
      {
        posDictName: "นักบริหาร",
        posDictField: "บริหาร",
        posTypeId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
        posLevelId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
        posExecutiveId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
        posDictExecutiveField: "นักบริหาร",
        posDictArea: "บริหาร",
      },
    ],
  })
  async createMaster(
    @Body()
    requestBody: CreatePosMaster,
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionCreate(request, "SYS_ORG");
    const posMaster = Object.assign(new PosMaster(), requestBody);
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }
    let orgRoot: any = null;
    let SName: any = null;
    let revisionId: any = null;
    if (requestBody.orgRootId != null)
      orgRoot = await this.orgRootRepository.findOne({
        where: { id: requestBody.orgRootId },
      });
    revisionId = orgRoot?.orgRevisionId;
    if (!orgRoot) {
      let orgChild1: any = null;
      if (requestBody.orgChild1Id != null)
        orgChild1 = await this.child1Repository.findOne({
          where: { id: requestBody.orgChild1Id },
        });
      revisionId = orgChild1?.orgRevisionId;
      if (!orgChild1) {
        let orgChild2: any = null;
        if (requestBody.orgChild2Id != null)
          orgChild2 = await this.child2Repository.findOne({
            where: { id: requestBody.orgChild2Id },
          });
        revisionId = orgChild2?.orgRevisionId;
        if (!orgChild2) {
          let orgChild3: any = null;
          if (requestBody.orgChild3Id != null)
            orgChild3 = await this.child3Repository.findOne({
              where: { id: requestBody.orgChild3Id },
            });
          revisionId = orgChild3?.orgRevisionId;
          if (!orgChild3) {
            let orgChild4: any = null;
            if (requestBody.orgChild4Id != null)
              orgChild4 = await this.child4Repository.findOne({
                where: { id: requestBody.orgChild4Id },
              });
            revisionId = orgChild4?.orgRevisionId;
            if (!orgChild4) {
              throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้าง");
            } else {
              const order: any = await this.posMasterRepository.findOne({
                where: {
                  orgChild4Id: orgChild4.id,
                },
                order: { posMasterOrder: "DESC" },
              });
              posMaster.posMasterOrder =
                order !== null && order !== undefined && order.posMasterOrder
                  ? order.posMasterOrder + 1
                  : 1;
              posMaster.orgRootId = orgChild4.orgRootId;
              posMaster.orgChild1Id = orgChild4.orgChild1Id;
              posMaster.orgChild2Id = orgChild4.orgChild2Id;
              posMaster.orgChild3Id = orgChild4.orgChild3Id;
              posMaster.orgChild4Id = orgChild4.id;
              posMaster.orgRevisionId = orgChild4.orgRevisionId;
              SName = orgChild4.orgChild4ShortName;
            }
          } else {
            const order: any = await this.posMasterRepository.findOne({
              where: {
                orgChild3Id: orgChild3.id,
                orgChild4Id: IsNull() || "",
              },
              order: { posMasterOrder: "DESC" },
            });
            posMaster.posMasterOrder =
              order !== null && order !== undefined && order.posMasterOrder
                ? order.posMasterOrder + 1
                : 1;
            posMaster.orgRootId = orgChild3.orgRootId;
            posMaster.orgChild1Id = orgChild3.orgChild1Id;
            posMaster.orgChild2Id = orgChild3.orgChild2Id;
            posMaster.orgChild3Id = orgChild3.id;
            posMaster.orgRevisionId = orgChild3.orgRevisionId;
            SName = orgChild3.orgChild3ShortName;
          }
        } else {
          const order: any = await this.posMasterRepository.findOne({
            where: {
              orgChild2Id: orgChild2.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
            },
            order: { posMasterOrder: "DESC" },
          });
          posMaster.posMasterOrder =
            order !== null && order !== undefined && order.posMasterOrder
              ? order.posMasterOrder + 1
              : 1;
          posMaster.orgRootId = orgChild2.orgRootId;
          posMaster.orgChild1Id = orgChild2.orgChild1Id;
          posMaster.orgChild2Id = orgChild2.id;
          posMaster.orgRevisionId = orgChild2.orgRevisionId;
          SName = orgChild2.orgChild2ShortName;
        }
      } else {
        const order: any = await this.posMasterRepository.findOne({
          where: {
            orgChild1Id: orgChild1.id,
            orgChild2Id: IsNull() || "",
            orgChild3Id: IsNull() || "",
            orgChild4Id: IsNull() || "",
          },
          order: { posMasterOrder: "DESC" },
        });
        posMaster.posMasterOrder =
          order !== null && order !== undefined && order.posMasterOrder
            ? order.posMasterOrder + 1
            : 1;
        posMaster.orgRootId = orgChild1.orgRootId;
        posMaster.orgChild1Id = orgChild1.id;
        posMaster.orgRevisionId = orgChild1.orgRevisionId;
        SName = orgChild1.orgChild1ShortName;
      }
    } else {
      const order: any = await this.posMasterRepository.findOne({
        where: {
          orgRootId: orgRoot.id,
          orgChild1Id: IsNull() || "",
          orgChild2Id: IsNull() || "",
          orgChild3Id: IsNull() || "",
          orgChild4Id: IsNull() || "",
        },
        order: { posMasterOrder: "DESC" },
      });
      posMaster.posMasterOrder =
        order !== null && order !== undefined && order.posMasterOrder
          ? order.posMasterOrder + 1
          : 1;
      posMaster.orgRootId = orgRoot.id;
      posMaster.orgRevisionId = orgRoot.orgRevisionId;
      SName = orgRoot.orgRootShortName;
    }
    const chk_SName0 = await this.posMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgRoot: { orgRootShortName: SName },
        orgChild1Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgRoot"],
    });
    if (chk_SName0 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }
    const chk_SName1 = await this.posMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild1: { orgChild1ShortName: SName },
        orgChild2Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgChild1"],
    });
    if (chk_SName1 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }
    const chk_SName2 = await this.posMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild2: { orgChild2ShortName: SName },
        orgChild3Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgChild2"],
    });
    if (chk_SName2 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }
    const chk_SName3 = await this.posMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild3: { orgChild3ShortName: SName },
        orgChild4Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgChild3"],
    });
    if (chk_SName3 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }
    const chk_SName4 = await this.posMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild4: { orgChild4ShortName: SName },
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgChild4"],
    });
    if (chk_SName4 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }
    const before = null;
    let chkRevision: any = null;
    if (revisionId) {
      chkRevision = await this.orgRevisionRepository.findOne({
        where: { id: revisionId },
      });
    }
    posMaster.createdUserId = request.user.sub;
    posMaster.createdFullName = request.user.name;
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.createdAt = new Date();
    posMaster.lastUpdatedAt = new Date();
    const saved = await this.posMasterRepository.save(posMaster, { data: request });

    // รอบสอง set ancestorDNA = id ที่เพิ่งได้มา
    // if (chkRevision?.orgRevisionIsCurrent) { //ปิดเพื่อให้โครงสร้างปัจจุบันและแบบร่างเอาตัวเองเป็น dna เมื่อสร้างใหม่
    saved.ancestorDNA = saved.id;
    await this.posMasterRepository.save(saved, { data: request });
    // }

    setLogDataDiff(request, { before, after: posMaster });
    await Promise.all(
      requestBody.positions.map(async (x: any) => {
        const position = Object.assign(new Position());
        position.orderNo = x.orderNo;
        position.positionName = x.posDictName;
        position.positionField = x.posDictField;
        position.posTypeId = x.posTypeId == "" ? null : x.posTypeId;
        position.posLevelId = x.posLevelId == "" ? null : x.posLevelId;
        position.posExecutiveId = x.posExecutiveId == "" ? null : x.posExecutiveId;
        position.positionExecutiveField = x.posDictExecutiveField;
        position.positionArea = x.posDictArea;
        position.isSpecial = x.isSpecial;
        position.positionIsSelected = false;
        position.posMasterId = posMaster.id;
        position.createdUserId = request.user.sub;
        position.createdFullName = request.user.name;
        position.lastUpdateUserId = request.user.sub;
        position.lastUpdateFullName = request.user.name;
        position.createdAt = new Date();
        position.lastUpdatedAt = new Date();
        await this.positionRepository.save(position, { data: request });
      }),
    );
    return new HttpSuccess(posMaster.id);
  }

  /**
   * API แก้ไขเลขที่ตำแหน่ง
   *
   * @summary ORG_034 - แก้ไขเลขที่ตำแหน่ง (ADMIN) #37
   *
   */
  @Put("master/{id}")
  @Example({
    posMasterNoPrefix: "กบ.",
    posMasterNo: "1",
    posMasterNoSuffix: "ช",
    posId: ["08db9e81-fc46-4e95-8b33-be4ca0016abf", "08db9e81-fc46-4e95-8b33-be4ca0016abf"],
    orgRootId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    orgChild1Id: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    orgChild2Id: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    orgChild3Id: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    orgChild4Id: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
    reason: "บริหาร",
    positions: [
      {
        posDictName: "นักบริหาร",
        posDictField: "บริหาร",
        posTypeId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
        posLevelId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
        posExecutiveId: "08db9e81-fc46-4e95-8b33-be4ca0016abf",
        posDictExecutiveField: "นักบริหาร",
        posDictArea: "บริหาร",
      },
    ],
  })
  async updateMaster(
    @Path() id: string,
    @Body()
    requestBody: CreatePosMaster,
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG");
    const posMaster = await this.posMasterRepository.findOne({
      relations: [
        "positions",
        "orgRevision",
        "orgRoot",
        "orgChild1",
        "orgChild2",
        "orgChild3",
        "orgChild4",
      ],
      where: { id: id },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลอัตรากำลัง");
    }
    let _null: any = null;
    posMaster.isDirector = requestBody.isDirector;
    posMaster.isStaff =
      requestBody.isStaff == null || requestBody.isStaff == undefined ? _null : requestBody.isStaff;
    // posMaster.isOfficer = requestBody.isOfficer;
    posMaster.positionSign =
      requestBody.positionSign == null || requestBody.positionSign == undefined
        ? _null
        : requestBody.positionSign;
    posMaster.posMasterNo = requestBody.posMasterNo;
    posMaster.posMasterNoPrefix = requestBody.posMasterNoPrefix ?? _null;
    posMaster.posMasterNoSuffix = requestBody.posMasterNoSuffix ?? _null;
    posMaster.reason = requestBody.reason == null ? "" : requestBody.reason;

    let orgRoot: any = null;
    let SName: any = null;
    if (requestBody.orgRootId != null)
      orgRoot = await this.orgRootRepository.findOne({
        where: { id: requestBody.orgRootId },
      });
    if (!orgRoot) {
      let orgChild1: any = null;
      if (requestBody.orgChild1Id != null)
        orgChild1 = await this.child1Repository.findOne({
          where: { id: requestBody.orgChild1Id },
        });
      if (!orgChild1) {
        let orgChild2: any = null;
        if (requestBody.orgChild2Id != null)
          orgChild2 = await this.child2Repository.findOne({
            where: { id: requestBody.orgChild2Id },
          });
        if (!orgChild2) {
          let orgChild3: any = null;
          if (requestBody.orgChild3Id != null)
            orgChild3 = await this.child3Repository.findOne({
              where: { id: requestBody.orgChild3Id },
            });
          if (!orgChild3) {
            let orgChild4: any = null;
            if (requestBody.orgChild4Id != null)
              orgChild4 = await this.child4Repository.findOne({
                where: { id: requestBody.orgChild4Id },
              });
            if (!orgChild4) {
              throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้าง");
            } else {
              SName = orgChild4.orgChild4ShortName;
            }
          } else {
            SName = orgChild3.orgChild3ShortName;
          }
        } else {
          SName = orgChild2.orgChild2ShortName;
        }
      } else {
        SName = orgChild1.orgChild1ShortName;
      }
    } else {
      SName = orgRoot.orgRootShortName;
    }

    // if (posMaster.orgChild4Id != null) {
    const chk_SName4 = await this.posMasterRepository.findOne({
      where: {
        orgChild4: { orgChild4ShortName: SName },
        posMasterNo: requestBody.posMasterNo,
        id: Not(posMaster.id),
        orgRevisionId: posMaster.orgRevisionId,
      },
    });
    if (chk_SName4 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถแก้ไขชื่อตำแหน่งซ้ำกับข้อมูลที่มีอยู่แล้วได้",
      );
    }
    // } else if (posMaster.orgChild3Id != null) {
    const chk_SName3 = await this.posMasterRepository.findOne({
      where: {
        orgChild3: { orgChild3ShortName: SName },
        posMasterNo: requestBody.posMasterNo,
        orgChild4Id: IsNull(),
        id: Not(posMaster.id),
        orgRevisionId: posMaster.orgRevisionId,
      },
    });
    if (chk_SName3 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถแก้ไขชื่อตำแหน่งซ้ำกับข้อมูลที่มีอยู่แล้วได้",
      );
    }
    // } else if (posMaster.orgChild2Id != null) {
    const chk_SName2 = await this.posMasterRepository.findOne({
      where: {
        orgChild2: { orgChild2ShortName: SName },
        posMasterNo: requestBody.posMasterNo,
        orgChild3Id: IsNull(),
        id: Not(posMaster.id),
        orgRevisionId: posMaster.orgRevisionId,
      },
    });
    if (chk_SName2 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถแก้ไขชื่อตำแหน่งซ้ำกับข้อมูลที่มีอยู่แล้วได้",
      );
    }
    // } else if (posMaster.orgChild1Id != null) {
    const chk_SName1 = await this.posMasterRepository.findOne({
      where: {
        orgChild1: { orgChild1ShortName: SName },
        posMasterNo: requestBody.posMasterNo,
        orgChild2Id: IsNull(),
        id: Not(posMaster.id),
        orgRevisionId: posMaster.orgRevisionId,
      },
    });
    if (chk_SName1 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถแก้ไขชื่อตำแหน่งซ้ำกับข้อมูลที่มีอยู่แล้วได้",
      );
    }
    // } else if (posMaster.orgRootId != null) {
    const chk_SName0 = await this.posMasterRepository.findOne({
      where: {
        orgRoot: { orgRootShortName: SName },
        posMasterNo: requestBody.posMasterNo,
        orgChild1Id: IsNull(),
        id: Not(posMaster.id),
        orgRevisionId: posMaster.orgRevisionId,
      },
    });
    if (chk_SName0 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถแก้ไขชื่อตำแหน่งซ้ำกับข้อมูลที่มีอยู่แล้วได้",
      );
    }
    // }
    const before = structuredClone(posMaster);
    posMaster.createdUserId = request.user.sub;
    posMaster.createdFullName = request.user.name;
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.createdAt = new Date();
    posMaster.lastUpdatedAt = new Date();
    await this.posMasterRepository.save(posMaster, { data: request });
    setLogDataDiff(request, { before, after: posMaster });

    const result = await Promise.all(
      requestBody.positions.map(async (x: any) => {
        const match = posMaster.positions.find((p: any) => p.id == x.id);
        if (match) {
          const oldValue = match.positionIsSelected;
          const newValue = x.positionIsSelected ?? false;

          logPositionIsSelectedChange(match.id, oldValue, newValue, {
            posMasterId: posMaster.id,
            userId: request.user.sub,
            endpoint: "updateMaster",
            action: "update_position",
          });

          match.positionIsSelected = newValue;
          match.orderNo = x.orderNo ?? null;
          return match;
        } else {
          x.id = x.id ?? undefined;
          x.posMasterId = posMaster.id;
          x.orderNo = x.orderNo ?? null;
          x.positionName = x.posDictName;
          x.positionField = x.posDictField;
          x.posExecutiveId = x.posExecutiveId || null;
          x.positionExecutiveField = x.posDictExecutiveField;
          x.positionArea = x.posDictArea;
          x.createdUserId = request.user.sub;
          x.createdFullName = request.user.name;
          x.lastUpdateUserId = request.user.sub;
          x.lastUpdateFullName = request.user.name;
          x.createdAt = new Date();
          x.lastUpdatedAt = new Date();
          return x;
        }
      }),
    );
    await this.positionRepository.save(result, { data: request });
    await Promise.all(
      posMaster.positions.map(async (x: any) => {
        const match = requestBody.positions.find((p: any) => p.id == x.id);
        if (!match) {
          //delete
          await this.positionRepository.remove(x);
        }
      }),
    );

    // อัพเดท org และ posMasterNo ตลอดไม่ต้องดัก isSit
    if (posMaster.orgRevision?.orgRevisionIsCurrent == true && posMaster.current_holderId) {
      const _profile = await this.profileRepository.findOne({
        where: { id: posMaster.current_holderId },
      });
      if (_profile) {
        _profile.posMasterNo = getPosMasterNo(posMaster);
        _profile.org = getOrgFullName(posMaster);
        await this.profileRepository.save(_profile);
      }
    }
    // ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
    if (posMaster.orgRevision?.orgRevisionIsCurrent == true && !posMaster.isSit) {
      const _position = requestBody.positions.find((p) => p.positionIsSelected == true);
      if (_position) {
        const _posExecutive = _position.posExecutiveId
          ? await this.posExecutiveRepository.findOne({ where: { id: _position.posExecutiveId } })
          : null;
        const current_holderId: any = posMaster.current_holderId;
        const _profile = await this.profileRepository.findOne({
          where: { id: current_holderId },
        });
        if (_profile) {
          _profile.position = _position.posDictName ?? _null;
          _profile.posTypeId = _position.posTypeId;
          _profile.posLevelId = _position.posLevelId;
          _profile.positionField = _position.posDictField ?? _null;
          _profile.posExecutive = _posExecutive?.posExecutiveName ?? _null;
          _profile.positionArea = _position.posDictArea ?? _null;
          _profile.positionExecutiveField = _position.posDictExecutiveField ?? _null;
          await this.profileRepository.save(_profile);
        }
      }
    }
    return new HttpSuccess(posMaster.id);
  }

  /**
   * API รายละเอียดอัตรากำลัง
   *
   * @summary ORG_037 - รายละเอียดอัตรากำลัง (ADMIN) #36
   *
   */
  @Get("position/{id}")
  async detailPosition(@Path() id: string) {
    const posMaster = await this.posMasterRepository.findOne({
      relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"],
      where: { id },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }
    let orgLevel: any;

    switch (true) {
      case !!posMaster.orgChild4Id:
        orgLevel = 4;
        break;
      case !!posMaster.orgChild3Id:
        orgLevel = 3;
        break;
      case !!posMaster.orgChild2Id:
        orgLevel = 2;
        break;
      case !!posMaster.orgChild1Id:
        orgLevel = 1;
        break;
      case !!posMaster.orgRootId:
        orgLevel = 0;
        break;
      default:
        orgLevel = null; // ถ้าไม่มีข้อมูลเลย
        break;
    }
    let shortName = "";
    let orgId: any;
    if (
      posMaster.orgRootId !== null &&
      posMaster.orgChild1Id == null &&
      posMaster.orgChild2Id == null &&
      posMaster.orgChild3Id == null &&
      posMaster.orgChild4Id == null
    ) {
      shortName = posMaster.orgRoot.orgRootShortName;
      orgId = posMaster.orgRootId;
    } else if (
      posMaster.orgRootId !== null &&
      posMaster.orgChild1Id !== null &&
      posMaster.orgChild2Id == null &&
      posMaster.orgChild3Id == null &&
      posMaster.orgChild4Id == null
    ) {
      shortName = posMaster.orgChild1.orgChild1ShortName;
      orgId = posMaster.orgChild1Id;
    } else if (
      posMaster.orgRootId !== null &&
      posMaster.orgChild1Id !== null &&
      posMaster.orgChild2Id !== null &&
      posMaster.orgChild3Id == null &&
      posMaster.orgChild4Id == null
    ) {
      shortName = posMaster.orgChild2.orgChild2ShortName;
      orgId = posMaster.orgChild2Id;
    } else if (
      posMaster.orgRootId !== null &&
      posMaster.orgChild1Id !== null &&
      posMaster.orgChild2Id !== null &&
      posMaster.orgChild3Id !== null &&
      posMaster.orgChild4Id == null
    ) {
      shortName = posMaster.orgChild3.orgChild3ShortName;
      orgId = posMaster.orgChild3Id;
    } else if (
      posMaster.orgRootId !== null &&
      posMaster.orgChild1Id !== null &&
      posMaster.orgChild2Id !== null &&
      posMaster.orgChild3Id !== null &&
      posMaster.orgChild4Id !== null
    ) {
      shortName = posMaster.orgChild4.orgChild4ShortName;
      orgId = posMaster.orgChild4Id;
    }
    const positions = await this.positionRepository.find({
      where: { posMasterId: posMaster.id },
      relations: ["posType", "posLevel", "posExecutive"],
      // order: { lastUpdatedAt: "ASC" },
      order: {
        // posType: {
        //   posTypeRank: "ASC",
        // },
        // posLevel: {
        //   posLevelRank: "ASC",
        // },
        orderNo: "ASC",
        createdAt: "ASC",
      },
    });
    const formattedData = {
      id: posMaster.id,
      posMasterNoPrefix: posMaster.posMasterNoPrefix,
      posMasterNo: posMaster.posMasterNo,
      posMasterNoSuffix: posMaster.posMasterNoSuffix,
      reason: posMaster.reason,
      //   isOfficer: posMaster.isOfficer,
      isStaff: posMaster.isStaff,
      orgLevel: orgLevel,
      orgShortname: shortName,
      orgId: orgId,
      isDirector: posMaster.isDirector,
      positionSign: posMaster.positionSign,
      positions: positions.map((position) => ({
        id: position.id,
        orderNo: position.orderNo,
        positionName: position.positionName,
        positionField: position.positionField,
        posTypeId: position.posTypeId,
        posTypeName: position.posType == null ? null : position.posType.posTypeName,
        posLevelId: position.posLevelId,
        posLevelName: position.posLevel == null ? null : position.posLevel.posLevelName,
        posExecutiveId: position.posExecutiveId,
        posExecutiveName:
          position.posExecutive == null ? null : position.posExecutive.posExecutiveName,
        positionExecutiveField: position.positionExecutiveField,
        positionArea: position.positionArea,
        positionIsSelected: position.positionIsSelected,
        isSpecial: position.isSpecial,
      })),
    };
    return new HttpSuccess(formattedData);
  }

  /**
   * API ลบอัตรากำลัง
   *
   * @summary ORG_035 - ลบอัตรากำลัง (ADMIN) #38
   *
   * @param {string} id  Id ตำแหน่ง
   */
  @Delete("master/{id}")
  async deletePosMaster(@Path() id: string, @Request() request: RequestWithUser) {
    await new permission().PermissionUpdate(request, "SYS_ORG");
    const delPosMaster = await this.posMasterRepository.findOne({
      where: { id },
      // relations: ["position"],
    });
    if (!delPosMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งในสายงานนี้");
    }
    await this.positionRepository.delete({ posMasterId: id });
    await this.posMasterRepository.delete({ id });
    return new HttpSuccess();
  }

  /**
   * API รายการอัตรากำลัง
   *
   * @summary ORG_070 - รายการอัตรากำลัง (ADMIN Menu) #56
   *
   */
  @Post("admin/master/list")
  async listForAdmin(
    @Request() request: RequestWithUser,
    @Body()
    body: {
      id: string | null;
      revisionId: string;
      type: number | null;
      isAll: boolean;
      isBlank: boolean;
      page: number;
      pageSize: number;
      keyword?: string;
    },
  ) {
    let typeCondition: any = {};
    let checkChildConditions: any = {};
    let keywordAsInt: any;
    let searchShortName = "1=1";
    let searchShortName0 = `CONCAT_WS(' ',orgRoot.orgRootShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName1 = `CONCAT_WS(' ',orgChild1.orgChild1ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName2 = `CONCAT_WS(' ',orgChild2.orgChild2ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName3 = `CONCAT_WS(' ',orgChild3.orgChild3ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName4 = `CONCAT_WS(' ',orgChild4.orgChild4ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    if (body.type != null && body.id != null) {
      if (body.type === 0) {
        typeCondition = {
          orgRootId: body.id,
        };
        if (!body.isAll) {
          checkChildConditions = {
            orgChild1Id: IsNull(),
          };
          searchShortName = `CONCAT_WS(' ',orgRoot.orgRootShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
        } else {
        }
      } else if (body.type === 1) {
        typeCondition = {
          orgChild1Id: body.id,
        };
        if (!body.isAll) {
          checkChildConditions = {
            orgChild2Id: IsNull(),
          };
          searchShortName = `CONCAT_WS(' ',orgChild1.orgChild1ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
        } else {
        }
      } else if (body.type === 2) {
        typeCondition = {
          orgChild2Id: body.id,
        };
        if (!body.isAll) {
          checkChildConditions = {
            orgChild3Id: IsNull(),
          };
          searchShortName = `CONCAT_WS(' ',orgChild2.orgChild2ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
        } else {
        }
      } else if (body.type === 3) {
        typeCondition = {
          orgChild3Id: body.id,
        };
        if (!body.isAll) {
          checkChildConditions = {
            orgChild4Id: IsNull(),
          };
          searchShortName = `CONCAT_WS(' ',orgChild3.orgChild3ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
        } else {
        }
      } else if (body.type === 4) {
        typeCondition = {
          orgChild4Id: body.id,
        };
        searchShortName = `CONCAT_WS(' ',orgChild4.orgChild4ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      }
    } else {
      body.isAll = true;
    }
    if (body.isBlank == true) {
      typeCondition.current_holderId = IsNull();
    }
    let findPosition: any;
    let masterId = new Array();
    let _authRoleId = new Array();
    let _exitsRole = false;
    if (body.keyword != null && body.keyword != "") {
      const findTypes: PosType[] = await this.posTypeRepository.find({
        where: { posTypeName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posTypeId: In(findTypes.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const findLevel: PosLevel[] = await this.posLevelRepository.find({
        where: { posLevelName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posLevelId: In(findLevel.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const findExecutive: PosExecutive[] = await this.posExecutiveRepository.find({
        where: { posExecutiveName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posExecutiveId: In(findExecutive.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      findPosition = await this.positionRepository.find({
        where: { positionName: Like(`%${body.keyword}%`) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const numericMatch = body.keyword == null ? null : body.keyword.match(/\d+/);
      keywordAsInt = numericMatch ? parseInt(numericMatch[0], 10) : null;
      masterId = [...new Set(masterId)];

      //serch name สิทธิ์
      _authRoleId = await this.authRoleRepo.find({
        where: {
          roleName: Like(`%${body.keyword}%`),
        },
      });
      if (_authRoleId.length > 0) {
        _exitsRole = true;
        _authRoleId = [...new Set(_authRoleId.map((x) => x.id))];
      }
    }

    let revisionCondition: any = {
      orgRevisionId: body.revisionId,
    };
    if (_exitsRole == true) {
      revisionCondition = {
        orgRevisionId: body.revisionId,
        authRoleId: In(_authRoleId),
      };
    }

    const conditions = [
      {
        ...checkChildConditions,
        ...typeCondition,
        ...revisionCondition,
        ...(body.keyword &&
          (masterId.length > 0
            ? { id: In(masterId) }
            : /^\d+$/.test(body.keyword) ? { posMasterNo: keywordAsInt } : { posMasterNo: Like(`%${body.keyword}%`) })),
      },
    ];
    let [posMaster, total] = await AppDataSource.getRepository(PosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("posMaster.next_holder", "next_holder")
      .leftJoinAndSelect("posMaster.orgRevision", "orgRevision")
      .leftJoinAndSelect("posMaster.posMasterAssigns", "posMasterAssigns")
      .leftJoinAndSelect("posMasterAssigns.assign", "assign")
      .leftJoinAndSelect("current_holder.posType", "posType")
      .leftJoinAndSelect("current_holder.posLevel", "posLevel")
      .where(conditions)
      //   .orWhere(
      //     new Brackets((qb) => {
      //       qb.andWhere(
      //         body.keyword != null && body.keyword != "" && _exitsRole
      //           ? `posMaster.authRoleId IN (:...authRoleId)'`
      //           : "1=1",
      //         { authRoleId: _authRoleId },
      //       )
      //         .andWhere(checkChildConditions)
      //         .andWhere(typeCondition)
      //         .andWhere(revisionCondition);
      //     }),
      //   )
      .orWhere(
        new Brackets((qb) => {
          qb.andWhere(
            body.keyword != null && body.keyword != ""
              ? body.isAll == false
                ? searchShortName
                : `CASE WHEN posMaster.orgChild1 is null THEN ${searchShortName0} WHEN posMaster.orgChild2 is null THEN ${searchShortName1} WHEN posMaster.orgChild3 is null THEN ${searchShortName2} WHEN posMaster.orgChild4 is null THEN ${searchShortName3} ELSE ${searchShortName4} END LIKE '%${body.keyword}%'`
              : "1=1",
          )
            .andWhere(checkChildConditions)
            .andWhere(typeCondition)
            .andWhere(revisionCondition);
        }),
      )
      //   .orWhere(
      //     new Brackets((qb) => {
      //       qb.andWhere(
      //         body.keyword != null && body.keyword != ""
      //           ? `CONCAT(current_holder.prefix, current_holder.firstName," ",current_holder.lastName)  like '%${body.keyword}%'`
      //           : "1=1",
      //         {
      //           keyword: `%${body.keyword}%`,
      //         },
      //       )
      //         .andWhere(checkChildConditions)
      //         .andWhere(typeCondition)
      //         .andWhere(revisionCondition);
      //     }),
      //   )
      .orWhere(
        new Brackets((qb) => {
          qb.andWhere(
            body.keyword != null && body.keyword != ""
              ? `CASE WHEN orgRevision.orgRevisionIsDraft = true THEN CONCAT(next_holder.prefix, next_holder.firstName,' ', next_holder.lastName) ELSE CONCAT(current_holder.prefix, current_holder.firstName,' ' , current_holder.lastName) END LIKE '%${body.keyword}%'`
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .andWhere(checkChildConditions)
            .andWhere(typeCondition)
            .andWhere(revisionCondition);
        }),
      )
      .orWhere(
        new Brackets((qb) => {
          qb.andWhere(
            body.keyword != null && body.keyword != ""
              ? `CASE WHEN orgRevision.orgRevisionIsDraft = true THEN next_holder.citizenId ELSE current_holder.citizenId END LIKE '%${body.keyword}%'`
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .andWhere(checkChildConditions)
            .andWhere(typeCondition)
            .andWhere(revisionCondition);
        }),
      )
      .orWhere(
        new Brackets((qb) => {
          qb.andWhere(
            body.keyword != null && body.keyword != ""
              ? `current_holder.posType LIKE :keyword`
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .andWhere(checkChildConditions)
            .andWhere(typeCondition)
            .andWhere(revisionCondition);
        }),
      )
      .orWhere(
        new Brackets((qb) => {
          qb.andWhere(
            body.keyword != null && body.keyword != ""
              ? `current_holder.posLevel LIKE :keyword`
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .andWhere(checkChildConditions)
            .andWhere(typeCondition)
            .andWhere(revisionCondition);
        }),
      )
      .orWhere(
        new Brackets((qb) => {
          qb.andWhere(
            body.keyword != null && body.keyword != ""
              ? `current_holder.position LIKE :keyword`
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .andWhere(checkChildConditions)
            .andWhere(typeCondition)
            .andWhere(revisionCondition);
        }),
      )
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .skip((body.page - 1) * body.pageSize)
      .take(body.pageSize)
      .getManyAndCount();

    //แก้ค้นหา
    let _position: any[] = [];
    let x: any = null;
    let y: any = null;
    if (body.keyword != null && body.keyword != "") {
      const position = await this.positionRepository.find({
        relations: ["posType", "posLevel", "posExecutive"],
        where: { posMasterId: In(posMaster.map((x) => x.id)) },
        order: { createdAt: "ASC" },
      });
      for (let data of position) {
        x = data.posMasterId;
        if (y != x) {
          if (
            data.positionName.includes(body.keyword) ||
            data.posType.posTypeName.includes(body.keyword) ||
            data.posLevel.posLevelName.includes(body.keyword)
          ) {
            _position.push(data);
          }
        }
        y = x;
      }
    }

    if (_position.length > 0) {
      posMaster = posMaster.filter((x) => _position.some((y) => y.posMasterId === x.id));
    }

    const formattedData = await Promise.all(
      posMaster.map(async (posMaster) => {
        const positions = await this.positionRepository.find({
          where: {
            posMasterId: posMaster.id,
          },
          relations: ["posLevel", "posType", "posExecutive"],
          order: {
            posType: { posTypeRank: "ASC" },
            posLevel: { posLevelRank: "ASC" },
          },
        });

        const authRoleName = await this.authRoleRepo.findOne({
          where: { id: String(posMaster.authRoleId) },
        });

        let profile: any;
        const chkRevision = await this.orgRevisionRepository.findOne({
          where: { id: posMaster.orgRevisionId },
        });
        if (chkRevision?.orgRevisionIsCurrent && !chkRevision?.orgRevisionIsDraft) {
          profile = await this.profileRepository.findOne({
            where: { id: String(posMaster.current_holderId) },
          });
        } else if (!chkRevision?.orgRevisionIsCurrent && chkRevision?.orgRevisionIsDraft) {
          profile = await this.profileRepository.findOne({
            where: { id: String(posMaster.next_holderId) },
          });
        }
        const type = await this.posTypeRepository.findOne({
          where: { id: String(profile?.posTypeId) },
        });
        const level = await this.posLevelRepository.findOne({
          where: { id: String(profile?.posLevelId) },
        });

        let shortName = "";

        if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id == null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 0;
          shortName = posMaster.orgRoot?.orgRootShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 1;
          shortName = posMaster.orgChild1?.orgChild1ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 2;
          shortName = posMaster.orgChild2?.orgChild2ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.type = 3;
          shortName = posMaster.orgChild3?.orgChild3ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.type = 4;
          shortName = posMaster.orgChild4?.orgChild4ShortName;
        }

        return {
          id: posMaster.id,
          current_holderId: posMaster.current_holderId,
          next_holderId: posMaster.next_holderId,
          isDirector: posMaster.isDirector,
          orgRootId: posMaster.orgRootId,
          orgChild1Id: posMaster.orgChild1Id,
          orgChild2Id: posMaster.orgChild2Id,
          orgChild3Id: posMaster.orgChild3Id,
          orgChild4Id: posMaster.orgChild4Id,
          posMasterNoPrefix: posMaster.posMasterNoPrefix ? posMaster.posMasterNoPrefix : null,
          posMasterNo: posMaster.posMasterNo ? posMaster.posMasterNo : null,
          posMasterNoSuffix: posMaster.posMasterNoSuffix ? posMaster.posMasterNoSuffix : null,
          reason: posMaster.reason,
          fullNameCurrentHolder:
            posMaster.current_holder == null
              ? null
              : `${posMaster.current_holder.prefix}${posMaster.current_holder.firstName} ${posMaster.current_holder.lastName}`,
          fullNameNextHolder:
            posMaster.next_holder == null
              ? null
              : `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`,
          orgShortname: shortName,
          isSit: posMaster.isSit,
          profilePosition: profile == null || profile.position == null ? null : profile.position,
          profilePostype: type == null || type.posTypeName == null ? null : type.posTypeName,
          profilePoslevel: level == null || level.posLevelName == null ? null : level.posLevelName,
          authRoleId: posMaster.authRoleId,
          profileIdNextHolder: posMaster.next_holderId,
          profileIdCurrentHolder: posMaster.current_holderId,
          authRoleName:
            authRoleName == null || authRoleName.roleName == null ? null : authRoleName.roleName,
          isPosMasterAssign: posMaster.posMasterAssigns.length > 0 ? true : false,
          posMasterAssigns: posMaster.posMasterAssigns.map((x) => ({
            id: x.id,
            assignId: x.assignId,
            commandSysId: x.assign.commandSysId,
            name: x.assign.name,
            description: x.assign.description,
          })),
          positions: positions.map((position: any) => ({
            id: position.id,
            positionName: position.positionName,
            positionField: position.positionField,
            posTypeId: position.posTypeId,
            posTypeName: position.posType == null ? null : position.posType.posTypeName,
            posLevelId: position.posLevelId,
            posLevelName: position.posLevel == null ? null : position.posLevel.posLevelName,
            posExecutiveId: position.posExecutiveId,
            posExecutiveName:
              position.posExecutive == null ? null : position.posExecutive.posExecutiveName,
            positionExecutiveField: position.positionExecutiveField,
            positionArea: position.positionArea,
            positionIsSelected: position.positionIsSelected,
            isSpecial: position.isSpecial,
          })),
        };
      }),
    );
    return new HttpSuccess({ data: formattedData, total });
  }

  /**
   * API รายการอัตรากำลัง
   *
   * @summary ORG_070 - รายการอัตรากำลัง (ADMIN) #56
   *
   */
  @Post("master/list")
  async list(
    @Request() request: RequestWithUser,
    @Body()
    body: {
      id: string;
      revisionId: string;
      type: number;
      isAll: boolean;
      page: number;
      pageSize: number;
      keyword?: string;
    },
  ) {
    let typeCondition: any = {};
    let checkChildConditions: any = {};
    let keywordAsInt: any;
    let searchShortName = "1=1";
    let searchShortName0 = `CONCAT_WS(' ',orgRoot.orgRootShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName1 = `CONCAT_WS(' ',orgChild1.orgChild1ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName2 = `CONCAT_WS(' ',orgChild2.orgChild2ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName3 = `CONCAT_WS(' ',orgChild3.orgChild3ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName4 = `CONCAT_WS(' ',orgChild4.orgChild4ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let _data = await new permission().PermissionOrgList(request, "SYS_ORG");
    if (body.type === 0) {
      typeCondition = {
        orgRootId: body.id,
      };
      if (!body.isAll) {
        checkChildConditions = {
          orgChild1Id: IsNull(),
        };
        searchShortName = `CONCAT_WS(' ',orgRoot.orgRootShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      }
    } else if (body.type === 1) {
      typeCondition = {
        orgChild1Id: body.id,
      };
      if (!body.isAll) {
        checkChildConditions = {
          orgChild2Id: IsNull(),
        };
        searchShortName = `CONCAT_WS(' ',orgChild1.orgChild1ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      }
    } else if (body.type === 2) {
      typeCondition = {
        orgChild2Id: body.id,
      };
      if (!body.isAll) {
        checkChildConditions = {
          orgChild3Id: IsNull(),
        };
        searchShortName = `CONCAT_WS(' ',orgChild2.orgChild2ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      }
    } else if (body.type === 3) {
      typeCondition = {
        orgChild3Id: body.id,
      };
      if (!body.isAll) {
        checkChildConditions = {
          orgChild4Id: IsNull(),
        };
        searchShortName = `CONCAT_WS(' ',orgChild3.orgChild3ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      }
    } else if (body.type === 4) {
      typeCondition = {
        orgChild4Id: body.id,
      };
      searchShortName = `CONCAT_WS(' ',orgChild4.orgChild4ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
    }
    let findPosition: any;
    let masterId = new Array();
    if (body.keyword != null && body.keyword != "") {
      const findTypes: PosType[] = await this.posTypeRepository.find({
        where: { posTypeName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posTypeId: In(findTypes.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const findLevel: PosLevel[] = await this.posLevelRepository.find({
        where: { posLevelName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posLevelId: In(findLevel.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const findExecutive: PosExecutive[] = await this.posExecutiveRepository.find({
        where: { posExecutiveName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posExecutiveId: In(findExecutive.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      findPosition = await this.positionRepository.find({
        where: { positionName: Like(`%${body.keyword}%`) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const numericMatch = body.keyword == null ? null : body.keyword.match(/\d+/);
      keywordAsInt = numericMatch ? parseInt(numericMatch[0], 10) : null;
      masterId = [...new Set(masterId)];
    }

    const revisionCondition = {
      orgRevisionId: body.revisionId,
    };
    const chkRevision = await this.orgRevisionRepository.findOne({
      where: { id: body.revisionId },
    });
    if (chkRevision != null && chkRevision.orgRevisionIsDraft == true)
      _data = {
        root: null,
        child1: null,
        child2: null,
        child3: null,
        child4: null,
        privilege: "OWNER",
      };
    const conditions = [
      {
        ...checkChildConditions,
        ...typeCondition,
        ...revisionCondition,
        ...(body.keyword &&
          (masterId.length > 0
            ? { id: In(masterId) }
            : /^\d+$/.test(body.keyword) ? { posMasterNo: keywordAsInt } : { posMasterNo: Like(`%${body.keyword}%`) })),
      },
    ];

    //Old
    // let [posMaster, total] = await AppDataSource.getRepository(PosMaster)
    //   .createQueryBuilder("posMaster")
    //   .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
    //   .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
    //   .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
    //   .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
    //   .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
    //   .leftJoinAndSelect("posMaster.current_holder", "current_holder")
    //   .leftJoinAndSelect("posMaster.next_holder", "next_holder")
    //   .leftJoinAndSelect("posMaster.orgRevision", "orgRevision")
    //   .where(conditions)
    //   .andWhere(
    //     _data.root != undefined && _data.root != null
    //       ? _data.root[0] != null
    //         ? `posMaster.orgRootId IN (:...root)`
    //         : `posMaster.orgRootId is null`
    //       : "1=1",
    //     {
    //       root: _data.root,
    //     },
    //   )
    //   .andWhere(
    //     _data.child1 != undefined && _data.child1 != null
    //       ? _data.child1[0] != null
    //         ? `posMaster.orgChild1Id IN (:...child1)`
    //         : `posMaster.orgChild1Id is ${_data.privilege == "PARENT" ? "not null" : "null"}`
    //       : "1=1",
    //     {
    //       child1: _data.child1,
    //     },
    //   )
    //   .andWhere(
    //     _data.child2 != undefined && _data.child2 != null
    //       ? _data.child2[0] != null
    //         ? `posMaster.orgChild2Id IN (:...child2)`
    //         : `posMaster.orgChild2Id is null`
    //       : "1=1",
    //     {
    //       child2: _data.child2,
    //     },
    //   )
    //   .andWhere(
    //     _data.child3 != undefined && _data.child3 != null
    //       ? _data.child3[0] != null
    //         ? `posMaster.orgChild3Id IN (:...child3)`
    //         : `posMaster.orgChild3Id is null`
    //       : "1=1",
    //     {
    //       child3: _data.child3,
    //     },
    //   )
    //   .andWhere(
    //     _data.child4 != undefined && _data.child4 != null
    //       ? _data.child4[0] != null
    //         ? `posMaster.orgChild4Id IN (:...child4)`
    //         : `posMaster.orgChild4Id is null`
    //       : "1=1",
    //     {
    //       child4: _data.child4,
    //     },
    //   )
    //   .andWhere(
    //     new Brackets((qb) => {
    //       qb.orWhere(
    //         new Brackets((qb) => {
    //           qb.andWhere(
    //             body.keyword != null && body.keyword != ""
    //               ? body.isAll == false
    //                 ? searchShortName
    //                 : `CASE WHEN posMaster.orgChild1 is null THEN ${searchShortName0} WHEN posMaster.orgChild2 is null THEN ${searchShortName1} WHEN posMaster.orgChild3 is null THEN ${searchShortName2} WHEN posMaster.orgChild4 is null THEN ${searchShortName3} ELSE ${searchShortName4} END LIKE '%${body.keyword}%'`
    //               : "1=1",
    //           )
    //             .andWhere(checkChildConditions)
    //             .andWhere(typeCondition)
    //             .andWhere(revisionCondition);
    //         }),
    //       )
    //         .orWhere(
    //           new Brackets((qb) => {
    //             qb.andWhere(
    //               body.keyword != null && body.keyword != ""
    //                 ? `CONCAT(current_holder.prefix, current_holder.firstName," ",current_holder.lastName)  like '%${body.keyword}%'`
    //                 : "1=1",
    //               {
    //                 keyword: `%${body.keyword}%`,
    //               },
    //             )
    //               .andWhere(checkChildConditions)
    //               .andWhere(typeCondition)
    //               .andWhere(revisionCondition);
    //           }),
    //         )
    //         .orWhere(
    //           new Brackets((qb) => {
    //             qb.andWhere(
    //               body.keyword != null && body.keyword != ""
    //                 ? `CASE WHEN orgRevision.orgRevisionIsDraft = true THEN CONCAT(next_holder.prefix, next_holder.firstName,' ', next_holder.lastName) ELSE CONCAT(current_holder.prefix, current_holder.firstName,' ' , current_holder.lastName) END LIKE '%${body.keyword}%'`
    //                 : "1=1",
    //               {
    //                 keyword: `%${body.keyword}%`,
    //               },
    //             )
    //               .andWhere(checkChildConditions)
    //               .andWhere(typeCondition)
    //               .andWhere(revisionCondition);
    //           }),
    //         );
    //     }),
    //   )
    //   .orderBy("orgRoot.orgRootOrder", "ASC")
    //   .addOrderBy("orgChild1.orgChild1Order", "ASC")
    //   .addOrderBy("orgChild2.orgChild2Order", "ASC")
    //   .addOrderBy("orgChild3.orgChild3Order", "ASC")
    //   .addOrderBy("orgChild4.orgChild4Order", "ASC")
    //   .addOrderBy("posMaster.posMasterOrder", "ASC")
    //   .addOrderBy("posMaster.posMasterCreatedAt", "ASC")
    //   .skip((body.page - 1) * body.pageSize)
    //   .take(body.pageSize)
    //   .getManyAndCount();

    //New
    let query = AppDataSource.getRepository(PosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("posMaster.next_holder", "next_holder")
      .leftJoinAndSelect("posMaster.orgRevision", "orgRevision")
      .where(conditions)
      .andWhere(
        _data.root != undefined && _data.root != null
          ? _data.root[0] != null
            ? "posMaster.orgRootId IN (:...root)"
            : "posMaster.orgRootId is null"
          : "1=1",
        { root: _data.root },
      )
      .andWhere(
        _data.child1 != undefined && _data.child1 != null
          ? _data.child1[0] != null
            ? "posMaster.orgChild1Id IN (:...child1)"
            : // : `posMaster.orgChild1Id is ${_data.privilege == "PARENT" ? "not null" : "null"}`
              `posMaster.orgChild1Id is null`
          : "1=1",
        { child1: _data.child1 },
      )
      .andWhere(
        _data.child2 != undefined && _data.child2 != null
          ? _data.child2[0] != null
            ? `posMaster.orgChild2Id IN (:...child2)`
            : `posMaster.orgChild2Id is null`
          : "1=1",
        {
          child2: _data.child2,
        },
      )
      .andWhere(
        _data.child3 != undefined && _data.child3 != null
          ? _data.child3[0] != null
            ? `posMaster.orgChild3Id IN (:...child3)`
            : `posMaster.orgChild3Id is null`
          : "1=1",
        {
          child3: _data.child3,
        },
      )
      .andWhere(
        _data.child4 != undefined && _data.child4 != null
          ? _data.child4[0] != null
            ? `posMaster.orgChild4Id IN (:...child4)`
            : `posMaster.orgChild4Id is null`
          : "1=1",
        {
          child4: _data.child4,
        },
      );
    // .andWhere(checkChildConditions)
    // .andWhere(typeCondition)
    // .andWhere(revisionCondition);

    if (body.keyword != null && body.keyword != "") {
      query
        .orWhere(
          new Brackets((qb) => {
            qb.andWhere(
              body.keyword != null && body.keyword != ""
                ? body.isAll == false
                  ? searchShortName
                  : `CASE WHEN posMaster.orgChild1 is null THEN ${searchShortName0} WHEN posMaster.orgChild2 is null THEN ${searchShortName1} WHEN posMaster.orgChild3 is null THEN ${searchShortName2} WHEN posMaster.orgChild4 is null THEN ${searchShortName3} ELSE ${searchShortName4} END LIKE '%${body.keyword}%'`
                : "1=1",
            )
              .andWhere(checkChildConditions)
              .andWhere(typeCondition)
              .andWhere(revisionCondition);
          }),
        )
        .orWhere(
          new Brackets((qb) => {
            qb.andWhere(
              body.keyword != null && body.keyword != ""
                ? `CONCAT(current_holder.prefix, current_holder.firstName," ",current_holder.lastName)  like '%${body.keyword}%'`
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
              .andWhere(checkChildConditions)
              .andWhere(typeCondition)
              .andWhere(revisionCondition);
          }),
        )
        .orWhere(
          new Brackets((qb) => {
            qb.andWhere(
              body.keyword != null && body.keyword != ""
                ? `CASE WHEN orgRevision.orgRevisionIsDraft = true THEN CONCAT(next_holder.prefix, next_holder.firstName,' ', next_holder.lastName) ELSE CONCAT(current_holder.prefix, current_holder.firstName,' ' , current_holder.lastName) END LIKE '%${body.keyword}%'`
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
              .andWhere(checkChildConditions)
              .andWhere(typeCondition)
              .andWhere(revisionCondition);
          }),
        );
    }

    let [posMaster, total] = await query
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .addOrderBy("posMaster.posMasterCreatedAt", "ASC")
      .skip((body.page - 1) * body.pageSize)
      .take(body.pageSize)
      .getManyAndCount();

    //แก้ค้นหา
    let _position: any[] = [];
    let x: any = null;
    let y: any = null;
    if (body.keyword != null && body.keyword != "") {
      const position = await this.positionRepository.find({
        relations: ["posType", "posLevel", "posExecutive"],
        where: { posMasterId: In(posMaster.map((x) => x.id)) },
        order: { createdAt: "ASC" },
      });
      for (let data of position) {
        x = data.posMasterId;
        if (y != x) {
          if (
            data.positionName.includes(body.keyword) ||
            data.posType.posTypeName.includes(body.keyword) ||
            data.posLevel.posLevelName.includes(body.keyword)
          ) {
            _position.push(data);
          }
        }
        y = x;
      }
    }

    if (_position.length > 0) {
      posMaster = posMaster.filter((x) => _position.some((y) => y.posMasterId === x.id));
    }

    const formattedData = await Promise.all(
      posMaster.map(async (posMaster) => {
        const positions = await this.positionRepository.find({
          where: {
            posMasterId: posMaster.id,
          },
          relations: ["posLevel", "posType", "posExecutive"],
          order: {
            // posType: { posTypeRank: "ASC" },
            // posLevel: { posLevelRank: "ASC" },
            orderNo: "ASC",
            createdAt: "ASC",
          },
        });

        const authRoleName = await this.authRoleRepo.findOne({
          where: { id: String(posMaster.authRoleId) },
        });

        let profile: any;
        const chkRevision = await this.orgRevisionRepository.findOne({
          where: { id: posMaster.orgRevisionId },
        });
        if (chkRevision?.orgRevisionIsCurrent && !chkRevision?.orgRevisionIsDraft) {
          profile = await this.profileRepository.findOne({
            where: { id: String(posMaster.current_holderId) },
          });
        } else if (!chkRevision?.orgRevisionIsCurrent && chkRevision?.orgRevisionIsDraft) {
          profile = await this.profileRepository.findOne({
            where: { id: String(posMaster.next_holderId) },
          });
        }
        const type = await this.posTypeRepository.findOne({
          where: { id: String(profile?.posTypeId) },
        });
        const level = await this.posLevelRepository.findOne({
          where: { id: String(profile?.posLevelId) },
        });

        let shortName = "";

        if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id == null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 0;
          shortName = posMaster.orgRoot.orgRootShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 1;
          shortName = posMaster.orgChild1.orgChild1ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 2;
          shortName = posMaster.orgChild2.orgChild2ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.type = 3;
          shortName = posMaster.orgChild3.orgChild3ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.type = 4;
          shortName = posMaster.orgChild4.orgChild4ShortName;
        }

        return {
          id: posMaster.id,
          ancestorDNA: posMaster.ancestorDNA,
          current_holderId: posMaster.current_holderId,
          next_holderId: posMaster.next_holderId,
          isDirector: posMaster.isDirector,
          orgRootId: posMaster.orgRootId,
          orgChild1Id: posMaster.orgChild1Id,
          orgChild2Id: posMaster.orgChild2Id,
          orgChild3Id: posMaster.orgChild3Id,
          orgChild4Id: posMaster.orgChild4Id,
          posMasterNoPrefix: posMaster.posMasterNoPrefix ? posMaster.posMasterNoPrefix : null,
          posMasterNo: posMaster.posMasterNo ? posMaster.posMasterNo : null,
          posMasterNoSuffix: posMaster.posMasterNoSuffix ? posMaster.posMasterNoSuffix : null,
          reason: posMaster.reason,
          fullNameCurrentHolder:
            posMaster.current_holder == null
              ? null
              : `${posMaster.current_holder.prefix}${posMaster.current_holder.firstName} ${posMaster.current_holder.lastName}`,
          fullNameNextHolder:
            posMaster.next_holder == null
              ? null
              : `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`,
          orgShortname: shortName,
          isSit: posMaster.isSit,
          profilePosition: profile == null || profile.position == null ? null : profile.position,
          profilePostype: type == null || type.posTypeName == null ? null : type.posTypeName,
          profilePoslevel: level == null || level.posLevelName == null ? null : level.posLevelName,
          authRoleId: posMaster.authRoleId,
          isCondition: posMaster.isCondition,
          conditionReason: posMaster.conditionReason,
          authRoleName:
            authRoleName == null || authRoleName.roleName == null ? null : authRoleName.roleName,
          positions: positions.map((position: any) => ({
            id: position.id,
            positionName: position.positionName,
            positionField: position.positionField,
            posTypeId: position.posTypeId,
            posTypeName: position.posType == null ? null : position.posType.posTypeName,
            posLevelId: position.posLevelId,
            posLevelName: position.posLevel == null ? null : position.posLevel.posLevelName,
            posExecutiveId: position.posExecutiveId,
            posExecutiveName:
              position.posExecutive == null ? null : position.posExecutive.posExecutiveName,
            positionExecutiveField: position.positionExecutiveField,
            positionArea: position.positionArea,
            positionIsSelected: position.positionIsSelected,
            isSpecial: position.isSpecial,
          })),
        };
      }),
    );

    if (
      _data.privilege === "NORMAL" ||
      _data.privilege === "CHILD" ||
      _data.privilege === "BROTHER"
    ) {
      //PARENT จะไม่มีทางเห็น ROOT , CHILD ยึดจาก CHILD ที่อยู่ลงไปข้างล่างและจะไม่เห็น CHILD ที่อยู่เหนือกว่า
      const nextChildMap: any = {
        //เอาไวเช็ค CHILD ถัดไป
        0: _data.child1,
        1: _data.child2,
        2: _data.child3,
        3: _data.child4,
      };
      const childValue = nextChildMap[body.type];
      if (_data.privilege === "NORMAL") {
        if (Array.isArray(childValue) && childValue.some((item) => item != null)) {
          return new HttpSuccess({ data: [], total: 0 });
        }
      } else if (_data.privilege === "CHILD" || _data.privilege === "BROTHER") {
        const higherChildChecks = [
          { type: [0], child: _data.child1, next: _data.child2 },
          { type: [0, 1], child: _data.child2, next: _data.child3 },
          { type: [0, 1, 2], child: _data.child3, next: _data.child4 },
          { type: [0, 1, 2, 3], child: _data.child4, next: true },
        ];

        for (const check of higherChildChecks) {
          if (Array.isArray(check.child) && check.next == null) {
            if (check.type.includes(body.type)) {
              return new HttpSuccess({ data: [], total: 0 });
            }
          }
        }
      }
    }
    return new HttpSuccess({ data: formattedData, total });
  }

  /**
   * API จัดลำดับตำแหน่ง
   *
   * @summary ORG_040 - จัดลำดับตำแหน่ง (ADMIN) #43
   *
   */
  @Post("sort")
  async Sort(
    @Body() requestBody: { id: string; type: number; sortId: string[] },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG");
    const before = null;
    switch (requestBody.type) {
      case 0: {
        const rootId = await this.posMasterRepository.findOne({
          where: { orgRootId: requestBody.id },
        });
        if (!rootId?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId: " + requestBody.id);
        }
        const listPosMasterId_0 = await this.posMasterRepository.find({
          where: {
            orgRootId: requestBody.id,
            orgChild1Id: IsNull(),
            orgChild2Id: IsNull(),
            orgChild3Id: IsNull(),
            orgChild4Id: IsNull(),
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_0) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 0.");
        }
        const sortData_0 = listPosMasterId_0.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        // Bulk update using CASE WHEN instead of save() per row
        const caseClauses_0 = sortData_0
          .map((d) => `WHEN '${d.id}' THEN ${d.posMasterOrder}`)
          .join(" ");
        const ids_0 = sortData_0.map((d) => `'${d.id}'`).join(",");
        await this.posMasterRepository
          .createQueryBuilder()
          .update(PosMaster)
          .set({
            posMasterOrder: () => `CASE id ${caseClauses_0} END`,
          })
          .where(`id IN (${ids_0})`)
          .execute();
        setLogDataDiff(request, { before, after: sortData_0 });
        break;
      }

      case 1: {
        const child1Id = await this.posMasterRepository.findOne({
          where: { orgChild1Id: requestBody.id },
        });
        if (!child1Id?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1Id: " + requestBody.id);
        }
        const listPosMasterId_1 = await this.posMasterRepository.find({
          where: {
            orgRootId: Not(IsNull()),
            orgChild1Id: requestBody.id,
            orgChild2Id: IsNull(),
            orgChild3Id: IsNull(),
            orgChild4Id: IsNull(),
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_1) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 1.");
        }
        const sortData_1 = listPosMasterId_1.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        // Bulk update using CASE WHEN instead of save() per row
        const caseClauses_1 = sortData_1
          .map((d) => `WHEN '${d.id}' THEN ${d.posMasterOrder}`)
          .join(" ");
        const ids_1 = sortData_1.map((d) => `'${d.id}'`).join(",");
        await this.posMasterRepository
          .createQueryBuilder()
          .update(PosMaster)
          .set({
            posMasterOrder: () => `CASE id ${caseClauses_1} END`,
          })
          .where(`id IN (${ids_1})`)
          .execute();
        setLogDataDiff(request, { before, after: sortData_1 });
        break;
      }

      case 2: {
        const child2Id = await this.posMasterRepository.findOne({
          where: { orgChild2Id: requestBody.id },
        });
        if (!child2Id?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2Id: " + requestBody.id);
        }
        const listPosMasterId_2 = await this.posMasterRepository.find({
          where: {
            orgRootId: Not(IsNull()),
            orgChild1Id: Not(IsNull()),
            orgChild2Id: requestBody.id,
            orgChild3Id: IsNull(),
            orgChild4Id: IsNull(),
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_2) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 2.");
        }
        const sortData_2 = listPosMasterId_2.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        // Bulk update using CASE WHEN instead of save() per row
        const caseClauses_2 = sortData_2
          .map((d) => `WHEN '${d.id}' THEN ${d.posMasterOrder}`)
          .join(" ");
        const ids_2 = sortData_2.map((d) => `'${d.id}'`).join(",");
        await this.posMasterRepository
          .createQueryBuilder()
          .update(PosMaster)
          .set({
            posMasterOrder: () => `CASE id ${caseClauses_2} END`,
          })
          .where(`id IN (${ids_2})`)
          .execute();
        setLogDataDiff(request, { before, after: sortData_2 });
        break;
      }

      case 3: {
        const child3Id = await this.posMasterRepository.findOne({
          where: { orgChild3Id: requestBody.id },
        });
        if (!child3Id?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found chil3Id: " + requestBody.id);
        }
        const listPosMasterId_3 = await this.posMasterRepository.find({
          where: {
            orgRootId: Not(IsNull()),
            orgChild1Id: Not(IsNull()),
            orgChild2Id: Not(IsNull()),
            orgChild3Id: requestBody.id,
            orgChild4Id: IsNull(),
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_3) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 3.");
        }
        const sortData_3 = listPosMasterId_3.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        // Bulk update using CASE WHEN instead of save() per row
        const caseClauses_3 = sortData_3
          .map((d) => `WHEN '${d.id}' THEN ${d.posMasterOrder}`)
          .join(" ");
        const ids_3 = sortData_3.map((d) => `'${d.id}'`).join(",");
        await this.posMasterRepository
          .createQueryBuilder()
          .update(PosMaster)
          .set({
            posMasterOrder: () => `CASE id ${caseClauses_3} END`,
          })
          .where(`id IN (${ids_3})`)
          .execute();
        setLogDataDiff(request, { before, after: sortData_3 });
        break;
      }

      case 4: {
        const child4Id = await this.posMasterRepository.findOne({
          where: { orgChild4Id: requestBody.id },
        });
        if (!child4Id?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child4Id: " + requestBody.id);
        }
        const listPosMasterId_4 = await this.posMasterRepository.find({
          where: {
            orgRootId: Not(IsNull()),
            orgChild1Id: Not(IsNull()),
            orgChild2Id: Not(IsNull()),
            orgChild3Id: Not(IsNull()),
            orgChild4Id: requestBody.id,
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_4) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 4.");
        }
        const sortData_4 = listPosMasterId_4.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        // Bulk update using CASE WHEN instead of save() per row
        const caseClauses_4 = sortData_4
          .map((d) => `WHEN '${d.id}' THEN ${d.posMasterOrder}`)
          .join(" ");
        const ids_4 = sortData_4.map((d) => `'${d.id}'`).join(",");
        await this.posMasterRepository
          .createQueryBuilder()
          .update(PosMaster)
          .set({
            posMasterOrder: () => `CASE id ${caseClauses_4} END`,
          })
          .where(`id IN (${ids_4})`)
          .execute();
        setLogDataDiff(request, { before, after: sortData_4 });
        break;
      }

      default:
        throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: " + requestBody.type);
    }
    return new HttpSuccess();
  }

  /**
   * API ดูประวัติอัตรากำลัง
   *
   * @summary ORG_054 - ดูประวัติอัตรากำลัง (ADMIN) #58
   *
   * @param {string} id  Id อัตรากำลัง
   */
  @Get("history/{id}")
  async getHistoryPosMater(@Path() id: string, @Request() request: RequestWithUser) {
    let _workflow = await new permission().Workflow(request, id, "SYS_ORG");
    if (_workflow == false) await new permission().PermissionGet(request, "SYS_ORG");

    // ใช้ query builder สำหรับประสิทธิภาพที่ดีขึ้น
    const queryBuilder = this.posMasterRepository
      .createQueryBuilder("pm")
      .leftJoinAndSelect("pm.orgRevision", "orgRevision")
      .leftJoinAndSelect("pm.orgRoot", "orgRoot")
      .leftJoinAndSelect("pm.orgChild1", "orgChild1")
      .leftJoinAndSelect("pm.orgChild2", "orgChild2")
      .leftJoinAndSelect("pm.orgChild3", "orgChild3")
      .leftJoinAndSelect("pm.orgChild4", "orgChild4")
      .leftJoinAndSelect("pm.current_holder", "current_holder")
      .leftJoinAndSelect("pm.positions", "positions")
      .leftJoinAndSelect("positions.posLevel", "posLevel")
      .leftJoinAndSelect("positions.posType", "posType")
      .leftJoinAndSelect("positions.posExecutive", "posExecutive");

    // หาข้อมูลหลัก
    const posMaster = await queryBuilder.where("pm.id = :id", { id }).getOne();

    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }

    // สร้าง conditions
    const ancestorDNA = posMaster.ancestorDNA || "123";
    let historyQuery = queryBuilder.where("pm.ancestorDNA = :ancestorDNA", { ancestorDNA });

    // เพิ่มเงื่อนไข draft
    if (
      posMaster.orgRevision?.orgRevisionIsCurrent != false &&
      posMaster.orgRevision?.orgRevisionIsDraft != true
    ) {
      historyQuery = historyQuery.andWhere("orgRevision.orgRevisionIsDraft != :isDraft", {
        isDraft: true,
      });
    }

    const posMasters = await historyQuery.orderBy("pm.lastUpdatedAt", "DESC").getMany();

    const _data = posMasters.map((item) => ({
      id: item.id,
      orgShortName:
        item.orgChild4?.orgChild4ShortName ||
        item.orgChild3?.orgChild3ShortName ||
        item.orgChild2?.orgChild2ShortName ||
        item.orgChild1?.orgChild1ShortName ||
        item.orgRoot?.orgRootShortName ||
        null,
      lastUpdatedAt: item.lastUpdatedAt,
      posMasterNoPrefix: item.posMasterNoPrefix,
      posMasterNo: item.posMasterNo,
      posMasterNoSuffix: item.posMasterNoSuffix,
      reason: item.reason,
      position: item.positions.map((x) => x.positionName).join("/"),
      posExecutive: item.positions
        .filter((x) => x.posExecutive)
        .map((x) => x.posExecutive!.posExecutiveName)
        .join("/"),
      posLevel: item.positions.map((x) => x.posLevel.posLevelName).join("/"),
      posType: item.positions.map((x) => x.posType.posTypeName).join("/"),
      fullname:
        `${item.current_holder?.prefix || ""}${item.current_holder?.firstName || ""} ${item.current_holder?.lastName || ""}`.trim(),
    }));

    return new HttpSuccess(_data);
  }
  /**
   * API ย้ายอัตรากำลัง
   *
   * @summary ORG_054 - ย้ายอัตรากำลัง (ADMIN) #59
   *
   */
  @Post("move")
  async movePosMaster(
    @Body() requestBody: { id: string; type: number; positionMaster: string[] },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG");
    const posMasters = await this.posMasterRepository.find({
      where: { id: In(requestBody.positionMaster) },
    });

    const type0LastPosMasterNo =
      requestBody.type == 0
        ? await this.posMasterRepository.find({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull(),
            },
          })
        : [];

    const type1LastPosMasterNo =
      requestBody.type == 1
        ? await this.posMasterRepository.find({
            where: {
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull(),
            },
          })
        : [];

    const type2LastPosMasterNo =
      requestBody.type == 2
        ? await this.posMasterRepository.find({
            where: {
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull(),
            },
          })
        : [];

    const type3LastPosMasterNo =
      requestBody.type == 3
        ? await this.posMasterRepository.find({
            where: {
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull(),
            },
          })
        : [];

    const type4LastPosMasterNo =
      requestBody.type == 4
        ? await this.posMasterRepository.find({
            where: {
              orgChild4Id: requestBody.id,
            },
          })
        : [];

    const allLastPosMasterNo = [
      ...type0LastPosMasterNo,
      ...type1LastPosMasterNo,
      ...type2LastPosMasterNo,
      ...type3LastPosMasterNo,
      ...type4LastPosMasterNo,
    ];

    // let maxPosMasterNo = Math.max(...allLastPosMasterNo.map((pos) => pos.posMasterNo), 0);
    let _shortName: string;
    let maxPosMasterOrder = Math.max(...allLastPosMasterNo.map((pos) => pos.posMasterOrder), 0);
    await Promise.all(
      posMasters.map(async (posMaster: any) => {
        let change = true;

        if (requestBody.type == 0) {
          const org = await this.orgRootRepository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            _shortName = org.orgRootShortName;
            const _posMaster = await this.posMasterRepository.findOne({
              where: {
                orgRootId: org.id,
                posMasterNo: posMaster.posMasterNo,
                orgChild1Id: IsNull() || "",
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgRootShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (
              posMaster.orgRootId == org.id &&
              posMaster.orgChild1Id == null &&
              posMaster.orgChild2Id == null &&
              posMaster.orgChild3Id == null &&
              posMaster.orgChild4Id == null
            )
              change = false;
            posMaster.orgRootId = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
            posMaster.orgChild1Id = null;
            posMaster.orgChild2Id = null;
            posMaster.orgChild3Id = null;
            posMaster.orgChild4Id = null;
          }
        }
        if (requestBody.type == 1) {
          const org = await this.child1Repository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            _shortName = org.orgChild1ShortName;
            const _posMaster = await this.posMasterRepository.findOne({
              where: {
                orgChild1Id: org.id,
                posMasterNo: posMaster.posMasterNo,
                orgChild2Id: IsNull() || "",
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgChild1ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (
              posMaster.orgChild1Id == org.id &&
              posMaster.orgChild2Id == null &&
              posMaster.orgChild3Id == null &&
              posMaster.orgChild4Id == null
            )
              change = false;
            posMaster.orgRootId = org.orgRootId;
            posMaster.orgChild1Id = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
            posMaster.orgChild2Id = null;
            posMaster.orgChild3Id = null;
            posMaster.orgChild4Id = null;
          }
        }
        if (requestBody.type == 2) {
          const org = await this.child2Repository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            _shortName = org.orgChild2ShortName;
            const _posMaster = await this.posMasterRepository.findOne({
              where: {
                orgChild2Id: org.id,
                posMasterNo: posMaster.posMasterNo,
                orgChild3Id: IsNull() || "",
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgChild2ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (
              posMaster.orgChild2Id == org.id &&
              posMaster.orgChild3Id == null &&
              posMaster.orgChild4Id == null
            )
              change = false;
            posMaster.orgRootId = org.orgRootId;
            posMaster.orgChild1Id = org.orgChild1Id;
            posMaster.orgChild2Id = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
            posMaster.orgChild3Id = null;
            posMaster.orgChild4Id = null;
          }
        }
        if (requestBody.type == 3) {
          const org = await this.child3Repository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            _shortName = org.orgChild3ShortName;
            const _posMaster = await this.posMasterRepository.findOne({
              where: {
                orgChild3Id: org.id,
                posMasterNo: posMaster.posMasterNo,
                orgChild4Id: IsNull() || "",
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgChild3ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (posMaster.orgChild3Id == org.id && posMaster.orgChild4Id == null) change = false;
            posMaster.orgRootId = org.orgRootId;
            posMaster.orgChild1Id = org.orgChild1Id;
            posMaster.orgChild2Id = org.orgChild2Id;
            posMaster.orgChild3Id = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
            posMaster.orgChild4Id = null;
          }
        }
        if (requestBody.type == 4) {
          const org = await this.child4Repository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            _shortName = org.orgChild4ShortName;
            const _posMaster = await this.posMasterRepository.findOne({
              where: {
                orgChild4Id: org.id,
                posMasterNo: posMaster.posMasterNo,
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgChild4ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );

            if (posMaster.orgChild4Id == org.id) change = false;
            posMaster.orgRootId = org.orgRootId;
            posMaster.orgChild1Id = org.orgChild1Id;
            posMaster.orgChild2Id = org.orgChild2Id;
            posMaster.orgChild3Id = org.orgChild3Id;
            posMaster.orgChild4Id = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
          }
        }

        //Check All Branch
        const orgRevision = await this.orgRevisionRepository.findOne({
          where: {
            // orgRevisionIsDraft: true,
            // orgRevisionIsCurrent: false,
            id: posMaster.orgRevisionId,
          },
        });
        const _orgRoot = await this.orgRootRepository.find({
          where: {
            orgRevisionId: orgRevision?.id,
            orgRootShortName: _shortName,
            id: Not(requestBody.id),
          },
        });
        if (_orgRoot.length > 0) {
          for (const r of _orgRoot) {
            const _posMasterRoot = await this.posMasterRepository.findOne({
              where: {
                orgRevisionId: orgRevision?.id,
                orgRootId: r.id,
                orgChild1Id: IsNull() || "",
                posMasterNo: posMaster.posMasterNo,
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMasterRoot != null) {
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${r.orgRootShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            }
          }
        }
        //child1
        const _orgChild1 = await this.child1Repository.find({
          where: {
            orgRevisionId: orgRevision?.id,
            orgChild1ShortName: _shortName,
            id: Not(requestBody.id),
          },
        });
        if (_orgChild1.length > 0) {
          for (const c1 of _orgChild1) {
            const _posMasterChild1 = await this.posMasterRepository.findOne({
              where: {
                orgRevisionId: orgRevision?.id,
                orgChild1Id: c1.id,
                orgChild2Id: IsNull() || "",
                posMasterNo: posMaster.posMasterNo,
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMasterChild1 != null) {
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${c1.orgChild1ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            }
          }
        }
        //child2
        const _orgChild2 = await this.child2Repository.find({
          where: {
            orgRevisionId: orgRevision?.id,
            orgChild2ShortName: _shortName,
            id: Not(requestBody.id),
          },
        });
        if (_orgChild2.length > 0) {
          for (const c2 of _orgChild2) {
            const _posMasterChild2 = await this.posMasterRepository.findOne({
              where: {
                orgRevisionId: orgRevision?.id,
                orgChild2Id: c2.id,
                orgChild3Id: IsNull() || "",
                posMasterNo: posMaster.posMasterNo,
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMasterChild2 != null) {
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${c2.orgChild2ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            }
          }
        }
        //child3
        const _orgChild3 = await this.child3Repository.find({
          where: {
            orgRevisionId: orgRevision?.id,
            orgChild3ShortName: _shortName,
            id: Not(requestBody.id),
          },
        });
        if (_orgChild3.length > 0) {
          for (const c3 of _orgChild3) {
            const _posMasterChild3 = await this.posMasterRepository.findOne({
              where: {
                orgRevisionId: orgRevision?.id,
                orgChild3Id: c3.id,
                orgChild4Id: IsNull() || "",
                posMasterNo: posMaster.posMasterNo,
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMasterChild3 != null) {
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${c3.orgChild3ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            }
          }
        }
        //child4
        const _orgChild4 = await this.child4Repository.find({
          where: {
            orgRevisionId: orgRevision?.id,
            orgChild4ShortName: _shortName,
            id: Not(requestBody.id),
          },
        });
        if (_orgChild4.length > 0) {
          for (const c4 of _orgChild4) {
            const _posMasterChild4 = await this.posMasterRepository.findOne({
              where: {
                orgRevisionId: orgRevision?.id,
                orgChild4Id: c4.id,
                posMasterNo: posMaster.posMasterNo,
                id: Not(In(requestBody.positionMaster)),
              },
            });
            if (_posMasterChild4 != null) {
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${c4.orgChild4ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            }
          }
        }
        const before = null;
        if (change == true) {
          posMaster.posMasterOrder = maxPosMasterOrder += 1;
          posMaster.createdUserId = request.user.sub;
          posMaster.createdFullName = request.user.name;
          posMaster.lastUpdateUserId = request.user.sub;
          posMaster.lastUpdateFullName = request.user.name;
          posMaster.createdAt = new Date();
          posMaster.lastUpdatedAt = new Date();
          await this.posMasterRepository.save(posMaster, { data: request });
          setLogDataDiff(request, { before, after: posMaster });

          // อัพเดท org และ posMasterNo ใน profile ตลอดไม่ต้องดัก isSit
          if (posMaster.current_holderId) {
            const orgRevision = await this.orgRevisionRepository.findOne({
              where: { id: posMaster.orgRevisionId },
            });
            if (orgRevision?.orgRevisionIsCurrent) {
              const pmWithOrg = await this.posMasterRepository.findOne({
                where: { id: posMaster.id },
                relations: [
                  "orgRoot",
                  "orgChild1",
                  "orgChild2",
                  "orgChild3",
                  "orgChild4",
                  "positions",
                  "positions.posExecutive",
                ],
              });
              const _profile = await this.profileRepository.findOne({
                where: { id: posMaster.current_holderId },
              });
              if (_profile && pmWithOrg) {
                const _null: any = null;
                _profile.posMasterNo = getPosMasterNo(pmWithOrg) ?? _null;
                _profile.org = getOrgFullName(pmWithOrg) ?? _null;
                // ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
                if (!pmWithOrg.isSit) {
                  const selectedPos = (pmWithOrg as any).positions?.find(
                    (p: any) => p.positionIsSelected === true,
                  );
                  if (selectedPos) {
                    _profile.position = selectedPos.positionName ?? _null;
                    _profile.posTypeId = selectedPos.posTypeId ?? _null;
                    _profile.posLevelId = selectedPos.posLevelId ?? _null;
                    _profile.positionField = selectedPos.positionField ?? _null;
                    _profile.posExecutive =
                      (selectedPos as any).posExecutive?.posExecutiveName ?? _null;
                    _profile.positionArea = selectedPos.positionArea ?? _null;
                    _profile.positionExecutiveField = selectedPos.positionExecutiveField ?? _null;
                  }
                }
                await this.profileRepository.save(_profile);
              }
            }
          }
        }
      }),
    );
    return new HttpSuccess();
  }

  /**
   * API ตำแหน่งทั้งหมด
   *
   * @summary ORG_055 - ตำแหน่งทั้งหมด (ADMIN) #60
   *
   */
  @Post("summary")
  async PositionSummary(@Body() requestBody: { id: string; type: number; isNode: boolean }) {
    let summary: any;
    let totalPosition: any;
    let totalPositionCurrentUse: any;
    let totalPositionCurrentVacant: any;
    let totalPositionNextUse: any;
    let totalPositionNextVacant: any;

    if (requestBody.isNode === true) {
      switch (requestBody.type) {
        case 0: {
          totalPosition = await this.posMasterRepository.count({
            where: { orgRootId: requestBody.id },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 1: {
          totalPosition = await this.posMasterRepository.count({
            where: { orgChild1Id: requestBody.id },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgChild1Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgChild1Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgChild1Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgChild1Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 2: {
          totalPosition = await this.posMasterRepository.count({
            where: { orgChild2Id: requestBody.id },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgChild2Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgChild2Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgChild2Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgChild2Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 3: {
          totalPosition = await this.posMasterRepository.count({
            where: { orgChild3Id: requestBody.id },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgChild3Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgChild3Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgChild3Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgChild3Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 4: {
          totalPosition = await this.posMasterRepository.count({
            where: { orgChild4Id: requestBody.id },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgChild4Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgChild4Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgChild4Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgChild4Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        default:
          break;
      }
    } else {
      switch (requestBody.type) {
        case 0: {
          totalPosition = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
            },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 1: {
          totalPosition = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
            },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 2: {
          totalPosition = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
            },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 3: {
          totalPosition = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
            },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 4: {
          totalPosition = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
            },
          });
          totalPositionCurrentUse = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.posMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        default:
          break;
      }
    }

    summary = {
      totalPosition: totalPosition,
      totalPositionCurrentUse: totalPositionCurrentUse,
      totalPositionCurrentVacant: totalPositionCurrentVacant,
      totalPositionNextUse: totalPositionNextUse,
      totalPositionNextVacant: totalPositionNextVacant,
    };
    return new HttpSuccess(summary);
  }
  /**
   * API สร้างคนครองตำแหน่ง
   *
   * @summary ORG_064 - สร้างคนครองตำแหน่ง (ADMIN) #70
   *
   */
  @Post("profile")
  async createHolder(
    @Body() requestBody: { posMaster: string; position: string; profileId: string; isSit: boolean },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG");
    const dataMaster = await this.posMasterRepository.findOne({
      where: { id: requestBody.posMaster },
      relations: ["positions", "orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"],
    });
    if (!dataMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }
    dataMaster.positions.forEach(async (position) => {
      if (position.id === requestBody.position) {
        position.positionIsSelected = true;
      } else {
        position.positionIsSelected = false;
      }
      await this.positionRepository.save(position);
    });
    const _null: any = null;
    const before = null;
    dataMaster.isSit = requestBody.isSit;
    // dataMaster.next_holderId = requestBody.profileId;
    dataMaster.lastUpdatedAt = new Date();
    //add on
    // dataMaster.conditionReason = _null;
    // dataMaster.isCondition = false;
    //เช็คถ้า revision ปัจจุบันให้ปั๊มที่ profile
    const chkRevision = await this.orgRevisionRepository.findOne({
      where: { id: dataMaster.orgRevisionId },
    });
    if (chkRevision?.orgRevisionIsCurrent) {
      const _profile = await this.profileRepository.findOne({
        where: { id: requestBody.profileId },
      });
      if (_profile) {
        let _position = await this.positionRepository.findOne({
          where: { id: requestBody.position, posMasterId: requestBody.posMaster },
          relations: ["posExecutive"],
        });
        if (_position) {
          // อัพเดท org และ posMasterNo ตลอดไม่ต้องดัก isSit
          _profile.posMasterNo = getPosMasterNo(dataMaster);
          _profile.org = getOrgFullName(dataMaster);
          // ถ้าไม่ใช่ตำแหน่งนั่งทับ (isSit = false) ถึงจะอัพเดทตำแหน่งในทะเบียนประวัติ
          if (!dataMaster.isSit) {
            _profile.position = _position.positionName;
            _profile.posTypeId = _position.posTypeId;
            _profile.posLevelId = _position.posLevelId;
            _profile.positionField = _position.positionField ?? _null;
            _profile.posExecutive = _position.posExecutive?.posExecutiveName ?? _null;
            _profile.positionArea = _position.positionArea ?? _null;
            _profile.positionExecutiveField = _position.positionExecutiveField ?? _null;
          }
          await this.profileRepository.save(_profile);
          setLogDataDiff(request, { before, after: _profile });
        }
      }
      dataMaster.current_holderId = requestBody.profileId;
      dataMaster.next_holderId = _null;
    } else {
      dataMaster.next_holderId = requestBody.profileId;
      dataMaster.current_holderId = _null;
    }
    await this.posMasterRepository.save(dataMaster, { data: request });
    if (chkRevision?.orgRevisionIsCurrent) {
      await CreatePosMasterHistoryOfficer(dataMaster.id, request);
    }
    setLogDataDiff(request, { before, after: dataMaster });

    return new HttpSuccess();
  }

  /**
   * API ลบคนครองตำแหน่ง
   *
   * @summary ORG_066 - ลบคนครองตำแหน่ง (ADMIN) #71
   *
   * @param  {string} id  *Id posMaster
   */
  @Post("profile/delete/{id}")
  async deleteHolder(@Path() id: string, @Request() request: RequestWithUser) {
    await new permission().PermissionUpdate(request, "SYS_ORG");
    const dataMaster = await this.posMasterRepository.findOne({
      where: { id: id },
      relations: ["positions", "orgRevision"],
    });
    if (!dataMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }

    if (dataMaster.orgRevision.orgRevisionIsCurrent) {
      await CreatePosMasterHistoryOfficer(dataMaster.id, request, "DELETE");
    }

    if (dataMaster.current_holderId) {
      await this.keycloakAttributeService.clearOrgDnaAttributes(
        [dataMaster.current_holderId],
        "PROFILE",
      );
    }

    let _profileId: string = "";
    if (dataMaster?.current_holderId) {
      _profileId = dataMaster?.current_holderId;
    }
    await this.posMasterRepository.update(id, {
      isSit: false,
      next_holderId: null,
      current_holderId: null,
      statusReport: "PENDING",
    });

    console.log(
      `[positionIsSelected-DEBUG] Deleting holder, resetting ALL positions to false (posMasterId: ${id}, userId: ${request.user.sub}, endpoint: deleteHolder)`
    );

    dataMaster.positions.forEach(async (position) => {
      logPositionIsSelectedChange(position.id, position.positionIsSelected, false, {
        posMasterId: id,
        userId: request.user.sub,
        endpoint: "deleteHolder",
        action: "delete_holder_reset_positions",
      });

      await this.positionRepository.update(position.id, {
        positionIsSelected: false,
      });
    });

    // //เช็คถ้า revision ปัจจุบันให้ปั๊มที่ profile
    // const chkRevision = await this.orgRevisionRepository.findOne({
    //   where: { id: dataMaster.orgRevisionId },
    // });
    // if (chkRevision?.orgRevisionIsCurrent) {
    //   const _profile = await this.profileRepository.findOne({
    //     where: { id: _profileId }
    //   });
    //   if (_profile) {
    //     const _null: any = null;
    //     const before = null;
    //     _profile.position = _null
    //     _profile.posTypeId = _null
    //     _profile.posLevelId = _null
    //     await this.profileRepository.save(_profile);
    //     setLogDataDiff(request, { before, after: _profile });
    //   }
    // }
    return new HttpSuccess();
  }

  /**
   * API สืบทอดตำแหน่ง
   *
   * @summary ORG_068 - สืบทอดตำแหน่ง (ADMIN) #74
   *
   */
  @Post("dna")
  async dna(
    @Body()
    requestBody: {
      draftRevisionId?: string | null; //ใช้เฉพาะเคสสืบทอดจากโครงสร้างปัจจุบัน
      draftPositionId: string; //ในเคสสืบทอดจากโครงสร้างปัจจุบันจะ "ตำแหน่งที่แบบร่าง" จะเป็น "ตำแหน่งปัจจุบัน" ใช้ draftRevisionId เพื่อเช็คว่าเป็นโครงสร้างปัจจุบันไหม
      publishRevisionId?: string | null; //ใช้เฉพาะเคสสืบทอดจากโครงสร้างปัจจุบัน
      publishPositionId: string; //ในเคสสืบทอดจากโครงสร้างปัจจุบันจะ "ตำแหน่งปัจจุบัน" จะเป็น "ตำแหน่งที่ต้องการจะสืบทอด" ตาม publishRevisionId ที่ส่งมา
    },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG");
    let whereConditionRevision: any = {};

    // ถ้ามี draftRevisionId ค่อยเพิ่มเข้าไป
    if (requestBody.draftRevisionId) {
      whereConditionRevision.id = requestBody.draftRevisionId;
    } else {
      whereConditionRevision.orgRevisionIsDraft = true;
    }

    const findDraft = await this.orgRevisionRepository.findOne({
      where: whereConditionRevision,
    });
    if (!findDraft) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้างที่เผยแพร่");
    }

    let whereConditionPub: any = {};
    // ถ้ามี publishPositionId ค่อยเพิ่มเข้าไป ***อันนี้อาจไม่ต้องทำเพราะใช้ publishPositionId where ได้โดยตรง (!!รอดูหน้าบ้าน!!)***
    if (requestBody.publishRevisionId) {
      whereConditionPub.id = requestBody.publishPositionId;
      whereConditionPub.orgRevisionId = requestBody.publishRevisionId;
    } else {
      whereConditionPub.id = requestBody.publishPositionId;
    }
    const dataPublish = await this.posMasterRepository.findOne({
      //เคสโครงสร้างปัจจุบัน: ตัวที่ต้องการจะสืบทอด
      where: whereConditionPub,
    });
    if (!dataPublish) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }

    let whereConditionDraft: any = {};
    // ถ้ามี publishPositionId ค่อยเพิ่มเข้าไป ***อันนี้อาจไม่ต้องทำเพราะใช้ draftPositionId where ได้โดยตรง (!!รอดูหน้าบ้าน!!)***
    if (requestBody.draftRevisionId) {
      whereConditionDraft.id = requestBody.draftPositionId;
      whereConditionDraft.orgRevisionId = requestBody.draftRevisionId;
    } else {
      whereConditionDraft.id = requestBody.draftPositionId;
    }
    const dataDraft = await this.posMasterRepository.findOne({
      //เคสโครงสร้างปัจจุบัน: ตัวปัจจุบัน
      where: whereConditionDraft,
    });
    if (!dataDraft) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }

    await this.posMasterRepository.update(
      { orgRevisionId: findDraft.id, ancestorDNA: dataPublish.ancestorDNA },
      { ancestorDNA: "" },
    );
    if (dataPublish.ancestorDNA == null || dataPublish.ancestorDNA == "")
      dataPublish.ancestorDNA = dataPublish.id;
    dataDraft.ancestorDNA = dataPublish.ancestorDNA;
    await this.posMasterRepository.save(dataDraft);
    await this.posMasterRepository.save(dataPublish);

    return new HttpSuccess();
  }

  /**
   * API ค้นหาตำแหน่งในระบบสมัครสอบ ขรก.
   *
   * @summary ค้นหาตำแหน่งในระบบสมัครสอบ ขรก.
   *
   */
  @Post("placement/search-all")
  async searchPlacementAll(
    @Body()
    body: {
      node: number;
      nodeId: string;
      position?: string | null;
      posType?: string | null;
      posLevel?: string | null;
      isAll: boolean;
      isBlank: boolean;
    },
  ) {
    let typeCondition: any = {};
    let conditionA =
      "positions.posTypeId LIKE :posType AND positions.posLevelId LIKE :posLevel AND positions.positionName LIKE :position";

    let posType = await this.posTypeRepository.findOne({
      where: { id: String(body.posType) },
    });
    let posLevel = await this.posLevelRepository.findOne({
      where: { id: String(body.posLevel) },
    });

    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,
        };
      } else if (body.node === 1) {
        typeCondition = {
          orgChild1Id: body.nodeId,
        };
      } else if (body.node === 2) {
        typeCondition = {
          orgChild2Id: body.nodeId,
        };
      } else if (body.node === 3) {
        typeCondition = {
          orgChild3Id: body.nodeId,
        };
      } else if (body.node === 4) {
        typeCondition = {
          orgChild4Id: body.nodeId,
        };
      }
    }
    if (body.isBlank == true) {
      typeCondition.current_holderId = IsNull();
    }

    const [posMaster, total] = await AppDataSource.getRepository(PosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRevision", "orgRevision")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("posMaster.next_holder", "next_holder")
      .leftJoinAndSelect("posMaster.positions", "positions")
      .leftJoinAndSelect("positions.posType", "posType")
      .leftJoinAndSelect("positions.posLevel", "posLevel")
      .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .andWhere("orgRevision.orgRevisionIsCurrent = true")
      .andWhere("orgRevision.orgRevisionIsDraft = false")
      .andWhere(
        new Brackets((qb) => {
          qb.andWhere(typeCondition).andWhere(conditionA == null ? "1=1" : conditionA, {
            posType: posType == null ? `%%` : `${posType.id}`,
            posLevel: posLevel == null ? `%%` : `${posLevel.id}`,
            position: body.position == null ? `%%` : `${body.position}`,
          });
        }),
      )
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .getManyAndCount();

    const _posType = await this.posTypeRepository.find({
      where: { posTypeName: In(["ทั่วไป", "วิชาการ"]) },
    });
    const _posLevel = await this.posLevelRepository.find({
      where: { posLevelName: In(["ปฏิบัติงาน", "ปฏิบัติการ"]) },
    });

    const formattedData = await Promise.all(
      posMaster.map(async (posMaster) => {
        let shortName = "";
        if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id == null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 0;
          shortName = posMaster.orgRoot.orgRootShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 1;
          shortName = posMaster.orgChild1.orgChild1ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 2;
          shortName = posMaster.orgChild2.orgChild2ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.node = 3;
          shortName = posMaster.orgChild3.orgChild3ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.node = 4;
          shortName = posMaster.orgChild4.orgChild4ShortName;
        }

        let node: any = null;
        let nodeId: any = null;
        if (posMaster.orgChild4Id != null) {
          node = 4;
          nodeId = posMaster.orgChild4Id;
        } else if (posMaster.orgChild3Id != null) {
          node = 3;
          nodeId = posMaster.orgChild3Id;
        } else if (posMaster.orgChild2Id != null) {
          node = 2;
          nodeId = posMaster.orgChild2Id;
        } else if (posMaster.orgChild1Id != null) {
          node = 1;
          nodeId = posMaster.orgChild1Id;
        } else if (posMaster.orgRootId != null) {
          node = 0;
          nodeId = posMaster.orgRootId;
        }

        let _position: any;
        if (posLevel == null && posType == null && body.position != null) {
          _position = posMaster.positions
            .filter(
              (x: any) =>
                _posType.some((y: any) => y.id == x.posTypeId) &&
                _posLevel.some((z: any) => z.id == x.posLevelId),
            )
            .map((position) => ({
              id: position.id,
              positionName: position.positionName,
              positionField: position.positionField,
              posTypeId: position.posTypeId,
              posTypeName: position.posType == null ? null : position.posType.posTypeName,
              posLevelId: position.posLevelId,
              posLevelName: position.posLevel == null ? null : position.posLevel.posLevelName,
              posExecutiveId: position.posExecutiveId,
              posExecutiveName:
                position.posExecutive == null ? null : position.posExecutive.posExecutiveName,
              positionExecutiveField: position.positionExecutiveField,
              positionArea: position.positionArea,
              positionIsSelected: position.positionIsSelected,
              isSpecial: position.isSpecial,
            }));
        } else {
          _position = posMaster.positions.map((position) => ({
            id: position.id,
            positionName: position.positionName,
            positionField: position.positionField,
            posTypeId: position.posTypeId,
            posTypeName: position.posType == null ? null : position.posType.posTypeName,
            posLevelId: position.posLevelId,
            posLevelName: position.posLevel == null ? null : position.posLevel.posLevelName,
            posExecutiveId: position.posExecutiveId,
            posExecutiveName:
              position.posExecutive == null ? null : position.posExecutive.posExecutiveName,
            positionExecutiveField: position.positionExecutiveField,
            positionArea: position.positionArea,
            positionIsSelected: position.positionIsSelected,
            isSpecial: position.isSpecial,
          }));
        }

        return {
          id: posMaster.id,
          node: node,
          nodeId: nodeId,
          isDirector: posMaster.isDirector,
          orgRootId: posMaster.orgRootId,
          orgChild1Id: posMaster.orgChild1Id,
          orgChild2Id: posMaster.orgChild2Id,
          orgChild3Id: posMaster.orgChild3Id,
          orgChild4Id: posMaster.orgChild4Id,
          isCondition: posMaster.isCondition,
          posMasterNoPrefix: posMaster.posMasterNoPrefix,
          posMasterNo: posMaster.posMasterNo,
          posMasterNoSuffix: posMaster.posMasterNoSuffix,
          orgShortname: shortName,
          isSit: posMaster.isSit,
          fullNameCurrentHolder:
            posMaster.current_holder == null
              ? null
              : `${posMaster.current_holder.prefix}${posMaster.current_holder.firstName} ${posMaster.current_holder.lastName}`,
          fullNameNextHolder:
            posMaster.next_holder == null
              ? null
              : `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`,
          isPosition: posMaster.positions.filter((x) => x.positionName == body.position).length > 0,
          positions: _position,
        };
      }),
    );
    return new HttpSuccess({ data: formattedData, total });
  }
  /**
   * API ค้นหาตำแหน่งในระบบสมัครสอบ ขรก.
   *
   * @summary ค้นหาตำแหน่งในระบบสมัครสอบ ขรก.
   *
   */
  @Post("placement/search")
  async searchPlacement(
    @Body()
    body: {
      node: number;
      nodeId: string;
      position: string;
      typeCommand: string | null;
      posType?: string | null;
      posLevel?: string | null;
      profileId?: string | null;
      isAll: boolean;
      isBlank: boolean;
    },
  ) {
    let typeCondition: any = {};
    let conditionA: any = "1=1";
    let params: any = {};
    let posType: any = {};
    let posLevel: any = {};

    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";
        params = {
          posType: posType?.id,
          posLevel: posLevel?.id,
        };
      } else if (body.typeCommand == "APPOINT") {
        // เดิม : กรองเฉพาะ posTypeRank ที่สูงกว่า
        // conditionA = "posType.posTypeRank > :posTypeRank";
        // ใหม่ : กรองเฉพาะ posType ที่สูงหรือต่ำกว่าก็ได้
        conditionA = "positions.posTypeId != :currentPosType";
        params = {
          // posTypeRank: posType?.posTypeRank ?? 0,
          currentPosType: posType?.id,
        };
      } 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) {
      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,
        };
      } else if (body.node === 1) {
        typeCondition = {
          orgChild1Id: body.nodeId,
        };
      } else if (body.node === 2) {
        typeCondition = {
          orgChild2Id: body.nodeId,
        };
      } else if (body.node === 3) {
        typeCondition = {
          orgChild3Id: body.nodeId,
        };
      } else if (body.node === 4) {
        typeCondition = {
          orgChild4Id: body.nodeId,
        };
      }
    }
    if (body.isBlank == true) {
      typeCondition.current_holderId = IsNull();
    }

    if (body.typeCommand === "MOVE" && body.profileId && !body.isBlank) {
      typeCondition.current_holderId = Not(body.profileId);
    }

    const [posMaster, total] = await AppDataSource.getRepository(PosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRevision", "orgRevision")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("posMaster.next_holder", "next_holder")
      .leftJoinAndSelect("posMaster.positions", "positions")
      .leftJoinAndSelect("positions.posType", "posType")
      .leftJoinAndSelect("positions.posLevel", "posLevel")
      .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .andWhere("posMaster.next_holderId IS NULL")
      .andWhere("orgRevision.orgRevisionIsCurrent = true")
      .andWhere("orgRevision.orgRevisionIsDraft = false")
      .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,
            // });
            .andWhere(conditionA, params);
        }),
      )
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .getManyAndCount();

    const formattedData = await Promise.all(
      posMaster.map(async (posMaster) => {
        let shortName = "";
        if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id == null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 0;
          shortName = posMaster.orgRoot.orgRootShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 1;
          shortName = posMaster.orgChild1.orgChild1ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 2;
          shortName = posMaster.orgChild2.orgChild2ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.node = 3;
          shortName = posMaster.orgChild3.orgChild3ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.node = 4;
          shortName = posMaster.orgChild4.orgChild4ShortName;
        }

        let node: any = null;
        let nodeId: any = null;
        if (posMaster.orgChild4Id != null) {
          node = 4;
          nodeId = posMaster.orgChild4Id;
        } else if (posMaster.orgChild3Id != null) {
          node = 3;
          nodeId = posMaster.orgChild3Id;
        } else if (posMaster.orgChild2Id != null) {
          node = 2;
          nodeId = posMaster.orgChild2Id;
        } else if (posMaster.orgChild1Id != null) {
          node = 1;
          nodeId = posMaster.orgChild1Id;
        } else if (posMaster.orgRootId != null) {
          node = 0;
          nodeId = posMaster.orgRootId;
        }

        return {
          id: posMaster.id,
          node: node,
          nodeId: nodeId,
          isDirector: posMaster.isDirector,
          orgRootId: posMaster.orgRootId,
          orgChild1Id: posMaster.orgChild1Id,
          orgChild2Id: posMaster.orgChild2Id,
          orgChild3Id: posMaster.orgChild3Id,
          orgChild4Id: posMaster.orgChild4Id,
          isCondition: posMaster.isCondition,
          posMasterNoPrefix: posMaster.posMasterNoPrefix,
          posMasterNo: posMaster.posMasterNo,
          posMasterNoSuffix: posMaster.posMasterNoSuffix,
          orgShortname: shortName,
          isSit: posMaster.isSit,
          fullNameCurrentHolder:
            posMaster.current_holder == null
              ? null
              : `${posMaster.current_holder.prefix}${posMaster.current_holder.firstName} ${posMaster.current_holder.lastName}`,
          fullNameNextHolder:
            posMaster.next_holder == null
              ? null
              : `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`,
          isPosition: posMaster.positions.filter((x) => x.positionName == body.position).length > 0,
          positions: posMaster.positions.map((position) => ({
            id: position.id,
            positionName: position.positionName,
            positionField: position.positionField,
            posTypeId: position.posTypeId,
            posTypeName: position.posType == null ? null : position.posType.posTypeName,
            posLevelId: position.posLevelId,
            posLevelName: position.posLevel == null ? null : position.posLevel.posLevelName,
            posExecutiveId: position.posExecutiveId,
            posExecutiveName:
              position.posExecutive == null ? null : position.posExecutive.posExecutiveName,
            positionExecutiveField: position.positionExecutiveField,
            positionArea: position.positionArea,
            positionIsSelected: position.positionIsSelected,
            isSpecial: position.isSpecial,
          })),
        };
      }),
    );
    return new HttpSuccess({ data: formattedData, total });
  }

  /**
   * API ค้นหาตำแหน่งในระบบสมัครสอบ ลูกจ้าง
   *
   * @summary ค้นหาตำแหน่งในระบบสมัครสอบ ลูกจ้าง
   *
   */
  @Post("placementemp/search")
  async searchPlacementEmp(
    @Body()
    body: {
      node: number;
      nodeId: string;
      position: string;
      typeCommand: string | null;
      posType?: string | null;
      posLevel?: string | null;
      isAll: boolean;
      isBlank: boolean;
    },
  ) {
    let typeCondition: any = {};
    let conditionA: any = null;

    let posType = await this.posTypeEmployeeRepository.findOne({
      where: { id: String(body.posType) },
    });
    let posLevel = await this.posLevelEmployeeRepository.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.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,
        };
      } else if (body.node === 1) {
        typeCondition = {
          orgChild1Id: body.nodeId,
        };
      } else if (body.node === 2) {
        typeCondition = {
          orgChild2Id: body.nodeId,
        };
      } else if (body.node === 3) {
        typeCondition = {
          orgChild3Id: body.nodeId,
        };
      } else if (body.node === 4) {
        typeCondition = {
          orgChild4Id: body.nodeId,
        };
      }
    }
    if (body.isBlank == true) {
      typeCondition.current_holderId = IsNull();
    }

    const [posMaster, total] = await AppDataSource.getRepository(EmployeePosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("posMaster.next_holder", "next_holder")
      .leftJoinAndSelect("posMaster.positions", "positions")
      .leftJoinAndSelect("positions.posType", "posType")
      .leftJoinAndSelect("positions.posLevel", "posLevel")
      // .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .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 ? "" : posType.posTypeRank,
            posLevelRank: posLevel == null ? "" : posLevel.posLevelRank,
          });
        }),
      )
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .getManyAndCount();

    const formattedData = await Promise.all(
      posMaster.map(async (posMaster) => {
        let shortName = "";
        if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id == null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 0;
          shortName = posMaster.orgRoot.orgRootShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 1;
          shortName = posMaster.orgChild1.orgChild1ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 2;
          shortName = posMaster.orgChild2.orgChild2ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.node = 3;
          shortName = posMaster.orgChild3.orgChild3ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.node = 4;
          shortName = posMaster.orgChild4.orgChild4ShortName;
        }

        let node: any = null;
        let nodeId: any = null;
        if (posMaster.orgChild4Id != null) {
          node = 4;
          nodeId = posMaster.orgChild4Id;
        } else if (posMaster.orgChild3Id != null) {
          node = 3;
          nodeId = posMaster.orgChild3Id;
        } else if (posMaster.orgChild2Id != null) {
          node = 2;
          nodeId = posMaster.orgChild2Id;
        } else if (posMaster.orgChild1Id != null) {
          node = 1;
          nodeId = posMaster.orgChild1Id;
        } else if (posMaster.orgRootId != null) {
          node = 0;
          nodeId = posMaster.orgRootId;
        }
        return {
          id: posMaster.id,
          node: node,
          nodeId: nodeId,
          isDirector: posMaster.isDirector,
          orgRootId: posMaster.orgRootId,
          orgChild1Id: posMaster.orgChild1Id,
          orgChild2Id: posMaster.orgChild2Id,
          orgChild3Id: posMaster.orgChild3Id,
          orgChild4Id: posMaster.orgChild4Id,
          posMasterNoPrefix: posMaster.posMasterNoPrefix,
          posMasterNo: posMaster.posMasterNo,
          posMasterNoSuffix: posMaster.posMasterNoSuffix,
          orgShortname: shortName,
          isSit: posMaster.isSit,
          isPosition: posMaster.positions.filter((x) => x.positionName == body.position).length > 0,
          // current_holder: posMaster.current_holderId ? posMaster.current_holderId : null,
          // next_holder: posMaster.next_holderId ? posMaster.next_holderId : null,
          fullNameCurrentHolder:
            posMaster.current_holder == null
              ? null
              : `${posMaster.current_holder.prefix}${posMaster.current_holder.firstName} ${posMaster.current_holder.lastName}`,
          fullNameNextHolder:
            posMaster.next_holder == null
              ? null
              : `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`,
          isCondition: posMaster.isCondition,
          conditionReason: posMaster.conditionReason,
          positions: posMaster.positions.map((position) => ({
            id: position.id,
            positionName: position.positionName,
            // positionField: position.positionField,
            posTypeId: position.posTypeId,
            posTypeName: position.posType == null ? null : position.posType.posTypeName,
            posLevelId: position.posLevelId,
            posLevelName:
              position.posType == null && position.posLevel == null
                ? null
                : `${position.posType.posTypeShortName} ${position.posLevel.posLevelName}`,
            // posExecutiveId: position.posExecutiveId,
            // posExecutiveName:
            //   position.posExecutive == null ? null : position.posExecutive.posExecutiveName,
            // positionExecutiveField: position.positionExecutiveField,
            // positionArea: position.positionArea,
            positionIsSelected: position.positionIsSelected,
            // isSpecial: position.isSpecial,
          })),
        };
      }),
    );
    return new HttpSuccess({ data: formattedData, total });
  }

  /**
   * API ค้นหาคนตามโครงสร้าง
   *
   * @summary ค้นหาคนตามโครงสร้าง
   *
   */
  @Post("profile/search")
  async searchProfile(
    @Body()
    body: {
      isAll: boolean;
      node: number;
      nodeId: string;
    },
  ) {
    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.node === 0) {
        typeCondition = {
          orgRootId: body.nodeId,
        };
      } else if (body.node === 1) {
        typeCondition = {
          orgChild1Id: body.nodeId,
        };
      } else if (body.node === 2) {
        typeCondition = {
          orgChild2Id: body.nodeId,
        };
      } else if (body.node === 3) {
        typeCondition = {
          orgChild3Id: body.nodeId,
        };
      } else if (body.node === 4) {
        typeCondition = {
          orgChild4Id: body.nodeId,
        };
      }
    }

    const [posMaster, total] = await AppDataSource.getRepository(PosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("posMaster.next_holder", "next_holder")
      .leftJoinAndSelect("posMaster.positions", "positions")
      .leftJoinAndSelect("positions.posType", "posType")
      .leftJoinAndSelect("positions.posLevel", "posLevel")
      .where("posMaster.current_holderId IS NOT NULL")
      .andWhere(
        new Brackets((qb) => {
          qb.orWhere(typeCondition);
        }),
      )
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .getManyAndCount();

    const formattedData = await Promise.all(
      posMaster.map(async (posMaster) => {
        let shortName = "";
        if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id == null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 0;
          shortName = posMaster.orgRoot.orgRootShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 1;
          shortName = posMaster.orgChild1.orgChild1ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id == null
        ) {
          body.node = 2;
          shortName = posMaster.orgChild2.orgChild2ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.node = 3;
          shortName = posMaster.orgChild3.orgChild3ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.node = 4;
          shortName = posMaster.orgChild4.orgChild4ShortName;
        }

        let node: any = null;
        let nodeId: any = null;
        if (posMaster.orgChild4Id != null) {
          node = 4;
          nodeId = posMaster.orgChild4Id;
        } else if (posMaster.orgChild3Id != null) {
          node = 3;
          nodeId = posMaster.orgChild3Id;
        } else if (posMaster.orgChild2Id != null) {
          node = 2;
          nodeId = posMaster.orgChild2Id;
        } else if (posMaster.orgChild1Id != null) {
          node = 1;
          nodeId = posMaster.orgChild1Id;
        } else if (posMaster.orgRootId != null) {
          node = 0;
          nodeId = posMaster.orgRootId;
        }
        const fullname =
          posMaster.current_holder.prefix +
          " " +
          posMaster.current_holder.firstName +
          " " +
          posMaster.current_holder.lastName;
        // Construct org path
        const _root = posMaster.orgRoot ? `${posMaster.orgRoot.orgRootName}` : "";
        const _child1 = posMaster.orgChild1 ? `${posMaster.orgChild1.orgChild1Name}/` : "";
        const _child2 = posMaster.orgChild2 ? `${posMaster.orgChild2.orgChild2Name}/` : "";
        const _child3 = posMaster.orgChild3 ? `${posMaster.orgChild3.orgChild3Name}/` : "";
        const _child4 = posMaster.orgChild4 ? `${posMaster.orgChild4.orgChild4Name}/` : "";
        return {
          id: posMaster.id,
          node: node,
          nodeId: nodeId,
          orgRootId: posMaster.orgRootId,
          orgChild1Id: posMaster.orgChild1Id,
          orgChild2Id: posMaster.orgChild2Id,
          orgChild3Id: posMaster.orgChild3Id,
          orgChild4Id: posMaster.orgChild4Id,
          posMasterNoPrefix: posMaster.posMasterNoPrefix,
          posMasterNo: posMaster.posMasterNo,
          posMasterNoSuffix: posMaster.posMasterNoSuffix,
          orgShortname: shortName,
          isSit: posMaster.isSit,
          name: fullname,
          prefix: posMaster.current_holder.prefix,
          firstName: posMaster.current_holder.firstName,
          lastName: posMaster.current_holder.lastName,
          profileId: posMaster.current_holder.id,
          citizenId: posMaster.current_holder.citizenId,
          position: posMaster.current_holder.position,
          organizationName: `${_child4}${_child3}${_child2}${_child1}${_root}`,
        };
      }),
    );
    return new HttpSuccess({ data: formattedData, total });
  }

  /**
   * API บันทึกตำแหน่งใหม่
   *
   * @summary บันทึกตำแหน่งใหม่
   *
   */
  @Post("report/current")
  async reportApproveCurrent(
    @Body()
    body: {
      posmasterId: string;
      positionId: string;
      profileId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    const posMaster = await this.posMasterRepository.findOne({
      where: { id: body.posmasterId },
    });
    if (posMaster == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");

    const posMasterOld = await this.posMasterRepository.findOne({
      where: {
        current_holderId: body.profileId,
        orgRevisionId: posMaster.orgRevisionId,
      },
    });
    if (posMasterOld != null) {
      posMasterOld.current_holderId = null;
      posMasterOld.lastUpdatedAt = new Date();
    }

    const positionOld = await this.positionRepository.findOne({
      where: {
        posMasterId: posMasterOld?.id,
        positionIsSelected: true,
      },
    });
    if (positionOld != null) {
      positionOld.positionIsSelected = false;
      await this.positionRepository.save(positionOld);
    }

    const checkPosition = await this.positionRepository.find({
      where: {
        posMasterId: body.posmasterId,
        positionIsSelected: true,
      },
    });
    if (checkPosition.length > 0) {
      const clearPosition = checkPosition.map((positions) => ({
        ...positions,
        positionIsSelected: false,
      }));
      await this.positionRepository.save(clearPosition);
    }

    const profile = await this.profileRepository.findOne({
      where: { id: body.profileId },
    });
    if (profile == null)
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");

    posMaster.current_holderId = body.profileId;
    posMaster.lastUpdatedAt = new Date();
    const _null: any = null;
    // posMaster.conditionReason = _null;
    // posMaster.isCondition = false;
    if (posMasterOld != null) {
      await this.posMasterRepository.save(posMasterOld);
      await CreatePosMasterHistoryOfficer(posMasterOld.id, request);
    }
    await this.posMasterRepository.save(posMaster);

    const positionNew = await this.positionRepository.findOne({
      where: {
        id: body.positionId,
        posMasterId: body.posmasterId,
      },
    });
    if (positionNew != null) {
      positionNew.positionIsSelected = true;
      profile.posLevelId = positionNew.posLevelId;
      profile.posTypeId = positionNew.posTypeId;
      profile.position = positionNew.positionName;
      await this.profileRepository.save(profile);
      await this.positionRepository.save(positionNew);
    }
    await CreatePosMasterHistoryOfficer(posMaster.id, request);

    return new HttpSuccess();
  }

  /**
   * API รายชื่อตามกลุ่มในโครงสร้าง
   *
   * @summary รายชื่อตามกลุ่มในโครงสร้าง
   *
   */
  @Post("report/draft")
  async reportDraft(
    @Body()
    body: {
      type: string;
      rootId: string;
    },
  ) {
    let conditionGroup = "";
    if (body.type.trim().toUpperCase() == "GROUP1.1") {
      conditionGroup =
        "(posType.posTypeName = 'ทั่วไป' AND posLevel.posLevelName = 'ชำนาญงาน') OR (posType.posTypeName = 'ทั่วไป' AND posLevel.posLevelName = 'ปฏิบัติงาน') OR (posType.posTypeName = 'วิชาการ' AND posLevel.posLevelName = 'ปฏิบัติการ') OR (posType.posTypeName = 'วิชาการ' AND posLevel.posLevelName = 'ชำนาญการ')";
    } else if (body.type.trim().toUpperCase() == "GROUP1.2") {
      conditionGroup =
        "(posType.posTypeName = 'ทั่วไป' AND posLevel.posLevelName = 'อาวุโส') OR (posType.posTypeName = 'วิชาการ' AND posLevel.posLevelName = 'ชำนาญการพิเศษ') OR (posType.posTypeName = 'อำนวยการ' AND posLevel.posLevelName = 'ต้น')";
    } else if (body.type.trim().toUpperCase() == "GROUP2") {
      conditionGroup =
        "(posType.posTypeName = 'ทั่วไป' AND posLevel.posLevelName = 'ทักษะพิเศษ') OR (posType.posTypeName = 'วิชาการ' AND posLevel.posLevelName = 'เชี่ยวชาญ') OR (posType.posTypeName = 'วิชาการ' AND posLevel.posLevelName = 'ทรงคุณวุฒิ') OR (posType.posTypeName = 'อำนวยการ' AND posLevel.posLevelName = 'สูง') OR (posType.posTypeName = 'บริหาร' AND posLevel.posLevelName = 'ต้น') OR (posType.posTypeName = 'บริหาร' AND posLevel.posLevelName = 'สูง')";
    } else {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "กลุ่มเป้าหมายไม่ถูกต้อง");
    }

    let posMaster = await AppDataSource.getRepository(PosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.next_holder", "next_holder")
      .leftJoinAndSelect("posMaster.positions", "positions")
      .leftJoinAndSelect("positions.posType", "posType")
      .leftJoinAndSelect("positions.posLevel", "posLevel")
      .leftJoinAndSelect("posMaster.orgRevision", "orgRevision")
      .andWhere("posMaster.orgRootId LIKE :orgRootId", {
        orgRootId: body.type.trim().toUpperCase() == "GROUP1.1" ? body.rootId : `%%`,
      })
      .andWhere("posMaster.statusReport = :statusReport", { statusReport: "PENDING" })
      .andWhere("posMaster.next_holderId IS NOT NULL")
      .andWhere("orgRevision.orgRevisionIsCurrent = :orgRevisionIsCurrent", {
        orgRevisionIsCurrent: false,
      })
      .andWhere("orgRevision.orgRevisionIsDraft = :orgRevisionIsDraft", {
        orgRevisionIsDraft: true,
      })
      .andWhere("positions.positionIsSelected = :isSelected", { isSelected: true })
      .andWhere(
        new Brackets((qb) => {
          qb.andWhere(conditionGroup);
        }),
      )
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .select([
        "posMaster.id",
        "posMaster.posMasterNo",
        "positions.positionName",
        "positions.positionIsSelected",
        "posType.posTypeName",
        "posLevel.posLevelName",
        "orgRoot.orgRootShortName",
        "orgChild1.orgChild1ShortName",
        "orgChild2.orgChild2ShortName",
        "orgChild3.orgChild3ShortName",
        "orgChild4.orgChild4ShortName",
        "next_holder.prefix",
        "next_holder.firstName",
        "next_holder.lastName",
        "next_holder.id",
        "next_holder.citizenId",
      ])
      .getMany();
    const _posMaster = posMaster.map((x) => {
      const posMasterNo =
        x.orgChild4 != null
          ? `${x.orgChild4.orgChild4ShortName} ${x.posMasterNo}`
          : x != null && x?.orgChild3 != null
            ? `${x.orgChild3.orgChild3ShortName} ${x.posMasterNo}`
            : x != null && x?.orgChild2 != null
              ? `${x.orgChild2.orgChild2ShortName} ${x.posMasterNo}`
              : x != null && x?.orgChild1 != null
                ? `${x.orgChild1.orgChild1ShortName} ${x.posMasterNo}`
                : x != null && x?.orgRoot != null
                  ? `${x.orgRoot.orgRootShortName} ${x.posMasterNo}`
                  : null;
      const position =
        x.positions.filter((x) => x.positionIsSelected == true).length > 0
          ? x.positions.filter((x) => x.positionIsSelected == true)[0]
          : null;
      return {
        id: x.id,
        posMasterNo: posMasterNo,
        positionName: position?.positionName || null,
        posType: position?.posType?.posTypeName || null,
        posLevel: position?.posLevel?.posLevelName || null,
        profileId: x.next_holder?.id || null,
        prefix: x.next_holder?.prefix || null,
        firstName: x.next_holder?.firstName || null,
        lastName: x.next_holder?.lastName || null,
        citizenId: x.next_holder?.citizenId || null,
      };
    });

    return new HttpSuccess(_posMaster);
  }

  /**
   * API รายการตำแหน่งติดเงื่อนไข
   *
   * @summary รายการตำแหน่งติดเงื่อนไข
   *
   */
  @Post("master/position-condition")
  async listPositionCondition(
    @Request() request: RequestWithUser,
    @Body()
    body: {
      id: string;
      revisionId: string;
      type: number;
      isAll: boolean; // true คือเลือกเฉพาะตำแหน่งติดเงื่อนไข / false คือเลือกตำแหน่งทั้งหมด
      page: number;
      pageSize: number;
      keyword?: string;
    },
  ) {
    let typeCondition: any = {};
    let checkChildConditions: any = {};
    let keywordAsInt: any;
    let searchShortName = "1=1";
    let searchShortName0 = `CONCAT_WS(' ',orgRoot.orgRootShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName1 = `CONCAT_WS(' ',orgChild1.orgChild1ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName2 = `CONCAT_WS(' ',orgChild2.orgChild2ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName3 = `CONCAT_WS(' ',orgChild3.orgChild3ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName4 = `CONCAT_WS(' ',orgChild4.orgChild4ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let _data = await new permission().PermissionOrgList(request, "SYS_POS_CONDITION");
    const orgDna = await new permission().checkDna(request, request.user.sub);
    let level: any = resolveNodeLevel(orgDna);

    const cannotViewRootPosMaster =
      _data.privilege === "PARENT" ||
      (_data.privilege === "BROTHER" && level > 1) ||
      (_data.privilege === "CHILD" && level > 0) ||
      (_data.privilege === "NORMAL" && level != 0);

    const cannotViewChild1PosMaster =
      (_data.privilege === "PARENT" && level > 1) ||
      (_data.privilege === "BROTHER" && level > 2) ||
      (_data.privilege === "CHILD" && level > 1) ||
      (_data.privilege === "NORMAL" && level !== 1);

    const cannotViewChild2PosMaster =
      (_data.privilege === "PARENT" && level > 2) ||
      (_data.privilege === "BROTHER" && level > 3) ||
      (_data.privilege === "CHILD" && level > 2) ||
      (_data.privilege === "NORMAL" && level !== 2);

    const cannotViewChild3PosMaster =
      (_data.privilege === "PARENT" && level > 3) ||
      (_data.privilege === "BROTHER" && level > 4) ||
      (_data.privilege === "CHILD" && level > 3) ||
      (_data.privilege === "NORMAL" && level !== 3);

    const cannotViewChild4PosMaster =
      (_data.privilege === "PARENT" && level > 4) ||
      (_data.privilege === "CHILD" && level > 4) ||
      (_data.privilege === "NORMAL" && level !== 4);

    if (body.type === 0) {
      typeCondition = {
        ...(cannotViewRootPosMaster ? { orgRootId: null } : { orgRootId: body.id }),
      };
      // if (!body.isAll) {
      //   checkChildConditions = {
      //     orgChild1Id: IsNull(),
      //   };
      //   searchShortName = `CONCAT_WS(' ',orgRoot.orgRootShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      // } else {
      // }
    } else if (body.type === 1) {
      typeCondition = {
        ...(cannotViewChild1PosMaster ? { orgChild1Id: null } : { orgChild1Id: body.id }),
      };
      // if (!body.isAll) {
      //   checkChildConditions = {
      //     orgChild2Id: IsNull(),
      //   };
      //   searchShortName = `CONCAT_WS(' ',orgChild1.orgChild1ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      // } else {
      // }
    } else if (body.type === 2) {
      typeCondition = {
        ...(cannotViewChild2PosMaster ? { orgChild2Id: null } : { orgChild2Id: body.id }),
      };
      // if (!body.isAll) {
      //   checkChildConditions = {
      //     orgChild3Id: IsNull(),
      //   };
      //   searchShortName = `CONCAT_WS(' ',orgChild2.orgChild2ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      // } else {
      // }
    } else if (body.type === 3) {
      typeCondition = {
        ...(cannotViewChild3PosMaster ? { orgChild3Id: null } : { orgChild3Id: body.id }),
      };
      // if (!body.isAll) {
      //   checkChildConditions = {
      //     orgChild4Id: IsNull(),
      //   };
      //   searchShortName = `CONCAT_WS(' ',orgChild3.orgChild3ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      // } else {
      // }
    } else if (body.type === 4) {
      typeCondition = {
        ...(cannotViewChild4PosMaster ? { orgChild4Id: null } : { orgChild4Id: body.id }),
      };
      searchShortName = `CONCAT_WS(' ',orgChild4.orgChild4ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
    }
    let findPosition: any;
    let masterId = new Array();
    if (body.keyword != null && body.keyword != "") {
      const findTypes: PosType[] = await this.posTypeRepository.find({
        where: { posTypeName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posTypeId: In(findTypes.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const findLevel: PosLevel[] = await this.posLevelRepository.find({
        where: { posLevelName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posLevelId: In(findLevel.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const findExecutive: PosExecutive[] = await this.posExecutiveRepository.find({
        where: { posExecutiveName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.positionRepository.find({
        where: { posExecutiveId: In(findExecutive.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      findPosition = await this.positionRepository.find({
        where: { positionName: Like(`%${body.keyword}%`) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const numericMatch = body.keyword == null ? null : body.keyword.match(/\d+/);
      keywordAsInt = numericMatch ? parseInt(numericMatch[0], 10) : null;
      masterId = [...new Set(masterId)];
    }

    const revisionCondition = {
      orgRevisionId: body.revisionId,
    };
    const chkRevision = await this.orgRevisionRepository.findOne({
      where: { id: body.revisionId },
    });
    if (chkRevision != null && chkRevision.orgRevisionIsDraft == true)
      _data = {
        root: null,
        child1: null,
        child2: null,
        child3: null,
        child4: null,
        privilege: "OWNER",
      };
    const conditions = [
      {
        ...checkChildConditions,
        ...typeCondition,
        ...revisionCondition,
        ...(body.keyword &&
          (masterId.length > 0
            ? { id: In(masterId) }
            : /^\d+$/.test(body.keyword) ? { posMasterNo: keywordAsInt } : { posMasterNo: Like(`%${body.keyword}%`) })),
        ...(!body.isAll && { isCondition: true }),
      },
    ];
    let [posMaster, total] = await AppDataSource.getRepository(PosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.orgRevision", "orgRevision")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("current_holder.posType", "posType")
      .leftJoinAndSelect("current_holder.posLevel", "posLevel")
      .where(conditions)
      // .andWhere(
      //   _data.root != undefined && _data.root != null
      //     ? _data.root[0] != null
      //       ? `posMaster.orgRootId IN (:...root)`
      //       : `posMaster.orgRootId is null`
      //     : "1=1",
      //   {
      //     root: _data.root,
      //   },
      // )
      // .andWhere(
      //   _data.child1 != undefined && _data.child1 != null
      //     ? _data.child1[0] != null
      //       ? `posMaster.orgChild1Id IN (:...child1)`
      //       : `posMaster.orgChild1Id is ${_data.privilege == "PARENT" ? "not null" : "null"}`
      //     : "1=1",
      //   {
      //     child1: _data.child1,
      //   },
      // )
      // .andWhere(
      //   _data.child2 != undefined && _data.child2 != null
      //     ? _data.child2[0] != null
      //       ? `posMaster.orgChild2Id IN (:...child2)`
      //       : `posMaster.orgChild2Id is null`
      //     : "1=1",
      //   {
      //     child2: _data.child2,
      //   },
      // )
      // .andWhere(
      //   _data.child3 != undefined && _data.child3 != null
      //     ? _data.child3[0] != null
      //       ? `posMaster.orgChild3Id IN (:...child3)`
      //       : `posMaster.orgChild3Id is null`
      //     : "1=1",
      //   {
      //     child3: _data.child3,
      //   },
      // )
      // .andWhere(
      //   _data.child4 != undefined && _data.child4 != null
      //     ? _data.child4[0] != null
      //       ? `posMaster.orgChild4Id IN (:...child4)`
      //       : `posMaster.orgChild4Id is null`
      //     : "1=1",
      //   {
      //     child4: _data.child4,
      //   },
      // )
      .orWhere(
        new Brackets((qb) => {
          qb.andWhere(
            body.keyword != null && body.keyword != ""
              ? `CASE WHEN posMaster.orgChild1 is null THEN ${searchShortName0} WHEN posMaster.orgChild2 is null THEN ${searchShortName1} WHEN posMaster.orgChild3 is null THEN ${searchShortName2} WHEN posMaster.orgChild4 is null THEN ${searchShortName3} ELSE ${searchShortName4} END LIKE '%${body.keyword}%'`
              : "1=1",
          )
            .andWhere(checkChildConditions)
            .andWhere(typeCondition)
            .andWhere(revisionCondition);
          if (!body.isAll) {
            qb.andWhere({ isCondition: true });
          }
        }),
      )
      .orWhere(
        new Brackets((qb) => {
          qb.andWhere(
            `posMaster.conditionReason LIKE '%${body.keyword}%' AND posMaster.conditionReason IS NOT NULL`,
          )
            .andWhere(checkChildConditions)
            .andWhere(typeCondition)
            .andWhere(revisionCondition);
          if (!body.isAll) {
            qb.andWhere({ isCondition: true });
          }
        }),
      )
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .skip((body.page - 1) * body.pageSize)
      .take(body.pageSize)
      .getManyAndCount();

    //แก้ค้นหา
    let _position: any[] = [];
    let x: any = null;
    let y: any = null;
    if (body.keyword != null && body.keyword != "") {
      const position = await this.positionRepository.find({
        relations: ["posType", "posLevel", "posExecutive"],
        where: { posMasterId: In(posMaster.map((x) => x.id)) },
        order: { createdAt: "ASC" },
      });
      for (let data of position) {
        x = data.posMasterId;
        if (y != x) {
          if (
            data.positionName.includes(body.keyword) ||
            data.posType.posTypeName.includes(body.keyword) ||
            data.posLevel.posLevelName.includes(body.keyword)
          ) {
            _position.push(data);
          }
        }
        y = x;
      }
    }

    if (_position.length > 0) {
      posMaster = posMaster.filter((x) => _position.some((y) => y.posMasterId === x.id));
    }

    const formattedData = await Promise.all(
      posMaster.map(async (posMaster) => {
        const positions = await this.positionRepository.find({
          where: {
            posMasterId: posMaster.id,
          },
          relations: ["posLevel", "posType", "posExecutive"],
          order: {
            posType: { posTypeRank: "ASC" },
            posLevel: { posLevelRank: "ASC" },
          },
        });
        let shortName = "";

        if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id == null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          shortName = posMaster.orgRoot.orgRootShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          shortName = posMaster.orgChild1.orgChild1ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id == null
        ) {
          shortName = posMaster.orgChild2.orgChild2ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          shortName = posMaster.orgChild3.orgChild3ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          shortName = posMaster.orgChild4.orgChild4ShortName;
        }

        return {
          id: posMaster.id,
          isDirector: posMaster.isDirector,
          isCondition: posMaster.isCondition,
          conditionReason: posMaster.conditionReason,
          posMasterNoPrefix: posMaster.posMasterNoPrefix ? posMaster.posMasterNoPrefix : null,
          posMasterNo: posMaster.posMasterNo ? posMaster.posMasterNo : null,
          posMasterNoSuffix: posMaster.posMasterNoSuffix ? posMaster.posMasterNoSuffix : null,
          orgShortname: shortName,
          profilePosition: positions[0]?.positionName,
          profilePostype: positions[0]?.posType?.posTypeName ?? null,
          profilePoslevel: positions[0]?.posLevel?.posLevelName ?? null,
          positions: positions.map((position: any) => ({
            id: position.id,
            positionName: position.positionName,
            positionField: position.positionField,
            posTypeName: position.posType == null ? null : position.posType.posTypeName,
            posLevelName: position.posLevel == null ? null : position.posLevel.posLevelName,
            posExecutiveName:
              position.posExecutive == null ? null : position.posExecutive.posExecutiveName,
            positionExecutiveField: position.positionExecutiveField,
            positionArea: position.positionArea,
          })),
        };
      }),
    );
    return new HttpSuccess({ data: formattedData, total });
  }

  /**
   * API แก้ไขตำแหน่งเงื่อนไข
   *
   * @summary แก้ไขตำแหน่งเงื่อนไข (ADMIN)
   *
   */
  @Put("master/position-condition/{id}")
  async updatePositionCondition(
    @Path() id: string,
    @Body()
    requestBody: {
      isCondition: boolean | null;
      conditionReason: string | null;
    },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_POS_CONDITION");
    const posMaster = await this.posMasterRepository.findOne({
      where: { id: id },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }

    Object.assign(posMaster, requestBody);
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.posMasterRepository.save(posMaster);
    return new HttpSuccess();
  }

  /**
   * API แก้ไขตำแหน่ง
   *
   * @summary แก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Post("officer/master/book")
  async posMasterBookOfficer(
    @Body()
    requestBody: {
      posMasterId: string;
      profileId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    const posMaster = await this.posMasterRepository.findOne({
      where: { id: requestBody.posMasterId },
    });
    if (!posMaster) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");

    const profile = await this.profileRepository.findOne({
      where: { id: requestBody.profileId },
    });
    if (!profile) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน");

    posMaster.next_holderId = requestBody.profileId;
    posMaster.lastUpdatedAt = new Date();
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    await this.posMasterRepository.save(posMaster);
    return new HttpSuccess();
  }

  /**
   * API แก้ไขตำแหน่ง
   *
   * @summary แก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Post("officer/master/clear")
  async posMasterClearOfficer(
    @Body()
    requestBody: {
      posMasterId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    const posMaster = await this.posMasterRepository.findOne({
      where: { id: requestBody.posMasterId },
    });
    if (!posMaster) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");

    posMaster.next_holderId = null;
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.posMasterRepository.save(posMaster);
    return new HttpSuccess();
  }

  /**
   * API แก้ไขตำแหน่ง
   *
   * @summary แก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Post("employee/master/book")
  async posMasterBookEmployee(
    @Body()
    requestBody: {
      posMasterId: string;
      profileId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    const posMaster = await this.employeePosMasterRepository.findOne({
      where: { id: requestBody.posMasterId },
    });
    if (!posMaster) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");

    const profile = await this.profileEmployeeRepository.findOne({
      where: { id: requestBody.profileId },
    });
    if (!profile) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน");

    posMaster.next_holderId = requestBody.profileId;
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.employeePosMasterRepository.save(posMaster);
    return new HttpSuccess();
  }

  /**
   * API แก้ไขตำแหน่ง
   *
   * @summary แก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Post("employee/master/clear")
  async posMasterClearEmployee(
    @Body()
    requestBody: {
      posMasterId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    const posMaster = await this.employeePosMasterRepository.findOne({
      where: { id: requestBody.posMasterId },
    });
    if (!posMaster) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");

    posMaster.next_holderId = null;
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.employeePosMasterRepository.save(posMaster);
    return new HttpSuccess();
  }

  /**
   * API แก้ไขตำแหน่ง
   *
   * @summary แก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Post("officer/master-old/book")
  async posMasterOldBookOfficer(
    @Body()
    requestBody: {
      posMasterId: string;
      posMasterOldId: string;
      profileId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    const posMaster = await this.posMasterRepository.findOne({
      where: { id: requestBody.posMasterId },
    });
    if (!posMaster) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");

    const profile = await this.profileRepository.findOne({
      where: { id: requestBody.profileId },
    });
    if (!profile) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน");

    posMaster.next_holderId = requestBody.profileId;
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.posMasterRepository.save(posMaster);

    if (requestBody.posMasterOldId != null) {
      const posMasterOld = await this.posMasterRepository.findOne({
        where: { id: requestBody.posMasterOldId },
      });
      if (!posMasterOld) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");

      posMasterOld.next_holderId = null;
      posMasterOld.lastUpdateUserId = request.user.sub;
      posMasterOld.lastUpdateFullName = request.user.name;
      posMasterOld.lastUpdatedAt = new Date();
      await this.posMasterRepository.save(posMasterOld);
    }
    return new HttpSuccess();
  }

  /**
   * API แก้ไขตำแหน่ง
   *
   * @summary แก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Post("employee/master-old/book")
  async posMasterOldBookEmployee(
    @Body()
    requestBody: {
      posMasterId: string;
      posMasterOldId: string;
      profileId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    const posMaster = await this.employeePosMasterRepository.findOne({
      where: { id: requestBody.posMasterId },
    });
    if (!posMaster) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");

    const profile = await this.profileEmployeeRepository.findOne({
      where: { id: requestBody.profileId },
    });
    if (!profile) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน");

    posMaster.next_holderId = requestBody.profileId;
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.employeePosMasterRepository.save(posMaster);

    if (requestBody.posMasterOldId != null) {
      const posMasterOld = await this.employeePosMasterRepository.findOne({
        where: { id: requestBody.posMasterOldId },
      });
      if (!posMasterOld) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง");

      posMasterOld.next_holderId = null;
      posMasterOld.lastUpdateUserId = request.user.sub;
      posMasterOld.lastUpdateFullName = request.user.name;
      posMasterOld.lastUpdatedAt = new Date();
      await this.employeePosMasterRepository.save(posMasterOld);
    }
    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);
  }
}
