Merge branch 'develop'

This commit is contained in:
Warunee Tamkoo 2025-08-19 14:56:28 +07:00
commit 4103863df3
22 changed files with 3085 additions and 224 deletions

View file

@ -0,0 +1,780 @@
import { Position } from "./../entities/Position";
import { ApiKey } from "./../entities/ApiKey";
import { ApiAttribute } from "./../entities/ApiAttribute";
import { CreateApi } from "./../entities/ApiName";
import { PosMaster } from "../entities/PosMaster";
import { OrgChild4 } from "../entities/OrgChild4";
import { OrgChild3 } from "../entities/OrgChild3";
import { OrgChild2 } from "../entities/OrgChild2";
import { OrgChild1 } from "../entities/OrgChild1";
import { OrgRoot } from "../entities/OrgRoot";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import { ProfileSalary } from "../entities/ProfileSalary";
import { ProfileOther } from "../entities/ProfileOther";
import { ProfileNopaid } from "../entities/ProfileNopaid";
import { ProfileLeave } from "../entities/ProfileLeave";
import { ProfileInsignia } from "../entities/ProfileInsignia";
import { ProfileHonor } from "../entities/ProfileHonor";
import { ProfileGovernment } from "../entities/ProfileGovernment";
import { ProfileFamilyMother } from "../entities/ProfileFamilyMother";
import { ProfileFamilyFather } from "../entities/ProfileFamilyFather";
import { ProfileFamilyCouple } from "../entities/ProfileFamilyCouple";
import { ProfileEducation } from "../entities/ProfileEducation";
import { ProfileDuty } from "../entities/ProfileDuty";
import { ProfileDiscipline } from "../entities/ProfileDiscipline";
import { ProfileDevelopment } from "../entities/ProfileDevelopment";
import { ProfileChildren } from "../entities/ProfileChildren";
import { ProfileChangeName } from "../entities/ProfileChangeName";
import { ProfileCertificate } from "../entities/ProfileCertificate";
import { ProfileAssessment } from "../entities/ProfileAssessment";
import { ProfileAbility } from "../entities/ProfileAbility";
import {
Controller,
Post,
Delete,
Route,
Security,
Tags,
Body,
Path,
Request,
Response,
Get,
Put,
Query,
} from "tsoa";
import { AppDataSource } from "../database/data-source";
import HttpSuccess from "../interfaces/http-success";
import HttpStatusCode from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
import { RequestWithUser } from "../middlewares/user";
import { ApiName } from "../entities/ApiName";
import { Profile } from "../entities/Profile";
import { SystemDefinition, EntityDefinition, SystemCode } from "./../interfaces/api-type";
@Route("api/v1/org/api-manage")
@Tags("ApiManage")
@Security("bearerAuth")
@Response(
HttpStatusCode.INTERNAL_SERVER_ERROR,
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class ApiManageController extends Controller {
private readonly profileRepository = AppDataSource.getRepository(Profile);
private readonly profileEmployeeRepository = AppDataSource.getRepository(ProfileEmployee);
private readonly profileGovernmentRepository = AppDataSource.getRepository(ProfileGovernment);
private readonly profileProfileSalaryRepository = AppDataSource.getRepository(ProfileSalary);
private readonly profileAbilityRepository = AppDataSource.getRepository(ProfileAbility);
private readonly profileAssessmentRepository = AppDataSource.getRepository(ProfileAssessment);
private readonly profileCertificateRepository = AppDataSource.getRepository(ProfileCertificate);
private readonly profileHonorRepository = AppDataSource.getRepository(ProfileHonor);
private readonly profileInsigniaRepository = AppDataSource.getRepository(ProfileInsignia);
private readonly profileLeaveRepository = AppDataSource.getRepository(ProfileLeave);
private readonly profileChangeNameRepository = AppDataSource.getRepository(ProfileChangeName);
private readonly profileDevelopmentRepository = AppDataSource.getRepository(ProfileDevelopment);
private readonly profileDisciplineRepository = AppDataSource.getRepository(ProfileDiscipline);
private readonly profileDutyRepository = AppDataSource.getRepository(ProfileDuty);
private readonly profileEducationRepository = AppDataSource.getRepository(ProfileEducation);
private readonly profileFamilyCoupleRepository = AppDataSource.getRepository(ProfileFamilyCouple);
private readonly profileFamilyFatherRepository = AppDataSource.getRepository(ProfileFamilyFather);
private readonly profileFamilyMotherRepository = AppDataSource.getRepository(ProfileFamilyMother);
private readonly profileChildrenRepository = AppDataSource.getRepository(ProfileChildren);
private readonly profileNopaidRepository = AppDataSource.getRepository(ProfileNopaid);
private readonly profileOtherRepository = AppDataSource.getRepository(ProfileOther);
private readonly orgRootRepository = AppDataSource.getRepository(OrgRoot);
private readonly orgChild1Repository = AppDataSource.getRepository(OrgChild1);
private readonly orgChild2Repository = AppDataSource.getRepository(OrgChild2);
private readonly orgChild3Repository = AppDataSource.getRepository(OrgChild3);
private readonly orgChild4Repository = AppDataSource.getRepository(OrgChild4);
private readonly posMasterRepository = AppDataSource.getRepository(PosMaster);
private readonly positionRepository = AppDataSource.getRepository(Position);
// รายการระบบ
private readonly systems: SystemDefinition[] = [
{
code: "registry",
name: "ข้อมูลทะเบียนประวัติข้าราชการ",
},
{
code: "registry_emp",
name: "ข้อมูลทะเบียนประวัติลูกจ้างประจำ",
},
{
code: "registry_temp",
name: "ข้อมูลทะเบียนประวัติลูกจ้างชั่วคราว",
},
{
code: "organization",
name: "ข้อมูลโครงสร้าง",
},
{
code: "position",
name: "ข้อมูลอัตรากำลัง",
},
];
// รายการเอนทิตีทั้งหมด
private readonly entities: EntityDefinition[] = [
{
name: "Profile",
repository: this.profileRepository,
description: "ข้อมูลหลัก",
isMain: true,
system: ["registry"],
},
{
name: "ProfileEmployee",
repository: this.profileEmployeeRepository,
description: "ข้อมูลหลัก",
isMain: true,
system: ["registry_emp", "registry_temp"],
},
{
name: "ProfileGovernment",
repository: this.profileGovernmentRepository,
description: "ข้อมูลราชการ",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileSalary",
repository: this.profileProfileSalaryRepository,
description: "ข้อมูลตำแหน่ง/เงินเดือน",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileAbility",
repository: this.profileAbilityRepository,
description: "ข้อมูลความสามารถ",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileAssessment",
repository: this.profileAssessmentRepository,
description: "ข้อมูลการประเมิน",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileCertificate",
repository: this.profileCertificateRepository,
description: "ข้อมูลใบรับรอง",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileHonor",
repository: this.profileHonorRepository,
description: "ข้อมูลเกียรติบัตร",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileInsignia",
repository: this.profileInsigniaRepository,
description: "ข้อมูลเครื่องหมาย",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileLeave",
repository: this.profileLeaveRepository,
description: "ข้อมูลการลา",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileChangeName",
repository: this.profileChangeNameRepository,
description: "ข้อมูลการเปลี่ยนชื่อ",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileDevelopment",
repository: this.profileDevelopmentRepository,
description: "ข้อมูลการพัฒนา",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileDiscipline",
repository: this.profileDisciplineRepository,
description: "ข้อมูลวินัย",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileDuty",
repository: this.profileDutyRepository,
description: "ข้อมูลหน้าที่ปฏิบัติราชการ",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileEducation",
repository: this.profileEducationRepository,
description: "ข้อมูลการศึกษา",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileFamilyCouple",
repository: this.profileFamilyCoupleRepository,
description: "ข้อมูลคู่สมรส",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileFamilyFather",
repository: this.profileFamilyFatherRepository,
description: "ข้อมูลบิดา",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileFamilyMother",
repository: this.profileFamilyMotherRepository,
description: "ข้อมูลมารดา",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileChildren",
repository: this.profileChildrenRepository,
description: "ข้อมูลบุตร",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileNopaid",
repository: this.profileNopaidRepository,
description: "ข้อมูลการไม่จ่ายเงินเดือน",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "ProfileOther",
repository: this.profileOtherRepository,
description: "ข้อมูลอื่นๆ",
system: ["registry", "registry_emp", "registry_temp"],
},
{
name: "OrgRoot",
repository: this.orgRootRepository,
description: "ข้อมูลหน่วยงาน",
isMain: true,
system: ["organization"],
},
{
name: "OrgChild1",
repository: this.orgChild1Repository,
description: "ข้อมูลส่วนราชการ ระดับที่ 1",
system: ["organization"],
},
{
name: "OrgChild2",
repository: this.orgChild2Repository,
description: "ข้อมูลส่วนราชการ ระดับที่ 2",
system: ["organization"],
},
{
name: "OrgChild3",
repository: this.orgChild3Repository,
description: "ข้อมูลส่วนราชการ ระดับที่ 3",
system: ["organization"],
},
{
name: "OrgChild4",
repository: this.orgChild4Repository,
description: "ข้อมูลส่วนราชการ ระดับที่ 4",
system: ["organization"],
},
{
name: "PosMaster",
repository: this.posMasterRepository,
description: "ข้อมูลอัตรากำลัง",
isMain: true,
system: ["position"],
},
{
name: "Position",
repository: this.positionRepository,
description: "ข้อมูลตำแหน่ง",
system: ["position"],
},
{
name: "OrgRoot",
repository: this.orgRootRepository,
description: "ข้อมูลหน่วยงาน",
system: ["position"],
},
{
name: "OrgChild1",
repository: this.orgChild1Repository,
description: "ข้อมูลส่วนราชการ ระดับที่ 1",
system: ["position"],
},
{
name: "OrgChild2",
repository: this.orgChild2Repository,
description: "ข้อมูลส่วนราชการ ระดับที่ 2",
system: ["position"],
},
{
name: "OrgChild3",
repository: this.orgChild3Repository,
description: "ข้อมูลส่วนราชการ ระดับที่ 3",
system: ["position"],
},
{
name: "OrgChild4",
repository: this.orgChild4Repository,
description: "ข้อมูลส่วนราชการ ระดับที่ 4",
system: ["position"],
},
{
name: "Profile",
repository: this.profileRepository,
description: "ข้อมูลคนครอง",
system: ["position"],
},
];
private readonly DEFAULT_PAGE_SIZE = 10; // ขนาดหน้าเริ่มต้น
private readonly EXCLUDED_COLUMNS = ["createdUserId", "lastUpdateUserId"]; // ฟิลด์ที่ไม่ต้องการแสดงในผลลัพธ์
private validateSuperAdminRole(user: any): void {
if (!user.role.includes("SUPER_ADMIN")) {
throw new HttpError(HttpStatusCode.FORBIDDEN, "คุณไม่มีสิทธิ์ในการเข้าถึงข้อมูลนี้");
}
}
private generateApiCode(): string {
return Math.random().toString(36).substring(2, 10).toUpperCase();
}
private createApiPath(system: SystemCode = "registry", code: string): string {
return `/api/v1/org/api-service/${system}/${code}`;
}
/**
* list systems
* @summary systems
*/
@Get("/systems")
async listSystems(): Promise<HttpSuccess> {
return new HttpSuccess(this.systems);
}
/**
* list fields by systems
* @summary fields systems
*/
@Get("/:system/fields")
async listAttribute(
@Request() req: RequestWithUser,
@Path("system") system: SystemCode,
): Promise<HttpSuccess | HttpError> {
try {
this.validateSuperAdminRole(req.user);
const result = this.entities
.filter((entity) => entity.system.includes(system))
.map(({ name, repository, description, isMain }) => ({
tb: name,
description,
isMain: isMain || false,
propertys: repository.metadata.columns
.filter(
(column: any) =>
!column.isPrimary && !this.EXCLUDED_COLUMNS.includes(column.propertyName),
)
.map((column: any) => ({
propertyName: column.propertyName,
type: typeof column.type === "string" ? column.type : "string",
comment: column.comment,
key: column.propertyName,
})),
}));
return new HttpSuccess(result);
} catch (error) {
throw new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
(error instanceof Error ? error.message : String(error)) ||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
);
}
}
/**
* list api
* @summary api
*/
@Get("/lists")
async listApi(
@Request() req: RequestWithUser,
@Query("page") page: number = 1,
@Query("pageSize") pageSize: number = this.DEFAULT_PAGE_SIZE,
@Query("keyword") keyword: string = "",
@Query("system") system: SystemCode | "" = "",
@Query("isActive") isActive: boolean = true,
): Promise<HttpSuccess | HttpError> {
try {
this.validateSuperAdminRole(req.user);
const offset = (page - 1) * pageSize;
const queryBuilder = AppDataSource.getRepository(ApiName)
.createQueryBuilder("apiName")
.where("apiName.isActive = :isActive", { isActive })
.select([
"apiName.id",
"apiName.name",
"apiName.code",
"apiName.pathApi",
"apiName.methodApi",
"apiName.system",
"apiName.isActive",
"apiName.createdAt",
"apiName.lastUpdatedAt",
]);
if (keyword?.trim()) {
queryBuilder.andWhere(
"(apiName.name LIKE :keyword OR apiName.code LIKE :keyword OR apiName.pathApi LIKE :keyword)",
{ keyword: `%${keyword.trim()}%` },
);
}
if (system) {
queryBuilder.andWhere("apiName.system = :system", { system });
}
const [apiNames, total] = await queryBuilder
.skip(offset)
.take(pageSize)
.orderBy("apiName.lastUpdatedAt", "DESC")
.addOrderBy("apiName.createdAt", "ASC")
.getManyAndCount();
return new HttpSuccess({
data: apiNames.map((api) => ({
...api,
system: this.systems.find((s) => s.code === api.system)?.name || api.system,
})),
total,
});
} catch (error) {
throw new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
(error instanceof Error ? error.message : String(error)) ||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
);
}
}
/**
* api
* @summary api
*/
@Post("")
async createApi(
@Request() req: RequestWithUser,
@Body() apiData: CreateApi,
): Promise<HttpSuccess | HttpError> {
const queryRunner = AppDataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
this.validateSuperAdminRole(req.user);
const code = this.generateApiCode();
const postData = {
name: apiData.name,
code,
pathApi: this.createApiPath(apiData.system as SystemCode, code),
methodApi: apiData.methodApi || "GET",
system: apiData.system || "registry",
isActive: apiData.isActive || false,
createdUserId: req.user?.sub,
createdFullName: req.user?.name || "",
};
const apiName = await queryRunner.manager.getRepository(ApiName).save(postData);
if (apiData.apiAttributes?.length) {
let orderingCounter = 0;
const attributesToSave = apiData.apiAttributes.flatMap((attr) =>
attr.propertyKey.map((propertyKey) => ({
apiNameId: apiName.id,
tbName: attr.tbName,
propertyKey,
ordering: orderingCounter++,
createdUserId: req.user?.sub,
createdFullName: req.user?.name || "",
})),
);
await queryRunner.manager.getRepository(ApiAttribute).save(attributesToSave);
}
await queryRunner.commitTransaction();
return new HttpSuccess(apiName.id);
} catch (error) {
await queryRunner.rollbackTransaction();
throw new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
(error instanceof Error ? error.message : String(error)) ||
"เกิดข้อผิดพลาด ไม่สามารถบันทึกข้อมูลได้ กรุณาลองใหม่ในภายหลัง",
);
} finally {
await queryRunner.release();
}
}
/**
* api
* @summary api
*/
@Get("/{id}")
async getApiById(
@Request() req: RequestWithUser,
@Path("id") id: string,
): Promise<HttpSuccess | HttpError> {
try {
this.validateSuperAdminRole(req.user);
const apiName = await AppDataSource.getRepository(ApiName).findOne({
select: {
id: true,
name: true,
code: true,
pathApi: true,
methodApi: true,
system: true,
isActive: true,
apiAttributes: true,
},
where: { id },
relations: ["apiAttributes"],
order: {
apiAttributes: {
ordering: "ASC",
},
},
});
if (!apiName) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบ API ที่ต้องการแก้ไข");
}
const items = {
...apiName,
apiAttributes: apiName.apiAttributes.map((attr) => ({
tbName: attr.tbName,
propertyKey: attr.propertyKey,
})),
};
return new HttpSuccess(items);
} catch (error) {
throw new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
(error instanceof Error ? error.message : String(error)) ||
"เกิดข้อผิดพลาด ไม่สามารถบันทึกข้อมูลได้ กรุณาลองใหม่ในภายหลัง",
);
}
}
/**
* api
* @summary api
*/
@Put("/{id}")
async editApi(
@Request() req: RequestWithUser,
@Path("id") id: string,
@Body() apiData: CreateApi,
): Promise<HttpSuccess | HttpError> {
const queryRunner = AppDataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
this.validateSuperAdminRole(req.user);
const apiName = await queryRunner.manager.getRepository(ApiName).findOneBy({ id });
if (!apiName) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบ API ที่ต้องการแก้ไข");
}
const updateData = {
name: apiData.name,
pathApi: this.createApiPath(apiData.system as SystemCode, apiName.code),
methodApi: apiData.methodApi || "GET",
system: apiData.system || "registry",
isActive: apiData.isActive || false,
lastUpdateUserId: req.user?.sub,
lastUpdateFullName: req.user?.name || "",
};
await queryRunner.manager.getRepository(ApiName).update(id, updateData);
await queryRunner.manager.getRepository(ApiAttribute).delete({ apiNameId: id });
if (apiData.apiAttributes?.length) {
let orderingCounter = 0;
const attributesToSave = apiData.apiAttributes.flatMap((attr) =>
attr.propertyKey.map((propertyKey) => ({
apiNameId: apiName.id,
tbName: attr.tbName,
propertyKey,
ordering: orderingCounter++,
lastUpdateUserId: req.user?.sub,
lastUpdateFullName: req.user?.name || "",
})),
);
await queryRunner.manager.getRepository(ApiAttribute).save(attributesToSave);
}
await queryRunner.commitTransaction();
return new HttpSuccess();
} catch (error) {
await queryRunner.rollbackTransaction();
throw new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
(error instanceof Error ? error.message : String(error)) ||
"เกิดข้อผิดพลาด ไม่สามารถบันทึกข้อมูลได้ กรุณาลองใหม่ในภายหลัง",
);
} finally {
await queryRunner.release();
}
}
/**
* api
* @summary api
*/
@Delete("/{id}")
async deleteApi(
@Request() req: RequestWithUser,
@Path("id") id: string,
): Promise<HttpSuccess | HttpError> {
const queryRunner = AppDataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
this.validateSuperAdminRole(req.user);
const checkUsed = await AppDataSource.getRepository(ApiKey)
.createQueryBuilder("apiKey")
.innerJoin("apiKey.apiNames", "apiName")
.where("apiName.id = :id", { id })
.getCount();
if (checkUsed > 0) {
throw new HttpError(
HttpStatusCode.BAD_REQUEST,
"ไม่สามารถลบ API นี้ได้ เนื่องจากมีการใช้งานอยู่",
);
}
await queryRunner.manager.getRepository(ApiAttribute).delete({ apiNameId: id });
await queryRunner.manager.getRepository(ApiName).delete({ id });
await queryRunner.commitTransaction();
return new HttpSuccess();
} catch (error) {
await queryRunner.rollbackTransaction();
throw new HttpError(
HttpStatusCode.INTERNAL_SERVER_ERROR,
(error instanceof Error ? error.message : String(error)) ||
"เกิดข้อผิดพลาด ไม่สามารถบันทึกข้อมูลได้ กรุณาลองใหม่ในภายหลัง",
);
} finally {
await queryRunner.release();
}
}
/**
* list systems
* @summary systems
*/
@Get("/manual/swagger")
async getManualRequestWebService(): Promise<HttpSuccess> {
const json = {
openapi: "3.0.0",
info: {
title: "Request Web Service",
version: "1.0.0",
description: "This is a manual request web service.",
},
servers: [
{
url: process.env.API_URL?.replace("/api/v1", "") || "http://localhost:13009",
},
{
url: "http://localhost:13009",
description: "Local server",
},
],
paths: {
"/api/v1/org/api-service/{system}/{code}": {
get: {
summary: "Get Registry Data",
parameters: [
{
name: "system",
in: "path",
required: true,
schema: {
type: "string",
enum: ["registry", "registry_emp", "registry_temp", "organization", "position"],
},
},
{
name: "code",
in: "path",
required: true,
schema: {
type: "string",
},
},
{
name: "page",
in: "query",
required: false,
schema: {
type: "integer",
default: 1,
},
},
{
name: "pageSize",
in: "query",
required: false,
schema: {
type: "integer",
default: 100,
},
},
],
responses: {
200: {
description: "Successful response",
},
400: {
description: "Bad request",
},
500: {
description: "Internal server error",
},
},
},
},
},
components: {
securitySchemes: {
ApiKeyAuth: {
type: "apiKey",
in: "header",
name: "X-API-Key",
},
},
},
security: [
{
ApiKeyAuth: [],
},
],
};
return new HttpSuccess(json);
}
}

View file

@ -0,0 +1,200 @@
import { Controller, Route, Security, Tags, Path, Request, Response, Get, Query } from "tsoa";
import { AppDataSource } from "../database/data-source";
import HttpSuccess from "../interfaces/http-success";
import HttpStatusCode from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
import { ApiName } from "../entities/ApiName";
import { isPermissionRequest } from "../middlewares/authWebService";
import { RequestWithUserWebService } from "../middlewares/user";
import { OrgRevision } from "../entities/OrgRevision";
import { ApiHistory } from "../entities/ApiHistory";
import { SystemCode } from "./../interfaces/api-type";
@Route("api/v1/org/api-service")
@Tags("ApiKey")
@Security("webServiceAuth")
@Response(
HttpStatusCode.INTERNAL_SERVER_ERROR,
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class ApiWebServiceController extends Controller {
private apiNameRepository = AppDataSource.getRepository(ApiName);
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
private apiHistoryRepository = AppDataSource.getRepository(ApiHistory);
/**
* list fields by systems
* @summary fields systems
*/
@Get("/:system/:code")
async listAttribute(
@Request() request: RequestWithUserWebService,
@Path("system")
system: SystemCode,
@Path("code") code: string,
@Query("page") page: number = 1,
@Query("pageSize") pageSize: number = 100,
): Promise<HttpSuccess | HttpError> {
const apiName = await this.apiNameRepository.findOne({
where: { code },
select: ["id", "code", "methodApi", "system", "isActive"],
relations: ["apiAttributes"],
order: {
apiAttributes: {
ordering: "ASC",
},
},
});
if (!apiName || apiName.system != system || !apiName.isActive || apiName.methodApi != "GET") {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบ API ที่ระบุ");
}
await isPermissionRequest(request, apiName.id);
const offset = (page - 1) * pageSize;
const propertyKey = apiName.apiAttributes.map((attr) => `${attr.tbName}.${attr.propertyKey}`);
let tbMain: string = "";
let condition: string = "1=1";
if (system == "registry") {
tbMain = "Profile";
} else if (system == "registry_emp") {
tbMain = "ProfileEmployee";
condition = `ProfileEmployee.employeeClass = "PERM"`;
} else if (system == "registry_temp") {
tbMain = "ProfileEmployee";
condition = `ProfileEmployee.employeeClass = "TEMP"`;
} else if (system == "organization") {
tbMain = "OrgRoot";
const revision = await this.orgRevisionRepository.findOne({
select: ["id"],
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
});
condition = `OrgRoot.orgRevisionId = "${revision?.id}"`;
} else if (system == "position") {
tbMain = "PosMaster";
const revision = await this.orgRevisionRepository.findOne({
select: ["id"],
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
});
condition = `PosMaster.orgRevisionId = "${revision?.id}"`;
}
const repo = AppDataSource.getRepository(tbMain);
const metadata = repo.metadata;
const relationMap: Record<string, string> = {};
metadata.relations.forEach((rel) => {
relationMap[rel.inverseEntityMetadata.name] = rel.propertyName;
});
// ดึงเฉพาะตารางรอง (ถ้าเลือกไว้)
let propertyOtherKey: any[] = [];
propertyOtherKey = [
...new Set(propertyKey.map((x) => x.split(".")[0]).filter((tb) => tb !== tbMain)),
];
const queryBuilder = repo.createQueryBuilder(tbMain);
// join กับตารารอง
if (propertyOtherKey.length > 0) {
propertyOtherKey.forEach((tb) => {
const relationName = relationMap[tb];
if (relationName) {
queryBuilder.leftJoin(
`${tbMain}.${relationName === "next_holder" ? "current_holder" : relationName}`, // เช็คว่าถ้าเป็น next_holder ให้ใช้ current_holder แทน
tb,
);
}
});
}
// // เพิ่ม Main.id เพราะจะใช้ pk ในการแมบและนับจำนวน
// if (!propertyKey.includes(`${Main}.id`)) {
// propertyKey.push(`${Main}.id`);
// }
// add FK
let pk: string = "";
const primaryColumns = metadata.primaryColumns;
primaryColumns.forEach((col) => {
pk = col.propertyName;
if (!propertyKey.includes(`${tbMain}.${pk}`)) {
propertyKey.push(`${tbMain}.${pk}`);
}
});
const [items, total] = await queryBuilder
.select(propertyKey)
.where(condition)
.orderBy(propertyKey[0], "ASC")
.skip(offset)
.take(pageSize)
.getManyAndCount();
// ลบ Main.id
// const results = items.map(({ id, ...x }) => x);
// const results = items.map(({ pk, ...x }) => x);
// const results = items.map(item => {
// primaryColumns.forEach(col => delete item[col.propertyName]);
// return item;
// });
// split object id ออกก่อน return
const data = items.map((item) => {
const { [pk]: removedPk, ...x } = item;
return x;
});
// console.log("queryBuilder ===> ", queryBuilder.getQuery());
// save api history after query success
const history = {
headerApi: JSON.stringify({
host: request.headers.host,
"x-api-key": request.headers["x-api-key"],
connection: request.headers.connection,
accept: request.headers.accept,
}),
tokenApi: Array.isArray(request.headers["x-api-key"])
? request.headers["x-api-key"][0] || ""
: request.headers["x-api-key"] || "",
requestApi: `${request.method} ${request.protocol}://${request.headers.host}${request.originalUrl || request.url}`,
responseApi: "OK",
ipApi: request.ip,
codeApi: code,
apiKeyId: request.user.id,
apiNameId: apiName.id,
createdFullName: request.user.name,
lastUpdateFullName: request.user.name,
};
await this.apiHistoryRepository.save(history);
// const results = data.map((item) => {
// const flattenedItem: any = {};
// // Extract nested object properties to top level
// Object.keys(item).forEach((key) => {
// const value = item[key];
// if (value && typeof value === "object") {
// // if (Array.isArray(value) && value.length === 1) {
// // // If array has single item, extract it as object
// // Object.assign(flattenedItem, value[0]);
// // } else
// if (!Array.isArray(value)) {
// // Merge nested object properties to top level
// Object.assign(flattenedItem, value);
// } else {
// // Keep arrays with multiple items or empty arrays as is
// flattenedItem[key] = value;
// }
// } else {
// // Keep primitive values as is
// flattenedItem[key] = value;
// }
// });
// return flattenedItem;
// });
return new HttpSuccess({ data: data, total });
}
}

View file

@ -3120,7 +3120,10 @@ export class CommandController extends Controller {
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) posMasterOld.current_holderId = null;
if (posMasterOld != null) {
posMasterOld.current_holderId = null;
posMasterOld.lastUpdatedAt = new Date();
}
const positionOld = await this.positionRepository.findOne({
where: {
@ -3148,6 +3151,7 @@ export class CommandController extends Controller {
}
posMaster.current_holderId = item.profileId;
posMaster.lastUpdatedAt = new Date();
posMaster.conditionReason = _null;
posMaster.isCondition = false;
if (posMasterOld != null) await this.posMasterRepository.save(posMasterOld);
@ -3304,7 +3308,10 @@ export class CommandController extends Controller {
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) posMasterOld.current_holderId = null;
if (posMasterOld != null) {
posMasterOld.current_holderId = null;
posMasterOld.lastUpdatedAt = new Date();
}
// if (posMasterOld != null) posMasterOld.next_holderId = null;
const positionOld = await this.employeePositionRepository.findOne({
@ -3333,6 +3340,7 @@ export class CommandController extends Controller {
}
posMaster.current_holderId = item.profileId;
posMaster.lastUpdatedAt = new Date();
posMaster.next_holderId = null;
if (posMasterOld != null) await this.employeePosMasterRepository.save(posMasterOld);
await this.employeePosMasterRepository.save(posMaster);
@ -3561,6 +3569,7 @@ export class CommandController extends Controller {
await this.positionRepository.save(clearPosition);
}
posMaster.current_holderId = profile.id;
posMaster.lastUpdatedAt = new Date();
posMaster.conditionReason = _null;
posMaster.isCondition = false;
await this.posMasterRepository.save(posMaster);
@ -5987,7 +5996,10 @@ export class CommandController extends Controller {
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) posMasterOld.current_holderId = null;
if (posMasterOld != null) {
posMasterOld.current_holderId = null;
posMasterOld.lastUpdatedAt = new Date();
}
const positionOld = await this.positionRepository.findOne({
where: {
@ -6015,6 +6027,7 @@ export class CommandController extends Controller {
}
posMaster.current_holderId = profile.id;
posMaster.lastUpdatedAt = new Date();
posMaster.conditionReason = _null;
posMaster.isCondition = false;
if (posMasterOld != null) await this.posMasterRepository.save(posMasterOld);
@ -6364,7 +6377,10 @@ export class CommandController extends Controller {
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) posMasterOld.current_holderId = null;
if (posMasterOld != null) {
posMasterOld.current_holderId = null;
posMasterOld.lastUpdatedAt = new Date();
}
// if (posMasterOld != null) posMasterOld.next_holderId = null;
const positionOld = await this.employeePositionRepository.findOne({
@ -6393,6 +6409,7 @@ export class CommandController extends Controller {
}
posMaster.current_holderId = profile.id;
posMaster.lastUpdatedAt = new Date();
posMaster.next_holderId = null;
if (posMasterOld != null) await this.employeePosMasterRepository.save(posMasterOld);
await this.employeePosMasterRepository.save(posMaster);
@ -6673,23 +6690,11 @@ export class CommandController extends Controller {
};
try {
// 8. บันทึกข้อมูลใหม่
const dataAct = new ProfileActposition();
Object.assign(dataAct, metaAct);
const historyAct = new ProfileActpositionHistory();
Object.assign(historyAct, { ...dataAct, id: undefined });
await this.actpositionRepository.save(dataAct);
historyAct.profileActpositionId = dataAct.id;
await this.actpositionHistoryRepository.save(historyAct);
// 9. ปิดสถานะรักษาการ
// 8. ปิดสถานะรักษาการ
const existingActPositions = await this.actpositionRepository.find({
where: {
profileId: item.posMasterChild.current_holderId,
status: true,
id: Not(dataAct.id),
},
});
@ -6702,6 +6707,17 @@ export class CommandController extends Controller {
await this.actpositionRepository.save(updatedActPositions);
}
// 9. บันทึกข้อมูลใหม่
const dataAct = new ProfileActposition();
Object.assign(dataAct, metaAct);
const historyAct = new ProfileActpositionHistory();
Object.assign(historyAct, { ...dataAct, id: undefined });
await this.actpositionRepository.save(dataAct);
historyAct.profileActpositionId = dataAct.id;
await this.actpositionHistoryRepository.save(historyAct);
} catch (error) {
console.error(`Error processing item ${item.id}:`, error);
throw new HttpError(

View file

@ -372,18 +372,22 @@ export class EmployeePositionController extends Controller {
// });
// }
findData = await this.employeePosDictRepository
.createQueryBuilder("posDict")
.leftJoinAndSelect("posDict.posType", "posType")
.leftJoinAndSelect("posDict.posLevel", "posLevel")
.where( keyword
? "CONCAT(posType.posTypeShortName, ' ', posLevel.posLevelName) LIKE :keyword":"1=1", {keyword: `%${keyword}%`})
.orderBy("posDict.posDictName", "ASC")
.addOrderBy("posDict.createdAt", "DESC")
.addOrderBy("posType.posTypeRank", "ASC")
.addOrderBy("posType.createdAt", "DESC")
.addOrderBy("posLevel.posLevelName", "ASC")
.addOrderBy("posLevel.createdAt", "DESC")
.getMany();
.createQueryBuilder("posDict")
.leftJoinAndSelect("posDict.posType", "posType")
.leftJoinAndSelect("posDict.posLevel", "posLevel")
.where(
keyword
? "CONCAT(posType.posTypeShortName, ' ', posLevel.posLevelName) LIKE :keyword"
: "1=1",
{ keyword: `%${keyword}%` },
)
.orderBy("posDict.posDictName", "ASC")
.addOrderBy("posDict.createdAt", "DESC")
.addOrderBy("posType.posTypeRank", "ASC")
.addOrderBy("posType.createdAt", "DESC")
.addOrderBy("posLevel.posLevelName", "ASC")
.addOrderBy("posLevel.createdAt", "DESC")
.getMany();
break;
default:
@ -2258,6 +2262,7 @@ export class EmployeePositionController extends Controller {
dataMaster.isSit = requestBody.isSit;
dataMaster.current_holderId = requestBody.profileId;
dataMaster.lastUpdatedAt = new Date();
// dataMaster.next_holderId = requestBody.profileId;
await this.employeePosMasterRepository.save(dataMaster);
@ -2394,7 +2399,10 @@ export class EmployeePositionController extends Controller {
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) posMasterOld.current_holderId = null;
if (posMasterOld != null) {
posMasterOld.current_holderId = null;
posMasterOld.lastUpdatedAt = new Date();
}
// if (posMasterOld != null) posMasterOld.next_holderId = null;
const positionOld = await this.employeePositionRepository.findOne({
@ -2429,6 +2437,7 @@ export class EmployeePositionController extends Controller {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");
posMaster.current_holderId = body.profileId;
posMaster.lastUpdatedAt = new Date();
// posMaster.next_holderId = body.profileId;
if (posMasterOld != null) await this.employeePosMasterRepository.save(posMasterOld);
await this.employeePosMasterRepository.save(posMaster);

View file

@ -2001,6 +2001,7 @@ export class EmployeeTempPositionController extends Controller {
dataMaster.isSit = requestBody.isSit;
dataMaster.current_holderId = requestBody.profileId;
dataMaster.lastUpdatedAt = new Date();
// dataMaster.next_holderId = requestBody.profileId;
await this.employeeTempPosMasterRepository.save(dataMaster);
@ -2137,7 +2138,10 @@ export class EmployeeTempPositionController extends Controller {
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) posMasterOld.current_holderId = null;
if (posMasterOld != null) {
posMasterOld.current_holderId = null;
posMasterOld.lastUpdatedAt = new Date();
}
// if (posMasterOld != null) posMasterOld.next_holderId = null;
const positionOld = await this.employeePositionRepository.findOne({
@ -2172,6 +2176,7 @@ export class EmployeeTempPositionController extends Controller {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");
posMaster.current_holderId = body.profileId;
posMaster.lastUpdatedAt = new Date();
// posMaster.next_holderId = body.profileId;
if (posMasterOld != null) await this.employeeTempPosMasterRepository.save(posMasterOld);
await this.employeeTempPosMasterRepository.save(posMaster);

View file

@ -340,7 +340,7 @@ export class OrgRootController extends Controller {
const before = structuredClone(orgRoot);
orgRoot.lastUpdateUserId = request.user.sub;
orgRoot.lastUpdateFullName = request.user.name;
orgRoot.lastUpdatedAt = new Date();
// orgRoot.lastUpdatedAt = new Date();
this.orgRootRepository.merge(orgRoot, {
...requestBody,
DEPARTMENT_CODE: requestBody.DEPARTMENT_CODE != null ? requestBody.DEPARTMENT_CODE : _null,

View file

@ -693,7 +693,11 @@ export class OrganizationDotnetController extends Controller {
}
}
}
let positionLeaveName = profile.posLevel?.posLevelName ?? null;
let positionLeaveName =
profile.posType == null && profile.posLevel == null
? ""
: `${profile.posType?.posTypeShortName ?? ""} ${profile.posLevel?.posLevelName ?? ""}`
const _profileCurrent = profile?.current_holders?.find(
(x) =>
x.orgRevision?.orgRevisionIsDraft === false &&

View file

@ -1431,11 +1431,77 @@ export class PositionController extends Controller {
@Get("position/{id}")
async detailPosition(@Path() id: string) {
const posMaster = await this.posMasterRepository.findOne({
relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4"],
where: { id },
});
if (!posMaster) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
}
let orgLevel: any;
switch (true) {
case !!posMaster.orgChild4Id:
orgLevel = 4;
break;
case !!posMaster.orgChild3Id:
orgLevel = 3;
break;
case !!posMaster.orgChild2Id:
orgLevel = 2;
break;
case !!posMaster.orgChild1Id:
orgLevel = 1;
break;
case !!posMaster.orgRootId:
orgLevel = 0;
break;
default:
orgLevel = null; // ถ้าไม่มีข้อมูลเลย
break;
}
let shortName = "";
let orgId: any;
if (
posMaster.orgRootId !== null &&
posMaster.orgChild1Id == null &&
posMaster.orgChild2Id == null &&
posMaster.orgChild3Id == null
) {
shortName = posMaster.orgRoot.orgRootShortName;
orgId = posMaster.orgRootId;
} else if (
posMaster.orgRootId !== null &&
posMaster.orgChild1Id !== null &&
posMaster.orgChild2Id == null &&
posMaster.orgChild3Id == null
) {
shortName = posMaster.orgChild1.orgChild1ShortName;
orgId = posMaster.orgChild1Id;
} else if (
posMaster.orgRootId !== null &&
posMaster.orgChild1Id !== null &&
posMaster.orgChild2Id !== null &&
posMaster.orgChild3Id == null
) {
shortName = posMaster.orgChild2.orgChild2ShortName;
orgId = posMaster.orgChild2Id;
} else if (
posMaster.orgRootId !== null &&
posMaster.orgChild1Id !== null &&
posMaster.orgChild2Id !== null &&
posMaster.orgChild3Id !== null
) {
shortName = posMaster.orgChild3.orgChild3ShortName;
orgId = posMaster.orgChild3Id;
} else if (
posMaster.orgRootId !== null &&
posMaster.orgChild1Id !== null &&
posMaster.orgChild2Id !== null &&
posMaster.orgChild3Id !== null
) {
shortName = posMaster.orgChild4.orgChild4ShortName;
orgId = posMaster.orgChild4Id;
}
const positions = await this.positionRepository.find({
where: { posMasterId: posMaster.id },
relations: ["posType", "posLevel", "posExecutive"],
@ -1457,6 +1523,9 @@ export class PositionController extends Controller {
reason: posMaster.reason,
// isOfficer: posMaster.isOfficer,
isStaff: posMaster.isStaff,
orgLevel: orgLevel,
orgShortname: shortName,
orgId: orgId,
isDirector: posMaster.isDirector,
positionSign: posMaster.positionSign,
positions: positions.map((position) => ({
@ -2582,69 +2651,72 @@ export class PositionController extends Controller {
async getHistoryPosMater(@Path() id: string, @Request() request: RequestWithUser) {
let _workflow = await new permission().Workflow(request, id, "SYS_ORG");
if (_workflow == false) await new permission().PermissionGet(request, "SYS_ORG");
const posMaster = await this.posMasterRepository.findOne({
where: { id },
});
// ใช้ query builder สำหรับประสิทธิภาพที่ดีขึ้น
const queryBuilder = this.posMasterRepository
.createQueryBuilder("pm")
.leftJoinAndSelect("pm.orgRevision", "orgRevision")
.leftJoinAndSelect("pm.orgRoot", "orgRoot")
.leftJoinAndSelect("pm.orgChild1", "orgChild1")
.leftJoinAndSelect("pm.orgChild2", "orgChild2")
.leftJoinAndSelect("pm.orgChild3", "orgChild3")
.leftJoinAndSelect("pm.orgChild4", "orgChild4")
.leftJoinAndSelect("pm.current_holder", "current_holder")
.leftJoinAndSelect("pm.positions", "positions")
.leftJoinAndSelect("positions.posLevel", "posLevel")
.leftJoinAndSelect("positions.posType", "posType")
.leftJoinAndSelect("positions.posExecutive", "posExecutive");
// หาข้อมูลหลัก
const posMaster = await queryBuilder.where("pm.id = :id", { id }).getOne();
if (!posMaster) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
}
const posMasters = await this.posMasterRepository.find({
where: {
ancestorDNA:
posMaster.ancestorDNA == null || posMaster.ancestorDNA == ""
? "123"
: posMaster.ancestorDNA,
},
order: { lastUpdatedAt: "DESC" },
relations: [
"orgRoot",
"orgChild1",
"orgChild2",
"orgChild3",
"orgChild4",
"current_holder",
"positions",
"positions.posLevel",
"positions.posType",
"positions.posExecutive",
],
});
// สร้าง conditions
const ancestorDNA = posMaster.ancestorDNA || "123";
let historyQuery = queryBuilder.where("pm.ancestorDNA = :ancestorDNA", { ancestorDNA });
// เพิ่มเงื่อนไข draft
if (
posMaster.orgRevision?.orgRevisionIsCurrent != false &&
posMaster.orgRevision?.orgRevisionIsDraft != true
) {
historyQuery = historyQuery.andWhere("orgRevision.orgRevisionIsDraft != :isDraft", {
isDraft: true,
});
}
const posMasters = await historyQuery.orderBy("pm.lastUpdatedAt", "DESC").getMany();
const _data = posMasters.map((item) => ({
id: item.id,
orgShortName:
item.orgRoot == null
? null
: item.orgChild1 == null
? item.orgRoot.orgRootShortName
: item.orgChild2 == null
? item.orgChild1.orgChild1ShortName
: item.orgChild3 == null
? item.orgChild2.orgChild2ShortName
: item.orgChild4 == null
? item.orgChild3.orgChild3ShortName
: item.orgChild4.orgChild4ShortName,
lastUpdatedAt: item.lastUpdatedAt ? item.lastUpdatedAt : null,
posMasterNoPrefix: item.posMasterNoPrefix ? item.posMasterNoPrefix : null,
posMasterNo: item.posMasterNo ? item.posMasterNo : null,
posMasterNoSuffix: item.posMasterNoSuffix ? item.posMasterNoSuffix : null,
reason: item.reason ? item.reason : null,
item.orgChild4?.orgChild4ShortName ||
item.orgChild3?.orgChild3ShortName ||
item.orgChild2?.orgChild2ShortName ||
item.orgChild1?.orgChild1ShortName ||
item.orgRoot?.orgRootShortName ||
null,
lastUpdatedAt: item.lastUpdatedAt,
posMasterNoPrefix: item.posMasterNoPrefix,
posMasterNo: item.posMasterNo,
posMasterNoSuffix: item.posMasterNoSuffix,
reason: item.reason,
position: item.positions.map((x) => x.positionName).join("/"),
posExecutive: item.positions
.filter((x) => x.posExecutive != null)
.map((x) => x.posExecutive?.posExecutiveName ?? null)
.filter((x) => x.posExecutive)
.map((x) => x.posExecutive!.posExecutiveName)
.join("/"),
posLevel: item.positions.map((x) => x.posLevel.posLevelName).join("/"),
posType: item.positions.map((x) => x.posType.posTypeName).join("/"),
fullname:
(item?.current_holder?.prefix ?? "") +
"" +
(item?.current_holder?.firstName ?? "") +
" " +
(item?.current_holder?.lastName ?? ""),
`${item.current_holder?.prefix || ""}${item.current_holder?.firstName || ""} ${item.current_holder?.lastName || ""}`.trim(),
}));
return new HttpSuccess(_data);
}
/**
* API
*
@ -3518,6 +3590,7 @@ export class PositionController extends Controller {
const before = null;
dataMaster.isSit = requestBody.isSit;
dataMaster.next_holderId = requestBody.profileId;
dataMaster.lastUpdatedAt = new Date();
//add on
dataMaster.conditionReason = _null;
dataMaster.isCondition = false;
@ -4658,7 +4731,10 @@ export class PositionController extends Controller {
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) posMasterOld.current_holderId = null;
if (posMasterOld != null) {
posMasterOld.current_holderId = null;
posMasterOld.lastUpdatedAt = new Date();
}
const positionOld = await this.positionRepository.findOne({
where: {
@ -4692,6 +4768,7 @@ export class PositionController extends Controller {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");
posMaster.current_holderId = body.profileId;
posMaster.lastUpdatedAt = new Date();
const _null: any = null;
posMaster.conditionReason = _null;
posMaster.isCondition = false;
@ -5245,6 +5322,7 @@ export class PositionController extends Controller {
if (!profile) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน");
posMaster.next_holderId = requestBody.profileId;
posMaster.lastUpdatedAt = new Date();
posMaster.lastUpdateUserId = request.user.sub;
posMaster.lastUpdateFullName = request.user.name;
posMaster.lastUpdatedAt = new Date();

View file

@ -1321,7 +1321,7 @@ export class ProfileController extends Controller {
"profileLeave.dateLeaveEnd AS dateLeaveEnd",
"profileLeave.leaveDays AS leaveDays",
"profileLeave.reason AS reason",
"leaveType.name as name"
"leaveType.name as name",
])
.where("profileLeave.profileId = :profileId", { profileId: id })
.andWhere("leaveType.code IN (:...codes)", { codes: ["LV-008", "LV-009", "LV-010"] })
@ -1331,10 +1331,12 @@ export class ProfileController extends Controller {
const leaves2 =
leave2_raw.length > 0
? leave2_raw.map((item) => ({
date: item.dateLeaveStart && item.dateLeaveEnd
? Extension.ToThaiNumber(Extension.ToThaiFullDate2(item.dateLeaveStart)) + " - "
+ Extension.ToThaiNumber(Extension.ToThaiFullDate2(item.dateLeaveEnd))
: "-",
date:
item.dateLeaveStart && item.dateLeaveEnd
? Extension.ToThaiNumber(Extension.ToThaiFullDate2(item.dateLeaveStart)) +
" - " +
Extension.ToThaiNumber(Extension.ToThaiFullDate2(item.dateLeaveEnd))
: "-",
type: item.name || "-",
leaveDays: item.leaveDays ? Extension.ToThaiNumber(item.leaveDays.toString()) : "-",
reason: item.reason || "-",
@ -1684,24 +1686,22 @@ export class ProfileController extends Controller {
)
: "";
let portfolios:any
await new CallAPI()
.GetData(req, `/development/portfolio/kk1/${profiles?.keycloak}`)
.then((x) => {
portfolios = x;
})
.catch(() => {});
let portfolios: any;
await new CallAPI()
.GetData(req, `/development/portfolio/kk1/${profiles?.keycloak}`)
.then((x) => {
portfolios = x;
})
.catch(() => {});
if (!portfolios) {
portfolios = [{ name: "-", year: "-" }]
portfolios = [{ name: "-", year: "-" }];
} else {
portfolios = portfolios.map((x: any) => ({
name: x.name ? Extension.ToThaiNumber(x.name) : "-",
year: x.year ? Extension.ToThaiNumber(x.year.toString()) : "-",
}));
}
else {
portfolios = portfolios.map((x:any) => ({
name: x.name ? x.name : "-",
year: x.year ? Extension.ToThaiNumber(x.year.toString()) : "-"
}))
}
const data = {
fullName: `${profiles?.prefix}${profiles?.firstName} ${profiles?.lastName}`,
prefix: profiles?.prefix != null ? profiles.prefix : "",
@ -1855,7 +1855,7 @@ export class ProfileController extends Controller {
assessments,
profileAbility,
otherIncome,
portfolios
portfolios,
};
return new HttpSuccess({
@ -2855,7 +2855,8 @@ export class ProfileController extends Controller {
},
});
if (!posMaster) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลการครองตำแหน่ง");
posMaster.current_holderId = "";
posMaster.current_holderId = null;
posMaster.lastUpdatedAt = new Date();
// return new HttpSuccess({ data: [], total: 0 });
} else if ((posMaster?.current_holder?.posLevel?.posLevelAuthority ?? null) == "GOVERNOR") {
return new HttpSuccess({ data: [], total: 0 });
@ -9616,6 +9617,46 @@ export class ProfileController extends Controller {
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgRoot.orgRootShortName,' ',posMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgChild1.orgChild1ShortName,' ',posMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgChild2.orgChild2ShortName,' ',posMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgChild3.orgChild3ShortName,' ',posMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgChild4.orgChild4ShortName,' ',posMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "current_holder.position LIKE :keyword"

View file

@ -5038,6 +5038,46 @@ export class ProfileEmployeeController extends Controller {
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgRoot.orgRootShortName,' ',employeePosMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgChild1.orgChild1ShortName,' ',employeePosMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgChild2.orgChild2ShortName,' ',employeePosMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgChild3.orgChild3ShortName,' ',employeePosMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "CONCAT(orgChild4.orgChild4ShortName,' ',employeePosMaster.posMasterNo) LIKE :keyword"
: "1=1",
{
keyword: `%${body.keyword}%`,
},
)
.orWhere(
body.keyword != null && body.keyword != ""
? "current_holder.position LIKE :keyword"

View file

@ -17,6 +17,7 @@ import {
import permission from "../interfaces/permission";
import { OrgRevision } from "../entities/OrgRevision";
import { In } from "typeorm";
import { ProfileSalary } from "../entities/ProfileSalary";
@Route("api/v1/org/profile-employee/government")
@Tags("ProfileEmployeeGovernment")
@Security("bearerAuth")
@ -26,6 +27,7 @@ export class ProfileGovernmentEmployeeController extends Controller {
private positionRepo = AppDataSource.getRepository(EmployeePosition);
private posMasterRepo = AppDataSource.getRepository(EmployeePosMaster);
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
private salaryRepo = AppDataSource.getRepository(ProfileSalary);
/**
*
* @summary
@ -150,32 +152,32 @@ export class ProfileGovernmentEmployeeController extends Controller {
const record = await this.profileEmployeeRepo.findOne({
where: {
id: profileEmployeeId,
profileSalary: {
commandCode: In([
"0",
"9",
"1",
"2",
"3",
"4",
"8",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
]),
}
// profileSalary: {
// commandCode: In([
// "0",
// "9",
// "1",
// "2",
// "3",
// "4",
// "8",
// "10",
// "11",
// "12",
// "13",
// "14",
// "15",
// "16",
// ]),
// }
},
relations: ["posType", "posLevel", "profileSalary"],
order: {
profileSalary: {
order: "DESC",
createdAt: "DESC"
}
}
relations: ["posType", "posLevel"/*, "profileSalary"*/],
// order: {
// profileSalary: {
// order: "DESC",
// createdAt: "DESC"
// }
// }
});
const posMaster = await this.posMasterRepo.findOne({
where: {
@ -216,16 +218,55 @@ export class ProfileGovernmentEmployeeController extends Controller {
}
}
let _OrgLeave:any = []
if (record?.isLeave && record?.profileSalary.length > 0) {
let orgLeave:string = ""
let posNoLeave:string = ""
if (record?.isLeave /*&& record?.profileSalary.length > 0*/) {
const profileSalary = await this.salaryRepo.find({
select: [
"orgRoot",
"orgChild1",
"orgChild2",
"orgChild3",
"orgChild4",
"posNoAbb",
"posNo"
],
where: {
profileEmployeeId: profileEmployeeId,
commandCode: In([
"0",
"9",
"1",
"2",
"3",
"4",
"8",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
]),
},
order: {
order: "DESC",
createdAt: "DESC"
}
});
_OrgLeave = [
record?.profileSalary[0].orgChild4 ? record?.profileSalary[0].orgChild4 : null,
record?.profileSalary[0].orgChild3 ? record?.profileSalary[0].orgChild3 : null,
record?.profileSalary[0].orgChild2 ? record?.profileSalary[0].orgChild2 : null,
record?.profileSalary[0].orgChild1 ? record?.profileSalary[0].orgChild1 : null,
record?.profileSalary[0].orgRoot ? record?.profileSalary[0].orgRoot : null,
profileSalary.length > 0 && profileSalary[0].orgChild4 ? profileSalary[0].orgChild4 : null,
profileSalary.length > 0 && profileSalary[0].orgChild3 ? profileSalary[0].orgChild3 : null,
profileSalary.length > 0 && profileSalary[0].orgChild2 ? profileSalary[0].orgChild2 : null,
profileSalary.length > 0 && profileSalary[0].orgChild1 ? profileSalary[0].orgChild1 : null,
profileSalary.length > 0 && profileSalary[0].orgRoot ? profileSalary[0].orgRoot : null,
];
orgLeave = _OrgLeave.filter((x:any) => x !== undefined && x !== null).join("\n");
posNoLeave = profileSalary.length > 0
? `${profileSalary[0].posNoAbb} ${profileSalary[0].posNo}`
: ""
}
const orgLeave = _OrgLeave.filter((x:any) => x !== undefined && x !== null).join("\n");
const data = {
org: record?.isLeave == false ? org : orgLeave, //สังกัด
position: record?.position, //ตำแหน่ง
@ -235,9 +276,9 @@ export class ProfileGovernmentEmployeeController extends Controller {
: `${record?.posType?.posTypeShortName ?? ""} ${record?.posLevel?.posLevelName ?? ""}`, //ระดับ
posMasterNo: record?.isLeave == false
? posMaster == null ? null : `${orgShortName} ${posMaster.posMasterNo}`
: record && record?.profileSalary.length > 0
: posNoLeave/*record && record?.profileSalary.length > 0
? `${record?.profileSalary[0].posNoAbb} ${record?.profileSalary[0].posNo}`
: null, //เลขที่ตำแหน่ง
: null*/, //
posType: record?.posType == null ? null : record?.posType.posTypeName, //ประเภท
dateLeave: record?.birthDate == null ? null : calculateRetireDate(record?.birthDate), //วันเกษียณ
dateAppoint: record?.dateAppoint, //วันที่สั่งบรรจุ
@ -265,29 +306,29 @@ export class ProfileGovernmentEmployeeController extends Controller {
const record = await this.profileEmployeeRepo.findOne({
where: {
id: profileEmployeeId,
profileSalary:{
commandCode: In([
"0",
"9",
"1",
"2",
"3",
"4",
"8",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
]),
}
// profileSalary:{
// commandCode: In([
// "0",
// "9",
// "1",
// "2",
// "3",
// "4",
// "8",
// "10",
// "11",
// "12",
// "13",
// "14",
// "15",
// "16",
// ]),
// }
},
relations: {
posType: true,
posLevel: true,
profileSalary: true
// profileSalary: true
},
});
const posMaster = await this.posMasterRepo.findOne({
@ -329,16 +370,55 @@ export class ProfileGovernmentEmployeeController extends Controller {
}
}
let _OrgLeave:any = []
if (record?.isLeave && record?.profileSalary.length > 0) {
let orgLeave:string = ""
let posNoLeave:string = ""
if (record?.isLeave /*&& record?.profileSalary.length > 0*/) {
const profileSalary = await this.salaryRepo.find({
select: [
"orgRoot",
"orgChild1",
"orgChild2",
"orgChild3",
"orgChild4",
"posNoAbb",
"posNo"
],
where: {
profileEmployeeId: profileEmployeeId,
commandCode: In([
"0",
"9",
"1",
"2",
"3",
"4",
"8",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
]),
},
order: {
order: "DESC",
createdAt: "DESC"
}
});
_OrgLeave = [
record?.profileSalary[0].orgChild4 ? record?.profileSalary[0].orgChild4 : null,
record?.profileSalary[0].orgChild3 ? record?.profileSalary[0].orgChild3 : null,
record?.profileSalary[0].orgChild2 ? record?.profileSalary[0].orgChild2 : null,
record?.profileSalary[0].orgChild1 ? record?.profileSalary[0].orgChild1 : null,
record?.profileSalary[0].orgRoot ? record?.profileSalary[0].orgRoot : null,
profileSalary.length > 0 && profileSalary[0].orgChild4 ? profileSalary[0].orgChild4 : null,
profileSalary.length > 0 && profileSalary[0].orgChild3 ? profileSalary[0].orgChild3 : null,
profileSalary.length > 0 && profileSalary[0].orgChild2 ? profileSalary[0].orgChild2 : null,
profileSalary.length > 0 && profileSalary[0].orgChild1 ? profileSalary[0].orgChild1 : null,
profileSalary.length > 0 && profileSalary[0].orgRoot ? profileSalary[0].orgRoot : null,
];
orgLeave = _OrgLeave.filter((x:any) => x !== undefined && x !== null).join("\n");
posNoLeave = profileSalary.length > 0
? `${profileSalary[0].posNoAbb} ${profileSalary[0].posNo}`
: ""
}
const orgLeave = _OrgLeave.filter((x:any) => x !== undefined && x !== null).join("\n");
const data = {
org: record?.isLeave == false ? org : orgLeave, //สังกัด
position: record?.position, //ตำแหน่ง
@ -350,9 +430,9 @@ export class ProfileGovernmentEmployeeController extends Controller {
? posMaster == null
? null
: `${orgShortName} ${posMaster.posMasterNo}`
: record && record.profileSalary.length > 0
: posNoLeave/*record && record.profileSalary.length > 0
? `${record?.profileSalary[0].posNoAbb} ${record?.profileSalary[0].posNo}`
: null, //เลขที่ตำแหน่ง
: null*/, //
posType: record?.posType == null ? null : record?.posType.posTypeName, //ประเภท
dateLeave: record?.birthDate == null ? null : calculateRetireDate(record?.birthDate), //วันเกษียณ
dateAppoint: record?.dateAppoint, //วันที่สั่งบรรจุ

View file

@ -47,9 +47,13 @@ export const AppDataSource = new DataSource({
logging: true,
// timezone: "Z",
entities:
process.env.NODE_ENV !== "production" ? ["src/entities/**/*.ts"] : ["dist/entities/**/*{.ts,.js}"],
process.env.NODE_ENV !== "production"
? ["src/entities/**/*.ts"]
: ["dist/entities/**/*{.ts,.js}"],
migrations:
process.env.NODE_ENV !== "production" ? ["src/entities/*.ts"] : ["dist/entities/*{.ts,.js}"],
process.env.NODE_ENV !== "production"
? ["src/migration/**/*.ts"]
: ["dist/migration/**/*{.ts,.js}"],
subscribers: [],
logger: new MyCustomLogger(),
});

View file

@ -0,0 +1,39 @@
import { ApiName } from "./ApiName";
import { Entity, Column, ManyToOne, JoinColumn } from "typeorm";
import { EntityBase } from "./base/Base";
@Entity("apiAttribute")
export class ApiAttribute extends EntityBase {
@Column({
nullable: false,
comment: "ชื่อตาราง",
length: 50,
})
tbName: string;
@Column({
nullable: false,
comment: "คีย์ของแอตทริบิวต์",
length: 255,
})
propertyKey: string;
@Column({
nullable: false,
comment: "ลำดับการแสดงผล",
default: 0,
type: "int",
})
ordering: number;
@Column({
nullable: false,
comment: "ไอดีของ API Name",
length: 36, // UUID length
})
apiNameId: string;
@ManyToOne(() => ApiName, (apiName) => apiName.apiAttributes)
@JoinColumn({ name: "apiNameId" })
apiName: ApiName;
}

View file

@ -1,3 +1,4 @@
import { ApiAttribute } from "./ApiAttribute";
import { Entity, Column, ManyToMany, JoinTable, OneToMany } from "typeorm";
import { EntityBase } from "./base/Base";
import { ApiKey } from "./ApiKey";
@ -29,10 +30,61 @@ export class ApiName extends EntityBase {
})
methodApi: string;
@Column({
nullable: false,
comment: "code สำหรับการเรียก API",
length: 8,
})
code: string;
@Column({
nullable: false,
comment: "code ระบบสำหรับการเรียก API",
length: 50,
default: "registry",
})
system: string;
@Column({
nullable: false,
comment: "สถานะการใช้งาน",
type: "boolean",
default: false,
})
isActive: boolean;
@ManyToMany(() => ApiKey, (apiKey) => apiKey.apiNames)
@JoinTable()
apiKeys: ApiKey[];
@OneToMany(() => ApiHistory, (v) => v.apiName)
apiHistorys: ApiHistory[];
@OneToMany(() => ApiAttribute, (v) => v.apiName)
apiAttributes: ApiAttribute[];
}
export class CreateApi {
@Column()
name: string;
@Column()
methodApi: "GET" | "POST" | "PUT";
@Column()
system: string;
@Column()
isActive: boolean;
@Column()
apiAttributes: CreateApiAttribute[];
}
export class CreateApiAttribute {
@Column()
tbName: string;
@Column()
propertyKey: string[];
}

View file

@ -0,0 +1,16 @@
type SystemCode = "registry" | "registry_emp" | "registry_temp" | "organization" | "position";
interface SystemDefinition {
code: SystemCode;
name: string;
}
interface EntityDefinition {
name: string;
repository: any;
description: string;
isMain?: boolean;
system: SystemCode[];
}
export { SystemCode, SystemDefinition, EntityDefinition };

View file

@ -553,6 +553,14 @@ export async function checkQueueInProgress(queueName: string) {
// return false;
}
export function chunkArray(array: any, size: number) {
const result = [];
for (let i = 0; i < array.length; i += size) {
result.push(array.slice(i, i + size));
}
return result;
}
export function commandTypePath(commandCode: string): string | null {
switch (commandCode) {
case "C-PM-01":

View file

@ -3,6 +3,7 @@ import { createDecoder, createVerifier } from "fast-jwt";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
import { handleWebServiceAuth } from "./authWebService";
if (!process.env.AUTH_PUBLIC_KEY && !process.env.AUTH_REALM_URL) {
throw new Error("Require keycloak AUTH_PUBLIC_KEY or AUTH_REALM_URL.");
@ -30,6 +31,11 @@ export async function expressAuthentication(
return { preferred_username: "bypassed" };
}
// เพิ่มการจัดการสำหรับ Web Service Authentication
if (securityName === "webServiceAuth") {
return await handleWebServiceAuth(request);
}
if (securityName !== "bearerAuth") throw new Error("ไม่ทราบวิธีการยืนยันตัวตน");
const token = request.headers["authorization"]?.includes("Bearer ")

View file

@ -0,0 +1,56 @@
import { RequestWithUserWebService } from "./user";
import { AppDataSource } from "../database/data-source";
import { ApiKey } from "../entities/ApiKey";
import * as express from "express";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
// เพิ่มฟังก์ชันสำหรับจัดการ Web Service Authentication
export async function handleWebServiceAuth(request: express.Request) {
// ตัวอย่างการใช้ API Key
const apiKey = request.headers["x-api-key"] as string;
if (!apiKey) {
throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่พบข้อมูลสำหรับยืนยันตัวตน");
}
// ตรวจสอบ API Key กับฐานข้อมูล
const apiKeyData = await AppDataSource.getRepository(ApiKey).findOne({
select: { id: true, name: true, keyApi: true },
where: { keyApi: apiKey },
relations: ["apiNames"],
});
if (!apiKeyData) {
throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่สามารถยืนยันตัวตนได้");
}
// บันทึก log data สำหรับ web service
if (!request.app.locals.logData) {
request.app.locals.logData = {};
}
request.app.locals.logData.id = apiKeyData.id;
request.app.locals.logData.name = apiKeyData.name;
request.app.locals.logData.accessApi = apiKeyData.apiNames.map((x) => x.id) ?? [];
// ส่งคืนข้อมูลผู้ใช้ที่ยืนยันตัวตน
return {
id: apiKeyData.id,
name: apiKeyData.name,
type: "web-service",
accessApi: apiKeyData.apiNames.map((x) => x.id) ?? [],
};
}
export function isPermissionRequest(
request: RequestWithUserWebService,
apiId: string,
): Promise<boolean> {
// ฟังก์ชันนี้ใช้เพื่อตรวจสอบสิทธิ์ของผู้ใช้ที่ร้องขอ API โดยตรวจสอบว่า user มีสิทธิ์เข้าถึง API ที่ร้องขอหรือไม่
const hasPermission = request.user.accessApi.includes(apiId);
if (!hasPermission) {
throw new HttpError(HttpStatus.FORBIDDEN, "คุณไม่มีสิทธิ์เข้าถึง API นี้");
}
return Promise.resolve(hasPermission);
}

View file

@ -11,3 +11,11 @@ export type RequestWithUser = Request & {
role: string[];
};
};
export type RequestWithUserWebService = Request & {
user: {
id: string;
name: string;
accessApi: string[];
};
};

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
import amqp from "amqplib";
import { AppDataSource } from "../database/data-source";
import { Command } from "../entities/Command";
import { commandTypePath } from "../interfaces/utils";
import { chunkArray, commandTypePath } from "../interfaces/utils";
import CallAPI from "../interfaces/call-api";
import HttpError from "../interfaces/http-error";
import HttpStatusCode from "../interfaces/http-status";
@ -115,46 +115,139 @@ function createConsumer( //----> consumer
async function handler(msg: amqp.ConsumeMessage): Promise<boolean> {
//----> condition before process consumer
// const repo = AppDataSource.getRepository(Command);
// const { data, token, user } = JSON.parse(msg.content.toString());
// const { id, status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt } = data;
// const command = await repo.findOne({
// where: { id: id },
// relations: ["commandType", "commandRecives"],
// });
// if (!command) return true;
// let waiting_message = `ระบบทำการออกคำสั่งเลขที่ ${command.commandNo}/${command.commandYear + 543}`;
// let success_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo}/${command.commandYear + 543} เสร็จสิ้น`;
// let error_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo}/${command.commandYear + 543} ผิดพลาด`
// if(command.commandType?.code == "C-PM-47"){
// waiting_message = `ระบบทำการออกคำสั่งเลขที่ ${command.commandNo}`;
// success_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo} เสร็จสิ้น`;
// error_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo} ผิดพลาด`;
// }
// if (user) {
// sendWebSocket(
// "send-command-notification",
// {
// success: true,
// message: waiting_message,
// payload: command,
// },
// { userId: user?.sub },
// ).catch(console.error);
// }
// const path = commandTypePath(command.commandType.code);
// if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ");
// return await new CallAPI()
// //chunk 50
// .PostData(
// {
// headers: { authorization: token },
// },
// path + "/excecute",
// {
// refIds: command.commandRecives //chunk
// .filter((x) => x.refId != null)
// .map((x) => ({
// refId: x.refId,
// commandNo: command.commandNo,
// commandYear: command.commandYear,
// commandId: command.id,
// remark: command.positionDetail,
// amount: x.amount,
// amountSpecial: x.amountSpecial,
// positionSalaryAmount: x.positionSalaryAmount,
// mouthSalaryAmount: x.mouthSalaryAmount,
// commandCode: command.commandType.commandCode,
// commandName: command.commandType.name,
// commandDateAffect: command.commandExcecuteDate,
// commandDateSign: command.commandAffectDate,
// })),
// },
// false,
// )
// .then(async (res) => {
// console.log("[AMQ] Excecute Command Success");
// Object.assign(command, { status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt });
// const result = await repo.save(command).catch((e) => console.log(e));
// if (user) {
// sendWebSocket(
// "send-command-notification",
// {
// success: true,
// message: success_message,
// payload: command,
// },
// { userId: user?.sub },
// ).catch(console.error);
// }
// return !!result;
// })
// .catch((e) => {
// console.error(e);
// if (user) {
// sendWebSocket(
// "send-command-notification",
// {
// success: false,
// message: error_message,
// payload: command,
// },
// { userId: user?.sub },
// ).catch(console.error);
// }
// return false;
// });
const repo = AppDataSource.getRepository(Command);
const { data, token, user } = JSON.parse(msg.content.toString());
const { id, status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt } = data;
const command = await repo.findOne({
where: { id: id },
relations: ["commandType", "commandRecives"],
});
if (!command) return true;
let waiting_message = `ระบบทำการออกคำสั่งเลขที่ ${command.commandNo}/${command.commandYear + 543}`;
let success_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo}/${command.commandYear + 543} เสร็จสิ้น`;
let error_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo}/${command.commandYear + 543} ผิดพลาด`
if(command.commandType?.code == "C-PM-47"){
let error_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo}/${command.commandYear + 543} ผิดพลาด`;
if (command.commandType?.code == "C-PM-47") {
waiting_message = `ระบบทำการออกคำสั่งเลขที่ ${command.commandNo}`;
success_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo} เสร็จสิ้น`;
error_message = `ระบบออกคำสั่งเลขที่ ${command.commandNo} ผิดพลาด`;
}
if (user) {
sendWebSocket(
"send-command-notification",
{
success: true,
message: waiting_message,
payload: command,
},
{ success: true, message: waiting_message, payload: command },
{ userId: user?.sub },
).catch(console.error);
}
const path = commandTypePath(command.commandType.code);
if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ");
return await new CallAPI()
.PostData(
{
headers: { authorization: token },
},
path + "/excecute",
{
refIds: command.commandRecives
.filter((x) => x.refId != null)
.map((x) => ({
try {
const allRefIds = new Set<string>();
const chunks = chunkArray(
command.commandRecives
.filter((x) => x.refId != null)
.map((x) => {
const key = `${x.refId}-${command.id}`;
if (allRefIds.has(key)) {
return null;
}
allRefIds.add(key);
return {
refId: x.refId,
commandNo: command.commandNo,
commandYear: command.commandYear,
@ -168,42 +261,46 @@ async function handler(msg: amqp.ConsumeMessage): Promise<boolean> {
commandName: command.commandType.name,
commandDateAffect: command.commandExcecuteDate,
commandDateSign: command.commandAffectDate,
})),
},
false,
)
.then(async (res) => {
console.log("[AMQ] Excecute Command Success");
Object.assign(command, { status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt });
const result = await repo.save(command).catch((e) => console.log(e));
if (user) {
sendWebSocket(
"send-command-notification",
{
success: true,
message: success_message,
payload: command,
},
{ userId: user?.sub },
).catch(console.error);
}
return !!result;
})
.catch((e) => {
console.error(e);
if (user) {
sendWebSocket(
"send-command-notification",
{
success: false,
message: error_message,
payload: command,
},
{ userId: user?.sub },
).catch(console.error);
}
return false;
});
};
})
.filter(Boolean),
20
);
for (const chunk of chunks) {
await new CallAPI().PostData(
{ headers: { authorization: token } },
path + "/excecute",
{ refIds: chunk },
false
);
}
Object.assign(command, { status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt });
const result = await repo.save(command);
if (user) {
sendWebSocket(
"send-command-notification",
{ success: true, message: success_message, payload: command },
{ userId: user?.sub },
).catch(console.error);
}
console.log("[AMQ] Excecute Command Success");
return !!result;
} catch (e) {
console.error(e);
if (user) {
sendWebSocket(
"send-command-notification",
{ success: false, message: error_message, payload: command },
{ userId: user?.sub },
).catch(console.error);
}
return false;
}
}
// async function handler(msg: amqp.ConsumeMessage): Promise<boolean> {

View file

@ -23,6 +23,12 @@
"name": "Authorization",
"description": "Keycloak Bearer Token",
"in": "header"
},
"webServiceAuth": {
"type": "apiKey",
"name": "X-API-Key",
"description": "API KEY สำหรับ Web Service",
"in": "header"
}
},
"tags": [