Merge branch 'develop' into adiDev

This commit is contained in:
AdisakKanthawilang 2025-08-04 16:44:43 +07:00
commit d1873b6c6b
4 changed files with 818 additions and 1088 deletions

View file

@ -85,6 +85,7 @@ import { OrgChild4 } from "../entities/OrgChild4";
import { ProfileSalaryHistory } from "../entities/ProfileSalaryHistory"; import { ProfileSalaryHistory } from "../entities/ProfileSalaryHistory";
import { ProfileAssistance } from "../entities/ProfileAssistance"; import { ProfileAssistance } from "../entities/ProfileAssistance";
import { CommandRecive } from "../entities/CommandRecive"; import { CommandRecive } from "../entities/CommandRecive";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
@Route("api/v1/org/profile") @Route("api/v1/org/profile")
@Tags("Profile") @Tags("Profile")
@Security("bearerAuth") @Security("bearerAuth")
@ -101,6 +102,7 @@ export class ProfileController extends Controller {
private orgChild3Repo = AppDataSource.getRepository(OrgChild3); private orgChild3Repo = AppDataSource.getRepository(OrgChild3);
private orgChild4Repo = AppDataSource.getRepository(OrgChild4); private orgChild4Repo = AppDataSource.getRepository(OrgChild4);
private posMasterRepo = AppDataSource.getRepository(PosMaster); private posMasterRepo = AppDataSource.getRepository(PosMaster);
private employeePosMasterRepo = AppDataSource.getRepository(EmployeePosMaster);
private profileRepo = AppDataSource.getRepository(Profile); private profileRepo = AppDataSource.getRepository(Profile);
private profileEmpRepo = AppDataSource.getRepository(ProfileEmployee); private profileEmpRepo = AppDataSource.getRepository(ProfileEmployee);
private profileHistoryRepo = AppDataSource.getRepository(ProfileHistory); private profileHistoryRepo = AppDataSource.getRepository(ProfileHistory);
@ -2053,6 +2055,109 @@ export class ProfileController extends Controller {
return new HttpSuccess({ caregiver, commander, chairman }); return new HttpSuccess({ caregiver, commander, chairman });
} }
/**
* API profileId
*
* @summary Profile (ADMIN)
*
* @param {string} profileId Profile ID
*/
@Get("org-user/{profileId}")
async getOrgUserByProfileId(@Path() profileId: string) {
// 1. หาข้อมูล org hierarchy สำหรับ profile นี้
const posMaster = await this.posMasterRepo.findOne({
where: {
current_holderId: profileId,
orgRevision: {
orgRevisionIsCurrent: true,
orgRevisionIsDraft: false,
},
},
select: {
id: true,
orgRoot: {
id: true,
orgRootName: true,
},
orgChild1: {
id: true,
orgChild1Name: true,
},
orgChild2: {
id: true,
orgChild2Name: true,
},
orgChild3: {
id: true,
orgChild3Name: true,
},
orgChild4: {
id: true,
orgChild4Name: true,
},
},
relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"],
});
// 2. ถ้าไม่พบใน PosMaster ให้ลองหาใน EmployeePosMaster
if (!posMaster) {
const employeePosMaster = await this.employeePosMasterRepo.findOne({
where: {
current_holderId: profileId,
orgRevision: {
orgRevisionIsCurrent: true,
orgRevisionIsDraft: false,
},
},
select: {
id: true,
orgRoot: {
id: true,
orgRootName: true,
},
orgChild1: {
id: true,
orgChild1Name: true,
},
orgChild2: {
id: true,
orgChild2Name: true,
},
orgChild3: {
id: true,
orgChild3Name: true,
},
orgChild4: {
id: true,
orgChild4Name: true,
},
},
relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"],
});
if (!employeePosMaster) {
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งสำหรับ Profile นี้");
}
return new HttpSuccess({
root: employeePosMaster.orgRoot?.orgRootName ?? null,
child1: employeePosMaster.orgChild1?.orgChild1Name ?? null,
child2: employeePosMaster.orgChild2?.orgChild2Name ?? null,
child3: employeePosMaster.orgChild3?.orgChild3Name ?? null,
child4: employeePosMaster.orgChild4?.orgChild4Name ?? null,
});
}
// 3. Return ข้อมูล org hierarchy
return new HttpSuccess({
root: posMaster.orgRoot?.orgRootName ?? null,
child1: posMaster.orgChild1?.orgChild1Name ?? null,
child2: posMaster.orgChild2?.orgChild2Name ?? null,
child3: posMaster.orgChild3?.orgChild3Name ?? null,
child4: posMaster.orgChild4?.orgChild4Name ?? null,
});
}
/** /**
* API * API
* *
@ -6257,21 +6362,20 @@ export class ProfileController extends Controller {
] ]
.filter(Boolean) .filter(Boolean)
.join("\n"); .join("\n");
const shortName = const shortName = !holder
!holder ? null
? null : holder.orgChild4 != null
: holder.orgChild4 != null ? `${holder.orgChild4.orgChild4ShortName} ${holder.posMasterNo}`
? `${holder.orgChild4.orgChild4ShortName} ${holder.posMasterNo}` : holder.orgChild3 != null
: holder.orgChild3 != null ? `${holder.orgChild3.orgChild3ShortName} ${holder.posMasterNo}`
? `${holder.orgChild3.orgChild3ShortName} ${holder.posMasterNo}` : holder.orgChild2 != null
: holder.orgChild2 != null ? `${holder.orgChild2.orgChild2ShortName} ${holder.posMasterNo}`
? `${holder.orgChild2.orgChild2ShortName} ${holder.posMasterNo}` : holder.orgChild1 != null
: holder.orgChild1 != null ? `${holder.orgChild1.orgChild1ShortName} ${holder.posMasterNo}`
? `${holder.orgChild1.orgChild1ShortName} ${holder.posMasterNo}` : holder.orgRoot != null
: holder.orgRoot != null ? `${holder.orgRoot.orgRootShortName} ${holder.posMasterNo}`
? `${holder.orgRoot.orgRootShortName} ${holder.posMasterNo}` : null;
: null;
return { return {
id: _data.id, id: _data.id,
@ -8264,237 +8368,152 @@ export class ProfileController extends Controller {
*/ */
@Post("search-personal") @Post("search-personal")
async getProfileBySearchKeyword( async getProfileBySearchKeyword(
@Request() request: RequestWithUser,
@Query("page") page: number = 1, @Query("page") page: number = 1,
@Query("pageSize") pageSize: number = 10, @Query("pageSize") pageSize: number = 10,
@Body() @Body()
body: { body: {
fieldName?: string | null; fieldName?: string | null;
keyword?: string; keyword?: string;
system?: string;
}, },
) { ) {
let findProfile: any; // ค้นหารายชื่อถ้าไม่ส่ง system มาให้ default ตามทะเบียนประวัติ
let total: any; let _system: string = "SYS_REGISTRY_OFFICER";
let revision = await this.orgRevisionRepo.findOne({ where: { orgRevisionIsCurrent: true } }); if (body.system) _system = body.system;
const skip = (page - 1) * pageSize; let _data = await new permission().PermissionOrgList(request, _system);
const take = pageSize;
let queryLike = `CONCAT(
IFNULL(orgChild4.orgChild4ShortName, '')," ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword OR CONCAT(
IFNULL(orgChild3.orgChild3ShortName, '')," ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword OR CONCAT(
IFNULL(orgChild2.orgChild2ShortName, '')," ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword OR CONCAT(
IFNULL(orgChild1.orgChild1ShortName, '')," ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword OR CONCAT(
IFNULL(orgRoot.orgRootShortName, '')," ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword`;
switch (body.fieldName) {
case "citizenId":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
citizenId: Like(`%${body.keyword}%`),
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
case "fullName":
[findProfile, total] = await this.profileRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.posType", "posType")
.leftJoinAndSelect("profile.posLevel", "posLevel")
.leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.where("current_holders.orgRevision = :revisionId", { revisionId: revision?.id })
.andWhere(
"CONCAT(profile.prefix, profile.firstName, ' ', profile.lastName) LIKE :keyword",
{ keyword: `%${body.keyword}%` },
)
.skip(skip)
.take(take)
.getManyAndCount();
break;
case "position":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
position: Like(`%${body.keyword}%`),
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
case "posNo":
[findProfile, total] = await this.profileRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.posType", "posType")
.leftJoinAndSelect("profile.posLevel", "posLevel")
.leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.where("current_holders.orgRevision = :revisionId", { revisionId: revision?.id })
.andWhere(
new Brackets((qb) => {
qb.orWhere(
body.keyword != undefined && body.keyword != null && body.keyword != ""
? queryLike
: "1=1",
{
keyword: `%${body.keyword}%`,
},
);
}),
)
.skip(skip)
.take(take)
.getManyAndCount();
break;
case "posType":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
posType: {
posTypeName: Like(`%${body.keyword}%`),
},
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
case "posLevel":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
posLevel: {
posLevelName: Like(`%${body.keyword}%`),
},
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
case "organization":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
current_holders: {
orgRevisionId: revision?.id,
orgRoot: {
orgRootName: Like(`%${body.keyword}%`),
},
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
default:
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
}
const findRevision = await this.orgRevisionRepo.findOne({ const findRevision = await this.orgRevisionRepo.findOne({
where: { orgRevisionIsCurrent: true }, where: { orgRevisionIsCurrent: true },
}); });
if (!findRevision) { if (!findRevision) {
throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision"); throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision");
} }
// let queryLike = `CONCAT(
// IFNULL(orgChild4.orgChild4ShortName, '')," ",
// IFNULL(current_holders.posMasterNo , '')
// ) LIKE :keyword OR CONCAT(
// IFNULL(orgChild3.orgChild3ShortName, '')," ",
// IFNULL(current_holders.posMasterNo , '')
// ) LIKE :keyword OR CONCAT(
// IFNULL(orgChild2.orgChild2ShortName, '')," ",
// IFNULL(current_holders.posMasterNo , '')
// ) LIKE :keyword OR CONCAT(
// IFNULL(orgChild1.orgChild1ShortName, '')," ",
// IFNULL(current_holders.posMasterNo , '')
// ) LIKE :keyword OR CONCAT(
// IFNULL(orgRoot.orgRootShortName, '')," ",
// IFNULL(current_holders.posMasterNo , '')
// ) LIKE :keyword`;
let queryLike = "1=1";
switch (body.fieldName) {
case "citizenId":
queryLike = "profile.citizenId LIKE :keyword";
break;
case "fullName":
queryLike =
"CONCAT(profile.prefix, profile.firstName, ' ', profile.lastName) LIKE :keyword";
break;
case "position":
queryLike = "profile.position LIKE :keyword";
break;
case "posNo":
queryLike = `
CASE
WHEN current_holders.orgChild4Id IS NOT NULL THEN CONCAT(orgChild4.orgChild4ShortName, " ", current_holders.posMasterNo)
WHEN current_holders.orgChild3Id IS NOT NULL THEN CONCAT(orgChild3.orgChild3ShortName, " ", current_holders.posMasterNo)
WHEN current_holders.orgChild2Id IS NOT NULL THEN CONCAT(orgChild2.orgChild2ShortName, " ", current_holders.posMasterNo)
WHEN current_holders.orgChild1Id IS NOT NULL THEN CONCAT(orgChild1.orgChild1ShortName, " ", current_holders.posMasterNo)
ELSE CONCAT(orgRoot.orgRootShortName, " ", current_holders.posMasterNo)
END LIKE :keyword
`;
break;
case "posType":
queryLike = "posType.posTypeName LIKE :keyword";
break;
case "posLevel":
queryLike = "posLevel.posLevelName LIKE :keyword";
break;
case "organization":
queryLike = "orgRoot.orgRootName LIKE :keyword";
break;
default:
queryLike = "1=1";
break;
}
const [findProfile, total] = await this.profileRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.posType", "posType")
.leftJoinAndSelect("profile.posLevel", "posLevel")
.leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.where("current_holders.orgRevision = :revisionId", { revisionId: findRevision?.id })
.andWhere(
_data.root != undefined && _data.root != null
? _data.root[0] != null
? `current_holders.orgRootId IN (:...root)`
: `current_holders.orgRootId is null`
: "1=1",
{ root: _data.root },
)
.andWhere(
_data.child1 != undefined && _data.child1 != null
? _data.child1[0] != null
? `current_holders.orgChild1Id IN (:...child1)`
: `current_holders.orgChild1Id is null`
: "1=1",
{ child1: _data.child1 },
)
.andWhere(
_data.child2 != undefined && _data.child2 != null
? _data.child2[0] != null
? `current_holders.orgChild2Id IN (:...child2)`
: `current_holders.orgChild2Id is null`
: "1=1",
{ child2: _data.child2 },
)
.andWhere(
_data.child3 != undefined && _data.child3 != null
? _data.child3[0] != null
? `current_holders.orgChild3Id IN (:...child3)`
: `current_holders.orgChild3Id is null`
: "1=1",
{ child3: _data.child3 },
)
.andWhere(
_data.child4 != undefined && _data.child4 != null
? _data.child4[0] != null
? `current_holders.orgChild4Id IN (:...child4)`
: `current_holders.orgChild4Id is null`
: "1=1",
{ child4: _data.child4 },
)
.andWhere(
new Brackets((qb) => {
qb.orWhere(body.keyword ? queryLike : "1=1", { keyword: `%${body.keyword}%` });
}),
)
.skip((page - 1) * pageSize)
.take(pageSize)
.getManyAndCount();
// const findRevision = await this.orgRevisionRepo.findOne({
// where: { orgRevisionIsCurrent: true },
// });
// if (!findRevision) {
// throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision");
// }
const mapDataProfile = await Promise.all( const mapDataProfile = await Promise.all(
findProfile.map(async (item: Profile) => { findProfile.map(async (item: Profile) => {

View file

@ -4010,243 +4010,127 @@ export class ProfileEmployeeController extends Controller {
*/ */
@Post("search-personal") @Post("search-personal")
async getProfileBySearchKeyword( async getProfileBySearchKeyword(
@Request() request: RequestWithUser,
@Query("page") page: number = 1, @Query("page") page: number = 1,
@Query("pageSize") pageSize: number = 10, @Query("pageSize") pageSize: number = 10,
@Body() @Body()
body: { body: {
fieldName: string; fieldName: string;
keyword?: string; keyword?: string;
system?: string;
}, },
) { ) {
let findProfile: any; // ค้นหารายชื่อถ้าไม่ส่ง system มาให้ default ตามทะเบียนประวัติ
let total: any; let _system:string ="SYS_REGISTRY_EMP";
let revision = await this.orgRevisionRepo.findOne({ where: { orgRevisionIsCurrent: true } }); if(body.system)
const skip = (page - 1) * pageSize; _system = body.system;
const take = pageSize; let _data = await new permission().PermissionOrgList(request, _system);
let queryLike = `CONCAT( const findRevision = await this.orgRevisionRepo.findOne({ where: { orgRevisionIsCurrent: true } });
IFNULL(orgChild4.orgChild4ShortName, ''), " ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword OR CONCAT(
IFNULL(orgChild3.orgChild3ShortName, ''), " ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword OR CONCAT(
IFNULL(orgChild2.orgChild2ShortName, ''), " ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword OR CONCAT(
IFNULL(orgChild1.orgChild1ShortName, ''), " ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword OR CONCAT(
IFNULL(orgRoot.orgRootShortName, ''), " ",
IFNULL(current_holders.posMasterNo , '')
) LIKE :keyword`;
switch (body.fieldName) {
case "citizenId":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
citizenId: Like(`%${body.keyword}%`),
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"profileSalary",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
case "fullName":
[findProfile, total] = await this.profileRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.posType", "posType")
.leftJoinAndSelect("profile.posLevel", "posLevel")
.leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.where("current_holders.orgRevision = :revisionId", { revisionId: revision?.id })
.andWhere(
"CONCAT(profile.prefix, profile.firstName, ' ', profile.lastName) LIKE :keyword",
{ keyword: `%${body.keyword}%` },
)
.skip(skip)
.take(take)
.getManyAndCount();
break;
case "position":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
position: Like(`%${body.keyword}%`),
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"profileSalary",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
case "posNo":
[findProfile, total] = await this.profileRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.posType", "posType")
.leftJoinAndSelect("profile.posLevel", "posLevel")
.leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.where("current_holders.orgRevision = :revisionId", { revisionId: revision?.id })
.andWhere(
new Brackets((qb) => {
qb.orWhere(
body.keyword != undefined && body.keyword != null && body.keyword != ""
? queryLike
: "1=1",
{
keyword: `%${body.keyword}%`,
},
);
}),
)
.skip(skip)
.take(take)
.getManyAndCount();
break;
case "posType":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
posType: {
posTypeName: Like(`%${body.keyword}%`),
},
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"profileSalary",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
// case "posLevel":
// [findProfile, total] = await this.profileRepo.findAndCount({
// where: {
// posLevel: {
// posLevelName: Like(`%${body.keyword}%`),
// },
// current_holders: {
// orgRevisionId: revision?.id,
// },
// },
// relations: [
// "posType",
// "posLevel",
// "current_holders",
// "profileSalary",
// "current_holders.orgRoot",
// "current_holders.orgChild1",
// "current_holders.orgChild2",
// "current_holders.orgChild3",
// "current_holders.orgChild4",
// ],
// skip,
// take,
// });
// break;
case "organization":
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
current_holders: {
orgRevisionId: revision?.id,
orgRoot: {
orgRootName: Like(`%${body.keyword}%`),
},
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"profileSalary",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
default:
[findProfile, total] = await this.profileRepo.findAndCount({
where: {
current_holders: {
orgRevisionId: revision?.id,
},
},
relations: [
"posType",
"posLevel",
"current_holders",
"profileSalary",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
}
const findRevision = await this.orgRevisionRepo.findOne({
where: { orgRevisionIsCurrent: true },
});
if (!findRevision) { if (!findRevision) {
throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision"); throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision");
} }
let queryLike = "1=1"
switch (body.fieldName) {
case "citizenId":
queryLike = "profile.citizenId LIKE :keyword";
break;
case "fullName":
queryLike = "CONCAT(profile.prefix, profile.firstName, ' ', profile.lastName) LIKE :keyword";
break;
case "position":
queryLike = "profile.position LIKE :keyword";
break;
case "posNo":
queryLike = `
CASE
WHEN current_holders.orgChild4Id IS NOT NULL THEN CONCAT(orgChild4.orgChild4ShortName, " ", current_holders.posMasterNo)
WHEN current_holders.orgChild3Id IS NOT NULL THEN CONCAT(orgChild3.orgChild3ShortName, " ", current_holders.posMasterNo)
WHEN current_holders.orgChild2Id IS NOT NULL THEN CONCAT(orgChild2.orgChild2ShortName, " ", current_holders.posMasterNo)
WHEN current_holders.orgChild1Id IS NOT NULL THEN CONCAT(orgChild1.orgChild1ShortName, " ", current_holders.posMasterNo)
ELSE CONCAT(orgRoot.orgRootShortName, " ", current_holders.posMasterNo)
END LIKE :keyword
`;
break;
case "posType":
queryLike = "posType.posTypeName LIKE :keyword";
break;
case "posLevel":
queryLike = "posLevel.posLevelName LIKE :keyword";
break;
case "organization":
queryLike = "orgRoot.orgRootName LIKE :keyword";
break;
default:
queryLike = "1=1"
break;
}
const [findProfile, total] = await this.profileRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.posType", "posType")
.leftJoinAndSelect("profile.posLevel", "posLevel")
.leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.where("current_holders.orgRevision = :revisionId", { revisionId: findRevision?.id })
.andWhere(
_data.root != undefined && _data.root != null
? _data.root[0] != null
? `current_holders.orgRootId IN (:...root)`
: `current_holders.orgRootId is null`
: "1=1",
{ root: _data.root },
)
.andWhere(
_data.child1 != undefined && _data.child1 != null
? _data.child1[0] != null
? `current_holders.orgChild1Id IN (:...child1)`
: `current_holders.orgChild1Id is null`
: "1=1",
{ child1: _data.child1 },
)
.andWhere(
_data.child2 != undefined && _data.child2 != null
? _data.child2[0] != null
? `current_holders.orgChild2Id IN (:...child2)`
: `current_holders.orgChild2Id is null`
: "1=1",
{ child2: _data.child2 },
)
.andWhere(
_data.child3 != undefined && _data.child3 != null
? _data.child3[0] != null
? `current_holders.orgChild3Id IN (:...child3)`
: `current_holders.orgChild3Id is null`
: "1=1",
{ child3: _data.child3 },
)
.andWhere(
_data.child4 != undefined && _data.child4 != null
? _data.child4[0] != null
? `current_holders.orgChild4Id IN (:...child4)`
: `current_holders.orgChild4Id is null`
: "1=1",
{ child4: _data.child4 },
)
.andWhere(
new Brackets((qb) => {
qb.orWhere(body.keyword ? queryLike : "1=1", { keyword: `%${body.keyword}%` });
}),
)
.skip((page - 1) * pageSize)
.take(pageSize)
.getManyAndCount();
const mapDataProfile = await Promise.all( const mapDataProfile = await Promise.all(
findProfile.map(async (item: ProfileEmployee) => { findProfile.map(async (item: ProfileEmployee) => {

View file

@ -1132,6 +1132,19 @@ export class ProfileEmployeeTempController extends Controller {
child4: _dataOrg.child4, child4: _dataOrg.child4,
}, },
) )
// หรือ ไม่ได้เลือกตำแหน่งในโครงสร้างลูกจ้างชั่วคราว แต่เลือกตำแหน่งในโครงสร้างลูกจ้างประจำแล้ว
.orWhere(
`current_holderTemps.orgRootId is null AND
profileEmployee.rootIdTemp is not null AND
profileEmployee.statusTemp = :statusTemp AND
profileEmployee.employeeClass = :type AND
profileEmployee.createdUserId = :keycloak`,
{
statusTemp: "PENDING",
type: "TEMP",
keycloak: request.user.sub
}
)
.getManyAndCount(); .getManyAndCount();
const data = await Promise.all( const data = await Promise.all(
record.map((_data) => { record.map((_data) => {
@ -2174,150 +2187,162 @@ export class ProfileEmployeeTempController extends Controller {
*/ */
@Post("search-personal") @Post("search-personal")
async getProfileBySearchKeyword( async getProfileBySearchKeyword(
@Request() request: RequestWithUser,
@Query("page") page: number = 1, @Query("page") page: number = 1,
@Query("pageSize") pageSize: number = 10, @Query("pageSize") pageSize: number = 10,
@Body() @Body()
body: { body: {
fieldName: string; fieldName: string;
keyword?: string; keyword?: string;
system?: string;
}, },
) { ) {
let findProfile: any; // ค้นหารายชื่อถ้าไม่ส่ง system มาให้ default ตามทะเบียนประวัติ
let total: any; let _system:string ="SYS_REGISTRY_TEMP";
const skip = (page - 1) * pageSize; if(body.system)
const take = pageSize; _system = body.system;
switch (body.fieldName) { let _data = await new permission().PermissionOrgList(request, _system);
case "citizenId": const findRevision = await this.orgRevisionRepo.findOne({ where: { orgRevisionIsCurrent: true } });
[findProfile, total] = await this.profileRepo.findAndCount({
where: { citizenId: Like(`%${body.keyword}%`) },
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
case "firstname":
[findProfile, total] = await this.profileRepo.findAndCount({
where: { firstName: Like(`%${body.keyword}%`) },
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
case "lastname":
[findProfile, total] = await this.profileRepo.findAndCount({
where: { lastName: Like(`%${body.keyword}%`) },
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
default:
[findProfile, total] = await this.profileRepo.findAndCount({
relations: [
"posType",
"posLevel",
"current_holders",
"current_holders.orgRoot",
"current_holders.orgChild1",
"current_holders.orgChild2",
"current_holders.orgChild3",
"current_holders.orgChild4",
],
skip,
take,
});
break;
}
const findRevision = await this.orgRevisionRepo.findOne({
where: { orgRevisionIsCurrent: true },
});
if (!findRevision) { if (!findRevision) {
throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision"); throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision");
} }
let queryLike = "1=1"
switch (body.fieldName) {
case "citizenId":
queryLike = "profile.citizenId LIKE :keyword";
break;
case "firstname":
queryLike = "profile.firstName LIKE :keyword";
break;
case "lastname":
queryLike = "profile.lastName LIKE :keyword";
break;
case "fullName":
queryLike = "CONCAT(profile.prefix, profile.firstName, ' ', profile.lastName) LIKE :keyword";
break;
default:
queryLike = "1=1"
break;
}
const [findProfile, total] = await this.profileRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.posType", "posType")
.leftJoinAndSelect("profile.posLevel", "posLevel")
// .leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("profile.current_holderTemps", "current_holderTemps")
.leftJoinAndSelect("current_holderTemps.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holderTemps.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holderTemps.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holderTemps.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holderTemps.orgChild4", "orgChild4")
.where("current_holderTemps.orgRevision = :revisionId", { revisionId: findRevision?.id })
.andWhere("profile.employeeClass = :employeeClass", { employeeClass: "TEMP" })
.andWhere(
_data.root != undefined && _data.root != null
? _data.root[0] != null
? `current_holderTemps.orgRootId IN (:...root)`
: `current_holderTemps.orgRootId is null`
: "1=1",
{ root: _data.root },
)
.andWhere(
_data.child1 != undefined && _data.child1 != null
? _data.child1[0] != null
? `current_holderTemps.orgChild1Id IN (:...child1)`
: `current_holderTemps.orgChild1Id is null`
: "1=1",
{ child1: _data.child1 },
)
.andWhere(
_data.child2 != undefined && _data.child2 != null
? _data.child2[0] != null
? `current_holderTemps.orgChild2Id IN (:...child2)`
: `current_holderTemps.orgChild2Id is null`
: "1=1",
{ child2: _data.child2 },
)
.andWhere(
_data.child3 != undefined && _data.child3 != null
? _data.child3[0] != null
? `current_holderTemps.orgChild3Id IN (:...child3)`
: `current_holderTemps.orgChild3Id is null`
: "1=1",
{ child3: _data.child3 },
)
.andWhere(
_data.child4 != undefined && _data.child4 != null
? _data.child4[0] != null
? `current_holderTemps.orgChild4Id IN (:...child4)`
: `current_holderTemps.orgChild4Id is null`
: "1=1",
{ child4: _data.child4 },
)
.andWhere(
new Brackets((qb) => {
qb.orWhere(body.keyword ? queryLike : "1=1", { keyword: `%${body.keyword}%` });
}),
)
.skip((page - 1) * pageSize)
.take(pageSize)
.getManyAndCount();
const mapDataProfile = await Promise.all( const mapDataProfile = await Promise.all(
findProfile.map(async (item: ProfileEmployee) => { findProfile.map(async (item: ProfileEmployee) => {
const fullName = `${item.prefix} ${item.firstName} ${item.lastName}`; const fullName = `${item.prefix} ${item.firstName} ${item.lastName}`;
const shortName = const shortName =
item.current_holders.length == 0 item.current_holderTemps.length == 0
? null ? null
: item.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && : item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id) != null &&
item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4 != item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4 !=
null null
? `${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4.orgChild4ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` ? `${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4.orgChild4ShortName} ${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
: item.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && : item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id) != null &&
item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3 != item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3 !=
null null
? `${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3.orgChild3ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` ? `${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3.orgChild3ShortName} ${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
: item.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && : item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id) != null &&
item.current_holders.find((x) => x.orgRevisionId == findRevision.id) item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)
?.orgChild2 != null ?.orgChild2 != null
? `${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild2.orgChild2ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` ? `${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgChild2.orgChild2ShortName} ${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
: item.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && : item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id) != null &&
item.current_holders.find((x) => x.orgRevisionId == findRevision.id) item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)
?.orgChild1 != null ?.orgChild1 != null
? `${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild1.orgChild1ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` ? `${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgChild1.orgChild1ShortName} ${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
: item.current_holders.find((x) => x.orgRevisionId == findRevision.id) != : item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id) !=
null && null &&
item.current_holders.find((x) => x.orgRevisionId == findRevision.id) item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)
?.orgRoot != null ?.orgRoot != null
? `${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot.orgRootShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}` ? `${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot.orgRootShortName} ${item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
: null; : null;
const root = const root =
item.current_holders.length == 0 || item.current_holderTemps.length == 0 ||
(item.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null && (item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id) != null &&
item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot == null) item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot == null)
? null ? null
: item.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot; : item.current_holderTemps.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot;
const rootHolder = item.current_holders?.find( const rootHolder = item.current_holderTemps?.find(
(x) => x.orgRevisionId == findRevision.id, (x) => x.orgRevisionId == findRevision.id,
)?.orgRoot; )?.orgRoot;
const child1Holder = item.current_holders?.find( const child1Holder = item.current_holderTemps?.find(
(x) => x.orgRevisionId == findRevision.id, (x) => x.orgRevisionId == findRevision.id,
)?.orgChild1; )?.orgChild1;
const child2Holder = item.current_holders?.find( const child2Holder = item.current_holderTemps?.find(
(x) => x.orgRevisionId == findRevision.id, (x) => x.orgRevisionId == findRevision.id,
)?.orgChild2; )?.orgChild2;
const child3Holder = item.current_holders?.find( const child3Holder = item.current_holderTemps?.find(
(x) => x.orgRevisionId == findRevision.id, (x) => x.orgRevisionId == findRevision.id,
)?.orgChild3; )?.orgChild3;
const child4Holder = item.current_holders?.find( const child4Holder = item.current_holderTemps?.find(
(x) => x.orgRevisionId == findRevision.id, (x) => x.orgRevisionId == findRevision.id,
)?.orgChild4; )?.orgChild4;
const posMasterNo = item.current_holders?.find( const posMasterNo = item.current_holderTemps?.find(
(x) => x.orgRevisionId == findRevision.id, (x) => x.orgRevisionId == findRevision.id,
)?.posMasterNo; )?.posMasterNo;
@ -2369,7 +2394,10 @@ export class ProfileEmployeeTempController extends Controller {
posTypeId: item.posTypeId, posTypeId: item.posTypeId,
posTypeName: item.posType?.posTypeName, posTypeName: item.posType?.posTypeName,
posLevelId: item.posLevelId, posLevelId: item.posLevelId,
posLevelName: item.posLevel?.posLevelName, posLevelName:
item.posLevel == null && item.posType == null
? null
: `${item.posType?.posTypeShortName} ${item.posLevel?.posLevelName}`,
educationDegree: educationDegree:
latestProfileEducation != null && latestProfileEducation.educationLevel != null latestProfileEducation != null && latestProfileEducation.educationLevel != null
? latestProfileEducation.educationLevel ? latestProfileEducation.educationLevel
@ -3972,7 +4000,10 @@ export class ProfileEmployeeTempController extends Controller {
posTypeId: item.posTypeId, posTypeId: item.posTypeId,
posTypeName: item.posType?.posTypeName, posTypeName: item.posType?.posTypeName,
posLevelId: item.posLevelId, posLevelId: item.posLevelId,
posLevelName: item.posLevel?.posLevelName, posLevelName:
item.posLevel == null && item.posType == null
? null
: `${item.posType?.posTypeShortName} ${item.posLevel?.posLevelName}`,
educationDegree: educationDegree:
latestProfileEducation != null && latestProfileEducation.educationLevel != null latestProfileEducation != null && latestProfileEducation.educationLevel != null
? latestProfileEducation.educationLevel ? latestProfileEducation.educationLevel

View file

@ -811,299 +811,200 @@ export class WorkflowController extends Controller {
type?: string | null; type?: string | null;
}, },
) { ) {
let posMasterUser = null; const userKeycloak = body.keycloakId ?? request.user.sub;
if (body.keycloakId) {
if (body.type == "employee") { // 1. Cache user lookup - ใช้ select เฉพาะ field ที่จำเป็น
posMasterUser = await this.posMasterEmpRepo.findOne({ const userSelectFields = {
where: { id: true,
orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, orgRootId: true,
current_holder: { keycloak: body.keycloakId }, orgChild1Id: true,
}, orgChild2Id: true,
relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"], orgChild3Id: true,
}); orgChild4Id: true,
} else { orgRevisionId: true,
posMasterUser = await this.posMasterRepo.findOne({ current_holder: {
where: { id: true,
orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, posType: { id: true, posTypeName: true },
current_holder: { keycloak: body.keycloakId }, posLevel: { id: true, posLevelName: true },
}, },
relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"], };
});
} let posMasterUser: any = null;
if (body.type === "employee") {
posMasterUser = await this.posMasterEmpRepo.findOne({
where: {
orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
current_holder: { keycloak: userKeycloak },
},
select: userSelectFields,
relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"],
});
} else { } else {
if (body.type == "employee") { posMasterUser = await this.posMasterRepo.findOne({
posMasterUser = await this.posMasterEmpRepo.findOne({ where: {
where: { orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, current_holder: { keycloak: userKeycloak },
current_holder: { keycloak: request.user.sub }, },
}, select: userSelectFields,
relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"], relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"],
}); });
} else {
posMasterUser = await this.posMasterRepo.findOne({
where: {
orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
current_holder: { keycloak: request.user.sub },
},
relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"],
});
}
} }
if (!posMasterUser || !posMasterUser.orgRootId) { if (!posMasterUser?.orgRootId) {
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบตำแหน่งผู้ใช้งาน"); throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบตำแหน่งผู้ใช้งาน");
} }
let condition: any = []; // 2. Pre-calculate conditions - ย้ายออกมาข้างนอก
const posType = posMasterUser.current_holder?.posType?.posTypeName;
const posLevel = posMasterUser.current_holder?.posLevel?.posLevelName;
let conditionOfficer: any = { const isLowLevel =
(posType === "ทั่วไป" && ["ชำนาญงาน", "ปฏิบัติงาน"].includes(posLevel)) ||
(posType === "วิชาการ" && ["ปฏิบัติการ", "ชำนาญการ"].includes(posLevel));
const isMidLevel =
(posType === "ทั่วไป" && posLevel === "อาวุโส") ||
(posType === "วิชาการ" && posLevel === "ชำนาญการพิเศษ") ||
(posType === "อำนวยการ" && posLevel === "ต้น");
// 3. สร้าง conditions แบบ optimized
const baseCondition = {
isDirector: true, isDirector: true,
isOfficer: true,
orgRevisionId: posMasterUser.orgRevisionId, orgRevisionId: posMasterUser.orgRevisionId,
};
const conditionOfficer = {
...baseCondition,
isOfficer: true,
orgChild1Id: IsNull(), orgChild1Id: IsNull(),
}; };
if (type.trim().toUpperCase() == "OPERATE" || body.type == "employee") { let mainConditions: any[] = [];
condition.push({
isDirector: true, if (type.trim().toUpperCase() === "OPERATE" || body.type === "employee") {
orgRootId: posMasterUser.orgRootId, mainConditions = [
orgRevisionId: posMasterUser.orgRevisionId, { ...baseCondition, orgRootId: posMasterUser.orgRootId, orgChild1Id: IsNull() },
orgChild1Id: IsNull(),
});
condition.push({
isDirector: true,
orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: IsNull(),
});
condition.push({
isDirector: true,
orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: IsNull(),
});
condition.push({
isDirector: true,
orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: posMasterUser.orgChild3Id,
orgChild4Id: IsNull(),
});
condition.push({
isDirector: true,
orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: posMasterUser.orgChild3Id,
orgChild4Id: posMasterUser.orgChild4Id,
});
} else {
condition = [
{ {
isDirector: true, ...baseCondition,
orgRootId: posMasterUser.orgRootId, orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId, orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: IsNull(),
},
{
...baseCondition,
orgRootId: posMasterUser.orgRootId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: IsNull(),
},
{
...baseCondition,
orgRootId: posMasterUser.orgRootId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: posMasterUser.orgChild3Id,
orgChild4Id: IsNull(),
},
{
...baseCondition,
orgRootId: posMasterUser.orgRootId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: posMasterUser.orgChild3Id,
orgChild4Id: posMasterUser.orgChild4Id,
}, },
]; ];
if ( } else if (isLowLevel) {
(posMasterUser.current_holder.posType.posTypeName == "ทั่วไป" && mainConditions = [
posMasterUser.current_holder.posLevel.posLevelName == "ชำนาญงาน") || {
(posMasterUser.current_holder.posType.posTypeName == "ทั่วไป" && ...baseCondition,
posMasterUser.current_holder.posLevel.posLevelName == "ปฏิบัติงาน") ||
(posMasterUser.current_holder.posType.posTypeName == "วิชาการ" &&
posMasterUser.current_holder.posLevel.posLevelName == "ปฏิบัติการ") ||
(posMasterUser.current_holder.posType.posTypeName == "วิชาการ" &&
posMasterUser.current_holder.posLevel.posLevelName == "ชำนาญการ")
) {
condition = {
isDirector: true,
orgRootId: posMasterUser.orgRootId, orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: IsNull(), orgChild1Id: IsNull(),
orgChild2Id: IsNull(), orgChild2Id: IsNull(),
orgChild3Id: IsNull(), orgChild3Id: IsNull(),
orgChild4Id: IsNull(), orgChild4Id: IsNull(),
}; },
} else if ( ];
(posMasterUser.current_holder.posType.posTypeName == "ทั่วไป" && } else if (isMidLevel) {
posMasterUser.current_holder.posLevel.posLevelName == "อาวุโส") || mainConditions = [
(posMasterUser.current_holder.posType.posTypeName == "วิชาการ" && {
posMasterUser.current_holder.posLevel.posLevelName == "ชำนาญการพิเศษ") || ...baseCondition,
(posMasterUser.current_holder.posType.posTypeName == "อำนวยการ" &&
posMasterUser.current_holder.posLevel.posLevelName == "ต้น")
) {
condition = {
isDirector: true,
isDeputy: true, isDeputy: true,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: IsNull(), orgChild1Id: IsNull(),
orgChild2Id: IsNull(), orgChild2Id: IsNull(),
orgChild3Id: IsNull(), orgChild3Id: IsNull(),
orgChild4Id: IsNull(), orgChild4Id: IsNull(),
}; },
} else { ];
} } else {
mainConditions = [{ ...baseCondition, orgRootId: posMasterUser.orgRootId }];
} }
if (body.isAct == true) { // 4. สร้าง optimized query builder
const [lists, total] = await AppDataSource.getRepository(viewDirectorActing) const repository = body.isAct
.createQueryBuilder("viewDirectorActing") ? AppDataSource.getRepository(viewDirectorActing)
.andWhere( : AppDataSource.getRepository(viewDirector);
new Brackets((qb) => {
qb.orWhere(condition).orWhere(conditionOfficer); const queryBuilder = repository.createQueryBuilder("entity");
}),
) // 5. แยก WHERE conditions ให้เร็วขึ้น
.andWhere( queryBuilder.where(
new Brackets((qb) => { new Brackets((qb) => {
qb.orWhere( mainConditions.forEach((condition, index) => {
body.keyword != null && body.keyword != "" if (index === 0) {
? "CONCAT(viewDirectorActing.prefix,viewDirectorActing.firstName,' ',viewDirectorActing.lastName) LIKE :keyword" qb.where(condition);
: "1=1", } else {
{ qb.orWhere(condition);
keyword: `%${body.keyword}%`, }
}, });
) qb.orWhere(conditionOfficer);
.orWhere( }),
body.keyword != null && body.keyword != "" );
? "viewDirectorActing.citizenId LIKE :keyword"
: "1=1", // 6. ปรับ search conditions ให้เร็วขึ้น
{ if (body.keyword?.trim()) {
keyword: `%${body.keyword}%`, const keyword = `%${body.keyword.trim()}%`;
}, const searchFields = [
) "CONCAT(entity.prefix, entity.firstName, ' ', entity.lastName)",
.orWhere( "entity.citizenId",
body.keyword != null && body.keyword != "" "entity.position",
? "viewDirectorActing.position LIKE :keyword" "entity.posLevel",
: "1=1", "entity.posType",
{ "entity.posNo",
keyword: `%${body.keyword}%`, "entity.posExecutiveName",
}, ];
)
.orWhere( if (body.isAct) {
body.keyword != null && body.keyword != "" searchFields.push("entity.actFullName");
? "viewDirectorActing.posLevel LIKE :keyword" }
: "1=1",
{ queryBuilder.andWhere(
keyword: `%${body.keyword}%`, `(${searchFields.map((field) => `${field} LIKE :keyword`).join(" OR ")})`,
}, { keyword },
) );
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirectorActing.posType LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirectorActing.actFullName LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirectorActing.posNo LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirectorActing.posExecutiveName LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
);
}),
)
.skip((body.page - 1) * body.pageSize)
.take(body.pageSize)
.getManyAndCount();
return new HttpSuccess({ data: lists, total });
} else {
const [lists, total] = await AppDataSource.getRepository(viewDirector)
.createQueryBuilder("viewDirector")
.andWhere(
new Brackets((qb) => {
qb.orWhere(condition).orWhere(conditionOfficer);
}),
)
.andWhere(
new Brackets((qb) => {
qb.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(viewDirector.prefix,viewDirector.firstName,' ',viewDirector.lastName) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.citizenId LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.position LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.posLevel LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.posType LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.posNo LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.posExecutiveName LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
);
}),
)
.skip((body.page - 1) * body.pageSize)
.take(body.pageSize)
.getManyAndCount();
return new HttpSuccess({ data: lists, total });
} }
// 7. Execute พร้อมกัน - ใช้ Promise.all
const [data, total] = await Promise.all([
queryBuilder
.skip((body.page - 1) * body.pageSize)
.take(body.pageSize)
.getMany(),
queryBuilder.getCount(),
]);
// 8. ปรับ response mapping (ถ้าจำเป็น)
const processedData = body.isAct
? data
: data.map((x: any) => ({
...x,
posExecutiveNameOrg:
x.posExecutiveName +
(x.orgChild4 ?? x.orgChild3 ?? x.orgChild2 ?? x.orgChild1 ?? x.orgRoot ?? ""),
}));
return new HttpSuccess({ data: processedData, total });
} }
/** /**
* *
@ -1122,290 +1023,185 @@ export class WorkflowController extends Controller {
keycloakId?: string | null; keycloakId?: string | null;
}, },
) { ) {
let posMasterUser: PosMaster = new PosMaster(); const userKeycloak = body.keycloakId ?? request.user.sub;
if (body.keycloakId) {
posMasterUser = (await this.posMasterRepo.findOne({ // 1. ใช้ select เฉพาะ field ที่จำเป็น - เหมือน getProfilePlacement
where: { const userSelectFields = {
orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, id: true,
current_holder: { keycloak: body.keycloakId }, orgRootId: true,
}, orgChild1Id: true,
relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"], orgChild2Id: true,
})) as PosMaster; orgChild3Id: true,
} else { orgChild4Id: true,
posMasterUser = (await this.posMasterRepo.findOne({ orgRevisionId: true,
where: { current_holder: {
orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, id: true,
current_holder: { keycloak: request.user.sub }, posType: { id: true, posTypeName: true },
}, posLevel: { id: true, posLevelName: true },
relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"], },
})) as PosMaster; };
const posMasterUser = await this.posMasterRepo.findOne({
where: {
orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
current_holder: { keycloak: userKeycloak },
},
select: userSelectFields,
relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"],
});
if (!posMasterUser?.orgRootId) {
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบตำแหน่งผู้ใช้งาน");
} }
if (!posMasterUser || !posMasterUser.orgRootId) // 2. Pre-calculate conditions - ปรับให้เหมือน getProfilePlacement
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบตำแหน่งผู้ใช้งาน"); const posType = posMasterUser.current_holder?.posType?.posTypeName;
const posLevel = posMasterUser.current_holder?.posLevel?.posLevelName;
let condition: any = []; const isLowLevel =
(posType === "ทั่วไป" && ["ชำนาญงาน", "ปฏิบัติงาน"].includes(posLevel)) ||
(posType === "วิชาการ" && ["ปฏิบัติการ", "ชำนาญการ"].includes(posLevel));
let conditionOfficer: any = { const isMidLevel =
(posType === "ทั่วไป" && posLevel === "อาวุโส") ||
(posType === "วิชาการ" && posLevel === "ชำนาญการพิเศษ") ||
(posType === "อำนวยการ" && posLevel === "ต้น");
// 3. สร้าง conditions แบบ optimized
const baseCondition = {
isDirector: true, isDirector: true,
isOfficer: true,
orgRevisionId: posMasterUser.orgRevisionId, orgRevisionId: posMasterUser.orgRevisionId,
};
const conditionOfficer = {
...baseCondition,
isOfficer: true,
orgChild1Id: IsNull(), orgChild1Id: IsNull(),
}; };
if (type.trim().toUpperCase() == "OPERATE") { let mainConditions: any[] = [];
condition.push({
isDirector: true, if (type.trim().toUpperCase() === "OPERATE") {
orgRootId: posMasterUser.orgRootId, mainConditions = [
orgRevisionId: posMasterUser.orgRevisionId, { ...baseCondition, orgRootId: posMasterUser.orgRootId, orgChild1Id: IsNull() },
orgChild1Id: IsNull(),
});
condition.push({
isDirector: true,
orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: IsNull(),
});
condition.push({
isDirector: true,
orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: IsNull(),
});
condition.push({
isDirector: true,
orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: posMasterUser.orgChild3Id,
orgChild4Id: IsNull(),
});
condition.push({
isDirector: true,
orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: posMasterUser.orgChild3Id,
orgChild4Id: posMasterUser.orgChild4Id,
});
} else {
condition = [
{ {
isDirector: true, ...baseCondition,
orgRootId: posMasterUser.orgRootId, orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId, orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: IsNull(),
},
{
...baseCondition,
orgRootId: posMasterUser.orgRootId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: IsNull(),
},
{
...baseCondition,
orgRootId: posMasterUser.orgRootId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: posMasterUser.orgChild3Id,
orgChild4Id: IsNull(),
},
{
...baseCondition,
orgRootId: posMasterUser.orgRootId,
orgChild1Id: posMasterUser.orgChild1Id,
orgChild2Id: posMasterUser.orgChild2Id,
orgChild3Id: posMasterUser.orgChild3Id,
orgChild4Id: posMasterUser.orgChild4Id,
}, },
]; ];
if ( } else if (isLowLevel) {
(posMasterUser.current_holder.posType.posTypeName == "ทั่วไป" && mainConditions = [
posMasterUser.current_holder.posLevel.posLevelName == "ชำนาญงาน") || {
(posMasterUser.current_holder.posType.posTypeName == "ทั่วไป" && ...baseCondition,
posMasterUser.current_holder.posLevel.posLevelName == "ปฏิบัติงาน") ||
(posMasterUser.current_holder.posType.posTypeName == "วิชาการ" &&
posMasterUser.current_holder.posLevel.posLevelName == "ปฏิบัติการ") ||
(posMasterUser.current_holder.posType.posTypeName == "วิชาการ" &&
posMasterUser.current_holder.posLevel.posLevelName == "ชำนาญการ")
) {
condition = {
isDirector: true,
orgRootId: posMasterUser.orgRootId, orgRootId: posMasterUser.orgRootId,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: IsNull(), orgChild1Id: IsNull(),
orgChild2Id: IsNull(), orgChild2Id: IsNull(),
orgChild3Id: IsNull(), orgChild3Id: IsNull(),
orgChild4Id: IsNull(), orgChild4Id: IsNull(),
}; },
} else if ( ];
(posMasterUser.current_holder.posType.posTypeName == "ทั่วไป" && } else if (isMidLevel) {
posMasterUser.current_holder.posLevel.posLevelName == "อาวุโส") || mainConditions = [
(posMasterUser.current_holder.posType.posTypeName == "วิชาการ" && {
posMasterUser.current_holder.posLevel.posLevelName == "ชำนาญการพิเศษ") || ...baseCondition,
(posMasterUser.current_holder.posType.posTypeName == "อำนวยการ" &&
posMasterUser.current_holder.posLevel.posLevelName == "ต้น")
) {
condition = {
isDirector: true,
isDeputy: true, isDeputy: true,
orgRevisionId: posMasterUser.orgRevisionId,
orgChild1Id: IsNull(), orgChild1Id: IsNull(),
orgChild2Id: IsNull(), orgChild2Id: IsNull(),
orgChild3Id: IsNull(), orgChild3Id: IsNull(),
orgChild4Id: IsNull(), orgChild4Id: IsNull(),
}; },
} else { ];
} } else {
mainConditions = [{ ...baseCondition, orgRootId: posMasterUser.orgRootId }];
} }
if (body.isAct == true) { // 4. สร้าง optimized query builder
const [lists, total] = await AppDataSource.getRepository(viewDirectorActing) const repository = body.isAct
.createQueryBuilder("viewDirectorActing") ? AppDataSource.getRepository(viewDirectorActing)
.andWhere( : AppDataSource.getRepository(viewDirector);
new Brackets((qb) => {
qb.orWhere(condition).orWhere(conditionOfficer); const queryBuilder = repository.createQueryBuilder("entity");
}),
) // 5. แยก WHERE conditions ให้เร็วขึ้น
.andWhere( queryBuilder.where(
new Brackets((qb) => { new Brackets((qb) => {
qb.orWhere( mainConditions.forEach((condition, index) => {
body.keyword != null && body.keyword != "" if (index === 0) {
? "CONCAT(viewDirectorActing.prefix,viewDirectorActing.firstName,' ',viewDirectorActing.lastName) LIKE :keyword" qb.where(condition);
: "1=1", } else {
{ qb.orWhere(condition);
keyword: `%${body.keyword}%`, }
}, });
) qb.orWhere(conditionOfficer);
.orWhere( }),
body.keyword != null && body.keyword != "" );
? "viewDirectorActing.citizenId LIKE :keyword"
: "1=1", // 6. ปรับ search conditions ให้เร็วขึ้น - แบบเดียวกับ getProfilePlacement
{ if (body.keyword?.trim()) {
keyword: `%${body.keyword}%`, const keyword = `%${body.keyword.trim()}%`;
}, const searchFields = [
) "CONCAT(entity.prefix, entity.firstName, ' ', entity.lastName)",
.orWhere( "entity.citizenId",
body.keyword != null && body.keyword != "" "entity.position",
? "viewDirectorActing.position LIKE :keyword" "entity.posLevel",
: "1=1", "entity.posType",
{ "entity.posNo",
keyword: `%${body.keyword}%`, "entity.posExecutiveName",
}, ];
)
.orWhere( if (body.isAct) {
body.keyword != null && body.keyword != "" searchFields.push("entity.actFullName");
? "viewDirectorActing.posLevel LIKE :keyword" }
: "1=1",
{ queryBuilder.andWhere(
keyword: `%${body.keyword}%`, `(${searchFields.map((field) => `${field} LIKE :keyword`).join(" OR ")})`,
}, { keyword },
) );
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirectorActing.posType LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirectorActing.actFullName LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirectorActing.posNo LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirectorActing.posExecutiveName LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
);
}),
)
.skip((body.page - 1) * body.pageSize)
.take(body.pageSize)
.getManyAndCount();
const data = lists.map((x) => ({
...x,
posExecutiveNameOrg:
x.posExecutiveName +
(x.orgChild4 ?? x.orgChild3 ?? x.orgChild2 ?? x.orgChild1 ?? x.orgRoot ?? ""),
}));
return new HttpSuccess({ data: data, total });
} else {
const [lists, total] = await AppDataSource.getRepository(viewDirector)
.createQueryBuilder("viewDirector")
.andWhere(
new Brackets((qb) => {
qb.orWhere(condition).orWhere(conditionOfficer);
}),
)
.andWhere(
new Brackets((qb) => {
qb.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(viewDirector.prefix,viewDirector.firstName,' ',viewDirector.lastName) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.citizenId LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.position LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.posLevel LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.posType LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.posNo LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "viewDirector.posExecutiveName LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
);
}),
)
.skip((body.page - 1) * body.pageSize)
.take(body.pageSize)
.getManyAndCount();
const data = lists.map((x) => ({
...x,
posExecutiveNameOrg:
x.posExecutiveName +
(x.orgChild4 ?? x.orgChild3 ?? x.orgChild2 ?? x.orgChild1 ?? x.orgRoot ?? ""),
}));
return new HttpSuccess({ data: data, total });
} }
// 7. Execute พร้อมกัน - ใช้ Promise.all
const [data, total] = await Promise.all([
queryBuilder
.skip((body.page - 1) * body.pageSize)
.take(body.pageSize)
.getMany(),
queryBuilder.getCount(),
]);
// 8. ปรับ response mapping
const processedData = data.map((x: any) => ({
...x,
posExecutiveNameOrg:
x.posExecutiveName +
(x.orgChild4 ?? x.orgChild3 ?? x.orgChild2 ?? x.orgChild1 ?? x.orgRoot ?? ""),
}));
return new HttpSuccess({ data: processedData, total });
} }
/** /**