diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 8bb79865..a78beb9a 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -19,10 +19,10 @@ import HttpSuccess from "../interfaces/http-success"; import HttpStatusCode from "../interfaces/http-status"; import HttpError from "../interfaces/http-error"; import { Command } from "../entities/Command"; -import { Brackets, LessThan, MoreThan, Double, In, Between } from "typeorm"; +import { Brackets, LessThan, MoreThan, Double, In, Not ,Between } from "typeorm"; import { CommandType } from "../entities/CommandType"; import { CommandSend } from "../entities/CommandSend"; -import { Profile } from "../entities/Profile"; +import { Profile, CreateProfileAllFields } from "../entities/Profile"; import { RequestWithUser } from "../middlewares/user"; import { OrgRevision } from "../entities/OrgRevision"; import { CommandSendCC } from "../entities/CommandSendCC"; @@ -32,9 +32,14 @@ import HttpStatus from "../interfaces/http-status"; import Extension from "../interfaces/extension"; import { ProfileEmployee } from "../entities/ProfileEmployee"; import CallAPI from "../interfaces/call-api"; -import { ProfileSalary } from "../entities/ProfileSalary"; +import { ProfileSalary, CreateProfileSalary } from "../entities/ProfileSalary"; import { ProfileSalaryHistory } from "../entities/ProfileSalaryHistory"; -import { removeProfileInOrganize, setLogDataDiff } from "../interfaces/utils"; +import { + calculateRetireDate, + calculateRetireLaw, + removeProfileInOrganize, + setLogDataDiff, +} from "../interfaces/utils"; import { Position } from "../entities/Position"; import { PosMaster } from "../entities/PosMaster"; import { EmployeePosition } from "../entities/EmployeePosition"; @@ -43,6 +48,14 @@ import { ProfileDiscipline } from "../entities/ProfileDiscipline"; import { ProfileDisciplineHistory } from "../entities/ProfileDisciplineHistory"; import { PosMasterAct } from "../entities/PosMasterAct"; import { sendToQueue } from "../services/rabbitmq"; +import { PosLevel } from "../entities/PosLevel"; +import { PosType } from "../entities/PosType"; +import { addUserRoles, createUser, getRoles } from "../keycloak"; +import { ProfileEducation, CreateProfileEducation } from "../entities/ProfileEducation"; +import { ProfileEducationHistory } from "../entities/ProfileEducationHistory"; +import { CreateProfileCertificate, ProfileCertificate } from "../entities/ProfileCertificate"; +import { ProfileCertificateHistory } from "../entities/ProfileCertificateHistory"; +import permission from "../interfaces/permission"; @Route("api/v1/org/command") @Tags("Command") @@ -71,6 +84,13 @@ export class CommandController extends Controller { private disciplineRepository = AppDataSource.getRepository(ProfileDiscipline); private disciplineHistoryRepository = AppDataSource.getRepository(ProfileDisciplineHistory); private posMasterActRepository = AppDataSource.getRepository(PosMasterAct); + private posLevelRepo = AppDataSource.getRepository(PosLevel); + private posTypeRepo = AppDataSource.getRepository(PosType); + private profileEducationRepo = AppDataSource.getRepository(ProfileEducation); + private profileEducationHistoryRepo = AppDataSource.getRepository(ProfileEducationHistory); + private certificateRepo = AppDataSource.getRepository(ProfileCertificate); + private certificateHistoryRepo = AppDataSource.getRepository(ProfileCertificateHistory); + private orgRevisionRepository = AppDataSource.getRepository(OrgRevision); /** * API list รายการคำสั่ง @@ -80,6 +100,7 @@ export class CommandController extends Controller { */ @Get("list") async GetResult( + @Request() request: RequestWithUser, @Query("page") page: number = 1, @Query("pageSize") pageSize: number = 10, @Query() keyword: string = "", @@ -87,8 +108,107 @@ export class CommandController extends Controller { @Query() year?: number, @Query() status?: string | null, ) { + let profilekArray: any = []; + + let _profile = await this.profileRepository.findOne({ + where: { keycloak: request.user.sub }, + relations: ["current_holders", "current_holders.orgRevision"], + }); + let isDirector = + _profile?.current_holders?.filter( + (x) => + x.orgRevision?.orgRevisionIsCurrent == true && x.orgRevision?.orgRevisionIsDraft == false, + )[0]?.isDirector || false; + if (isDirector) { + let _data: any = { + root: null, + child1: null, + child2: null, + child3: null, + child4: null, + }; + if (!request.user.role.includes("SUPER_ADMIN")) { + _data = await new permission().PermissionOrgList(request, "COMMAND"); + } + const profiles = await this.profileRepository + .createQueryBuilder("profile") + .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") + .andWhere( + _data.root != undefined && _data.root != null + ? _data.root[0] != null + ? `current_holders.orgRootId IN (:...root)` + : `current_holders.orgRootId is null` + : "1=1", + { + root: _data.root, + }, + ) + .andWhere( + _data.child1 != undefined && _data.child1 != null + ? _data.child1[0] != null + ? `current_holders.orgChild1Id IN (:...child1)` + : `current_holders.orgChild1Id is null` + : "1=1", + { + child1: _data.child1, + }, + ) + .andWhere( + _data.child2 != undefined && _data.child2 != null + ? _data.child2[0] != null + ? `current_holders.orgChild2Id IN (:...child2)` + : `current_holders.orgChild2Id is null` + : "1=1", + { + child2: _data.child2, + }, + ) + .andWhere( + _data.child3 != undefined && _data.child3 != null + ? _data.child3[0] != null + ? `current_holders.orgChild3Id IN (:...child3)` + : `current_holders.orgChild3Id is null` + : "1=1", + { + child3: _data.child3, + }, + ) + .andWhere( + _data.child4 != undefined && _data.child4 != null + ? _data.child4[0] != null + ? `current_holders.orgChild4Id IN (:...child4)` + : `current_holders.orgChild4Id is null` + : "1=1", + { + child4: _data.child4, + }, + ) + .select("profile.keycloak", "keycloak") + .getRawMany(); + profilekArray = profiles.map((p) => p.keycloak); + } + const [commands, total] = await this.commandRepository .createQueryBuilder("command") + .andWhere( + new Brackets((qb) => { + qb.orWhere( + profilekArray.length > 0 + ? "command.createdUserId IN (:...profilekArray)" + : "command.createdUserId='1'", + { + profilekArray: profilekArray, + }, + ).orWhere("command.createdUserId = :createdUserId", { + createdUserId: request.user.sub, + }); + }), + ) .andWhere( status != null && status != undefined && status != "" ? "command.status IN (:...status)" @@ -248,8 +368,7 @@ export class CommandController extends Controller { detailFooter: string | null; commandAffectDate: Date | null; commandExcecuteDate: Date | null; - isBangkok: boolean | null; - isAttachment: boolean | null; + isBangkok: string | null; }, @Request() request: RequestWithUser, ) { @@ -906,7 +1025,7 @@ export class CommandController extends Controller { payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, - receiveDate: command.commandExcecuteDate, + isSendNotification: true, }) .catch((error) => { console.error("Error calling API:", error); @@ -1019,9 +1138,33 @@ export class CommandController extends Controller { if (!command) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลคำสั่งนี้"); } - + let issue = + command.isBangkok == "OFFICE" + ? "สำนักปลัดกรุงเทพมหานคร" + : command.isBangkok == "BANGKOK" + ? "กรุงเทพมหานคร" + : null; + if (issue == null) { + const orgRevisionActive = await this.orgRevisionRepository.findOne({ + where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, + relations: ["posMasters", "posMasters.orgRoot"], + }); + if (orgRevisionActive != null) { + const profile = await this.profileRepository.findOne({ + where: { + keycloak: command.createdUserId.toString(), + }, + }); + if (profile != null) { + issue = + orgRevisionActive?.posMasters?.filter((x) => x.current_holderId == profile.id)[0] + ?.orgRoot?.orgRootName || null; + } + } + } + if (issue == null) issue = "..................................."; const _command = { - issue: "...................................", + issue: issue, commandNo: command.commandNo, commandYear: command.commandYear, commandTitle: command.issue, @@ -1038,6 +1181,9 @@ export class CommandController extends Controller { : Extension.ToThaiNumber(Extension.ToThaiFullDate2(command.commandExcecuteDate)), name: "...................................", position: "...................................", + authorizedUserFullName: "...................................", + authorizedPosition: "...................................", + commandAffectDate: "...................................", }; return new HttpSuccess({ template: command.commandType.fileCover, @@ -1066,7 +1212,6 @@ export class CommandController extends Controller { let _command: any = []; const path = this.commandTypePath(command.commandType.code); if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ"); - await new CallAPI() .PostData(request, path + "/attachment", { refIds: command.commandRecives @@ -1087,15 +1232,51 @@ export class CommandController extends Controller { })), }) .then(async (res) => { - console.log(res); _command = res; }) .catch(() => {}); + let issue = + command.isBangkok == "OFFICE" + ? "สำนักปลัดกรุงเทพมหานคร" + : command.isBangkok == "BANGKOK" + ? "กรุงเทพมหานคร" + : null; + if (issue == null) { + const orgRevisionActive = await this.orgRevisionRepository.findOne({ + where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, + relations: ["posMasters", "posMasters.orgRoot"], + }); + if (orgRevisionActive != null) { + const profile = await this.profileRepository.findOne({ + where: { + keycloak: command.createdUserId.toString(), + }, + }); + if (profile != null) { + issue = + orgRevisionActive?.posMasters?.filter((x) => x.current_holderId == profile.id)[0] + ?.orgRoot?.orgRootName || null; + } + } + } + if (issue == null) issue = "..................................."; return new HttpSuccess({ template: command.commandType.fileAttachment, reportName: "xlsx-report", - data: _command, + data: { + data: _command, + issuerOrganizationName: issue, + commandNo: command.commandNo == null ? "" : Extension.ToThaiNumber(command.commandNo), + commandYear: + command.commandYear == null + ? "" + : Extension.ToThaiNumber(Extension.ToThaiYear(command.commandYear).toString()), + commandExcecuteDate: + command.commandExcecuteDate == null + ? "" + : Extension.ToThaiNumber(Extension.ToThaiFullDate2(command.commandExcecuteDate)), + }, }); } @@ -2040,6 +2221,206 @@ export class CommandController extends Controller { return new HttpSuccess(); } + @Post("excexute/create-officer-profile") + public async CreateOfficeProfileExcecute( + @Request() req: RequestWithUser, + @Body() + body: { + data: { + bodyProfile: CreateProfileAllFields; + bodyEducations?: CreateProfileEducation[]; + bodyCertificates?: CreateProfileCertificate[]; + bodySalarys?: CreateProfileSalary | null; + bodyPosition?: { + posmasterId: string; + positionId: string; + } | null; + }[]; + }, + ) { + await Promise.all( + body.data.map(async (item) => { + const before = null; + const meta = { + createdUserId: req.user.sub, + createdFullName: req.user.name, + lastUpdateUserId: req.user.sub, + lastUpdateFullName: req.user.name, + createdAt: new Date(), + lastUpdatedAt: new Date(), + }; + const _null: any = null; + if (item.bodyProfile.posLevelId === "") item.bodyProfile.posLevelId = null; + if (item.bodyProfile.posTypeId === "") item.bodyProfile.posTypeId = null; + if ( + item.bodyProfile.posLevelId && + !(await this.posLevelRepo.findOneBy({ id: item.bodyProfile.posLevelId })) + ) { + throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลระดับตำแหน่งนี้"); + } + if ( + item.bodyProfile.posTypeId && + !(await this.posTypeRepo.findOneBy({ id: item.bodyProfile.posTypeId })) + ) { + throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้"); + } + + let profile: any = await this.profileRepository.findOneBy({ + citizenId: item.bodyProfile.citizenId, + }); + if (!profile) { + profile = Object.assign({ ...item.bodyProfile, ...meta }); + profile.dateRetire = + item.bodyProfile.birthDate == null + ? _null + : calculateRetireDate(item.bodyProfile.birthDate); + profile.dateRetireLaw = + item.bodyProfile.birthDate == null + ? _null + : calculateRetireLaw(item.bodyProfile.birthDate); + const userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { + firstName: profile.firstName, + lastName: profile.lastName, + email: profile.email, + }); + if (typeof userKeycloakId !== "string") { + throw new Error(userKeycloakId.errorMessage); + } + const list = await getRoles(); + if (!Array.isArray(list)) + throw new Error("Failed. Cannot get role(s) data from the server."); + const result = await addUserRoles( + userKeycloakId, + list + .filter((v) => v.name === "USER") + .map((x) => ({ + id: x.id, + name: x.name, + })), + ); + if (!result) throw new Error("Failed. Cannot set user's role."); + profile.keycloak = userKeycloakId; + await this.profileRepository.save(profile); + setLogDataDiff(req, { before, after: profile }); + } + if (profile && profile.id) { + //Educations + if (item.bodyEducations && item.bodyEducations.length > 0) { + await Promise.all( + item.bodyEducations.map(async (education) => { + const profileEdu = new ProfileEducation(); + Object.assign(profileEdu, { ...education, ...meta }); + const eduHistory = new ProfileEducationHistory(); + Object.assign(eduHistory, { ...profileEdu, id: undefined }); + profileEdu.profileId = profile.id; + await this.profileEducationRepo.save(profileEdu, { data: req }); + setLogDataDiff(req, { before, after: profileEdu }); + eduHistory.profileEducationId = profileEdu.id; + await this.profileEducationHistoryRepo.save(eduHistory, { data: req }); + }), + ); + } + + //Certificates + if (item.bodyCertificates && item.bodyCertificates.length > 0) { + await Promise.all( + item.bodyCertificates.map(async (cer) => { + const profileCer = new ProfileCertificate(); + Object.assign(profileCer, { ...cer, ...meta }); + const cerHistory = new ProfileCertificateHistory(); + Object.assign(cerHistory, { ...profileCer, id: undefined }); + profileCer.profileId = profile.id; + await this.certificateRepo.save(profileCer, { data: req }); + setLogDataDiff(req, { before, after: profileCer }); + cerHistory.profileCertificateId = profileCer.id; + await this.certificateHistoryRepo.save(cerHistory, { data: req }); + }), + ); + } + //Salary + if (item.bodySalarys && item.bodySalarys != null) { + const dest_item = await this.salaryRepo.findOne({ + where: { profileId: profile.id }, + order: { order: "DESC" }, + }); + const profileSal = new ProfileSalary(); + Object.assign(profileSal, { ...item.bodySalarys, ...meta }); + const salaryHistory = new ProfileSalaryHistory(); + Object.assign(salaryHistory, { ...profileSal, id: undefined }); + profileSal.order = dest_item == null ? 1 : dest_item.order + 1; + profileSal.profileId = profile.id; + await this.salaryRepo.save(profileSal, { data: req }); + setLogDataDiff(req, { before, after: profileSal }); + salaryHistory.profileSalaryId = profileSal.id; + await this.salaryHistoryRepo.save(salaryHistory, { data: req }); + } + //Position + if (item.bodyPosition && item.bodyPosition != null) { + const posMaster = await this.posMasterRepository.findOne({ + where: { id: item.bodyPosition.posmasterId }, + }); + if (posMaster == null) + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้"); + + const posMasterOld = await this.posMasterRepository.findOne({ + where: { + current_holderId: profile.id, + orgRevisionId: posMaster.orgRevisionId, + }, + }); + if (posMasterOld != null) posMasterOld.current_holderId = null; + + const positionOld = await this.positionRepository.findOne({ + where: { + posMasterId: posMasterOld?.id, + positionIsSelected: true, + }, + }); + if (positionOld != null) { + positionOld.positionIsSelected = false; + await this.positionRepository.save(positionOld); + } + + const checkPosition = await this.positionRepository.find({ + where: { + posMasterId: item.bodyPosition.posmasterId, + positionIsSelected: true, + }, + }); + if (checkPosition.length > 0) { + const clearPosition = checkPosition.map((positions) => ({ + ...positions, + positionIsSelected: false, + })); + await this.positionRepository.save(clearPosition); + } + + posMaster.current_holderId = profile.id; + if (posMasterOld != null) await this.posMasterRepository.save(posMasterOld); + await this.posMasterRepository.save(posMaster); + + const positionNew = await this.positionRepository.findOne({ + where: { + id: item.bodyPosition.positionId, + posMasterId: item.bodyPosition.posmasterId, + }, + }); + if (positionNew != null) { + positionNew.positionIsSelected = true; + profile.posLevelId = positionNew.posLevelId; + profile.posTypeId = positionNew.posTypeId; + profile.position = positionNew.positionName; + await this.profileRepository.save(profile, { data: req }); + setLogDataDiff(req, { before, after: profile }); + await this.positionRepository.save(positionNew, { data: req }); + } + } + } + }), + ); + return new HttpSuccess(); + } + @Post("command21/employee/report/excecute") public async command21SalaryEmployeeExcecute( @Request() req: RequestWithUser, @@ -2181,6 +2562,28 @@ export class CommandController extends Controller { refIds: string[]; }, ) { + const profile = await this.profileEmployeeRepository.find({ where: { id: In(body.refIds) } }); + const data = profile.map((_data) => ({ + ..._data, + statusTemp: "REPORT", + })); + await this.profileEmployeeRepository.save(data); + return new HttpSuccess(); + } + @Post("command21/employee/delete") + public async command21SalaryEmployeeDelete( + @Request() req: RequestWithUser, + @Body() + body: { + refIds: string[]; + }, + ) { + const profile = await this.profileEmployeeRepository.find({ where: { id: In(body.refIds) } }); + const data = profile.map((_data) => ({ + ..._data, + statusTemp: "WAITTING", + })); + await this.profileEmployeeRepository.save(data); return new HttpSuccess(); } @@ -2211,6 +2614,28 @@ export class CommandController extends Controller { refIds: string[]; }, ) { + // const profile = await this.profileEmployeeRepository.find({ where: { id: In(body.refIds) } }); + // const data = profile.map((_data) => ({ + // ..._data, + // statusTemp: "DONE", + // })); + // await this.profileEmployeeRepository.save(data); + return new HttpSuccess(); + } + @Post("command40/officer/delete") + public async command40SalaryOfficerDelete( + @Request() req: RequestWithUser, + @Body() + body: { + refIds: string[]; + }, + ) { + // const profile = await this.profileEmployeeRepository.find({ where: { id: In(body.refIds) } }); + // const data = profile.map((_data) => ({ + // ..._data, + // statusTemp: "WAITTING", + // })); + // await this.profileEmployeeRepository.save(data); return new HttpSuccess(); } @Post("command40/officer/report/attachment") @@ -2281,8 +2706,7 @@ export class CommandController extends Controller { "" + posMasterAct.posMasterChild?.current_holder?.firstName ?? "" + " " + posMasterAct.posMasterChild?.current_holder?.lastName ?? null, - organization: _organization, - position: posMasterAct.posMasterChild?.current_holder?.position ?? null, + oc: (posMasterAct.posMasterChild?.current_holder?.position ?? null) + "/" + _organization, postype: posMasterAct.posMasterChild?.current_holder?.posType?.posTypeName ?? null, poslevel: posMasterAct.posMasterChild?.current_holder?.posLevel?.posLevelName ?? null, organizationNew: _organizationNew, @@ -2360,7 +2784,7 @@ export class CommandController extends Controller { case "C-PM-13": return "/placement/transfer/command/report"; case "C-PM-14": - return "/placement/Receive/command/report"; + return "/placement/receive/command/report"; case "C-PM-15": return "/placement/officer/command/report"; case "C-PM-16": diff --git a/src/controllers/DPISController.ts b/src/controllers/DPISController.ts index 644bd612..597a997b 100644 --- a/src/controllers/DPISController.ts +++ b/src/controllers/DPISController.ts @@ -1,24 +1,68 @@ -import { - Controller, - Example, - Get, - Path, - Response, - Route, - Security, - SuccessResponse, - Tags, -} from "tsoa"; +import { Controller, Example, Get, Path, Response, Route, SuccessResponse, Tags } from "tsoa"; +import { DateTime } from "@elastic/elasticsearch/lib/api/types"; +import { Double } from "typeorm"; import { AppDataSource } from "../database/data-source"; import { Profile } from "../entities/Profile"; import HttpError from "../interfaces/http-error"; import HttpStatus from "../interfaces/http-status"; -import HttpSuccess from "../interfaces/http-success"; + +interface DPISResponse { + status: number; + message: string; + result?: DPISResult; +} + +interface DPISResult { + citizenId: string; + prefix: string; + firstName: string; + lastName: string; + gender: string; + physicalStatus: string; + QualityWorkforce: boolean; + birthDate: DateTime; + dateAppoint: DateTime; + dateStart: DateTime; + dateRetire: DateTime; + isLeave: boolean; + isProbation: boolean; + leaveReason: string; + positionLevel: string; + positionType: string; + educations: ProfileEducationResult[]; + leaves: ProfileLeaveResult[]; + salaries: ProfileSalaryResult[]; +} + +interface ProfileLeaveResult { + dateLeaveStart: DateTime; + dateLeaveEnd: DateTime; + leaveType: string; + totalLeave: number; +} + +interface ProfileEducationResult { + country: string; + degree: string; + field: string; + institute: string; + educationLevel: string; +} + +interface ProfileSalaryResult { + posNo: string; + position: string; + positionType: string; + positionLevel: string; + amount: Double; + positionSalaryAmount: Double; + monthSalaryAmount: Double; +} @Route("api/v1/dpis") @Tags("DPIS") -@Security("bearerAuth") +// @Security("bearerAuth") @Response( HttpStatus.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง", @@ -28,179 +72,86 @@ export class DPISController extends Controller { private profileRepo = AppDataSource.getRepository(Profile); /** - * 1. API Get Profile จาก เลขประจำตัวประชาชน + * แสดงข้อมูลข้าราชการจากเลขประจำตัวประชาชน * - * @summary 1. API Get Profile จาก เลขประจำตัวประชาชน + * @summary แสดงข้อมูลข้าราชการจากเลขประจำตัวประชาชน * * @param {string} citizenId เลขประจำตัวประชาชน * - * @returns ข้อมูลขปงข้าราชการที่ค้นหาพบในระบบ + * @returns ข้อมูลของข้าราชการที่ค้นหาพบในระบบ */ @Get("{citizenId}") @Example({ - id: "08dc4c9f-2710-4e98-8340-c9f2a65467db", - avatar: null, - avatarName: null, - rank: null, - prefix: "นาย", - firstName: "สุรศักดิ์", - lastName: "จันทร์ศรี", - citizenId: "1103700765894", - position: "เจ้าพนักงานสาธารณสุข", - posLevelId: "1526d9d3-d8b1-43ab-81b5-a84dfbe08262", - email: "userUat43@test.test", - phone: null, - keycloak: "bac99314-8163-4671-9af6-cf994167e939", - isProbation: false, - isLeave: false, - leaveReason: null, - dateRetire: "2055-05-06T17:00:00.000Z", - dateAppoint: "2022-11-24T17:00:00.000Z", - dateRetireLaw: "2055-09-29T17:00:00.000Z", - dateStart: "2022-11-24T17:00:00.000Z", - govAgeAbsent: 0, - govAgePlus: 0, - birthDate: "1995-05-06T17:00:00.000Z", - reasonSameDate: null, - telephoneNumber: "990686659", - nationality: "ไทย", - gender: "หญิง", - relationship: "โสด", - religion: "พุทธ", - bloodGroup: null, - registrationAddress: "21/1 หมู่ที่ 2", - registrationProvinceId: "24bf701c-33d6-436e-ad49-6f82bb3ae029", - registrationDistrictId: "34bf701c-33d6-436e-ad49-6f82bb3b0642", - registrationSubDistrictId: "44bf701c-33d6-436e-ad49-6f82bb3b3427", - registrationZipCode: "22110", - currentAddress: "21/1 หมู่ที่ 2", - currentProvinceId: "24bf701c-33d6-436e-ad49-6f82bb3ae029", - currentSubDistrictId: "44bf701c-33d6-436e-ad49-6f82bb3b3427", - currentZipCode: "22110", - dutyTimeId: null, - dutyTimeEffectiveDate: null, - posLevel: { - id: "1526d9d3-d8b1-43ab-81b5-a84dfbe08262", - createdAt: "2024-01-26T05:42:53.761Z", - createdUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0", - lastUpdatedAt: "2024-01-26T05:42:53.761Z", - lastUpdateUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0", - createdFullName: "สาวิตรี ศรีสมัย", - lastUpdateFullName: "สาวิตรี ศรีสมัย", - posLevelName: "ปฏิบัติงาน", - posLevelRank: 1, - posLevelAuthority: null, - posTypeId: "1526d9d3-d8b1-43ab-81b5-a84dfbe08061", + status: 200, + message: "Success", + result: { + citizenId: "1103700765894", + prefix: "นาย", + firstName: "สุรศักดิ์", + lastName: "จันทร์ศรี", + gender: "หญิง", + physicalStatus: "ปกติ", + QualityWorkforce: true, + birthDate: "1995-05-06T17:00:00.000Z", + dateAppoint: "2022-11-24T17:00:00.000Z", + dateStart: "2022-11-24T17:00:00.000Z", + dateRetire: "2055-05-06T17:00:00.000Z", + isLeave: false, + isProbation: false, + leaveReason: null, + positionLevel: "ปฏิบัติงาน", + positionType: "ทั่วไป", + educations: [], + salaries: [ + { + posNo: "ขพน.65", + position: "เจ้าพนักงานสาธารณสุข", + positionType: "ทั่วไป", + positionLevel: "ปฏิบัติงาน", + amount: 11860, + positionSalaryAmount: 0, + monthSalaryAmount: 0, + }, + { + posNo: "ขพน.65", + position: + "เจ้าพนักงานสาธารณสุขปฏิบัติงาน ฝ่ายสิ่งแวดล้อมและสุขาภิบาล สำนักงานเขตพระนคร\n(ทดลองปฏิบัติหน้าที่ราชการ)", + positionType: "ทั่วไป", + positionLevel: "ปฏิบัติงาน", + amount: 11860, + positionSalaryAmount: 0, + monthSalaryAmount: 0, + }, + { + posNo: "ขพน.65", + position: + "เจ้าพนักงานสาธารณสุขปฏิบัติงาน ฝ่ายสิ่งแวดล้อมและสุขาภิบาล สำนักงานเขตพระนคร\n(ทดลองปฏิบัติหน้าที่ราชการ)", + positionType: "ทั่วไป", + positionLevel: "ปฏิบัติงาน", + amount: 11500, + positionSalaryAmount: 0, + monthSalaryAmount: 0, + }, + ], + leaves: [], }, - posType: { - id: "1526d9d3-d8b1-43ab-81b5-a84dfbe08061", - createdAt: "2024-01-26T05:42:53.761Z", - createdUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0", - lastUpdatedAt: "2024-08-25T09:41:14.000Z", - lastUpdateUserId: "01378019-5286-4e1d-ae43-826b648af4aa", - createdFullName: "สาวิตรี ศรีสมัย", - lastUpdateFullName: "Super Admin", - posTypeName: "ทั่วไป", - posTypeRank: 1, - }, - profileSalary: [ - { - id: "eef6d0b6-ef64-4389-b497-c74a62e5f334", - createdAt: "2024-08-22T02:23:57.193Z", - createdUserId: "94ba986d-f871-46a2-be92-46c0cbf0bc56", - lastUpdatedAt: "2024-08-22T02:23:57.193Z", - lastUpdateUserId: "94ba986d-f871-46a2-be92-46c0cbf0bc56", - createdFullName: "กานต์พิชชา นาคศรี", - lastUpdateFullName: "กานต์พิชชา นาคศรี", - profileId: "08dc4c9f-2710-4e98-8340-c9f2a65467db", - profileEmployeeId: null, - date: "2024-08-22T09:23:18.000Z", - posNo: "ขพน.65", - position: "เจ้าพนักงานสาธารณสุข", - positionLine: "ปฏิบัติงานสาธารณสุข", - positionPathSide: null, - positionExecutive: null, - positionType: "ทั่วไป", - positionLevel: "ปฏิบัติงาน", - amount: 11860, - positionSalaryAmount: 0, - mouthSalaryAmount: 0, - refCommandNo: null, - templateDoc: "ปรับโครงสร้าง", - order: 3, - }, - { - id: "916fcf0c-f0d5-4efb-af46-0f1942de5c19", - createdAt: "2024-06-27T22:01:25.959Z", - createdUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0", - lastUpdatedAt: "2024-06-27T23:24:50.219Z", - lastUpdateUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0", - createdFullName: "โกศล สิงหนาท", - lastUpdateFullName: "โกศล สิงหนาท", - profileId: "08dc4c9f-2710-4e98-8340-c9f2a65467db", - profileEmployeeId: null, - date: "2023-03-31T17:00:00.000Z", - posNo: "ขพน.65", - position: - "เจ้าพนักงานสาธารณสุขปฏิบัติงาน ฝ่ายสิ่งแวดล้อมและสุขาภิบาล สำนักงานเขตพระนคร\n(ทดลองปฏิบัติหน้าที่ราชการ)", - positionLine: null, - positionPathSide: null, - positionExecutive: null, - positionType: "ทั่วไป", - positionLevel: "ปฏิบัติงาน", - amount: 11860, - positionSalaryAmount: 0, - mouthSalaryAmount: 0, - refCommandNo: null, - templateDoc: "เลื่อนขั้นเงินเดือน คำสั่ง ขพน.ที่ 159/2566 ลว. 6 มิ.ย. 2566", - order: 2, - }, - { - id: "161bea25-0451-4eff-bbfd-709e88a1700f", - createdAt: "2024-06-27T22:01:25.881Z", - createdUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0", - lastUpdatedAt: "2024-06-27T23:24:50.219Z", - lastUpdateUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0", - createdFullName: "โกศล สิงหนาท", - lastUpdateFullName: "โกศล สิงหนาท", - profileId: "08dc4c9f-2710-4e98-8340-c9f2a65467db", - profileEmployeeId: null, - date: "2022-11-24T17:00:00.000Z", - posNo: "ขพน.65", - position: - "เจ้าพนักงานสาธารณสุขปฏิบัติงาน ฝ่ายสิ่งแวดล้อมและสุขาภิบาล สำนักงานเขตพระนคร\n(ทดลองปฏิบัติหน้าที่ราชการ)", - positionLine: null, - positionPathSide: null, - positionExecutive: null, - positionType: "ทั่วไป", - positionLevel: "ปฏิบัติงาน", - amount: 11500, - positionSalaryAmount: 0, - mouthSalaryAmount: 0, - refCommandNo: null, - templateDoc: - "บรรจุและแต่งตั้งผู้สอบแข่งขันได้ คำสั่ง ขพน.ที่ 374/2565 ลว. 29 พ.ย. 2565 โดยมีเงื่อนไขว่าต้องปฏิบัติงานให้กรุงเทพมหานครเป็นระยะเวลาไม่น้อยกว่า 5 ปี นับแต่วันที่ได้รับการบรรจุและแต่งตั้ง \nโดยห้ามโอนไปหน่วยงานหรือส่วนราชการอื่น เว้นแต่ลาออกจากราชการ\n", - order: 1, - }, - ], - profileInsignia: [], }) - async GetProfileCitizenIdAsync(@Path() citizenId: string) { + async GetProfileCitizenIdAsync(@Path() citizenId: string): Promise { const profile = await this.profileRepo.findOne({ relations: { posLevel: true, posType: true, profileSalary: true, - profileInsignias: true, profileEducations: true, + profileLeaves: true, }, where: { citizenId: citizenId }, order: { profileSalary: { date: "DESC", }, - profileInsignias: { - receiveDate: "DESC", + profileLeaves: { + dateLeaveStart: "ASC", }, profileEducations: { degree: "ASC", @@ -209,45 +160,61 @@ export class DPISController extends Controller { }); if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); - const mapProfile = { + const mapProfile: DPISResult = { citizenId: profile.citizenId, prefix: profile.prefix, firstName: profile.firstName, lastName: profile.lastName, - rank: profile.rank, - position: profile.position, - isProbation: profile.isProbation, - isLeave: profile.isLeave, - leaveReason: profile.leaveReason, - dateRetire: profile.dateRetire, - dateAppoint: profile.dateAppoint, - dateRetireLaw: profile.dateRetireLaw, - dateStart: profile.dateStart, - birthDate: profile.birthDate, - telephoneNumber: profile.telephoneNumber, - nationality: profile.nationality, gender: profile.gender, - relationship: profile.relationship, - religion: profile.religion, - bloodGroup: profile.bloodGroup, - registrationAddress: profile.registrationAddress, - registrationProvinceId: profile.registrationProvinceId, - registrationDistrictId: profile.registrationDistrictId, - registrationSubDistrictId: profile.registrationSubDistrictId, - registrationZipCode: profile.registrationZipCode, - currentAddress: profile.currentAddress, - currentProvinceId: profile.currentProvinceId, - currentSubDistrictId: profile.currentSubDistrictId, - currentZipCode: profile.currentZipCode, - dutyTimeId: profile.dutyTimeId, - dutyTimeEffectiveDate: profile.dutyTimeEffectiveDate, - posLevel: profile.posLevel ? profile.posLevel : null, - posType: profile.posType ? profile.posType : null, - profileSalary: profile.profileSalary, - profileInsignia: profile.profileInsignias, - profileEducation: profile.profileEducations, + physicalStatus: "ปกติ", + QualityWorkforce: true, + birthDate: profile.birthDate, + dateAppoint: profile.dateAppoint, + dateStart: profile.dateStart, + dateRetire: profile.dateRetire, + isLeave: profile.isLeave, + isProbation: profile.isProbation, + leaveReason: profile.leaveReason, + positionLevel: profile.posLevel ? profile.posLevel.posLevelName : "", + positionType: profile.posType ? profile.posType.posTypeName : "", + + // educations + educations: profile.profileEducations.map((item) => { + return { + country: item.country, + degree: item.degree, + field: item.field, + institute: item.institute, + educationLevel: item.educationLevel, + }; + }), + + salaries: profile.profileSalary.map((item) => { + return { + posNo: item.posNo, + position: item.position, + positionType: item.positionType, + positionLevel: item.positionLevel, + amount: item.amount, + positionSalaryAmount: item.positionSalaryAmount, + monthSalaryAmount: item.mouthSalaryAmount, + }; + }), + + leaves: profile.profileLeaves.map((item) => { + return { + dateLeaveStart: item.dateLeaveStart, + dateLeaveEnd: item.dateLeaveEnd, + leaveType: item.leaveType ? item.leaveType.name : "", + totalLeave: item.totalLeave, + }; + }), }; - return new HttpSuccess(mapProfile); + return { + status: 200, + message: "Success", + result: mapProfile, + }; } } diff --git a/src/controllers/DevelopmentRequestController.ts b/src/controllers/DevelopmentRequestController.ts index e9745e79..10ec4363 100644 --- a/src/controllers/DevelopmentRequestController.ts +++ b/src/controllers/DevelopmentRequestController.ts @@ -301,17 +301,8 @@ export class DevelopmentRequestController extends Controller { }); if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); await new permission().PermissionUpdate(req, "SYS_REGISTRY_OFFICER"); - const before = structuredClone(record); - requestBody.status = requestBody.status.trim().toUpperCase(); - Object.assign(record, requestBody); - - record.lastUpdateUserId = req.user.sub; - record.lastUpdateFullName = req.user.name; - record.lastUpdatedAt = new Date(); - - await this.developmentRequestRepository.save(record, { data: req }); - setLogDataDiff(req, { before, after: record }); - if (requestBody.status == "APPROVE") { + + if (requestBody.status == "APPROVE" && record.status == "PENDING") { let profileDevelopment = new ProfileDevelopment(); const meta = { createdUserId: req.user.sub, @@ -368,7 +359,16 @@ export class DevelopmentRequestController extends Controller { ); } } + const before = structuredClone(record); + requestBody.status = requestBody.status.trim().toUpperCase(); + Object.assign(record, requestBody); + record.lastUpdateUserId = req.user.sub; + record.lastUpdateFullName = req.user.name; + record.lastUpdatedAt = new Date(); + + await this.developmentRequestRepository.save(record, { data: req }); + setLogDataDiff(req, { before, after: record }); return new HttpSuccess(record.id); } diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index 8db60923..0d7ffbbc 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -1412,6 +1412,783 @@ export class OrganizationController extends Controller { return new HttpSuccess(formattedData); } + /** + * API รายละเอียดโครงสร้าง + * + * @summary ORG_023 - รายละเอียดโครงสร้าง (ADMIN) #25 + * + */ + @Get("super-admin/{id}") + async detailSuperAdmin(@Path() id: string, @Request() request: RequestWithUser) { + // let _data: any = { + // root: null, + // child1: null, + // child2: null, + // child3: null, + // child4: null, + // }; + + // const orgRevision = await this.orgRevisionRepository.findOne({ where: { id } }); + // if (!orgRevision) { + // throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล"); + // } + // if (!request.user.role.includes("SUPER_ADMIN")) { + // if (orgRevision.orgRevisionIsDraft == true && orgRevision.orgRevisionIsCurrent == false) { + // _data = await this.listAuthSysOrgFuncByRevisionIdN(request, "SYS_ORG", orgRevision.id); + // } else { + // _data = await this.listAuthSysOrgFuncByRevisionIdC(request, "SYS_ORG", orgRevision.id); + // } + // } + + const orgRevision = await this.orgRevisionRepository.findOne({ + where: { id: id }, + relations: ["posMasters"], + }); + if (!orgRevision) return new HttpSuccess([]); + + let rootId: any = null; + if (!request.user.role.includes("SUPER_ADMIN")) { + const profile = await this.profileRepo.findOne({ + where: { + keycloak: request.user.sub, + }, + }); + if (profile == null) return new HttpSuccess([]); + + if (!request.user.role.includes("SUPER_ADMIN")) { + if (orgRevision.orgRevisionIsDraft == true && orgRevision.orgRevisionIsCurrent == false) { + rootId = + orgRevision?.posMasters?.filter((x) => x.next_holderId == profile.id)[0]?.orgRootId || + null; + if (!rootId) return new HttpSuccess([]); + } else { + rootId = + orgRevision?.posMasters?.filter((x) => x.current_holderId == profile.id)[0] + ?.orgRootId || null; + if (!rootId) return new HttpSuccess([]); + } + } + } + + const orgRootData = await AppDataSource.getRepository(OrgRoot) + .createQueryBuilder("orgRoot") + .where("orgRoot.orgRevisionId = :id", { id }) + .andWhere(rootId != null ? `orgRoot.id = :rootId` : "1=1", { + rootId: rootId, + }) + .select([ + "orgRoot.id", + "orgRoot.orgRootName", + "orgRoot.orgRootShortName", + "orgRoot.orgRootCode", + "orgRoot.orgRootOrder", + "orgRoot.orgRootPhoneEx", + "orgRoot.orgRootPhoneIn", + "orgRoot.orgRootFax", + "orgRoot.orgRevisionId", + "orgRoot.orgRootRank", + "orgRoot.orgRootRankSub", + "orgRoot.responsibility", + ]) + .orderBy("orgRoot.orgRootOrder", "ASC") + .getMany(); + const orgRootIds = orgRootData.map((orgRoot) => orgRoot.id) || null; + const orgChild1Data = + orgRootIds && orgRootIds.length > 0 + ? await AppDataSource.getRepository(OrgChild1) + .createQueryBuilder("orgChild1") + .where("orgChild1.orgRootId IN (:...ids)", { ids: orgRootIds }) + .select([ + "orgChild1.id", + "orgChild1.isOfficer", + "orgChild1.orgChild1Name", + "orgChild1.orgChild1ShortName", + "orgChild1.orgChild1Code", + "orgChild1.orgChild1Order", + "orgChild1.orgChild1PhoneEx", + "orgChild1.orgChild1PhoneIn", + "orgChild1.orgChild1Fax", + "orgChild1.orgRootId", + "orgChild1.orgChild1Rank", + "orgChild1.orgChild1RankSub", + "orgChild1.responsibility", + ]) + .orderBy("orgChild1.orgChild1Order", "ASC") + .getMany() + : []; + + const orgChild1Ids = orgChild1Data.map((orgChild1) => orgChild1.id) || null; + const orgChild2Data = + orgChild1Ids && orgChild1Ids.length > 0 + ? await AppDataSource.getRepository(OrgChild2) + .createQueryBuilder("orgChild2") + .where("orgChild2.orgChild1Id IN (:...ids)", { ids: orgChild1Ids }) + .select([ + "orgChild2.id", + "orgChild2.orgChild2Name", + "orgChild2.orgChild2ShortName", + "orgChild2.orgChild2Code", + "orgChild2.orgChild2Order", + "orgChild2.orgChild2PhoneEx", + "orgChild2.orgChild2PhoneIn", + "orgChild2.orgChild2Fax", + "orgChild2.orgRootId", + "orgChild2.orgChild2Rank", + "orgChild2.orgChild2RankSub", + "orgChild2.orgChild1Id", + "orgChild2.responsibility", + ]) + .orderBy("orgChild2.orgChild2Order", "ASC") + .getMany() + : []; + + const orgChild2Ids = orgChild2Data.map((orgChild2) => orgChild2.id) || null; + const orgChild3Data = + orgChild2Ids && orgChild2Ids.length > 0 + ? await AppDataSource.getRepository(OrgChild3) + .createQueryBuilder("orgChild3") + .where("orgChild3.orgChild2Id IN (:...ids)", { ids: orgChild2Ids }) + .select([ + "orgChild3.id", + "orgChild3.orgChild3Name", + "orgChild3.orgChild3ShortName", + "orgChild3.orgChild3Code", + "orgChild3.orgChild3Order", + "orgChild3.orgChild3PhoneEx", + "orgChild3.orgChild3PhoneIn", + "orgChild3.orgChild3Fax", + "orgChild3.orgRootId", + "orgChild3.orgChild3Rank", + "orgChild3.orgChild3RankSub", + "orgChild3.orgChild2Id", + "orgChild3.responsibility", + ]) + .orderBy("orgChild3.orgChild3Order", "ASC") + .getMany() + : []; + + const orgChild3Ids = orgChild3Data.map((orgChild3) => orgChild3.id) || null; + const orgChild4Data = + orgChild3Ids && orgChild3Ids.length > 0 + ? await AppDataSource.getRepository(OrgChild4) + .createQueryBuilder("orgChild4") + .where("orgChild4.orgChild3Id IN (:...ids)", { ids: orgChild3Ids }) + .select([ + "orgChild4.id", + "orgChild4.orgChild4Name", + "orgChild4.orgChild4ShortName", + "orgChild4.orgChild4Code", + "orgChild4.orgChild4Order", + "orgChild4.orgChild4PhoneEx", + "orgChild4.orgChild4PhoneIn", + "orgChild4.orgChild4Fax", + "orgChild4.orgRootId", + "orgChild4.orgChild4Rank", + "orgChild4.orgChild4RankSub", + "orgChild4.orgChild3Id", + "orgChild4.responsibility", + ]) + .orderBy("orgChild4.orgChild4Order", "ASC") + .getMany() + : []; + + // const formattedData = orgRootData.map((orgRoot) => { + const formattedData = await Promise.all( + orgRootData.map(async (orgRoot) => { + return { + orgTreeId: orgRoot.id, + orgLevel: 0, + orgName: orgRoot.orgRootName, + orgTreeName: orgRoot.orgRootName, + orgTreeShortName: orgRoot.orgRootShortName, + orgTreeCode: orgRoot.orgRootCode, + orgCode: orgRoot.orgRootCode + "00", + orgTreeRank: orgRoot.orgRootRank, + orgTreeRankSub: orgRoot.orgRootRankSub, + orgTreeOrder: orgRoot.orgRootOrder, + orgTreePhoneEx: orgRoot.orgRootPhoneEx, + orgTreePhoneIn: orgRoot.orgRootPhoneIn, + orgTreeFax: orgRoot.orgRootFax, + orgRevisionId: orgRoot.orgRevisionId, + orgRootName: orgRoot.orgRootName, + responsibility: orgRoot.responsibility, + labelName: + orgRoot.orgRootName + " " + orgRoot.orgRootCode + "00" + " " + orgRoot.orgRootShortName, + totalPosition: await this.posMasterRepository.count({ + where: { orgRevisionId: orgRoot.orgRevisionId, orgRootId: orgRoot.id }, + }), + totalPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + current_holderId: IsNull() || "", + }, + }), + totalPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + next_holderId: IsNull() || "", + }, + }), + totalRootPosition: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: IsNull() || "", + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + }, + }), + totalRootPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: IsNull() || "", + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: IsNull() || "", + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + current_holderId: IsNull() || "", + }, + }), + totalRootPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: IsNull() || "", + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: IsNull() || "", + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + next_holderId: IsNull() || "", + }, + }), + + children: await Promise.all( + orgChild1Data + .filter((orgChild1) => orgChild1.orgRootId === orgRoot.id) + .map(async (orgChild1) => ({ + orgTreeId: orgChild1.id, + orgRootId: orgRoot.id, + orgLevel: 1, + orgName: `${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`, + orgTreeName: orgChild1.orgChild1Name, + orgTreeShortName: orgChild1.orgChild1ShortName, + orgTreeCode: orgChild1.orgChild1Code, + orgCode: orgRoot.orgRootCode + orgChild1.orgChild1Code, + orgTreeRank: orgChild1.orgChild1Rank, + orgTreeRankSub: orgChild1.orgChild1RankSub, + orgTreeOrder: orgChild1.orgChild1Order, + orgRootCode: orgRoot.orgRootCode, + orgTreePhoneEx: orgChild1.orgChild1PhoneEx, + orgTreePhoneIn: orgChild1.orgChild1PhoneIn, + orgTreeFax: orgChild1.orgChild1Fax, + orgRevisionId: orgRoot.orgRevisionId, + orgRootName: orgRoot.orgRootName, + responsibility: orgChild1.responsibility, + isOfficer: orgChild1.isOfficer, + labelName: + orgChild1.orgChild1Name + + " " + + orgRoot.orgRootCode + + orgChild1.orgChild1Code + + " " + + orgChild1.orgChild1ShortName, + totalPosition: await this.posMasterRepository.count({ + where: { orgRevisionId: orgRoot.orgRevisionId, orgChild1Id: orgChild1.id }, + }), + totalPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild1Id: orgChild1.id, + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild1Id: orgChild1.id, + current_holderId: IsNull() || "", + }, + }), + totalPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild1Id: orgChild1.id, + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild1Id: orgChild1.id, + next_holderId: IsNull() || "", + }, + }), + totalRootPosition: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + }, + }), + totalRootPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + current_holderId: IsNull() || "", + }, + }), + totalRootPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: IsNull() || "", + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + next_holderId: IsNull() || "", + }, + }), + + children: await Promise.all( + orgChild2Data + .filter((orgChild2) => orgChild2.orgChild1Id === orgChild1.id) + .map(async (orgChild2) => ({ + orgTreeId: orgChild2.id, + orgRootId: orgChild1.id, + orgLevel: 2, + orgName: `${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`, + orgTreeName: orgChild2.orgChild2Name, + orgTreeShortName: orgChild2.orgChild2ShortName, + orgTreeCode: orgChild2.orgChild2Code, + orgCode: orgRoot.orgRootCode + orgChild2.orgChild2Code, + orgTreeRank: orgChild2.orgChild2Rank, + orgTreeRankSub: orgChild2.orgChild2RankSub, + orgTreeOrder: orgChild2.orgChild2Order, + orgRootCode: orgRoot.orgRootCode, + orgTreePhoneEx: orgChild2.orgChild2PhoneEx, + orgTreePhoneIn: orgChild2.orgChild2PhoneIn, + orgTreeFax: orgChild2.orgChild2Fax, + orgRevisionId: orgRoot.orgRevisionId, + orgRootName: orgRoot.orgRootName, + responsibility: orgChild2.responsibility, + labelName: + orgChild2.orgChild2Name + + " " + + orgRoot.orgRootCode + + orgChild2.orgChild2Code + + " " + + orgChild2.orgChild2ShortName, + totalPosition: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild2Id: orgChild2.id, + }, + }), + totalPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild2Id: orgChild2.id, + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild2Id: orgChild2.id, + current_holderId: IsNull() || "", + }, + }), + totalPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild2Id: orgChild2.id, + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild2Id: orgChild2.id, + next_holderId: IsNull() || "", + }, + }), + totalRootPosition: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + }, + }), + totalRootPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + current_holderId: IsNull() || "", + }, + }), + totalRootPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: IsNull() || "", + orgChild4Id: IsNull() || "", + next_holderId: IsNull() || "", + }, + }), + + children: await Promise.all( + orgChild3Data + .filter((orgChild3) => orgChild3.orgChild2Id === orgChild2.id) + .map(async (orgChild3) => ({ + orgTreeId: orgChild3.id, + orgRootId: orgChild2.id, + orgLevel: 3, + orgName: `${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`, + orgTreeName: orgChild3.orgChild3Name, + orgTreeShortName: orgChild3.orgChild3ShortName, + orgTreeCode: orgChild3.orgChild3Code, + orgCode: orgRoot.orgRootCode + orgChild3.orgChild3Code, + orgTreeRank: orgChild3.orgChild3Rank, + orgTreeRankSub: orgChild3.orgChild3RankSub, + orgTreeOrder: orgChild3.orgChild3Order, + orgRootCode: orgRoot.orgRootCode, + orgTreePhoneEx: orgChild3.orgChild3PhoneEx, + orgTreePhoneIn: orgChild3.orgChild3PhoneIn, + orgTreeFax: orgChild3.orgChild3Fax, + orgRevisionId: orgRoot.orgRevisionId, + orgRootName: orgRoot.orgRootName, + responsibility: orgChild3.responsibility, + labelName: + orgChild3.orgChild3Name + + " " + + orgRoot.orgRootCode + + orgChild3.orgChild3Code + + " " + + orgChild3.orgChild3ShortName, + totalPosition: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild3Id: orgChild3.id, + }, + }), + totalPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild3Id: orgChild3.id, + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild3Id: orgChild3.id, + current_holderId: IsNull() || "", + }, + }), + totalPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild3Id: orgChild3.id, + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild3Id: orgChild3.id, + next_holderId: IsNull() || "", + }, + }), + totalRootPosition: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: IsNull() || "", + }, + }), + totalRootPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: IsNull() || "", + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: IsNull() || "", + current_holderId: IsNull() || "", + }, + }), + totalRootPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: IsNull() || "", + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: IsNull() || "", + next_holderId: IsNull() || "", + }, + }), + + children: await Promise.all( + orgChild4Data + .filter((orgChild4) => orgChild4.orgChild3Id === orgChild3.id) + .map(async (orgChild4) => ({ + orgTreeId: orgChild4.id, + orgRootId: orgChild3.id, + orgLevel: 4, + orgName: `${orgChild4.orgChild4Name}/${orgChild3.orgChild3Name}/${orgChild2.orgChild2Name}/${orgChild1.orgChild1Name}/${orgRoot.orgRootName}`, + orgTreeName: orgChild4.orgChild4Name, + orgTreeShortName: orgChild4.orgChild4ShortName, + orgTreeCode: orgChild4.orgChild4Code, + orgCode: orgRoot.orgRootCode + orgChild4.orgChild4Code, + orgTreeRank: orgChild4.orgChild4Rank, + orgTreeRankSub: orgChild4.orgChild4RankSub, + orgTreeOrder: orgChild4.orgChild4Order, + orgRootCode: orgRoot.orgRootCode, + orgTreePhoneEx: orgChild4.orgChild4PhoneEx, + orgTreePhoneIn: orgChild4.orgChild4PhoneIn, + orgTreeFax: orgChild4.orgChild4Fax, + orgRevisionId: orgRoot.orgRevisionId, + orgRootName: orgRoot.orgRootName, + responsibility: orgChild4.responsibility, + labelName: + orgChild4.orgChild4Name + + " " + + orgRoot.orgRootCode + + orgChild4.orgChild4Code + + " " + + orgChild4.orgChild4ShortName, + totalPosition: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild4Id: orgChild4.id, + }, + }), + totalPositionCurrentUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild4Id: orgChild4.id, + current_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionCurrentVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild4Id: orgChild4.id, + current_holderId: IsNull() || "", + }, + }), + totalPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild4Id: orgChild4.id, + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalPositionNextVacant: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgChild4Id: orgChild4.id, + next_holderId: IsNull() || "", + }, + }), + totalRootPosition: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: orgChild4.id, + }, + }), + totalRootPositionCurrentUse: await this.posMasterRepository.count( + { + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: orgChild4.id, + current_holderId: Not(IsNull()) || Not(""), + }, + }, + ), + totalRootPositionCurrentVacant: + await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: orgChild4.id, + current_holderId: IsNull() || "", + }, + }), + totalRootPositionNextUse: await this.posMasterRepository.count({ + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: orgChild4.id, + next_holderId: Not(IsNull()) || Not(""), + }, + }), + totalRootPositionNextVacant: await this.posMasterRepository.count( + { + where: { + orgRevisionId: orgRoot.orgRevisionId, + orgRootId: orgRoot.id, + orgChild1Id: orgChild1.id, + orgChild2Id: orgChild2.id, + orgChild3Id: orgChild3.id, + orgChild4Id: orgChild4.id, + next_holderId: IsNull() || "", + }, + }, + ), + })), + ), + })), + ), + })), + ), + })), + ), + }; + }), + ); + + return new HttpSuccess(formattedData); + } + /** * API รายละเอียดโครงสร้าง * @@ -1454,7 +2231,6 @@ export class OrganizationController extends Controller { child3: null, child4: null, }; - console.log(_data); } const orgRootData = await AppDataSource.getRepository(OrgRoot) @@ -5739,9 +6515,9 @@ export class OrganizationController extends Controller { return new HttpSuccess(formattedData); } /** - * API เช็คสกจในระบบ + * API เช็ค org ในระบบ * - * @summary - เช็คสกจในระบบ (ADMIN) + * @summary - เช็ค org ในระบบ (ADMIN) * */ @Get("check/child1/{id}") @@ -5756,4 +6532,206 @@ export class OrganizationController extends Controller { const check = orgRevision.orgChild1s.find((x) => x.isOfficer == true); return new HttpSuccess(check != null); } + public async listAuthSysOrgFuncByRevisionIdN( + request: RequestWithUser, + system: string, + revisionId: string, + ) { + let profile = await this.profileRepo.findOne({ + where: { + keycloak: request.user.sub, + }, + relations: ["next_holders", "next_holders.authRole", "next_holders.authRole.authRoles"], + }); + let data: any = { + root: [null], + child1: [null], + child2: [null], + child3: [null], + child4: [null], + }; + if (!profile) { + return { + root: null, + child1: null, + child2: null, + child3: null, + child4: null, + }; + } + + let attrOwnership = + profile?.next_holders + .filter((x) => x.orgRevisionId == revisionId)[0] + ?.authRole?.authRoles?.filter((x) => x.authSysId == system)[0]?.attrOwnership || null; + + let attrPrivilege = + profile?.next_holders + .filter((x) => x.orgRevisionId == revisionId)[0] + ?.authRole?.authRoles?.filter((x) => x.authSysId == system)[0]?.attrPrivilege || null; + + const posMaster = await this.posMasterRepository.findOne({ + where: { + next_holderId: profile.id, + orgRevisionId: revisionId, + }, + }); + if (!posMaster) { + data = { + root: [null], + child1: [null], + child2: [null], + child3: [null], + child4: [null], + }; + } else if (attrOwnership == "OWNER") { + data = { + root: null, + child1: null, + child2: null, + child3: null, + child4: null, + }; + } else if (attrPrivilege == "ROOT") { + data = { + root: [posMaster.orgRootId], + child1: null, + child2: null, + child3: null, + child4: null, + privilege: "ROOT", + }; + } else if (attrPrivilege == "CHILD") { + let node = 4; + if (posMaster.orgChild1Id == null) { + node = 0; + } else if (posMaster.orgChild2Id == null) { + node = 1; + } else if (posMaster.orgChild3Id == null) { + node = 2; + } else if (posMaster.orgChild4Id == null) { + node = 3; + } + data = { + root: node >= 0 ? [posMaster.orgRootId] : null, + child1: node >= 1 ? [posMaster.orgChild1Id] : null, + child2: node >= 2 ? [posMaster.orgChild2Id] : null, + child3: node >= 3 ? [posMaster.orgChild3Id] : null, + child4: node >= 4 ? [posMaster.orgChild4Id] : null, + }; + } else if (attrPrivilege == "NORMAL") { + data = { + root: [posMaster.orgRootId], + child1: [posMaster.orgChild1Id], + child2: [posMaster.orgChild2Id], + child3: [posMaster.orgChild3Id], + child4: [posMaster.orgChild4Id], + }; + } else if (attrPrivilege == "SPECIFIC") { + } + return data; + } + public async listAuthSysOrgFuncByRevisionIdC( + request: RequestWithUser, + system: string, + revisionId: string, + ) { + let profile = await this.profileRepo.findOne({ + where: { + keycloak: request.user.sub, + }, + relations: [ + "current_holders", + "current_holders.authRole", + "current_holders.authRole.authRoles", + ], + }); + let data: any = { + root: [null], + child1: [null], + child2: [null], + child3: [null], + child4: [null], + }; + if (!profile) { + return { + root: null, + child1: null, + child2: null, + child3: null, + child4: null, + }; + } + + let attrOwnership = + profile?.current_holders + .filter((x) => x.orgRevisionId == revisionId)[0] + ?.authRole?.authRoles?.filter((x) => x.authSysId == system)[0]?.attrOwnership || null; + + let attrPrivilege = + profile?.current_holders + .filter((x) => x.orgRevisionId == revisionId)[0] + ?.authRole?.authRoles?.filter((x) => x.authSysId == system)[0]?.attrPrivilege || null; + + const posMaster = await this.posMasterRepository.findOne({ + where: { + next_holderId: profile.id, + orgRevisionId: revisionId, + }, + }); + if (!posMaster) { + data = { + root: [null], + child1: [null], + child2: [null], + child3: [null], + child4: [null], + }; + } else if (attrOwnership == "OWNER") { + data = { + root: null, + child1: null, + child2: null, + child3: null, + child4: null, + }; + } else if (attrPrivilege == "ROOT") { + data = { + root: [posMaster.orgRootId], + child1: null, + child2: null, + child3: null, + child4: null, + privilege: "ROOT", + }; + } else if (attrPrivilege == "CHILD") { + let node = 4; + if (posMaster.orgChild1Id == null) { + node = 0; + } else if (posMaster.orgChild2Id == null) { + node = 1; + } else if (posMaster.orgChild3Id == null) { + node = 2; + } else if (posMaster.orgChild4Id == null) { + node = 3; + } + data = { + root: node >= 0 ? [posMaster.orgRootId] : null, + child1: node >= 1 ? [posMaster.orgChild1Id] : null, + child2: node >= 2 ? [posMaster.orgChild2Id] : null, + child3: node >= 3 ? [posMaster.orgChild3Id] : null, + child4: node >= 4 ? [posMaster.orgChild4Id] : null, + }; + } else if (attrPrivilege == "NORMAL") { + data = { + root: [posMaster.orgRootId], + child1: [posMaster.orgChild1Id], + child2: [posMaster.orgChild2Id], + child3: [posMaster.orgChild3Id], + child4: [posMaster.orgChild4Id], + }; + } else if (attrPrivilege == "SPECIFIC") { + } + return data; + } } diff --git a/src/controllers/PermissionController.ts b/src/controllers/PermissionController.ts index fb9f67a6..0b10b738 100644 --- a/src/controllers/PermissionController.ts +++ b/src/controllers/PermissionController.ts @@ -310,7 +310,6 @@ export class PermissionController extends Controller { } let privilege = await this.Permission(request, system, action); - console.log(privilege); let reply = await getAsync("posMaster_" + profile.id); if (reply != null) { reply = JSON.parse(reply); @@ -685,19 +684,6 @@ export class PermissionController extends Controller { } public async PermissionOrg(req: RequestWithUser, system: string, action: string) { - // if ( - // req.headers.hasOwnProperty("api_key") && - // req.headers["api_key"] && - // req.headers["api_key"] == process.env.API_KEY - // ) { - // return { - // root: null, - // child1: null, - // child2: null, - // child3: null, - // child4: null, - // }; - // } let x: any = await this.listAuthSysOrgFunc(req, system, action); let privilege = x.privilege; diff --git a/src/controllers/PermissionOrgController.ts b/src/controllers/PermissionOrgController.ts index 9cd157f5..1e17ac8e 100644 --- a/src/controllers/PermissionOrgController.ts +++ b/src/controllers/PermissionOrgController.ts @@ -25,6 +25,10 @@ import { RequestWithUser } from "../middlewares/user"; import { PermissionOrg } from "../entities/PermissionOrg"; import { Profile } from "../entities/Profile"; import HttpStatus from "../interfaces/http-status"; +import permission from "../interfaces/permission"; +import { PosMaster } from "../entities/PosMaster"; +import { EmployeePosMaster } from "../entities/EmployeePosMaster"; +import { ProfileEmployee } from "../entities/ProfileEmployee"; @Route("api/v1/org/permission-org") @Tags("PermissionOrg") @@ -39,6 +43,10 @@ export class PermissionOrgController extends Controller { private profileRepository = AppDataSource.getRepository(Profile); private orgRevisionRepository = AppDataSource.getRepository(OrgRevision); private permissionOrgRepository = AppDataSource.getRepository(PermissionOrg); + private posMasterRepository = AppDataSource.getRepository(PosMaster); + private posMasterEmpRepository = AppDataSource.getRepository(EmployeePosMaster); + private profileRepo = AppDataSource.getRepository(Profile); + private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee); /** * API หาสำนักทั้งหมดแบบร่าง @@ -48,22 +56,35 @@ export class PermissionOrgController extends Controller { */ @Get() async GetActiveRootIdAdmin(@Request() request: RequestWithUser) { - // if (!request.user.role.includes("SUPER_ADMIN")) { - // throw new HttpError(HttpStatus.FORBIDDEN, "ไม่มีสิทธิ์ใช้งานระบบนี้"); - // } const orgRevisionActive = await this.orgRevisionRepository.findOne({ where: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true }, + relations: ["posMasters"], }); - if (!orgRevisionActive) { - throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่แบบร่างอยู่ตอนนี้"); - } + if (!orgRevisionActive) return new HttpSuccess([]); + let rootId: any = null; + if (!request.user.role.includes("SUPER_ADMIN")) { + const profile = await this.profileRepo.findOne({ + where: { + keycloak: request.user.sub, + }, + }); + if (profile == null) return new HttpSuccess([]); - const data = await this.orgRootRepository.find({ - where: { orgRevisionId: orgRevisionActive.id }, - order: { - orgRootOrder: "ASC", - }, - }); + if (!request.user.role.includes("SUPER_ADMIN")) { + rootId = + orgRevisionActive?.posMasters?.filter((x) => x.next_holderId == profile.id)[0] + ?.orgRootId || null; + if (!rootId) return new HttpSuccess([]); + } + } + const data = await AppDataSource.getRepository(OrgRoot) + .createQueryBuilder("orgRoot") + .where("orgRoot.orgRevisionId = :id", { id: orgRevisionActive.id }) + .andWhere(rootId != null ? `orgRoot.id = :rootId` : "1=1", { + rootId: rootId, + }) + .orderBy("orgRoot.orgRootOrder", "ASC") + .getMany(); return new HttpSuccess(data); } @@ -500,4 +521,38 @@ export class PermissionOrgController extends Controller { await this.permissionOrgRepository.delete(_delPermissionOrg.id); return new HttpSuccess(); } + public async listAuthSysOrgFuncByRevisionId( + request: RequestWithUser, + system: string, + revisionId: string, + ) { + let profile = await this.profileRepo.findOne({ + where: { + keycloak: request.user.sub, + }, + relations: ["next_holders", "next_holders.authRole", "next_holders.authRole.authRoles"], + }); + if (!profile) { + return [null]; + } + + let attrOwnership = + profile?.next_holders + .filter((x) => x.orgRevisionId == revisionId)[0] + ?.authRole?.authRoles?.filter((x) => x.authSysId == system)[0]?.attrOwnership || null; + + const posMaster = await this.posMasterRepository.findOne({ + where: { + next_holderId: profile.id, + orgRevisionId: revisionId, + }, + }); + if (!posMaster) { + return [null]; + } else if (attrOwnership == "OWNER") { + return null; + } else { + return [posMaster.orgRootId]; + } + } } diff --git a/src/controllers/ProfileController.ts b/src/controllers/ProfileController.ts index e24a7cad..2b06b51d 100644 --- a/src/controllers/ProfileController.ts +++ b/src/controllers/ProfileController.ts @@ -63,6 +63,7 @@ import { updateName } from "../keycloak"; import permission from "../interfaces/permission"; import { PosMasterAct } from "../entities/PosMasterAct"; import axios from "axios"; +import { OrgChild1 } from "../entities/OrgChild1"; @Route("api/v1/org/profile") @Tags("Profile") @Security("bearerAuth") @@ -101,6 +102,7 @@ export class ProfileController extends Controller { private disciplineHistoryRepository = AppDataSource.getRepository(ProfileDisciplineHistory); private profileLeaveRepository = AppDataSource.getRepository(ProfileLeave); private posMasterActRepository = AppDataSource.getRepository(PosMasterAct); + private orgChild1Repository = AppDataSource.getRepository(OrgChild1); /** * report ประวัติแบบย่อ ข้าราชการ @@ -934,6 +936,91 @@ export class ProfileController extends Controller { return new HttpSuccess({ caregiver, commander, chairman }); } + + /** + * API + * + * @summary API + * + */ + @Get("admin-keycloak") + async listProfileIdByorg(@Request() request: RequestWithUser) { + let _data: any = { + root: null, + child1: null, + child2: null, + child3: null, + child4: null, + }; + if (!request.user.role.includes("SUPER_ADMIN")) { + _data = await new permission().PermissionOrgList(request, "SYS_ORG"); + } + const profiles = await this.profileRepo + .createQueryBuilder("profile") + .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") + .andWhere( + _data.root != undefined && _data.root != null + ? _data.root[0] != null + ? `current_holders.orgRootId IN (:...root)` + : `current_holders.orgRootId is null` + : "1=1", + { + root: _data.root, + }, + ) + .andWhere( + _data.child1 != undefined && _data.child1 != null + ? _data.child1[0] != null + ? `current_holders.orgChild1Id IN (:...child1)` + : `current_holders.orgChild1Id is null` + : "1=1", + { + child1: _data.child1, + }, + ) + .andWhere( + _data.child2 != undefined && _data.child2 != null + ? _data.child2[0] != null + ? `current_holders.orgChild2Id IN (:...child2)` + : `current_holders.orgChild2Id is null` + : "1=1", + { + child2: _data.child2, + }, + ) + .andWhere( + _data.child3 != undefined && _data.child3 != null + ? _data.child3[0] != null + ? `current_holders.orgChild3Id IN (:...child3)` + : `current_holders.orgChild3Id is null` + : "1=1", + { + child3: _data.child3, + }, + ) + .andWhere( + _data.child4 != undefined && _data.child4 != null + ? _data.child4[0] != null + ? `current_holders.orgChild4Id IN (:...child4)` + : `current_holders.orgChild4Id is null` + : "1=1", + { + child4: _data.child4, + }, + ) + .andWhere({ keycloak: Not(IsNull()) }) + .andWhere({ keycloak: Not("") }) + .select("profile.keycloak", "keycloak") + .getRawMany(); + const keycloakArray = profiles.map((p) => p.keycloak); + + return new HttpSuccess(keycloakArray); + } /** * * @@ -3407,6 +3494,32 @@ export class ProfileController extends Controller { return new HttpSuccess(_profile); } + /** + * API เช็ค สกจ + * + * @summary เช็ค สกจ + * + */ + @Get("keycloak/idofficer") + async getIsOfficerByKeycloak(@Request() request: RequestWithUser) { + const posMasters = await this.posMasterRepo.findOne({ + where: { + current_holder: { + keycloak: request.user.sub, + }, + orgRevision: { + orgRevisionIsCurrent: true, + orgRevisionIsDraft: false, + }, + }, + relations: ["orgChild1"], + }); + if (posMasters == null || posMasters.orgRoot == null) { + return new HttpSuccess(false); + } + return new HttpSuccess(posMasters); + } + /** * API ข้อมูลทะเบียนประวัติตาม keycloakid * @@ -4800,6 +4913,7 @@ export class ProfileController extends Controller { const isProbation: boolean = true; const [findProfile, total] = await AppDataSource.getRepository(Profile) .createQueryBuilder("profile") + .leftJoinAndSelect("profile.profileSalary", "profileSalary") .leftJoinAndSelect("profile.posLevel", "posLevel") .leftJoinAndSelect("profile.posType", "posType") .leftJoinAndSelect("profile.current_holders", "current_holders") @@ -4914,9 +5028,13 @@ export class ProfileController extends Controller { lastName: item.lastName, position: item.position, idcard: item.citizenId, + refCommandNo: + item.profileSalary.sort((a, b) => b.order - a.order).length == 0 + ? null + : item.profileSalary.sort((a, b) => b.order - a.order)[0].refCommandNo, posLevelName: item.posLevel == null ? null : item.posLevel.posLevelName, posTypeName: item.posType == null ? null : item.posType.posTypeName, - posNo: `${posMaster == null ? null : posMaster.posMasterNo}${shortName}`, + posNo: posMaster == null ? null : `${posMaster.posMasterNo}${shortName}`, positionField: position == null ? null : position.positionField, positionArea: position == null ? null : position.positionArea, posExecutiveName: posExecutive, diff --git a/src/controllers/ProfileDevelopmentController.ts b/src/controllers/ProfileDevelopmentController.ts index 76aab0fa..08948b7c 100644 --- a/src/controllers/ProfileDevelopmentController.ts +++ b/src/controllers/ProfileDevelopmentController.ts @@ -10,6 +10,7 @@ import { Route, Security, Tags, + Query } from "tsoa"; import { AppDataSource } from "../database/data-source"; import HttpSuccess from "../interfaces/http-success"; @@ -25,7 +26,7 @@ import { } from "../entities/ProfileDevelopment"; import permission from "../interfaces/permission"; import { DevelopmentProject } from "../entities/DevelopmentProject"; -import { In } from "typeorm"; +import { In, Brackets } from "typeorm"; @Route("api/v1/org/profile/development") @Tags("ProfileDevelopment") @Security("bearerAuth") @@ -49,13 +50,58 @@ export class ProfileDevelopmentController extends Controller { } @Get("{profileId}") - public async getDevelopment(@Path() profileId: string, @Request() req: RequestWithUser) { + public async getDevelopment( + @Path() profileId: string, + @Request() req: RequestWithUser, + @Query("page") page: number = 1, + @Query("pageSize") pageSize: number = 10, + @Query() searchKeyword: string = "", + ) { await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_OFFICER", profileId); - const lists = await this.developmentRepository.find({ - where: { profileId: profileId }, - order: { createdAt: "ASC" }, - }); - return new HttpSuccess(lists); + const [profileDevelopment, total] = await AppDataSource.getRepository(ProfileDevelopment) + .createQueryBuilder("profileDevelopment") + .where({ profileId: profileId }) + .andWhere( + new Brackets((qb) => { + qb.where( + searchKeyword != undefined && searchKeyword != null && searchKeyword != "" + ? "profileDevelopment.name LIKE :keyword" + : "1=1", + { + keyword: `%${searchKeyword}%`, + }, + ) + .orWhere( + searchKeyword != undefined && searchKeyword != null && searchKeyword != "" + ? "profileDevelopment.developmentTarget LIKE :keyword" + : "1=1", + { + keyword: `%${searchKeyword}%`, + }, + ) + .orWhere( + searchKeyword != undefined && searchKeyword != null && searchKeyword != "" + ? "profileDevelopment.developmentResults LIKE :keyword" + : "1=1", + { + keyword: `%${searchKeyword}%`, + }, + ) + .orWhere( + searchKeyword != undefined && searchKeyword != null && searchKeyword != "" + ? "profileDevelopment.developmentReport LIKE :keyword" + : "1=1", + { + keyword: `%${searchKeyword}%`, + }, + ); + }), + ) + .orderBy("profileDevelopment.createdAt", "ASC") + .skip((page - 1) * pageSize) + .take(pageSize) + .getManyAndCount(); + return new HttpSuccess({ data: profileDevelopment, total }); } @Get("history/{developmentId}") diff --git a/src/controllers/ProfileEditController.ts b/src/controllers/ProfileEditController.ts index fac2767d..f1b9d7c8 100644 --- a/src/controllers/ProfileEditController.ts +++ b/src/controllers/ProfileEditController.ts @@ -122,6 +122,8 @@ export class ProfileEditController extends Controller { .getManyAndCount(); const _data = getProfileEdit.map((item) => ({ id: item.id, + idcard: item.profile.citizenId, + profileId: item.profile.id, topic: item.topic, detail: item.detail, status: item.status, @@ -151,10 +153,10 @@ export class ProfileEditController extends Controller { // return new HttpSuccess(getProfileEdit); // } - @Get("{profileId}") - public async detailProfileEdit(@Path() profileId: string) { + @Get("{id}") + public async detailProfileEdit(@Path() id: string) { const getProfileEdit = await this.profileEditRepo.findOne({ - where: { profileId: profileId }, + where: { id: id }, relations: ["profile"], }); if (!getProfileEdit) { diff --git a/src/controllers/ProfileEditEmployeeController.ts b/src/controllers/ProfileEditEmployeeController.ts index d4cdda23..7d8ef83e 100644 --- a/src/controllers/ProfileEditEmployeeController.ts +++ b/src/controllers/ProfileEditEmployeeController.ts @@ -129,6 +129,8 @@ export class ProfileEditEmployeeController extends Controller { const _data = getProfileEdit.map((item) => ({ id: item.id, + idcard: item.profile.citizenId, + profileId: item.profile.id, topic: item.topic, detail: item.detail, status: item.status, diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 280fd12d..456de900 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -30,11 +30,15 @@ import { getRoleMappings, getUserCount, enableStatus, + getUserCountOrg, + getUserListOrg, } from "../keycloak"; import { AppDataSource } from "../database/data-source"; import { Profile } from "../entities/Profile"; import { ProfileEmployee } from "../entities/ProfileEmployee"; -import { IsNull } from "typeorm"; +import { IsNull, Not } from "typeorm"; +import { RequestWithUser } from "../middlewares/user"; +import permission from "../interfaces/permission"; // import * as io from "../lib/websocket"; // import elasticsearch from "../elasticsearch"; // import { StorageFolder } from "../interfaces/storage-fs"; @@ -94,7 +98,6 @@ export class KeycloakController extends Controller { firstName: body.firstName, lastName: body.lastName, email: body.email, - requiredActions: ["UPDATE_PASSWORD"], }); if (typeof userId !== "string") { @@ -239,7 +242,89 @@ export class KeycloakController extends Controller { } @Get("user") - async getUserList(@Query() first = "", @Query() max = "", @Query() search = "") { + async getUserList( + @Request() request: RequestWithUser, + @Query() first = "", + @Query() max = "", + @Query() search = "", + ) { + // let _data: any = { + // root: null, + // child1: null, + // child2: null, + // child3: null, + // child4: null, + // }; + // if (!request.user.role.includes("SUPER_ADMIN")) { + // _data = await new permission().PermissionOrgList(request, "SYS_ORG"); + // } + // const profiles = await this.profileRepo + // .createQueryBuilder("profile") + // .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") + // .andWhere( + // _data.root != undefined && _data.root != null + // ? _data.root[0] != null + // ? `current_holders.orgRootId IN (:...root)` + // : `current_holders.orgRootId is null` + // : "1=1", + // { + // root: _data.root, + // }, + // ) + // .andWhere( + // _data.child1 != undefined && _data.child1 != null + // ? _data.child1[0] != null + // ? `current_holders.orgChild1Id IN (:...child1)` + // : `current_holders.orgChild1Id is null` + // : "1=1", + // { + // child1: _data.child1, + // }, + // ) + // .andWhere( + // _data.child2 != undefined && _data.child2 != null + // ? _data.child2[0] != null + // ? `current_holders.orgChild2Id IN (:...child2)` + // : `current_holders.orgChild2Id is null` + // : "1=1", + // { + // child2: _data.child2, + // }, + // ) + // .andWhere( + // _data.child3 != undefined && _data.child3 != null + // ? _data.child3[0] != null + // ? `current_holders.orgChild3Id IN (:...child3)` + // : `current_holders.orgChild3Id is null` + // : "1=1", + // { + // child3: _data.child3, + // }, + // ) + // .andWhere( + // _data.child4 != undefined && _data.child4 != null + // ? _data.child4[0] != null + // ? `current_holders.orgChild4Id IN (:...child4)` + // : `current_holders.orgChild4Id is null` + // : "1=1", + // { + // child4: _data.child4, + // }, + // ) + // .andWhere({ keycloak: Not(IsNull()) }) + // .andWhere({ keycloak: Not("") }) + // .select("profile.keycloak", "keycloak") + // .getRawMany(); + // let keycloakArray = profiles.map((p) => p.keycloak); + + // const total = await getUserCountOrg(first, max, search, keycloakArray); + // const result = await getUserListOrg(first, max, search, keycloakArray); + const total = await getUserCount(first, max, search); const result = await getUserList(first, max, search); diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts new file mode 100644 index 00000000..45de5fa2 --- /dev/null +++ b/src/controllers/WorkflowController.ts @@ -0,0 +1,254 @@ +import { Body, Controller, Post, Request, Route, Security, Tags } from "tsoa"; +import { AppDataSource } from "../database/data-source"; +import { RequestWithUser } from "../middlewares/user"; +import HttpError from "../interfaces/http-error"; +import HttpStatus from "../interfaces/http-status"; +import HttpSuccess from "../interfaces/http-success"; +import { Workflow } from "../entities/Workflow"; +import { State } from "../entities/State"; +import { StateOperator } from "../entities/StateOperator"; +import { StateOperatorUser } from "../entities/StateOperatorUser"; +import CallAPI from "../interfaces/call-api"; +import { Profile } from "../entities/Profile"; + +@Route("api/v1/org/workflow") +@Tags("AuthRole") +@Security("bearerAuth") +export class WorkflowController extends Controller { + private workflowRepo = AppDataSource.getRepository(Workflow); + private stateRepo = AppDataSource.getRepository(State); + private stateOperatorRepo = AppDataSource.getRepository(StateOperator); + private stateOperatorUserRepo = AppDataSource.getRepository(StateOperatorUser); + private profileRepo = AppDataSource.getRepository(Profile); + + @Post("check-workflow") + public async checkWorkflow( + @Request() req: RequestWithUser, + @Body() + body: { + sysName: string; + posLevelName: string; + posTypeName: string; + profiles: { + profile: string; + operator: string; + order: number; + }[]; + }, + ) { + const workflow = await this.workflowRepo.findOne({ + where: { + sysName: body.sysName, + posLevelName: body.posLevelName, + posTypeName: body.posTypeName, + }, + relations: ["states"], + }); + if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบกระบวนการนี้ได้"); + await Promise.all( + body.profiles.map(async (item) => { + const operatoeUser = new StateOperatorUser(); + operatoeUser.profile = item.profile; + operatoeUser.operator = item.operator.trim().toLocaleUpperCase(); + operatoeUser.order = item.order; + operatoeUser.workflowId = workflow.id; + operatoeUser.createdUserId = req.user.sub; + operatoeUser.createdFullName = req.user.name; + operatoeUser.createdAt = new Date(); + operatoeUser.lastUpdateUserId = req.user.sub; + operatoeUser.lastUpdateFullName = req.user.name; + operatoeUser.lastUpdatedAt = new Date(); + await this.stateOperatorUserRepo.save(operatoeUser); + }), + ); + return new HttpSuccess({ + workflowId: workflow.id, + stateId: workflow.states.sort((a, b) => a.order - b.order)[0].id, + // stateName: workflow.states.sort((a, b) => a.order - b.order)[0].name, + // stateType: workflow.states.sort((a, b) => a.order - b.order)[0].type, + }); + } + + @Post("check-iscan") + public async checkIsCan( + @Request() req: RequestWithUser, + @Body() + body: { + workflowId: string; + stateId: string; + profile: string; + action: string; + }, + ) { + const stateOperatorUser = await this.stateOperatorUserRepo.findOne({ + where: { + profile: body.profile, + workflowId: body.workflowId, + }, + }); + if (!stateOperatorUser) + throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); + + const operator = await this.stateOperatorRepo.findOne({ + where: { + operator: stateOperatorUser.operator, + state: { id: body.stateId, workflow: { id: body.workflowId } }, + }, + }); + if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + + let isCan = false; + switch (body.action.trim().toLocaleUpperCase()) { + case "VIEW": + isCan = operator.canView; + case "UPDATE": + isCan = operator.canUpdate; + case "DELETE": + isCan = operator.canDelete; + case "CANCEL": + isCan = operator.canCancel; + case "OPERATE": + isCan = operator.canOperate; + case "CHANGESTATE": + isCan = operator.canChangeState; + case "COMMENT": + isCan = operator.canComment; + case "SIGN": + isCan = operator.canSign; + default: + isCan = false; + } + if (isCan == false) { + throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการได้"); + } else { + return new HttpSuccess(); + } + } + + @Post("check-iscan-all") + public async checkIsCanAll( + @Request() req: RequestWithUser, + @Body() + body: { + workflowId: string; + stateId: string; + }, + ) { + const profile = await this.profileRepo.findOne({ + where: { + keycloak: req.user.sub, + }, + }); + if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + const stateOperatorUser = await this.stateOperatorUserRepo.findOne({ + where: { + profile: profile.id, + workflowId: body.workflowId, + }, + }); + if (!stateOperatorUser) + throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); + + const operator = await this.stateOperatorRepo.findOne({ + where: { + operator: stateOperatorUser.operator, + state: { id: body.stateId, workflow: { id: body.workflowId } }, + }, + }); + if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + return new HttpSuccess(operator); + } + + @Post("state-next") + public async stateNext( + @Request() req: RequestWithUser, + @Body() + body: { + stateId: string; + }, + ) { + const state = await this.stateRepo.findOne({ + where: { + id: body.stateId, + }, + relations: ["stateOperators", "workflow", "workflow.stateOperatorUsers"], + }); + if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + const _state = await this.stateRepo.findOne({ + where: { + order: state.order + 1, + workflowId: state.workflowId, + }, + relations: ["stateOperators"], + }); + //noti + let profileNow = state.workflow.stateOperatorUsers + .filter((x) => state.stateOperators.map((s) => s.operator).includes(x.operator)) + .map((x) => x.profile); + await new CallAPI() + .PostData(req, "/placement/noti/profiles", { + subject: `รายการถูกส่ง`, + body: `รายการถูกส่ง`, + receiverUserId: profileNow, + payload: "", //แนบไฟล์ + isSendMail: true, + isSendInbox: true, + isSendNotification: true, + }) + .catch((error) => { + console.error("Error calling API:", error); + }); + if (_state != null) { + let profileNext = state.workflow.stateOperatorUsers + .filter((x) => _state.stateOperators.map((s) => s.operator).includes(x.operator)) + .map((x) => x.profile); + await new CallAPI() + .PostData(req, "/placement/noti/profiles", { + subject: `ได้รับรายการ`, + body: `ได้รับรายการ`, + receiverUserId: profileNext, + payload: "", //แนบไฟล์ + isSendMail: true, + isSendInbox: true, + isSendNotification: true, + }) + .catch((error) => { + console.error("Error calling API:", error); + }); + } + + return new HttpSuccess({ + stateId: _state?.id || null, + stateName: _state?.name || null, + stateType: _state?.type || null, + }); + } + + @Post("state-back") + public async stateBack( + @Request() req: RequestWithUser, + @Body() + body: { + stateId: string; + }, + ) { + const state = await this.stateRepo.findOne({ + where: { + id: body.stateId, + }, + }); + if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + const _state = await this.stateRepo.findOne({ + where: { + order: state.order - 1, + workflowId: state.workflowId, + }, + }); + + return new HttpSuccess({ + stateId: _state?.id || null, + stateName: _state?.name || null, + stateType: _state?.type || null, + }); + } +} diff --git a/src/entities/Command.ts b/src/entities/Command.ts index 2819176d..3254aac7 100644 --- a/src/entities/Command.ts +++ b/src/entities/Command.ts @@ -94,11 +94,11 @@ export class Command extends EntityBase { @Column({ nullable: true, - default: null, - type: "boolean", comment: "คำสั่งกรุงเทพมหานคร", + length: 20, + default: null, }) - isBangkok: boolean; + isBangkok: string; @Column({ comment: "สถานะบัญชีแนบท้าย", diff --git a/src/entities/CommandSys.ts b/src/entities/CommandSys.ts index 77c1be5d..7e50f3ae 100644 --- a/src/entities/CommandSys.ts +++ b/src/entities/CommandSys.ts @@ -9,6 +9,7 @@ import { import { CommandType } from "./CommandType"; import { CommandSalary } from "./CommandSalary"; import { Assign } from "./Assign"; +import { Workflow } from "./Workflow"; @Entity("commandSys") export class CommandSys { @@ -75,6 +76,9 @@ export class CommandSys { @OneToMany(() => Assign, (assgin) => assgin.commandAssignSys) assgins: Assign[]; + + // @OneToMany(() => Workflow, (workflow) => workflow.commandSys) + // workflows: Workflow[]; } export class CreateCommandSys { diff --git a/src/entities/MetaState.ts b/src/entities/MetaState.ts new file mode 100644 index 00000000..fa2cf5ec --- /dev/null +++ b/src/entities/MetaState.ts @@ -0,0 +1,46 @@ +import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { MetaStateOperator } from "./MetaStateOperator"; +import { Workflow } from "./Workflow"; +import { metaWorkflow } from "./MetaWorkflow"; + +@Entity("metaState") +export class MetaState extends EntityBase { + @Column({ + nullable: true, + comment: "ชื่อประเภทขั้นตอน", + length: 255, + default: null, + }) + name: string; + + @Column({ + nullable: true, + comment: "ประเภทขั้นตอน", + length: 255, + default: null, + }) + type: string; + + @Column({ + nullable: true, + comment: "ลำดับ", + default: null, + }) + order: number; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง metaWorkflow", + default: null, + }) + metaWorkflowId: string; + + @ManyToOne(() => metaWorkflow, (metaWorkflow) => metaWorkflow.metaStates) + @JoinColumn({ name: "metaWorkflowId" }) + metaWorkflow: metaWorkflow; + + @OneToMany(() => MetaStateOperator, (metaStateOperator) => metaStateOperator.metaState) + metaStateOperators: MetaStateOperator[]; +} diff --git a/src/entities/MetaStateOperator.ts b/src/entities/MetaStateOperator.ts new file mode 100644 index 00000000..f23c1c7f --- /dev/null +++ b/src/entities/MetaStateOperator.ts @@ -0,0 +1,74 @@ +import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { MetaState } from "./MetaState"; + +@Entity("metaStateOperator") +export class MetaStateOperator extends EntityBase { + @Column({ + nullable: true, + comment: "ผู้ดำเนินการ", + length: 255, + default: null, + }) + operator: string; + + @Column({ + comment: "ดูเอกสาร", + default: false, + }) + canView: boolean; + + @Column({ + comment: "แก้ไขเอกสาร", + default: false, + }) + canUpdate: boolean; + + @Column({ + comment: "ลบเอกสาร", + default: false, + }) + canDelete: boolean; + + @Column({ + comment: "ยกเลิกเอกสาร", + default: false, + }) + canCancel: boolean; + + @Column({ + comment: "ดำเนินการเอกสาร", + default: false, + }) + canOperate: boolean; + + @Column({ + comment: "เปลี่ยนสถานะเอกสาร", + default: false, + }) + canChangeState: boolean; + + @Column({ + comment: "แสดงความเห็นเอกสาร", + default: false, + }) + canComment: boolean; + + @Column({ + comment: "ลงนามอนุมัติ", + default: false, + }) + canSign: boolean; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง metaState", + default: null, + }) + metaStateId: string; + + @ManyToOne(() => MetaState, (metaState) => metaState.metaStateOperators) + @JoinColumn({ name: "metaStateId" }) + metaState: MetaState; +} diff --git a/src/entities/MetaWorkflow.ts b/src/entities/MetaWorkflow.ts new file mode 100644 index 00000000..e787457c --- /dev/null +++ b/src/entities/MetaWorkflow.ts @@ -0,0 +1,52 @@ +import { Entity, Column, OneToMany } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { MetaState } from "./MetaState"; + +@Entity("metaWorkflow") +export class metaWorkflow extends EntityBase { + @Column({ + nullable: true, + comment: "ชื่อ flow", + length: 255, + default: null, + }) + name: string; + + @Column({ + nullable: true, + comment: "ระบบ", //PLACEMENT + length: 255, + default: null, + }) + category: string; + + @OneToMany(() => MetaState, (metaState) => metaState.metaWorkflow) + metaStates: MetaState[]; + + @Column({ + nullable: true, + comment: "ชื่อระบบ", //สอบคัดเลือก + length: 100, + default: null, + }) + sysName: string; + + @Column({ + nullable: true, + comment: "ชื่อระดับ", + length: 100, + default: null, + }) + posLevelName: string; + + @Column({ + nullable: true, + comment: "ชื่อประเภท", + length: 100, + default: null, + }) + posTypeName: string; + + // @OneToMany(() => metaStateOperatorUser, (metaStateOperatorUser) => metaStateOperatorUser.metaWorkflow) + // metaStateOperatorUsers: metaStateOperatorUser[]; +} diff --git a/src/entities/PosLevel.ts b/src/entities/PosLevel.ts index e7c00d7d..7eb67e93 100644 --- a/src/entities/PosLevel.ts +++ b/src/entities/PosLevel.ts @@ -5,6 +5,7 @@ import { Position } from "./Position"; import { PosDict } from "./PosDict"; import { Profile } from "./Profile"; import { profile } from "console"; +import { Workflow } from "./Workflow"; enum PosLevelAuthority { HEAD = "HEAD", @@ -56,6 +57,9 @@ export class PosLevel extends EntityBase { @OneToMany(() => Profile, (profile) => profile.posLevel) profiles: Profile[]; + +// @OneToMany(() => Workflow, (workflow) => workflow.posLevel) +// workflows: Workflow[]; } export class CreatePosLevel { diff --git a/src/entities/PosType.ts b/src/entities/PosType.ts index de9ab4f7..9abb9633 100644 --- a/src/entities/PosType.ts +++ b/src/entities/PosType.ts @@ -4,6 +4,7 @@ import { PosLevel } from "./PosLevel"; import { Position } from "./Position"; import { PosDict } from "./PosDict"; import { Profile } from "./Profile"; +import { Workflow } from "./Workflow"; @Entity("posType") export class PosType extends EntityBase { @@ -34,6 +35,9 @@ export class PosType extends EntityBase { @OneToMany(() => Profile, (profile) => profile.posType) profiles: Profile[]; + + // @OneToMany(() => Workflow, (workflow) => workflow.posType) + // workflows: Workflow[]; } export class CreatePosType { diff --git a/src/entities/State.ts b/src/entities/State.ts new file mode 100644 index 00000000..949f0167 --- /dev/null +++ b/src/entities/State.ts @@ -0,0 +1,45 @@ +import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { StateOperator } from "./StateOperator"; +import { Workflow } from "./Workflow"; + +@Entity("state") +export class State extends EntityBase { + @Column({ + nullable: true, + comment: "ชื่อประเภทขั้นตอน", + length: 255, + default: null, + }) + name: string; + + @Column({ + nullable: true, + comment: "ประเภทขั้นตอน", + length: 255, + default: null, + }) + type: string; + + @Column({ + nullable: true, + comment: "ลำดับ", + default: null, + }) + order: number; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง workflow", + default: null, + }) + workflowId: string; + + @ManyToOne(() => Workflow, (workflow) => workflow.states) + @JoinColumn({ name: "workflowId" }) + workflow: Workflow; + + @OneToMany(() => StateOperator, (stateOperator) => stateOperator.state) + stateOperators: StateOperator[]; +} diff --git a/src/entities/StateOperator.ts b/src/entities/StateOperator.ts new file mode 100644 index 00000000..4e0406d3 --- /dev/null +++ b/src/entities/StateOperator.ts @@ -0,0 +1,75 @@ +import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { State } from "./State"; +import { StateOperatorUser } from "./StateOperatorUser"; + +@Entity("stateOperator") +export class StateOperator extends EntityBase { + @Column({ + nullable: true, + comment: "ผู้ดำเนินการ", + length: 255, + default: null, + }) + operator: string; + + @Column({ + comment: "ดูเอกสาร", + default: false, + }) + canView: boolean; + + @Column({ + comment: "แก้ไขเอกสาร", + default: false, + }) + canUpdate: boolean; + + @Column({ + comment: "ลบเอกสาร", + default: false, + }) + canDelete: boolean; + + @Column({ + comment: "ยกเลิกเอกสาร", + default: false, + }) + canCancel: boolean; + + @Column({ + comment: "ดำเนินการเอกสาร", + default: false, + }) + canOperate: boolean; + + @Column({ + comment: "เปลี่ยนสถานะเอกสาร", + default: false, + }) + canChangeState: boolean; + + @Column({ + comment: "แสดงความเห็นเอกสาร", + default: false, + }) + canComment: boolean; + + @Column({ + comment: "ลงนามอนุมัติ", + default: false, + }) + canSign: boolean; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง state", + default: null, + }) + stateId: string; + + @ManyToOne(() => State, (state) => state.stateOperators) + @JoinColumn({ name: "stateId" }) + state: State; +} diff --git a/src/entities/StateOperatorUser.ts b/src/entities/StateOperatorUser.ts new file mode 100644 index 00000000..5c890dd7 --- /dev/null +++ b/src/entities/StateOperatorUser.ts @@ -0,0 +1,50 @@ +import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { StateOperator } from "./StateOperator"; +import { Workflow } from "./Workflow"; + +@Entity("stateOperatorUser") +export class StateOperatorUser extends EntityBase { + @Column({ + nullable: true, + comment: "ผู้ดำเนินการ", + length: 255, + default: null, + }) + operator: string; + + @Column({ + nullable: true, + comment: "", + length: 255, + default: null, + }) + profile: string; + + @Column({ + nullable: true, + comment: "ลำดับ", + default: null, + }) + order: number; + + @Column({ + nullable: true, + comment: "ผู้ดำเนินการ", + length: 255, + default: null, + }) + refId: string; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง workflow", + default: null, + }) + workflowId: string; + + @ManyToOne(() => Workflow, (workflow) => workflow.stateOperatorUsers) + @JoinColumn({ name: "workflowId" }) + workflow: Workflow; +} diff --git a/src/entities/Workflow.ts b/src/entities/Workflow.ts new file mode 100644 index 00000000..c41d442c --- /dev/null +++ b/src/entities/Workflow.ts @@ -0,0 +1,53 @@ +import { Entity, Column, OneToMany } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { State } from "./State"; +import { StateOperatorUser } from "./StateOperatorUser"; + +@Entity("workflow") +export class Workflow extends EntityBase { + @Column({ + nullable: true, + comment: "ชื่อ flow", + length: 255, + default: null, + }) + name: string; + + @Column({ + nullable: true, + comment: "ระบบ", //PLACEMENT + length: 255, + default: null, + }) + category: string; + + @OneToMany(() => State, (state) => state.workflow) + states: State[]; + + @Column({ + nullable: true, + comment: "ชื่อระบบ", //สอบคัดเลือก + length: 100, + default: null, + }) + sysName: string; + + @Column({ + nullable: true, + comment: "ชื่อระดับ", + length: 100, + default: null, + }) + posLevelName: string; + + @Column({ + nullable: true, + comment: "ชื่อประเภท", + length: 100, + default: null, + }) + posTypeName: string; + + @OneToMany(() => StateOperatorUser, (stateOperatorUser) => stateOperatorUser.workflow) + stateOperatorUsers: StateOperatorUser[]; +} diff --git a/src/interfaces/call-api.ts b/src/interfaces/call-api.ts index 588ea9c3..9e62e712 100644 --- a/src/interfaces/call-api.ts +++ b/src/interfaces/call-api.ts @@ -76,7 +76,6 @@ class CallAPI { response: JSON.stringify(error), }, }); - console.log(error); throw error; } } diff --git a/src/interfaces/permission.ts b/src/interfaces/permission.ts index b1c03f77..e063de6b 100644 --- a/src/interfaces/permission.ts +++ b/src/interfaces/permission.ts @@ -53,7 +53,6 @@ class CheckAuth { return await new CallAPI() .GetData(req, `/org/permission/org/${system}/${action}`) .then(async (x) => { - console.log(x); let privilege = x.privilege; // if (action.trim().toLocaleUpperCase() == "CREATE") // privilege = await this.PermissionCreate(req, system); @@ -84,7 +83,16 @@ class CheckAuth { } else if (x.orgChild4Id == null) { node = 3; } - if (privilege == "ROOT") { + if (privilege == "OWNER") { + data = { + root: null, + child1: null, + child2: null, + child3: null, + child4: null, + privilege: "OWNER", + }; + } else if (privilege == "ROOT") { data = { root: [x.orgRootId], child1: null, @@ -112,15 +120,6 @@ class CheckAuth { privilege: "NORMAL", }; } else if (privilege == "SPECIFIC") { - } else if (privilege == "OWNER") { - data = { - root: null, - child1: null, - child2: null, - child3: null, - child4: null, - privilege: "OWNER", - }; } return data; diff --git a/src/keycloak/index.ts b/src/keycloak/index.ts index 7384e0f8..0bc0b49f 100644 --- a/src/keycloak/index.ts +++ b/src/keycloak/index.ts @@ -75,7 +75,7 @@ export async function createUser(username: string, password: string, opts?: Reco method: "POST", body: JSON.stringify({ enabled: true, - credentials: [{ type: "password", value: password }], + credentials: [{ type: "password", value: password ,temporary: false,}], username, ...opts, }), @@ -168,6 +168,69 @@ export async function getUserCount(first = "", max = "", search = "") { return await res.json(); } +/** + * Get keycloak user list + * + * Client must have permission to manage realm's user + * + * @returns user list if success, false otherwise. + */ +export async function getUserListOrg(first = "", max = "", search = "", userIds: string[] = []) { + const userIdsParam = userIds.join(","); + const res = await fetch( + // `${KC_URL}/admin/realms/${KC_REALM}/users`.concat(!!search ? `?search=${search}` : ""), + `${KC_URL}/admin/realms/${KC_REALM}/users?first=${first || "0"}&max=${max || "-1"}${search ? `&search=${search}` : ""}${userIdsParam ? `&id=${userIdsParam}` : ""}`, + { + // prettier-ignore + headers: { + "authorization": `Bearer ${await getToken()}`, + "content-type": `application/json`, + }, + }, + ).catch((e) => console.log("Keycloak Error: ", e)); + + if (!res) return false; + if (!res.ok) { + return Boolean(console.error("Keycloak Error Response: ", await res.json())); + } + + return ((await res.json()) as any[]).map((v: Record) => ({ + id: v.id, + username: v.username, + firstName: v.firstName, + lastName: v.lastName, + email: v.email, + enabled: v.enabled, + })); +} + +export async function getUserCountOrg(first = "", max = "", search = "", userIds: string[] = []) { + console.log(userIds); + const userIdsParam = userIds.join(","); + console.log(userIdsParam); + console.log("xxxxxxxxxxxxxxxxx"); + console.log( + `${KC_URL}/admin/realms/${KC_REALM}/users/count?first=${first || "0"}&max=${max || "-1"}${search ? `&search=${search}` : ""}${userIdsParam && userIdsParam != "" ? `&id=${userIdsParam}` : ""}`, + ); + console.log("aaaaaaaaaaaaaaaaaa"); + const res = await fetch( + `${KC_URL}/admin/realms/${KC_REALM}/users/count?first=${first || "0"}&max=${max || "-1"}${search ? `&search=${search}` : ""}${userIdsParam && userIdsParam != "" ? `&id=${userIdsParam}` : ""}`, + { + headers: { + authorization: `Bearer ${await getToken()}`, + "content-type": `application/json`, + }, + }, + ).catch((e) => console.log("Keycloak Error: ", e)); + + if (!res) return false; + if (!res.ok) { + return Boolean(console.error("Keycloak Error Response: ", await res.json())); + } + + return await res.json(); +} + /** * Update keycloak user by uuid * diff --git a/src/migration/1728399911271-add_table_workflow.ts b/src/migration/1728399911271-add_table_workflow.ts new file mode 100644 index 00000000..6bf432c0 --- /dev/null +++ b/src/migration/1728399911271-add_table_workflow.ts @@ -0,0 +1,28 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow1728399911271 implements MigrationInterface { + name = 'AddTableWorkflow1728399911271' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE \`stateOperator\` (\`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL COMMENT 'สร้างข้อมูลเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`createdUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่สร้างข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`lastUpdatedAt\` datetime(6) NOT NULL COMMENT 'แก้ไขข้อมูลล่าสุดเมื่อ' DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`lastUpdateUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่แก้ไขข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`createdFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่สร้างข้อมูล' DEFAULT 'string', \`lastUpdateFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่แก้ไขข้อมูลล่าสุด' DEFAULT 'string', \`operator\` varchar(255) NULL COMMENT 'ผู้ดำเนินการ', \`canView\` tinyint NOT NULL COMMENT 'ดูเอกสาร' DEFAULT 0, \`canUpdate\` tinyint NOT NULL COMMENT 'แก้ไขเอกสาร' DEFAULT 0, \`canDelete\` tinyint NOT NULL COMMENT 'ลบเอกสาร' DEFAULT 0, \`canCancel\` tinyint NOT NULL COMMENT 'ยกเลิกเอกสาร' DEFAULT 0, \`canOperate\` tinyint NOT NULL COMMENT 'ดำเนินการเอกสาร' DEFAULT 0, \`canChangeState\` tinyint NOT NULL COMMENT 'เปลี่ยนสถานะเอกสาร' DEFAULT 0, \`canComment\` tinyint NOT NULL COMMENT 'แสดงความเห็นเอกสาร' DEFAULT 0, \`canSign\` tinyint NOT NULL COMMENT 'ลงนามอนุมัติ' DEFAULT 0, \`stateId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง state', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`CREATE TABLE \`state\` (\`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL COMMENT 'สร้างข้อมูลเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`createdUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่สร้างข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`lastUpdatedAt\` datetime(6) NOT NULL COMMENT 'แก้ไขข้อมูลล่าสุดเมื่อ' DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`lastUpdateUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่แก้ไขข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`createdFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่สร้างข้อมูล' DEFAULT 'string', \`lastUpdateFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่แก้ไขข้อมูลล่าสุด' DEFAULT 'string', \`name\` varchar(255) NULL COMMENT 'ชื่อประเภทขั้นตอน', \`type\` varchar(255) NULL COMMENT 'ประเภทขั้นตอน', \`order\` varchar(255) NULL COMMENT 'ลำดับ', \`workflowId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง workflow', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`CREATE TABLE \`workflow\` (\`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL COMMENT 'สร้างข้อมูลเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`createdUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่สร้างข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`lastUpdatedAt\` datetime(6) NOT NULL COMMENT 'แก้ไขข้อมูลล่าสุดเมื่อ' DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`lastUpdateUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่แก้ไขข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`createdFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่สร้างข้อมูล' DEFAULT 'string', \`lastUpdateFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่แก้ไขข้อมูลล่าสุด' DEFAULT 'string', \`name\` varchar(255) NULL COMMENT 'ชื่อ flow', \`category\` varchar(255) NULL COMMENT 'ระบบ', \`commandSysId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง commandSys', \`posLevelId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง posLevel', \`posTypeId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง posType', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`ALTER TABLE \`stateOperator\` ADD CONSTRAINT \`FK_72292e09e5c83c34016a4b17ce4\` FOREIGN KEY (\`stateId\`) REFERENCES \`state\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`state\` ADD CONSTRAINT \`FK_fad8656b57142ed4a41584057a7\` FOREIGN KEY (\`workflowId\`) REFERENCES \`workflow\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD CONSTRAINT \`FK_248dca7108cc3ba484d7eac2bc2\` FOREIGN KEY (\`commandSysId\`) REFERENCES \`commandSys\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD CONSTRAINT \`FK_0eadcb967c5bdb18867395b8bf9\` FOREIGN KEY (\`posLevelId\`) REFERENCES \`posLevel\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD CONSTRAINT \`FK_77889a7cde943b64fc28dd06025\` FOREIGN KEY (\`posTypeId\`) REFERENCES \`posType\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` DROP FOREIGN KEY \`FK_77889a7cde943b64fc28dd06025\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP FOREIGN KEY \`FK_0eadcb967c5bdb18867395b8bf9\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP FOREIGN KEY \`FK_248dca7108cc3ba484d7eac2bc2\``); + await queryRunner.query(`ALTER TABLE \`state\` DROP FOREIGN KEY \`FK_fad8656b57142ed4a41584057a7\``); + await queryRunner.query(`ALTER TABLE \`stateOperator\` DROP FOREIGN KEY \`FK_72292e09e5c83c34016a4b17ce4\``); + await queryRunner.query(`DROP TABLE \`workflow\``); + await queryRunner.query(`DROP TABLE \`state\``); + await queryRunner.query(`DROP TABLE \`stateOperator\``); + } + +} diff --git a/src/migration/1728442861469-add_table_workflow1.ts b/src/migration/1728442861469-add_table_workflow1.ts new file mode 100644 index 00000000..7b26d1e8 --- /dev/null +++ b/src/migration/1728442861469-add_table_workflow1.ts @@ -0,0 +1,30 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow11728442861469 implements MigrationInterface { + name = 'AddTableWorkflow11728442861469' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` DROP FOREIGN KEY \`FK_0eadcb967c5bdb18867395b8bf9\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP FOREIGN KEY \`FK_248dca7108cc3ba484d7eac2bc2\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP FOREIGN KEY \`FK_77889a7cde943b64fc28dd06025\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`commandSysId\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`posLevelId\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`posTypeId\``); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`commandSysName\` varchar(100) NULL COMMENT 'ชื่อระบบ'`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`posLevelName\` varchar(100) NULL COMMENT 'ชื่อระดับ'`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`posTypeName\` varchar(100) NULL COMMENT 'ชื่อประเภท'`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`posTypeName\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`posLevelName\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`commandSysName\``); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`posTypeId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง posType'`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`posLevelId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง posLevel'`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`commandSysId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง commandSys'`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD CONSTRAINT \`FK_77889a7cde943b64fc28dd06025\` FOREIGN KEY (\`posTypeId\`) REFERENCES \`posType\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD CONSTRAINT \`FK_248dca7108cc3ba484d7eac2bc2\` FOREIGN KEY (\`commandSysId\`) REFERENCES \`commandSys\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD CONSTRAINT \`FK_0eadcb967c5bdb18867395b8bf9\` FOREIGN KEY (\`posLevelId\`) REFERENCES \`posLevel\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + +} diff --git a/src/migration/1728456793035-add_table_workflow2.ts b/src/migration/1728456793035-add_table_workflow2.ts new file mode 100644 index 00000000..748304cd --- /dev/null +++ b/src/migration/1728456793035-add_table_workflow2.ts @@ -0,0 +1,26 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow21728456793035 implements MigrationInterface { + name = 'AddTableWorkflow21728456793035' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` CHANGE \`commandSysName\` \`sysName\` varchar(100) NULL COMMENT 'ชื่อระบบ'`); + await queryRunner.query(`CREATE TABLE \`stateOperatorUser\` (\`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL COMMENT 'สร้างข้อมูลเมื่อ' DEFAULT CURRENT_TIMESTAMP(6), \`createdUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่สร้างข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`lastUpdatedAt\` datetime(6) NOT NULL COMMENT 'แก้ไขข้อมูลล่าสุดเมื่อ' DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`lastUpdateUserId\` varchar(40) NOT NULL COMMENT 'User Id ที่แก้ไขข้อมูล' DEFAULT '00000000-0000-0000-0000-000000000000', \`createdFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่สร้างข้อมูล' DEFAULT 'string', \`lastUpdateFullName\` varchar(200) NOT NULL COMMENT 'ชื่อ User ที่แก้ไขข้อมูลล่าสุด' DEFAULT 'string', \`profile\` varchar(255) NULL, \`type\` varchar(255) NULL, \`order\` int NULL COMMENT 'ลำดับ', \`stateOperatorId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง stateOperator', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`ALTER TABLE \`command\` DROP COLUMN \`isBangkok\``); + await queryRunner.query(`ALTER TABLE \`command\` ADD \`isBangkok\` varchar(20) NULL COMMENT 'คำสั่งกรุงเทพมหานคร'`); + await queryRunner.query(`ALTER TABLE \`state\` DROP COLUMN \`order\``); + await queryRunner.query(`ALTER TABLE \`state\` ADD \`order\` int NULL COMMENT 'ลำดับ'`); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD CONSTRAINT \`FK_bef7391c37f03a3b809406beebf\` FOREIGN KEY (\`stateOperatorId\`) REFERENCES \`stateOperator\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP FOREIGN KEY \`FK_bef7391c37f03a3b809406beebf\``); + await queryRunner.query(`ALTER TABLE \`state\` DROP COLUMN \`order\``); + await queryRunner.query(`ALTER TABLE \`state\` ADD \`order\` varchar(255) NULL COMMENT 'ลำดับ'`); + await queryRunner.query(`ALTER TABLE \`command\` DROP COLUMN \`isBangkok\``); + await queryRunner.query(`ALTER TABLE \`command\` ADD \`isBangkok\` tinyint NULL COMMENT 'คำสั่งกรุงเทพมหานคร'`); + await queryRunner.query(`DROP TABLE \`stateOperatorUser\``); + await queryRunner.query(`ALTER TABLE \`workflow\` CHANGE \`sysName\` \`commandSysName\` varchar(100) NULL COMMENT 'ชื่อระบบ'`); + } + +} diff --git a/src/migration/1728465477520-add_table_workflow3.ts b/src/migration/1728465477520-add_table_workflow3.ts new file mode 100644 index 00000000..24dfbcb9 --- /dev/null +++ b/src/migration/1728465477520-add_table_workflow3.ts @@ -0,0 +1,26 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow31728465477520 implements MigrationInterface { + name = 'AddTableWorkflow31728465477520' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP FOREIGN KEY \`FK_bef7391c37f03a3b809406beebf\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP COLUMN \`stateOperatorId\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP COLUMN \`type\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD \`operator\` varchar(255) NULL COMMENT 'ผู้ดำเนินการ'`); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD \`refId\` varchar(255) NULL COMMENT 'ผู้ดำเนินการ'`); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD \`workflowId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง workflow'`); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD CONSTRAINT \`FK_9499ff9ae0444f59f19800aca05\` FOREIGN KEY (\`workflowId\`) REFERENCES \`workflow\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP FOREIGN KEY \`FK_9499ff9ae0444f59f19800aca05\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP COLUMN \`workflowId\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP COLUMN \`refId\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP COLUMN \`operator\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD \`type\` varchar(255) NULL`); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD \`stateOperatorId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง stateOperator'`); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD CONSTRAINT \`FK_bef7391c37f03a3b809406beebf\` FOREIGN KEY (\`stateOperatorId\`) REFERENCES \`stateOperator\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + +}