Merge branch 'develop' into dev

* develop:
  Issue/#1880 (#22)
  Task/#1839 (#21)
  fix
  revert /api/v1/kpi/period
  sort ประเมินผลการปฏิบัติราชการระดับบุคคล
This commit is contained in:
Warunee Tamkoo 2025-10-22 11:04:57 +07:00
commit 0528eaa282
5 changed files with 173 additions and 68 deletions

22
.github/workflows/discord-notify.yml vendored Normal file
View file

@ -0,0 +1,22 @@
name: Discord PR Notify
on:
pull_request:
types: [opened]
jobs:
discord:
runs-on: ubuntu-latest
steps:
- name: Send Discord
run: |
curl -X POST "${{ secrets.DISCORD_WEBHOOK_PULLREQUEST }}" \
-H "Content-Type: application/json" \
-d '{
"embeds": [{
"title": "🔔 **Service:** ${{ github.repository }}",
"description": "👤 **Author:** ${{ github.event.pull_request.user.login }}\n🌿 **Branch:** ${{ github.event.pull_request.head.ref }} → ${{ github.event.pull_request.base.ref }}\n📦 **Pull Request:** [#${{ github.event.pull_request.number }} - ${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})",
"color": 5814783,
"timestamp": "${{ github.event.pull_request.created_at }}"
}]
}'

View file

@ -235,20 +235,32 @@ export class kpiPeriodController extends Controller {
@Query("pageSize") pageSize: number = 10, @Query("pageSize") pageSize: number = 10,
@Query("year") year?: number, @Query("year") year?: number,
@Query("keyword") keyword?: string, @Query("keyword") keyword?: string,
@Query("sortBy") sortBy?: string,
@Query("descending") descending?: boolean,
) { ) {
await new permission().PermissionList(request, "SYS_KPI_ROUND"); await new permission().PermissionList(request, "SYS_KPI_ROUND");
const [kpiPeriod, total] = await AppDataSource.getRepository(KpiPeriod) let query = await AppDataSource.getRepository(KpiPeriod)
.createQueryBuilder("kpiPeriod") .createQueryBuilder("kpiPeriod")
.andWhere( .andWhere(
year !== 0 && year != null && year != undefined ? "kpiPeriod.year = :year" : "1=1", year !== 0 && year != null && year != undefined ? "kpiPeriod.year = :year" : "1=1",
{ year: year }, { year: year },
) )
.orderBy("kpiPeriod.year", "DESC")
.addOrderBy("kpiPeriod.durationKPI", "DESC") if (sortBy) {
.addOrderBy("kpiPeriod.startDate", "DESC") query = query.orderBy(
.skip((page - 1) * pageSize) `kpiPeriod.${sortBy}`,
.take(pageSize) descending ? "DESC" : "ASC"
.getManyAndCount(); );
}else{
query = query.orderBy("kpiPeriod.year", "DESC")
.addOrderBy("kpiPeriod.durationKPI", "DESC")
.addOrderBy("kpiPeriod.startDate", "DESC")
}
const [kpiPeriod, total] = await query
.skip((page - 1) * pageSize)
.take(pageSize)
.getManyAndCount();
return new HttpSuccess({ data: kpiPeriod, total }); return new HttpSuccess({ data: kpiPeriod, total });
} }
@ -291,7 +303,7 @@ export class kpiPeriodController extends Controller {
@Query("year") year?: number, @Query("year") year?: number,
@Query("keyword") keyword?: string, @Query("keyword") keyword?: string,
) { ) {
const [kpiPeriod, total] = await AppDataSource.getRepository(KpiPeriod) const [kpiPeriod,total] = await AppDataSource.getRepository(KpiPeriod)
.createQueryBuilder("kpiPeriod") .createQueryBuilder("kpiPeriod")
.andWhere( .andWhere(
year !== 0 && year != null && year != undefined ? "kpiPeriod.year = :year" : "1=1", year !== 0 && year != null && year != undefined ? "kpiPeriod.year = :year" : "1=1",

View file

@ -360,6 +360,8 @@ export class KpiUserDevelopmentController extends Controller {
// results?: string | null; // results?: string | null;
// reqedit?: string | null; // reqedit?: string | null;
// evaluating?: boolean | null; // evaluating?: boolean | null;
sortBy?: string;
descending?: boolean;
}, },
) { ) {
// await new permission().PermissionList(request, "SYS_RESULT"); // await new permission().PermissionList(request, "SYS_RESULT");
@ -372,7 +374,7 @@ export class KpiUserDevelopmentController extends Controller {
_data = x; _data = x;
}) })
.catch((x) => {}); .catch((x) => {});
const [kpiUserDevelopment, total] = await AppDataSource.getRepository(KpiUserDevelopment) let query = await AppDataSource.getRepository(KpiUserDevelopment)
.createQueryBuilder("kpiUserDevelopment") .createQueryBuilder("kpiUserDevelopment")
.leftJoinAndSelect("kpiUserDevelopment.kpiUserEvaluation", "kpiUserEvaluation") .leftJoinAndSelect("kpiUserDevelopment.kpiUserEvaluation", "kpiUserEvaluation")
.leftJoinAndSelect("kpiUserEvaluation.kpiPeriod", "kpiPeriod") .leftJoinAndSelect("kpiUserEvaluation.kpiPeriod", "kpiPeriod")
@ -476,7 +478,46 @@ export class KpiUserDevelopmentController extends Controller {
}); });
}), }),
) )
.orderBy("kpiUserDevelopment.createdAt", "ASC")
if (requestBody.sortBy) {
if(requestBody.sortBy === "developmentName"){
query = query.orderBy(
`kpiUserDevelopment.name`,
requestBody.descending ? "DESC" : "ASC"
);
}else if (requestBody.sortBy === "organization"){
query = query
.orderBy(`kpiUserEvaluation.child4`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child3`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child2`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child1`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.org`, requestBody.descending ? "DESC" : "ASC");
}else if(requestBody.sortBy === "firstname"){
query = query.orderBy(
`kpiUserEvaluation.firstName`,
requestBody.descending ? "DESC" : "ASC"
);
}else if(requestBody.sortBy === "lastname"){
query = query.orderBy(
`kpiUserEvaluation.lastName`,
requestBody.descending ? "DESC" : "ASC"
);
}else if(requestBody.sortBy === "root"){
query = query.orderBy(
`kpiUserEvaluation.org`,
requestBody.descending ? "DESC" : "ASC"
);
}else{
query = query.orderBy(
`kpiUserEvaluation.${requestBody.sortBy}`,
requestBody.descending ? "DESC" : "ASC"
);
}
}else{
query = query.orderBy("kpiUserDevelopment.createdAt", "ASC")
}
const [kpiUserDevelopment, total] = await query
.skip((requestBody.page - 1) * requestBody.pageSize) .skip((requestBody.page - 1) * requestBody.pageSize)
.take(requestBody.pageSize) .take(requestBody.pageSize)
.getManyAndCount(); .getManyAndCount();

View file

@ -241,6 +241,8 @@ export class KpiUserEvaluationController extends Controller {
results?: string | null; results?: string | null;
reqedit?: string | null; reqedit?: string | null;
evaluating?: boolean | null; evaluating?: boolean | null;
sortBy?: string;
descending?: boolean;
}, },
) { ) {
// await new permission().PermissionList(request, "SYS_RESULT"); // await new permission().PermissionList(request, "SYS_RESULT");
@ -253,7 +255,7 @@ export class KpiUserEvaluationController extends Controller {
_data = x; _data = x;
}) })
.catch((x) => {}); .catch((x) => {});
const [kpiUserEvaluation, total] = await AppDataSource.getRepository(KpiUserEvaluation) let query = await AppDataSource.getRepository(KpiUserEvaluation)
.createQueryBuilder("kpiUserEvaluation") .createQueryBuilder("kpiUserEvaluation")
.andWhere( .andWhere(
_data.root != undefined && _data.root != null _data.root != undefined && _data.root != null
@ -385,7 +387,31 @@ export class KpiUserEvaluationController extends Controller {
}); });
}), }),
) )
.orderBy("kpiUserEvaluation.createdAt", "DESC")
if (requestBody.sortBy) {
if(requestBody.sortBy === "root"){
query = query.orderBy(
`kpiUserEvaluation.org`,
requestBody.descending ? "DESC" : "ASC"
);
}else if(requestBody.sortBy === "organization"){
query = query
.orderBy(`kpiUserEvaluation.child4`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child3`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child2`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child1`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.org`, requestBody.descending ? "DESC" : "ASC");
}else{
query = query.orderBy(
`kpiUserEvaluation.${requestBody.sortBy}`,
requestBody.descending ? "DESC" : "ASC"
);
}
}else{
query = query.orderBy("kpiUserEvaluation.createdAt", "DESC")
}
const [kpiUserEvaluation, total] = await query
.skip((requestBody.page - 1) * requestBody.pageSize) .skip((requestBody.page - 1) * requestBody.pageSize)
.take(requestBody.pageSize) .take(requestBody.pageSize)
.getManyAndCount(); .getManyAndCount();
@ -441,6 +467,8 @@ export class KpiUserEvaluationController extends Controller {
keyword?: string; keyword?: string;
status?: string | null; status?: string | null;
results?: string | null; results?: string | null;
sortBy?: string;
descending?: boolean;
}, },
) { ) {
let _data = await new permission().PermissionOrgList(request, "SYS_KPI_LIST"); let _data = await new permission().PermissionOrgList(request, "SYS_KPI_LIST");
@ -452,7 +480,7 @@ export class KpiUserEvaluationController extends Controller {
.catch((x) => {}); .catch((x) => {});
let conditionFullName = let conditionFullName =
"CONCAT(kpiUserEvaluation.prefix, kpiUserEvaluation.firstName, ' ', kpiUserEvaluation.lastName) LIKE :keyword"; "CONCAT(kpiUserEvaluation.prefix, kpiUserEvaluation.firstName, ' ', kpiUserEvaluation.lastName) LIKE :keyword";
const [kpiUserEvaluation, total] = await AppDataSource.getRepository(KpiUserEvaluation) let query = await AppDataSource.getRepository(KpiUserEvaluation)
.createQueryBuilder("kpiUserEvaluation") .createQueryBuilder("kpiUserEvaluation")
.leftJoinAndSelect("kpiUserEvaluation.kpiPeriod", "kpiPeriod") .leftJoinAndSelect("kpiUserEvaluation.kpiPeriod", "kpiPeriod")
.andWhere( .andWhere(
@ -564,8 +592,32 @@ export class KpiUserEvaluationController extends Controller {
child4: _data.child4, child4: _data.child4,
}, },
) )
.orderBy("kpiPeriod.year", "DESC")
.addOrderBy("kpiUserEvaluation.createdAt", "DESC") if (requestBody.sortBy) {
if(requestBody.sortBy === "root"){
query = query.orderBy(
`kpiUserEvaluation.org`,
requestBody.descending ? "DESC" : "ASC"
);
}else if(requestBody.sortBy === "organization"){
query = query
.orderBy(`kpiUserEvaluation.child4`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child3`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child2`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.child1`, requestBody.descending ? "DESC" : "ASC")
.addOrderBy(`kpiUserEvaluation.org`, requestBody.descending ? "DESC" : "ASC");
}else{
query = query.orderBy(
`kpiUserEvaluation.${requestBody.sortBy}`,
requestBody.descending ? "DESC" : "ASC"
);
}
}else{
query = query.orderBy("kpiPeriod.year", "DESC")
.addOrderBy("kpiUserEvaluation.createdAt", "DESC")
}
const [kpiUserEvaluation, total] = await query
.skip((requestBody.page - 1) * requestBody.pageSize) .skip((requestBody.page - 1) * requestBody.pageSize)
.take(requestBody.pageSize) .take(requestBody.pageSize)
.getManyAndCount(); .getManyAndCount();

View file

@ -184,61 +184,39 @@ class CheckAuth {
}); });
} }
public async checkOrg(token: any, keycloakId: string) { public async checkOrg(token: any, keycloakId: string) {
try { const redisClient = await this.redis.createClient({
// Validate required environment variables host: process.env.REDIS_HOST,
const REDIS_HOST = process.env.REDIS_HOST; port: process.env.REDIS_PORT,
const REDIS_PORT = process.env.REDIS_PORT ? Number(process.env.REDIS_PORT) : 6379; })
const getAsync = promisify(redisClient.get).bind(redisClient)
try {
let reply = await getAsync("org_" + keycloakId)
if (reply != null) {
reply = JSON.parse(reply)
} else {
if (!keycloakId) throw new Error("No KeycloakId provided")
const x = await new CallAPI().GetData(
{
headers: { authorization: token },
},
`/org/permission/checkOrg/${keycloakId}`,
false
)
if (!REDIS_HOST) { const data = {
throw new Error("REDIS_HOST is not set in environment variables"); orgRootId: x.orgRootId,
} orgChild1Id: x.orgChild1Id,
orgChild2Id: x.orgChild2Id,
orgChild3Id: x.orgChild3Id,
orgChild4Id: x.orgChild4Id,
}
console.log(`[REDIS] Connecting to Redis at ${REDIS_HOST}:${REDIS_PORT}`); return data
}
// Create Redis client } catch (error) {
const redisClient = this.redis.createClient({ console.error("Error calling API:", error)
socket: { throw error
host: REDIS_HOST, }
port: REDIS_PORT,
},
});
redisClient.on("error", (err: any) => {
console.error("[REDIS] Connection error:", err.message);
});
await redisClient.connect();
console.log("[REDIS] Connected successfully!");
const getAsync = promisify(redisClient.get).bind(redisClient);
let reply = await getAsync("org_" + keycloakId);
if (reply != null) {
reply = JSON.parse(reply);
} else {
if (!keycloakId) throw new Error("No KeycloakId provided");
const x = await new CallAPI().GetData(
{
headers: { authorization: token },
},
`/org/permission/checkOrg/${keycloakId}`,
false,
);
const data = {
orgRootId: x.orgRootId,
orgChild1Id: x.orgChild1Id,
orgChild2Id: x.orgChild2Id,
orgChild3Id: x.orgChild3Id,
orgChild4Id: x.orgChild4Id,
};
return data;
}
} catch (error) {
console.error("Error calling API:", error);
throw error;
}
} }
public async PermissionCreate(req: RequestWithUser, system: string) { public async PermissionCreate(req: RequestWithUser, system: string) {
return await this.Permission(req, system, "CREATE"); return await this.Permission(req, system, "CREATE");