Merge branch 'develop' of github.com:Frappet/hrms-api-org into develop

# Conflicts:
#	src/controllers/CommandController.ts
This commit is contained in:
mamoss 2025-07-11 16:33:25 +07:00
commit 6c8f162cfa
6 changed files with 346 additions and 58 deletions

View file

@ -90,6 +90,7 @@ import { EmployeeTempPosMaster } from "../entities/EmployeeTempPosMaster";
import { ProfileInsignia, CreateProfileInsignia } from "../entities/ProfileInsignia";
import { ProfileInsigniaHistory } from "../entities/ProfileInsigniaHistory";
import { Gender } from "../entities/Gender";
import { ProfileAvatar } from "../entities/ProfileAvatar";
@Route("api/v1/org/command")
@Tags("Command")
@Security("bearerAuth")
@ -143,6 +144,7 @@ export class CommandController extends Controller {
private insigniaRepo = AppDataSource.getRepository(ProfileInsignia);
private insigniaHistoryRepo = AppDataSource.getRepository(ProfileInsigniaHistory);
private genderRepo = AppDataSource.getRepository(Gender);
private avatarRepository = AppDataSource.getRepository(ProfileAvatar);
/**
* API list
@ -5512,7 +5514,7 @@ export class CommandController extends Controller {
let profile: any = await this.profileRepository.findOne({
where: { citizenId: item.bodyProfile.citizenId /*, isActive: true */ },
relations: ["roleKeycloaks", "profileInsignias"],
relations: ["roleKeycloaks", "profileInsignias", "profileAvatars"],
});
let _oldInsigniaIds: string[] = [];
if (!profile) {
@ -5963,6 +5965,48 @@ export class CommandController extends Controller {
await this.insigniaHistoryRepo.save(history, { data: req });
}
}
// เพิ่มรูปภาพโปรไฟล์
if (item.bodyProfile.objectRefId) {
const _profileAvatar = new ProfileAvatar();
Object.assign(_profileAvatar, {
...meta,
profileId: profile.id,
profileEmployeeId: undefined,
});
if (profile.profileAvatars && profile.profileAvatars.length > 0) {
await Promise.all(
profile.profileAvatars.map(async (item: any) => {
item.isActive = false;
await this.avatarRepository.save(item);
}),
);
}
await this.avatarRepository.save(_profileAvatar);
let avatar = `ทะเบียนประวัติ/โปรไฟล์/${profile.id}`;
let fileName = `profile-${_profileAvatar.id}`;
_profileAvatar.isActive = true;
_profileAvatar.avatar = avatar;
_profileAvatar.avatarName = fileName;
await this.avatarRepository.save(_profileAvatar, { data: req });
profile.avatar = avatar;
profile.avatarName = fileName;
await this.profileRepository.save(profile, { data: req });
const checkAvatar = await this.avatarRepository.findOne({
where: { avatar: avatar, avatarName: fileName },
});
if (checkAvatar && checkAvatar.profileId == null) {
checkAvatar.profileId = profile.id;
await this.avatarRepository.save(checkAvatar);
}
//duplicate รูปภาพโปรไฟล์โดยอิงจากรูปภาพเดิม
await new CallAPI()
.PostData(req, `/salary/file/avatar/${item.bodyProfile.objectRefId}`, {
prefix: avatar,
fileName: fileName,
})
.then(() => {})
.catch(() => {});
}
}
}),
);

View file

@ -26,6 +26,7 @@ import { Position } from "../entities/Position";
import { Insignia } from "../entities/Insignia";
import { CreateProfileInsignia, ProfileInsignia } from "../entities/ProfileInsignia";
import { PosMaster } from "../entities/PosMaster";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
import { EmployeePosDict } from "../entities/EmployeePosDict";
import { calculateRetireLaw } from "../interfaces/utils";
import Extension from "../interfaces/extension";
@ -44,6 +45,7 @@ export class OrganizationDotnetController extends Controller {
private profileEmpRepo = AppDataSource.getRepository(ProfileEmployee);
private positionRepository = AppDataSource.getRepository(Position);
private posMasterRepository = AppDataSource.getRepository(PosMaster);
private empPosMasterRepository = AppDataSource.getRepository(EmployeePosMaster);
private insigniaRepo = AppDataSource.getRepository(ProfileInsignia);
private employeePosDictRepository = AppDataSource.getRepository(EmployeePosDict);
@ -188,10 +190,103 @@ export class OrganizationDotnetController extends Controller {
citizenId?: string | null;
firstName?: string | null;
lastName?: string | null;
role?: string | null;
nodeId?: string | null;
node?: number | null;
},
) {
const profileRepository = AppDataSource.getRepository(ProfileEmployee);
const queryBuilder = profileRepository
// const profileRepository = AppDataSource.getRepository(ProfileEmployee);
// const queryBuilder = profileRepository
// .createQueryBuilder("profile")
// .leftJoinAndSelect("profile.posLevel", "posLevel")
// .leftJoinAndSelect("profile.posType", "posType")
// .leftJoinAndSelect("profile.profileSalary", "profileSalary")
// .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")
// .orderBy("profileSalary.order", "DESC");
// if (body.citizenId || body.firstName || body.lastName) {
// queryBuilder.where(
// new Brackets((qb) => {
// if (body.citizenId) {
// qb.orWhere("profile.citizenId LIKE :citizenId", { citizenId: `%${body.citizenId}%` });
// }
// if (body.firstName) {
// qb.orWhere("profile.firstName LIKE :firstName", { firstName: `%${body.firstName}%` });
// }
// if (body.lastName) {
// qb.orWhere("profile.lastName LIKE :lastName", { lastName: `%${body.lastName}%` });
// }
// }),
// );
// }
// const profileEmp = await queryBuilder.getMany();
let condition = "1=1";
let conditionParams = {};
if (body.role === "CHILD") {
switch (body.node) {
case 0:
condition = "orgRoot.ancestorDNA = :nodeId";
break;
case 1:
condition = "orgChild1.ancestorDNA = :nodeId";
break;
case 2:
condition = "orgChild2.ancestorDNA = :nodeId";
break;
case 3:
condition = "orgChild3.ancestorDNA = :nodeId";
break;
case 4:
condition = "orgChild4.ancestorDNA = :nodeId";
break;
default:
condition = "1=1";
break;
}
conditionParams = { nodeId: body.nodeId };
}
else if (body.role === "ROOT") {
condition = "orgRoot.ancestorDNA = :nodeId";
conditionParams = { nodeId: body.nodeId };
}
else if (body.role === "NORMAL") {
switch (body.node) {
case 0:
condition = "orgRoot.ancestorDNA = :nodeId AND current_holders.orgChild1 IS NULL";
break;
case 1:
condition = "orgChild1.ancestorDNA = :nodeId AND current_holders.orgChild2 IS NULL";
break;
case 2:
condition = "orgChild2.ancestorDNA = :nodeId AND current_holders.orgChild3 IS NULL";
break;
case 3:
condition = "orgChild3.ancestorDNA = :nodeId AND current_holders.orgChild4 IS NULL";
break;
case 4:
condition = "orgChild4.ancestorDNA = :nodeId";
break;
default:
condition = "1=1";
break;
}
conditionParams = { nodeId: body.nodeId };
}
const findRevision = await this.orgRevisionRepo.findOne({
where: { orgRevisionIsCurrent: true },
});
if (!findRevision) {
throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision");
}
const profileEmp = await this.profileEmpRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.posLevel", "posLevel")
.leftJoinAndSelect("profile.posType", "posType")
@ -202,10 +297,8 @@ export class OrganizationDotnetController extends Controller {
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.orderBy("profileSalary.order", "DESC");
if (body.citizenId || body.firstName || body.lastName) {
queryBuilder.where(
.where("current_holders.orgRevisionId = :orgRevisionId", { orgRevisionId: findRevision.id })
.andWhere(
new Brackets((qb) => {
if (body.citizenId) {
qb.orWhere("profile.citizenId LIKE :citizenId", { citizenId: `%${body.citizenId}%` });
@ -217,14 +310,10 @@ export class OrganizationDotnetController extends Controller {
qb.orWhere("profile.lastName LIKE :lastName", { lastName: `%${body.lastName}%` });
}
}),
);
}
const profileEmp = await queryBuilder.getMany();
const findRevision = await this.orgRevisionRepo.findOne({
where: { orgRevisionIsCurrent: true },
});
)
.andWhere(condition, conditionParams)
.orderBy("profileSalary.order", "DESC")
.getMany()
const profileEmp_ = await Promise.all(
profileEmp.map((item: ProfileEmployee) => {
@ -4121,19 +4210,39 @@ export class OrganizationDotnetController extends Controller {
if (body.role === "OWNER" || body.role === "CHILD") {
switch (node) {
case 0:
typeCondition = { orgRootId: body.nodeId };
typeCondition = {
orgRoot: {
ancestorDNA: body.nodeId
}
};
break;
case 1:
typeCondition = { orgChild1Id: body.nodeId };
typeCondition = {
orgChild1: {
ancestorDNA: body.nodeId
}
};
break;
case 2:
typeCondition = { orgChild2Id: body.nodeId };
typeCondition = {
orgChild2: {
ancestorDNA: body.nodeId
}
};
break;
case 3:
typeCondition = { orgChild3Id: body.nodeId };
typeCondition = {
orgChild3: {
ancestorDNA: body.nodeId
}
};
break;
case 4:
typeCondition = { orgChild4Id: body.nodeId };
typeCondition = {
orgChild4: {
ancestorDNA: body.nodeId
}
};
break;
case null:
typeCondition = {};
@ -4144,32 +4253,49 @@ export class OrganizationDotnetController extends Controller {
}
} else if (body.role === "ROOT") {
typeCondition = {
orgRootId: body.nodeId
orgRoot: {
ancestorDNA: body.nodeId
},
};
} else if (body.role === "NORMAL") {
switch (node) {
case 0:
typeCondition = {
orgRootId: body.nodeId,
orgChild1Id: IsNull(),
orgRoot: {
ancestorDNA: body.nodeId
},
orgChild1: IsNull()
};
break;
case 1:
typeCondition = {
orgChild1Id: body.nodeId,
orgChild2Id: IsNull(),
orgChild1: {
ancestorDNA: body.nodeId
},
orgChild2: IsNull()
};
break;
case 2:
typeCondition = {
orgChild2Id: body.nodeId,
orgChild3Id: IsNull(),
orgChild2: {
ancestorDNA: body.nodeId
},
orgChild3: IsNull()
};
break;
case 3:
typeCondition = {
orgChild3Id: body.nodeId,
orgChild4Id: IsNull(),
orgChild3: {
ancestorDNA: body.nodeId
},
orgChild4: IsNull()
};
break;
case 4:
typeCondition = {
orgChild4: {
ancestorDNA: body.nodeId
},
};
break;
default:
@ -4190,6 +4316,26 @@ export class OrganizationDotnetController extends Controller {
"current_holders.orgChild3",
"current_holders.orgChild4",
],
order: {
current_holders: {
orgRoot: {
orgRootOrder: "ASC",
},
orgChild1: {
orgChild1Order: "ASC",
},
orgChild2: {
orgChild2Order: "ASC",
},
orgChild3: {
orgChild3Order: "ASC",
},
orgChild4: {
orgChild4Order: "ASC",
},
posMasterNo: "ASC",
}
}
});
if (body.isRetirement) {
profile = await this.profileRepo.find({
@ -4211,7 +4357,7 @@ export class OrganizationDotnetController extends Controller {
});
}
let findRevision = await this.orgRevisionRepo.findOne({
where: { orgRevisionIsCurrent: true },
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }
});
if (body.revisionId) {
@ -4221,7 +4367,7 @@ export class OrganizationDotnetController extends Controller {
}
const profile_ = await Promise.all(
profile.map((item: Profile) => {
profile.map(async(item: Profile) => {
const shortName =
item.current_holders.length == 0
? null
@ -4250,17 +4396,25 @@ export class OrganizationDotnetController extends Controller {
const Oc =
item.current_holders.length == 0
? null
: body.node == 4 && item.current_holders[0].orgChild4 != null
: item.current_holders[0].orgChild4 != null
? `${item.current_holders[0].orgChild4.orgChild4Name}/${item.current_holders[0].orgChild3.orgChild3Name}/${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
: body.node == 3 && item.current_holders[0].orgChild3 != null
: item.current_holders[0].orgChild3 != null
? `${item.current_holders[0].orgChild3.orgChild3Name}/${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
: body.node == 2 && item.current_holders[0].orgChild2 != null
: item.current_holders[0].orgChild2 != null
? `${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
: body.node == 1 && item.current_holders[0].orgChild1 != null
: item.current_holders[0].orgChild1 != null
? `${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
: body.node == 0 && item.current_holders[0].orgRoot != null
: item.current_holders[0].orgRoot != null
? `${item.current_holders[0].orgRoot.orgRootName}`
: null;
let _posMaster = await this.posMasterRepository.findOne({
where: {
orgRevisionId: findRevision?.id,
current_holderId: item.id
}
});
return {
id: item.id,
prefix: item.prefix,
@ -4273,6 +4427,11 @@ export class OrganizationDotnetController extends Controller {
positionLevel: item.posLevel?.posLevelName ?? null,
positionType: item.posType?.posTypeName ?? null,
oc: Oc,
orgRootId: _posMaster?.orgRootId,
orgChild1Id: _posMaster?.orgChild1Id,
orgChild2Id: _posMaster?.orgChild2Id,
orgChild3Id: _posMaster?.orgChild3Id,
orgChild4Id: _posMaster?.orgChild4Id
};
}),
);
@ -4611,19 +4770,39 @@ export class OrganizationDotnetController extends Controller {
if (body.role === "OWNER" || body.role === "CHILD") {
switch (node) {
case 0:
typeCondition = { orgRootId: body.nodeId };
typeCondition = {
orgRoot: {
ancestorDNA: body.nodeId
}
};
break;
case 1:
typeCondition = { orgChild1Id: body.nodeId };
typeCondition = {
orgChild1: {
ancestorDNA: body.nodeId
}
};
break;
case 2:
typeCondition = { orgChild2Id: body.nodeId };
typeCondition = {
orgChild2: {
ancestorDNA: body.nodeId
}
};
break;
case 3:
typeCondition = { orgChild3Id: body.nodeId };
typeCondition = {
orgChild3: {
ancestorDNA: body.nodeId
}
};
break;
case 4:
typeCondition = { orgChild4Id: body.nodeId };
typeCondition = {
orgChild4: {
ancestorDNA: body.nodeId
}
};
break;
case null:
typeCondition = {};
@ -4634,32 +4813,49 @@ export class OrganizationDotnetController extends Controller {
}
} else if (body.role === "ROOT") {
typeCondition = {
orgRootId: body.nodeId
orgRoot: {
ancestorDNA: body.nodeId
},
};
} else if (body.role === "NORMAL") {
switch (node) {
case 0:
typeCondition = {
orgRootId: body.nodeId,
orgChild1Id: IsNull(),
orgRoot: {
ancestorDNA: body.nodeId
},
orgChild1: IsNull()
};
break;
case 1:
typeCondition = {
orgChild1Id: body.nodeId,
orgChild2Id: IsNull(),
orgChild1: {
ancestorDNA: body.nodeId
},
orgChild2: IsNull()
};
break;
case 2:
typeCondition = {
orgChild2Id: body.nodeId,
orgChild3Id: IsNull(),
orgChild2: {
ancestorDNA: body.nodeId
},
orgChild3: IsNull()
};
break;
case 3:
typeCondition = {
orgChild3Id: body.nodeId,
orgChild4Id: IsNull(),
orgChild3: {
ancestorDNA: body.nodeId
},
orgChild4: IsNull()
};
break;
case 4:
typeCondition = {
orgChild4: {
ancestorDNA: body.nodeId
},
};
break;
default:
@ -4680,6 +4876,26 @@ export class OrganizationDotnetController extends Controller {
"current_holders.orgChild3",
"current_holders.orgChild4",
],
order: {
current_holders: {
orgRoot: {
orgRootOrder: "ASC",
},
orgChild1: {
orgChild1Order: "ASC",
},
orgChild2: {
orgChild2Order: "ASC",
},
orgChild3: {
orgChild3Order: "ASC",
},
orgChild4: {
orgChild4Order: "ASC",
},
posMasterNo: "ASC",
}
}
});
if (body.isRetirement) {
profile = await this.profileEmpRepo.find({
@ -4701,7 +4917,7 @@ export class OrganizationDotnetController extends Controller {
});
}
let findRevision = await this.orgRevisionRepo.findOne({
where: { orgRevisionIsCurrent: true },
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }
});
if (body.revisionId) {
@ -4711,7 +4927,7 @@ export class OrganizationDotnetController extends Controller {
}
const profile_ = await Promise.all(
profile.map((item: ProfileEmployee) => {
profile.map(async(item: ProfileEmployee) => {
const shortName =
item.current_holders.length == 0
? null
@ -4740,17 +4956,25 @@ export class OrganizationDotnetController extends Controller {
const Oc =
item.current_holders.length == 0
? null
: body.node == 4 && item.current_holders[0].orgChild4 != null
: item.current_holders[0].orgChild4 != null
? `${item.current_holders[0].orgChild4.orgChild4Name}/${item.current_holders[0].orgChild3.orgChild3Name}/${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
: body.node == 3 && item.current_holders[0].orgChild3 != null
: item.current_holders[0].orgChild3 != null
? `${item.current_holders[0].orgChild3.orgChild3Name}/${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
: body.node == 2 && item.current_holders[0].orgChild2 != null
: item.current_holders[0].orgChild2 != null
? `${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
: body.node == 1 && item.current_holders[0].orgChild1 != null
: item.current_holders[0].orgChild1 != null
? `${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
: body.node == 0 && item.current_holders[0].orgRoot != null
: item.current_holders[0].orgRoot != null
? `${item.current_holders[0].orgRoot.orgRootName}`
: null;
let _posMaster = await this.empPosMasterRepository.findOne({
where: {
orgRevisionId: findRevision?.id,
current_holderId: item.id
}
});
return {
id: item.id,
prefix: item.prefix,
@ -4760,9 +4984,16 @@ export class OrganizationDotnetController extends Controller {
keycloak: item.keycloak,
posNo: shortName,
position: item.position,
positionLevel: item.posLevel?.posLevelName ?? null,
positionLevel: item.posType?.posTypeShortName && item.posLevel?.posLevelName
? `${item.posType?.posTypeShortName} ${item.posLevel?.posLevelName}`
: null,
positionType: item.posType?.posTypeName ?? null,
oc: Oc,
orgRootId: _posMaster?.orgRootId,
orgChild1Id: _posMaster?.orgChild1Id,
orgChild2Id: _posMaster?.orgChild2Id,
orgChild3Id: _posMaster?.orgChild3Id,
orgChild4Id: _posMaster?.orgChild4Id,
};
}),
);

View file

@ -1153,6 +1153,7 @@ export class ProfileController extends Controller {
"commandNo",
"positionCee",
"amount",
"amountSpecial",
"remark",
],
where: {
@ -1176,6 +1177,8 @@ export class ProfileController extends Controller {
: null,
salary:
item.amount != null ? Extension.ToThaiNumber(item.amount.toLocaleString()) : null,
special:
item.amountSpecial != null ? Extension.ToThaiNumber(item.amountSpecial.toLocaleString()) : null,
rank: item.positionLevel != null ? Extension.ToThaiNumber(item.positionLevel) : null,
refAll: item.remark ? Extension.ToThaiNumber(item.remark) : null,
positionLevel: item.positionLevel
@ -1202,6 +1205,7 @@ export class ProfileController extends Controller {
position: "-",
posNo: "-",
salary: "-",
special: "-",
rank: "-",
refAll: "-",
positionLevel: "-",

View file

@ -1150,6 +1150,7 @@ export class ProfileEmployeeController extends Controller {
"commandNo",
"positionCee",
"amount",
"amountSpecial",
"remark",
],
where: {
@ -1173,6 +1174,8 @@ export class ProfileEmployeeController extends Controller {
: null,
salary:
item.amount != null ? Extension.ToThaiNumber(item.amount.toLocaleString()) : null,
special:
item.amountSpecial != null ? Extension.ToThaiNumber(item.amountSpecial.toLocaleString()) : null,
rank: item.positionLevel != null ? Extension.ToThaiNumber(item.positionLevel) : null,
refAll: item.remark ? Extension.ToThaiNumber(item.remark) : null,
positionLevel: item.positionLevel
@ -1199,6 +1202,7 @@ export class ProfileEmployeeController extends Controller {
position: "-",
posNo: "-",
salary: "-",
special: "-",
rank: "-",
refAll: "-",
positionLevel: "-",

View file

@ -670,6 +670,7 @@ export class ProfileEmployeeTempController extends Controller {
"positionSalaryAmount",
"commandNo",
"amount",
"amountSpecial",
"remark",
],
where: { profileEmployeeId: id },
@ -686,6 +687,8 @@ export class ProfileEmployeeTempController extends Controller {
PosNo: item.posNo != null ? Extension.ToThaiNumber(item.posNo) : null,
Salary:
item.amount != null ? Extension.ToThaiNumber(item.amount.toLocaleString()) : null,
Special:
item.amountSpecial != null ? Extension.ToThaiNumber(item.amountSpecial.toLocaleString()) : null,
Rank: item.positionLevel != null ? Extension.ToThaiNumber(item.positionLevel) : null,
RefAll: item.remark ? Extension.ToThaiNumber(item.remark) : null,
PositionLevel:
@ -709,6 +712,7 @@ export class ProfileEmployeeTempController extends Controller {
Position: "-",
PosNo: "-",
Salary: "-",
Special: "-",
Rank: "-",
RefAll: "-",
PositionLevel: "-",

View file

@ -857,6 +857,7 @@ export class CreateProfileAllFields {
currentZipCode: string | null;
amount?: Double | null;
amountSpecial?: Double | null;
objectRefId?: string | null;
}
export type UpdateProfile = {