From 4efc3f381b6a2681cea48c9762e2a9cd9d34aa2e Mon Sep 17 00:00:00 2001 From: Bright Date: Tue, 8 Oct 2024 16:35:08 +0700 Subject: [PATCH 01/41] =?UTF-8?q?=E0=B8=AD=E0=B8=AD=E0=B8=81=E0=B8=84?= =?UTF-8?q?=E0=B8=B3=E0=B8=AA=E0=B8=B1=E0=B9=88=E0=B8=87=2001=2002?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/CommandController.ts | 231 ++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 3 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 6ddc0829..0c969531 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -22,7 +22,7 @@ import { Command } from "../entities/Command"; import { Brackets, LessThan, MoreThan, Double, In } 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,16 @@ 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 { + calculateAge, + calculateRetireDate, + calculateRetireLaw, + calculateRetireYear, + removeProfileInOrganize, + setLogDataDiff, +} from "../interfaces/utils"; import { Position } from "../entities/Position"; import { PosMaster } from "../entities/PosMaster"; import { EmployeePosition } from "../entities/EmployeePosition"; @@ -42,6 +49,35 @@ import { EmployeePosMaster } from "../entities/EmployeePosMaster"; import { ProfileDiscipline } from "../entities/ProfileDiscipline"; import { ProfileDisciplineHistory } from "../entities/ProfileDisciplineHistory"; import { PosMasterAct } from "../entities/PosMasterAct"; +import { PosLevel } from "../entities/PosLevel"; +import { PosType } from "../entities/PosType"; +import { + addUserGroup, + addUserRoles, + createGroup, + createUser, + deleteGroup, + deleteUser, + editUser, + getGroups, + getRoles, + getUser, + getUserGroups, + getUserList, + removeUserGroup, + removeUserRoles, + getRoleMappings, + getUserCount, + enableStatus, +} from "../keycloak"; +import { ProfileEducation, CreateProfileEducation } from "../entities/ProfileEducation"; +import { ProfileEducationHistory } from "../entities/ProfileEducationHistory"; +import { + CreateProfileCertificate, + ProfileCertificate, + UpdateProfileCertificate, +} from "../entities/ProfileCertificate"; +import { ProfileCertificateHistory } from "../entities/ProfileCertificateHistory"; @Route("api/v1/org/command") @Tags("Command") @@ -70,6 +106,12 @@ 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); /** * API list รายการคำสั่ง @@ -1990,6 +2032,189 @@ 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 + bodyPosition: { + posmasterId: string; + positionId: string; + } + }[]; + }, + ) { + await Promise.all( + body.data.map(async (item) => { + const profile = await this.profileRepository.findOneBy({ citizenId: item.bodyProfile.citizenId }); + if (profile) { + throw new HttpError(HttpStatus.BAD_REQUEST, "พบ profile ซ้ำ"); + } + 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(), + }; + 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, "ไม่พบข้อมูลประเภทตำแหน่งนี้"); + } + + const profile_: Profile = Object.assign({ ...item.bodyProfile, ...meta }); + const _null: any = null; + profile_.dateRetire = item.bodyProfile.birthDate == null ? _null : calculateRetireDate(item.bodyProfile.birthDate); + profile_.dateRetireLaw = item.bodyProfile.birthDate == null ? _null : calculateRetireLaw(item.bodyProfile.birthDate); + await this.profileRepository.save(profile_); + // setLogDataDiff(req, { before, after: profile_ }); + if(profile_ && profile_.id) { + const userKeycloakId = await createUser(profile_.citizenId, profile_.citizenId, { //User, Password + firstName: profile_.firstName, + lastName: profile_.lastName, + email: profile_.email, + requiredActions: ["UPDATE_PASSWORD"], + }); + 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."); + + //Educations + 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 + 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 + 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(history, { ...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 + 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; + profile_.keycloak = userKeycloakId; // Update KeyCloak + 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, From 9d8e14b3932b9978a1d1cc7f6f072e864369b634 Mon Sep 17 00:00:00 2001 From: kittapath Date: Tue, 8 Oct 2024 22:07:04 +0700 Subject: [PATCH 02/41] migrate db --- src/entities/CommandSys.ts | 4 + src/entities/PosLevel.ts | 4 + src/entities/PosType.ts | 4 + src/entities/State.ts | 46 ++++++++++ src/entities/StateOperator.ts | 74 ++++++++++++++++ src/entities/Workflow.ts | 88 +++++++++++++++++++ .../1728399911271-add_table_workflow.ts | 28 ++++++ 7 files changed, 248 insertions(+) create mode 100644 src/entities/State.ts create mode 100644 src/entities/StateOperator.ts create mode 100644 src/entities/Workflow.ts create mode 100644 src/migration/1728399911271-add_table_workflow.ts diff --git a/src/entities/CommandSys.ts b/src/entities/CommandSys.ts index 77c1be5d..0aee2270 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/PosLevel.ts b/src/entities/PosLevel.ts index e7c00d7d..807ce0ec 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..6b5cc2b1 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..3bef1d7c --- /dev/null +++ b/src/entities/State.ts @@ -0,0 +1,46 @@ +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: "ลำดับ", + length: 255, + default: null, + }) + order: string; + + @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..07ae241c --- /dev/null +++ b/src/entities/StateOperator.ts @@ -0,0 +1,74 @@ +import { Entity, Column, ManyToOne, JoinColumn } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { State } from "./State"; + +@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/Workflow.ts b/src/entities/Workflow.ts new file mode 100644 index 00000000..dd5d7b71 --- /dev/null +++ b/src/entities/Workflow.ts @@ -0,0 +1,88 @@ +import { Entity, Column, OneToMany, ManyToOne, JoinColumn } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { State } from "./State"; +import { CommandSys } from "./CommandSys"; +import { PosLevel } from "./PosLevel"; +import { PosType } from "./PosType"; + +@Entity("workflow") +export class Workflow extends EntityBase { + @Column({ + nullable: true, + comment: "ชื่อ flow", + length: 255, + default: null, + }) + name: string; + + @Column({ + nullable: true, + comment: "ระบบ", + length: 255, + default: null, + }) + category: string; + + // @Column({ + // nullable: true, + // comment: "กรุ๊ปเลือด", + // length: 255, + // default: null, + // }) + // rank: string; + + // @Column({ + // nullable: true, + // comment: "กรุ๊ปเลือด", + // length: 255, + // default: null, + // }) + // executive: string; + + // @Column({ + // nullable: true, + // comment: "หมวดหมู่ระบบ", + // length: 255, + // default: null, + // }) + // system: string; + + @OneToMany(() => State, (state) => state.workflow) + states: State[]; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง commandSys", + default: null, + }) + commandSysId: string; + + @ManyToOne(() => CommandSys, (commandSys) => commandSys.workflows) + @JoinColumn({ name: "commandSysId" }) + commandSys: CommandSys; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง posLevel", + default: null, + }) + posLevelId: string; + + @ManyToOne(() => PosLevel, (posLevel) => posLevel.workflows) + @JoinColumn({ name: "posLevelId" }) + posLevel: PosLevel; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง posType", + default: null, + }) + posTypeId: string; + + @ManyToOne(() => PosType, (posType) => posType.workflows) + @JoinColumn({ name: "posTypeId" }) + posType: PosType; +} 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\``); + } + +} From 87b6fdf0d20eda6febd158c5cadbb190ed0de005 Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 9 Oct 2024 10:05:39 +0700 Subject: [PATCH 03/41] =?UTF-8?q?=E0=B9=81=E0=B8=81=E0=B9=89=20db=20workfl?= =?UTF-8?q?ow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/CommandSys.ts | 4 +- src/entities/PosLevel.ts | 4 +- src/entities/PosType.ts | 4 +- src/entities/Workflow.ts | 94 +++++++++---------- .../1728442861469-add_table_workflow1.ts | 30 ++++++ 5 files changed, 83 insertions(+), 53 deletions(-) create mode 100644 src/migration/1728442861469-add_table_workflow1.ts diff --git a/src/entities/CommandSys.ts b/src/entities/CommandSys.ts index 0aee2270..7e50f3ae 100644 --- a/src/entities/CommandSys.ts +++ b/src/entities/CommandSys.ts @@ -77,8 +77,8 @@ export class CommandSys { @OneToMany(() => Assign, (assgin) => assgin.commandAssignSys) assgins: Assign[]; - @OneToMany(() => Workflow, (workflow) => workflow.commandSys) - workflows: Workflow[]; + // @OneToMany(() => Workflow, (workflow) => workflow.commandSys) + // workflows: Workflow[]; } export class CreateCommandSys { diff --git a/src/entities/PosLevel.ts b/src/entities/PosLevel.ts index 807ce0ec..7eb67e93 100644 --- a/src/entities/PosLevel.ts +++ b/src/entities/PosLevel.ts @@ -58,8 +58,8 @@ export class PosLevel extends EntityBase { @OneToMany(() => Profile, (profile) => profile.posLevel) profiles: Profile[]; - @OneToMany(() => Workflow, (workflow) => workflow.posLevel) - workflows: Workflow[]; +// @OneToMany(() => Workflow, (workflow) => workflow.posLevel) +// workflows: Workflow[]; } export class CreatePosLevel { diff --git a/src/entities/PosType.ts b/src/entities/PosType.ts index 6b5cc2b1..9abb9633 100644 --- a/src/entities/PosType.ts +++ b/src/entities/PosType.ts @@ -36,8 +36,8 @@ export class PosType extends EntityBase { @OneToMany(() => Profile, (profile) => profile.posType) profiles: Profile[]; - @OneToMany(() => Workflow, (workflow) => workflow.posType) - workflows: Workflow[]; + // @OneToMany(() => Workflow, (workflow) => workflow.posType) + // workflows: Workflow[]; } export class CreatePosType { diff --git a/src/entities/Workflow.ts b/src/entities/Workflow.ts index dd5d7b71..8b81b00d 100644 --- a/src/entities/Workflow.ts +++ b/src/entities/Workflow.ts @@ -23,66 +23,66 @@ export class Workflow extends EntityBase { }) category: string; - // @Column({ - // nullable: true, - // comment: "กรุ๊ปเลือด", - // length: 255, - // default: null, - // }) - // rank: string; - - // @Column({ - // nullable: true, - // comment: "กรุ๊ปเลือด", - // length: 255, - // default: null, - // }) - // executive: string; - - // @Column({ - // nullable: true, - // comment: "หมวดหมู่ระบบ", - // length: 255, - // default: null, - // }) - // system: string; - @OneToMany(() => State, (state) => state.workflow) states: State[]; - @Column({ - nullable: true, - length: 40, - comment: "คีย์นอก(FK)ของตาราง commandSys", - default: null, - }) - commandSysId: string; + // @Column({ + // nullable: true, + // length: 40, + // comment: "คีย์นอก(FK)ของตาราง commandSys", + // default: null, + // }) + // commandSysId: string; - @ManyToOne(() => CommandSys, (commandSys) => commandSys.workflows) - @JoinColumn({ name: "commandSysId" }) - commandSys: CommandSys; + // @ManyToOne(() => CommandSys, (commandSys) => commandSys.workflows) + // @JoinColumn({ name: "commandSysId" }) + // commandSys: CommandSys; + + // @Column({ + // nullable: true, + // length: 40, + // comment: "คีย์นอก(FK)ของตาราง posLevel", + // default: null, + // }) + // posLevelId: string; + + // @ManyToOne(() => PosLevel, (posLevel) => posLevel.workflows) + // @JoinColumn({ name: "posLevelId" }) + // posLevel: PosLevel; + + // @Column({ + // nullable: true, + // length: 40, + // comment: "คีย์นอก(FK)ของตาราง posType", + // default: null, + // }) + // posTypeId: string; + + // @ManyToOne(() => PosType, (posType) => posType.workflows) + // @JoinColumn({ name: "posTypeId" }) + // posType: PosType; @Column({ nullable: true, - length: 40, - comment: "คีย์นอก(FK)ของตาราง posLevel", + comment: "ชื่อระบบ", + length: 100, default: null, }) - posLevelId: string; - - @ManyToOne(() => PosLevel, (posLevel) => posLevel.workflows) - @JoinColumn({ name: "posLevelId" }) - posLevel: PosLevel; + commandSysName: string; @Column({ nullable: true, - length: 40, - comment: "คีย์นอก(FK)ของตาราง posType", + comment: "ชื่อระดับ", + length: 100, default: null, }) - posTypeId: string; + posLevelName: string; - @ManyToOne(() => PosType, (posType) => posType.workflows) - @JoinColumn({ name: "posTypeId" }) - posType: PosType; + @Column({ + nullable: true, + comment: "ชื่อประเภท", + length: 100, + default: null, + }) + posTypeName: string; } 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`); + } + +} From 189f518e30229c10f2057f1269129402d41ed443 Mon Sep 17 00:00:00 2001 From: waruneeauy Date: Wed, 9 Oct 2024 12:02:47 +0700 Subject: [PATCH 04/41] fixing bug --- src/controllers/ProfileController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/ProfileController.ts b/src/controllers/ProfileController.ts index e24a7cad..f1f6c5f1 100644 --- a/src/controllers/ProfileController.ts +++ b/src/controllers/ProfileController.ts @@ -4916,7 +4916,7 @@ export class ProfileController extends Controller { idcard: item.citizenId, 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, From 5440bce2570fbeb646e390dcc48172f9fb1c658a Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 9 Oct 2024 12:53:13 +0700 Subject: [PATCH 05/41] =?UTF-8?q?=E0=B9=80=E0=B8=8A=E0=B9=87=E0=B8=84=20?= =?UTF-8?q?=E0=B8=AA=E0=B8=81=E0=B8=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/CommandController.ts | 116 +++++++++++++++------------ src/controllers/ProfileController.ts | 28 +++++++ src/entities/Command.ts | 6 +- src/entities/State.ts | 3 +- src/entities/Workflow.ts | 47 +---------- 5 files changed, 101 insertions(+), 99 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 830f6299..7ccf2203 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -167,12 +167,9 @@ export class CommandController extends Controller { new Brackets((qb) => { qb.where(keyword != null && keyword != "" ? "command.commandNo LIKE :keyword" : "1=1", { keyword: `%${keyword}%`, - }).orWhere( - keyword != null && keyword != "" ? "command.issue LIKE :keyword" : "1=1", - { - keyword: `%${keyword}%`, - }, - ); + }).orWhere(keyword != null && keyword != "" ? "command.issue LIKE :keyword" : "1=1", { + keyword: `%${keyword}%`, + }); }), ) .orderBy("command.createdAt", "DESC") @@ -292,7 +289,7 @@ export class CommandController extends Controller { detailFooter: string | null; commandAffectDate: Date | null; commandExcecuteDate: Date | null; - isBangkok: boolean | null; + isBangkok: string | null; isAttachment: boolean | null; }, @Request() request: RequestWithUser, @@ -942,12 +939,12 @@ export class CommandController extends Controller { .filter((x) => x.profileId != null) .map(async (x) => x.profileId); - await new CallAPI() + await new CallAPI() .PostData(request, "/placement/noti/profiles", { subject: `${command.issue}`, body: `${command.issue}`, receiverUserId: profiles, - payload: "",//แนบไฟล์ + payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, receiveDate: command.commandExcecuteDate, @@ -1109,7 +1106,7 @@ export class CommandController extends Controller { commandExcecuteDate?: Date | null; persons: { refId: string; - profileId?: string|null; + profileId?: string | null; citizenId: string; prefix: string; firstName: string; @@ -2038,20 +2035,22 @@ export class CommandController extends Controller { @Body() body: { data: { - bodyProfile: CreateProfileAllFields - bodyEducations: CreateProfileEducation[] - bodyCertificates: CreateProfileCertificate[] - bodySalarys: CreateProfileSalary + bodyProfile: CreateProfileAllFields; + bodyEducations: CreateProfileEducation[]; + bodyCertificates: CreateProfileCertificate[]; + bodySalarys: CreateProfileSalary; bodyPosition: { posmasterId: string; positionId: string; - } + }; }[]; }, ) { await Promise.all( body.data.map(async (item) => { - const profile = await this.profileRepository.findOneBy({ citizenId: item.bodyProfile.citizenId }); + const profile = await this.profileRepository.findOneBy({ + citizenId: item.bodyProfile.citizenId, + }); if (profile) { throw new HttpError(HttpStatus.BAD_REQUEST, "พบ profile ซ้ำ"); } @@ -2067,22 +2066,35 @@ export class CommandController extends Controller { 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 }))) { + 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 }))) { + if ( + item.bodyProfile.posTypeId && + !(await this.posTypeRepo.findOneBy({ id: item.bodyProfile.posTypeId })) + ) { throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้"); } const profile_: Profile = Object.assign({ ...item.bodyProfile, ...meta }); const _null: any = null; - profile_.dateRetire = item.bodyProfile.birthDate == null ? _null : calculateRetireDate(item.bodyProfile.birthDate); - profile_.dateRetireLaw = item.bodyProfile.birthDate == null ? _null : calculateRetireLaw(item.bodyProfile.birthDate); + profile_.dateRetire = + item.bodyProfile.birthDate == null + ? _null + : calculateRetireDate(item.bodyProfile.birthDate); + profile_.dateRetireLaw = + item.bodyProfile.birthDate == null + ? _null + : calculateRetireLaw(item.bodyProfile.birthDate); await this.profileRepository.save(profile_); // setLogDataDiff(req, { before, after: profile_ }); - if(profile_ && profile_.id) { - const userKeycloakId = await createUser(profile_.citizenId, profile_.citizenId, { //User, Password + if (profile_ && profile_.id) { + const userKeycloakId = await createUser(profile_.citizenId, profile_.citizenId, { + //User, Password firstName: profile_.firstName, lastName: profile_.lastName, email: profile_.email, @@ -2092,7 +2104,8 @@ export class CommandController extends Controller { 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."); + if (!Array.isArray(list)) + throw new Error("Failed. Cannot get role(s) data from the server."); const result = await addUserRoles( userKeycloakId, list @@ -2100,10 +2113,10 @@ export class CommandController extends Controller { .map((x) => ({ id: x.id, name: x.name, - })) + })), ); if (!result) throw new Error("Failed. Cannot set user's role."); - + //Educations await Promise.all( item.bodyEducations.map(async (education) => { @@ -2116,7 +2129,7 @@ export class CommandController extends Controller { setLogDataDiff(req, { before, after: profileEdu }); eduHistory.profileEducationId = profileEdu.id; await this.profileEducationHistoryRepo.save(eduHistory, { data: req }); - }) + }), ); //Certificates @@ -2126,36 +2139,37 @@ export class CommandController extends Controller { Object.assign(profileCer, { ...cer, ...meta }); const cerHistory = new ProfileCertificateHistory(); Object.assign(cerHistory, { ...profileCer, id: undefined }); - profileCer.profileId = profile_.id + 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 - 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(history, { ...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 }); + 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(history, { ...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 const posMaster = await this.posMasterRepository.findOne({ where: { id: item.bodyPosition.posmasterId }, }); - if (posMaster == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้"); - + if (posMaster == null) + throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้"); + const posMasterOld = await this.posMasterRepository.findOne({ where: { current_holderId: profile_.id, @@ -2163,7 +2177,7 @@ export class CommandController extends Controller { }, }); if (posMasterOld != null) posMasterOld.current_holderId = null; - + const positionOld = await this.positionRepository.findOne({ where: { posMasterId: posMasterOld?.id, @@ -2174,7 +2188,7 @@ export class CommandController extends Controller { positionOld.positionIsSelected = false; await this.positionRepository.save(positionOld); } - + const checkPosition = await this.positionRepository.find({ where: { posMasterId: item.bodyPosition.posmasterId, @@ -2188,11 +2202,11 @@ export class CommandController extends Controller { })); 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, @@ -2204,13 +2218,13 @@ export class CommandController extends Controller { profile_.posLevelId = positionNew.posLevelId; profile_.posTypeId = positionNew.posTypeId; profile_.position = positionNew.positionName; - profile_.keycloak = userKeycloakId; // Update KeyCloak - await this.profileRepository.save(profile_, { data: req }); + profile_.keycloak = userKeycloakId; // Update KeyCloak + await this.profileRepository.save(profile_, { data: req }); setLogDataDiff(req, { before, after: profile_ }); await this.positionRepository.save(positionNew, { data: req }); } } - }) + }), ); return new HttpSuccess(); } diff --git a/src/controllers/ProfileController.ts b/src/controllers/ProfileController.ts index e24a7cad..100f375a 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 ประวัติแบบย่อ ข้าราชการ @@ -3407,6 +3409,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) { + return new HttpSuccess(false); + } + return new HttpSuccess(posMasters.orgChild1.isOfficer); + } + /** * API ข้อมูลทะเบียนประวัติตาม keycloakid * 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/State.ts b/src/entities/State.ts index 3bef1d7c..949f0167 100644 --- a/src/entities/State.ts +++ b/src/entities/State.ts @@ -24,10 +24,9 @@ export class State extends EntityBase { @Column({ nullable: true, comment: "ลำดับ", - length: 255, default: null, }) - order: string; + order: number; @Column({ nullable: true, diff --git a/src/entities/Workflow.ts b/src/entities/Workflow.ts index 8b81b00d..4b1ffa1b 100644 --- a/src/entities/Workflow.ts +++ b/src/entities/Workflow.ts @@ -1,9 +1,6 @@ -import { Entity, Column, OneToMany, ManyToOne, JoinColumn } from "typeorm"; +import { Entity, Column, OneToMany } from "typeorm"; import { EntityBase } from "./base/Base"; import { State } from "./State"; -import { CommandSys } from "./CommandSys"; -import { PosLevel } from "./PosLevel"; -import { PosType } from "./PosType"; @Entity("workflow") export class Workflow extends EntityBase { @@ -17,7 +14,7 @@ export class Workflow extends EntityBase { @Column({ nullable: true, - comment: "ระบบ", + comment: "ระบบ", //PLACEMENT length: 255, default: null, }) @@ -26,49 +23,13 @@ export class Workflow extends EntityBase { @OneToMany(() => State, (state) => state.workflow) states: State[]; - // @Column({ - // nullable: true, - // length: 40, - // comment: "คีย์นอก(FK)ของตาราง commandSys", - // default: null, - // }) - // commandSysId: string; - - // @ManyToOne(() => CommandSys, (commandSys) => commandSys.workflows) - // @JoinColumn({ name: "commandSysId" }) - // commandSys: CommandSys; - - // @Column({ - // nullable: true, - // length: 40, - // comment: "คีย์นอก(FK)ของตาราง posLevel", - // default: null, - // }) - // posLevelId: string; - - // @ManyToOne(() => PosLevel, (posLevel) => posLevel.workflows) - // @JoinColumn({ name: "posLevelId" }) - // posLevel: PosLevel; - - // @Column({ - // nullable: true, - // length: 40, - // comment: "คีย์นอก(FK)ของตาราง posType", - // default: null, - // }) - // posTypeId: string; - - // @ManyToOne(() => PosType, (posType) => posType.workflows) - // @JoinColumn({ name: "posTypeId" }) - // posType: PosType; - @Column({ nullable: true, - comment: "ชื่อระบบ", + comment: "ชื่อระบบ", //สอบคัดเลือก length: 100, default: null, }) - commandSysName: string; + sysName: string; @Column({ nullable: true, From b14d2d4a4663c2bb969a32e778daae836d7d69e6 Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 9 Oct 2024 13:13:47 +0700 Subject: [PATCH 06/41] no message --- src/controllers/ProfileController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/ProfileController.ts b/src/controllers/ProfileController.ts index 26f5a20f..4aa78e2b 100644 --- a/src/controllers/ProfileController.ts +++ b/src/controllers/ProfileController.ts @@ -3429,10 +3429,10 @@ export class ProfileController extends Controller { }, relations: ["orgChild1"], }); - if (!posMasters) { + if (posMasters == null || posMasters.orgRoot == null) { return new HttpSuccess(false); } - return new HttpSuccess(posMasters.orgChild1.isOfficer); + return new HttpSuccess(posMasters); } /** From 428ed28b64ca8e4eba824027b91127e66ba674f0 Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 9 Oct 2024 14:14:36 +0700 Subject: [PATCH 07/41] no message --- src/controllers/WorkflowController.ts | 149 ++++++++++++++++++ src/entities/StateOperator.ts | 6 +- src/entities/StateOperatorUser.ts | 42 +++++ .../1728456793035-add_table_workflow2.ts | 26 +++ 4 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/controllers/WorkflowController.ts create mode 100644 src/entities/StateOperatorUser.ts create mode 100644 src/migration/1728456793035-add_table_workflow2.ts diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts new file mode 100644 index 00000000..8121499a --- /dev/null +++ b/src/controllers/WorkflowController.ts @@ -0,0 +1,149 @@ +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"; + +@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); + + @Post("check-iscan") + public async checkIsCan( + @Request() req: RequestWithUser, + @Body() + body: { + workflowId: string; + stateId: string; + operator: string; + action: string; + }, + ) { + const operator = await this.stateOperatorRepo.findOne({ + where: { + operator: body.operator, + state: { id: body.stateId, workflow: { id: body.workflowId } }, + }, + }); + if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + + let isCan = false; + switch (body.action) { + 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-workflow") + public async checkWorkflow( + @Request() req: RequestWithUser, + @Body() + body: { + sysName: string; + posLevelName: string; + posTypeName: string; + }, + ) { + 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, "ไม่พบข้อมูล"); + + 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("state-next") + public async stateNext( + @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, + }); + } + + @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/StateOperator.ts b/src/entities/StateOperator.ts index 07ae241c..5438ece9 100644 --- a/src/entities/StateOperator.ts +++ b/src/entities/StateOperator.ts @@ -1,6 +1,7 @@ -import { Entity, Column, ManyToOne, JoinColumn } from "typeorm"; +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 { @@ -71,4 +72,7 @@ export class StateOperator extends EntityBase { @ManyToOne(() => State, (state) => state.stateOperators) @JoinColumn({ name: "stateId" }) state: State; + + @OneToMany(() => StateOperatorUser, (stateOperatorUser) => stateOperatorUser.stateOperator) + stateOperatorUsers: StateOperatorUser[]; } diff --git a/src/entities/StateOperatorUser.ts b/src/entities/StateOperatorUser.ts new file mode 100644 index 00000000..dd4bc5cc --- /dev/null +++ b/src/entities/StateOperatorUser.ts @@ -0,0 +1,42 @@ +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, + }) + profile: string; + + @Column({ + nullable: true, + comment: "", + length: 255, + default: null, + }) + type: string; //commander + + @Column({ + nullable: true, + comment: "ลำดับ", + default: null, + }) + order: number; // + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง stateOperator", + default: null, + }) + stateOperatorId: string; + + @ManyToOne(() => StateOperator, (stateOperator) => stateOperator.stateOperatorUsers) + @JoinColumn({ name: "stateOperatorId" }) + stateOperator: StateOperator; +} 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 'ชื่อระบบ'`); + } + +} From 8c7a0bb792fd60fa2bc283dbe1c605144942e6b9 Mon Sep 17 00:00:00 2001 From: Bright Date: Wed, 9 Oct 2024 15:45:42 +0700 Subject: [PATCH 08/41] fix exec command 01, 02 --- src/controllers/CommandController.ts | 86 +++++++++++----------------- 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 7ccf2203..4d25fda5 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -2048,12 +2048,6 @@ export class CommandController extends Controller { ) { await Promise.all( body.data.map(async (item) => { - const profile = await this.profileRepository.findOneBy({ - citizenId: item.bodyProfile.citizenId, - }); - if (profile) { - throw new HttpError(HttpStatus.BAD_REQUEST, "พบ profile ซ้ำ"); - } const before = null; const meta = { createdUserId: req.user.sub, @@ -2063,41 +2057,25 @@ export class CommandController extends Controller { 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 })) - ) { + 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 })) - ) { + if (item.bodyProfile.posTypeId && !(await this.posTypeRepo.findOneBy({ id: item.bodyProfile.posTypeId }))) { throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้"); } - const profile_: Profile = Object.assign({ ...item.bodyProfile, ...meta }); - const _null: any = null; - profile_.dateRetire = - item.bodyProfile.birthDate == null - ? _null - : calculateRetireDate(item.bodyProfile.birthDate); - profile_.dateRetireLaw = - item.bodyProfile.birthDate == null - ? _null - : calculateRetireLaw(item.bodyProfile.birthDate); - await this.profileRepository.save(profile_); - // setLogDataDiff(req, { before, after: profile_ }); - if (profile_ && profile_.id) { - const userKeycloakId = await createUser(profile_.citizenId, profile_.citizenId, { - //User, Password - firstName: profile_.firstName, - lastName: profile_.lastName, - email: profile_.email, + 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, requiredActions: ["UPDATE_PASSWORD"], }); if (typeof userKeycloakId !== "string") { @@ -2116,7 +2094,12 @@ export class CommandController extends Controller { })), ); 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 await Promise.all( item.bodyEducations.map(async (education) => { @@ -2124,14 +2107,13 @@ export class CommandController extends Controller { Object.assign(profileEdu, { ...education, ...meta }); const eduHistory = new ProfileEducationHistory(); Object.assign(eduHistory, { ...profileEdu, id: undefined }); - profileEdu.profileId = profile_.id; + 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 await Promise.all( item.bodyCertificates.map(async (cer) => { @@ -2139,40 +2121,38 @@ export class CommandController extends Controller { Object.assign(profileCer, { ...cer, ...meta }); const cerHistory = new ProfileCertificateHistory(); Object.assign(cerHistory, { ...profileCer, id: undefined }); - profileCer.profileId = profile_.id; + 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 const dest_item = await this.salaryRepo.findOne({ - where: { profileId: profile_.id }, + where: { profileId: profile.id }, order: { order: "DESC" }, }); const profileSal = new ProfileSalary(); Object.assign(profileSal, { ...item.bodySalarys, ...meta }); const salaryHistory = new ProfileSalaryHistory(); - Object.assign(history, { ...profileSal, id: undefined }); - (profileSal.order = dest_item == null ? 1 : dest_item.order + 1), - (profileSal.profileId = profile_.id); + 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 const posMaster = await this.posMasterRepository.findOne({ where: { id: item.bodyPosition.posmasterId }, }); - if (posMaster == null) + if (posMaster == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้"); const posMasterOld = await this.posMasterRepository.findOne({ where: { - current_holderId: profile_.id, + current_holderId: profile.id, orgRevisionId: posMaster.orgRevisionId, }, }); @@ -2203,7 +2183,7 @@ export class CommandController extends Controller { await this.positionRepository.save(clearPosition); } - posMaster.current_holderId = profile_.id; + posMaster.current_holderId = profile.id; if (posMasterOld != null) await this.posMasterRepository.save(posMasterOld); await this.posMasterRepository.save(posMaster); @@ -2215,15 +2195,15 @@ export class CommandController extends Controller { }); if (positionNew != null) { positionNew.positionIsSelected = true; - profile_.posLevelId = positionNew.posLevelId; - profile_.posTypeId = positionNew.posTypeId; - profile_.position = positionNew.positionName; - profile_.keycloak = userKeycloakId; // Update KeyCloak - await this.profileRepository.save(profile_, { data: req }); - setLogDataDiff(req, { before, after: profile_ }); + 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 }); } } + // console.log(`${item.bodyProfile.citizenId} ==> Success`) }), ); return new HttpSuccess(); From 7b83f91d731e30f8d3aea9b9cc159cd72b695f76 Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 9 Oct 2024 16:20:43 +0700 Subject: [PATCH 09/41] no message --- src/controllers/CommandController.ts | 4 + src/controllers/ProfileController.ts | 5 + src/controllers/WorkflowController.ts | 143 +++++++++++++++--- src/entities/StateOperator.ts | 3 - src/entities/StateOperatorUser.ts | 36 +++-- src/entities/Workflow.ts | 4 + .../1728465477520-add_table_workflow3.ts | 26 ++++ 7 files changed, 185 insertions(+), 36 deletions(-) create mode 100644 src/migration/1728465477520-add_table_workflow3.ts diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 7ccf2203..5c320875 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -121,6 +121,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 = "", @@ -130,6 +131,9 @@ export class CommandController extends Controller { ) { const [commands, total] = await this.commandRepository .createQueryBuilder("command") + .andWhere("command.createdUserId = :createdUserId", { + createdUserId: request.user.sub, + }) .andWhere( status != null && status != undefined && status != "" ? "command.status IN (:...status)" diff --git a/src/controllers/ProfileController.ts b/src/controllers/ProfileController.ts index 4aa78e2b..3b382b3e 100644 --- a/src/controllers/ProfileController.ts +++ b/src/controllers/ProfileController.ts @@ -4828,6 +4828,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") @@ -4942,6 +4943,10 @@ 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}`, diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 8121499a..139cc11a 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -7,6 +7,9 @@ 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") @@ -15,6 +18,56 @@ 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( @@ -23,20 +76,29 @@ export class WorkflowController extends Controller { body: { workflowId: string; stateId: string; - operator: 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: body.operator, + 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) { + switch (body.action.trim().toLocaleUpperCase()) { case "VIEW": isCan = operator.canView; case "UPDATE": @@ -63,32 +125,38 @@ export class WorkflowController extends Controller { } } - @Post("check-workflow") - public async checkWorkflow( + @Post("check-iscan-all") + public async checkIsCanAll( @Request() req: RequestWithUser, @Body() body: { - sysName: string; - posLevelName: string; - posTypeName: string; + workflowId: string; + stateId: string; }, ) { - const workflow = await this.workflowRepo.findOne({ + const profile = await this.profileRepo.findOne({ where: { - sysName: body.sysName, - posLevelName: body.posLevelName, - posTypeName: body.posTypeName, + keycloak: req.user.sub, }, - relations: ["states"], }); - if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + 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, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); - 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, + 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") @@ -103,6 +171,7 @@ export class WorkflowController extends Controller { where: { id: body.stateId, }, + relations: ["stateOperators", "workflow", "workflow.stateOperatorUsers"], }); if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); const _state = await this.stateRepo.findOne({ @@ -110,7 +179,43 @@ export class WorkflowController extends Controller { 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, + receiveDate: new Date(), + }) + .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, + receiveDate: new Date(), + }) + .catch((error) => { + console.error("Error calling API:", error); + }); + } return new HttpSuccess({ stateId: _state?.id || null, diff --git a/src/entities/StateOperator.ts b/src/entities/StateOperator.ts index 5438ece9..4e0406d3 100644 --- a/src/entities/StateOperator.ts +++ b/src/entities/StateOperator.ts @@ -72,7 +72,4 @@ export class StateOperator extends EntityBase { @ManyToOne(() => State, (state) => state.stateOperators) @JoinColumn({ name: "stateId" }) state: State; - - @OneToMany(() => StateOperatorUser, (stateOperatorUser) => stateOperatorUser.stateOperator) - stateOperatorUsers: StateOperatorUser[]; } diff --git a/src/entities/StateOperatorUser.ts b/src/entities/StateOperatorUser.ts index dd4bc5cc..5c890dd7 100644 --- a/src/entities/StateOperatorUser.ts +++ b/src/entities/StateOperatorUser.ts @@ -5,6 +5,14 @@ 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: "", @@ -13,30 +21,30 @@ export class StateOperatorUser extends EntityBase { }) profile: string; - @Column({ - nullable: true, - comment: "", - length: 255, - default: null, - }) - type: string; //commander - @Column({ nullable: true, comment: "ลำดับ", default: null, }) - order: number; // + order: number; + + @Column({ + nullable: true, + comment: "ผู้ดำเนินการ", + length: 255, + default: null, + }) + refId: string; @Column({ nullable: true, length: 40, - comment: "คีย์นอก(FK)ของตาราง stateOperator", + comment: "คีย์นอก(FK)ของตาราง workflow", default: null, }) - stateOperatorId: string; + workflowId: string; - @ManyToOne(() => StateOperator, (stateOperator) => stateOperator.stateOperatorUsers) - @JoinColumn({ name: "stateOperatorId" }) - stateOperator: StateOperator; + @ManyToOne(() => Workflow, (workflow) => workflow.stateOperatorUsers) + @JoinColumn({ name: "workflowId" }) + workflow: Workflow; } diff --git a/src/entities/Workflow.ts b/src/entities/Workflow.ts index 4b1ffa1b..c41d442c 100644 --- a/src/entities/Workflow.ts +++ b/src/entities/Workflow.ts @@ -1,6 +1,7 @@ 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 { @@ -46,4 +47,7 @@ export class Workflow extends EntityBase { default: null, }) posTypeName: string; + + @OneToMany(() => StateOperatorUser, (stateOperatorUser) => stateOperatorUser.workflow) + stateOperatorUsers: StateOperatorUser[]; } 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`); + } + +} From e43c29dbc4742c8b14e63d57115702b6a5e5ae97 Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 00:35:17 +0700 Subject: [PATCH 10/41] no message --- src/controllers/CommandController.ts | 2 - src/controllers/OrganizationController.ts | 791 ++++++++++++++++++++- src/controllers/PermissionController.ts | 14 - src/controllers/PermissionOrgController.ts | 77 +- src/controllers/ProfileController.ts | 85 +++ src/controllers/UserController.ts | 90 ++- src/interfaces/call-api.ts | 1 - src/interfaces/permission.ts | 1 - src/keycloak/index.ts | 63 ++ 9 files changed, 1095 insertions(+), 29 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 712c1f50..f0ba1287 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -1080,7 +1080,6 @@ export class CommandController extends Controller { })), }) .then(async (res) => { - console.log(res); _command = res; }) .catch(() => {}); @@ -2207,7 +2206,6 @@ export class CommandController extends Controller { await this.positionRepository.save(positionNew, { data: req }); } } - // console.log(`${item.bodyProfile.citizenId} ==> Success`) }), ); return new HttpSuccess(); diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index 8db60923..b4005ffc 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -1412,6 +1412,796 @@ 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")) { + _data = await new permission().PermissionOrgList(request, "SYS_ORG"); + } + + const orgRootData = await AppDataSource.getRepository(OrgRoot) + .createQueryBuilder("orgRoot") + .where("orgRoot.orgRevisionId = :id", { id }) + .andWhere( + _data.root != undefined && _data.root != null + ? _data.root[0] != null + ? `orgRoot.id IN (:...node)` + : `orgRoot.id is null` + : "1=1", + { + node: _data.root, + }, + ) + .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 }) + .andWhere( + _data.child1 != undefined && _data.child1 != null + ? _data.child1[0] != null + ? `orgChild1.id IN (:...node)` + : `orgChild1.id is null` + : "1=1", + { + node: _data.child1, + }, + ) + .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 }) + .andWhere( + _data.child2 != undefined && _data.child2 != null + ? _data.child2[0] != null + ? `orgChild2.id IN (:...node)` + : `orgChild2.id is null` + : "1=1", + { + node: _data.child2, + }, + ) + .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 }) + .andWhere( + _data.child3 != undefined && _data.child3 != null + ? _data.child3[0] != null + ? `orgChild3.id IN (:...node)` + : `orgChild3.id is null` + : "1=1", + { + node: _data.child3, + }, + ) + .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 }) + .andWhere( + _data.child4 != undefined && _data.child4 != null + ? _data.child4[0] != null + ? `orgChild4.id IN (:...node)` + : `orgChild4.id is null` + : "1=1", + { + node: _data.child4, + }, + ) + .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 +2244,6 @@ export class OrganizationController extends Controller { child3: null, child4: null, }; - console.log(_data); } const orgRootData = await AppDataSource.getRepository(OrgRoot) 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..3fffe3b6 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 หาสำนักทั้งหมดแบบร่าง @@ -55,15 +63,28 @@ export class PermissionOrgController extends Controller { where: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true }, }); if (!orgRevisionActive) { - throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่แบบร่างอยู่ตอนนี้"); + return new HttpSuccess([]); } - - const data = await this.orgRootRepository.find({ - where: { orgRevisionId: orgRevisionActive.id }, - order: { - orgRootOrder: "ASC", - }, - }); + let _data: any = [null]; + if (!request.user.role.includes("SUPER_ADMIN")) { + _data = await this.listAuthSysOrgFuncByRevisionId(request, "SYS_ORG", orgRevisionActive.id); + } + console.log(_data); + const data = await AppDataSource.getRepository(OrgRoot) + .createQueryBuilder("orgRoot") + .where("orgRoot.orgRevisionId = :id", { id: orgRevisionActive.id }) + .andWhere( + _data != undefined && _data != null + ? _data[0] != null + ? `orgRoot.id IN (:...node)` + : `orgRoot.id is null` + : "1=1", + { + node: _data, + }, + ) + .orderBy("orgRoot.orgRootOrder", "ASC") + .getMany(); return new HttpSuccess(data); } @@ -500,4 +521,44 @@ 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, + // current_holders: { orgRevisionId: revisionId }, + }, + relations: ["next_holders", "next_holders.authRole", "next_holders.authRole.authRoles"], + }); + console.log(request.user.sub); + console.log(revisionId); + console.log(profile); + 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, + }, + }); + console.log(posMaster); + console.log(attrOwnership); + 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 3b382b3e..2b06b51d 100644 --- a/src/controllers/ProfileController.ts +++ b/src/controllers/ProfileController.ts @@ -936,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); + } /** * * diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 280fd12d..911a4762 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"; @@ -239,7 +243,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/interfaces/call-api.ts b/src/interfaces/call-api.ts index 456c2f80..24169649 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..b69afce3 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); diff --git a/src/keycloak/index.ts b/src/keycloak/index.ts index 7384e0f8..19856b99 100644 --- a/src/keycloak/index.ts +++ b/src/keycloak/index.ts @@ -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 * From 0119ff5722a10e754d4dd2d23c53bbd79e8c911c Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 11:12:31 +0700 Subject: [PATCH 11/41] list command --- src/controllers/CommandController.ts | 173 ++++++++++++----- src/controllers/OrganizationController.ts | 212 ++++++++++++++++++++- src/controllers/PermissionOrgController.ts | 9 +- src/interfaces/permission.ts | 20 +- 4 files changed, 350 insertions(+), 64 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index f0ba1287..d83831a8 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -19,7 +19,7 @@ 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 } from "typeorm"; +import { Brackets, LessThan, MoreThan, Double, In, Not } from "typeorm"; import { CommandType } from "../entities/CommandType"; import { CommandSend } from "../entities/CommandSend"; import { Profile, CreateProfileAllFields } from "../entities/Profile"; @@ -35,10 +35,8 @@ import CallAPI from "../interfaces/call-api"; import { ProfileSalary, CreateProfileSalary } from "../entities/ProfileSalary"; import { ProfileSalaryHistory } from "../entities/ProfileSalaryHistory"; import { - calculateAge, calculateRetireDate, calculateRetireLaw, - calculateRetireYear, removeProfileInOrganize, setLogDataDiff, } from "../interfaces/utils"; @@ -51,33 +49,12 @@ import { ProfileDisciplineHistory } from "../entities/ProfileDisciplineHistory"; import { PosMasterAct } from "../entities/PosMasterAct"; import { PosLevel } from "../entities/PosLevel"; import { PosType } from "../entities/PosType"; -import { - addUserGroup, - addUserRoles, - createGroup, - createUser, - deleteGroup, - deleteUser, - editUser, - getGroups, - getRoles, - getUser, - getUserGroups, - getUserList, - removeUserGroup, - removeUserRoles, - getRoleMappings, - getUserCount, - enableStatus, -} from "../keycloak"; +import { addUserRoles, createUser, getRoles } from "../keycloak"; import { ProfileEducation, CreateProfileEducation } from "../entities/ProfileEducation"; import { ProfileEducationHistory } from "../entities/ProfileEducationHistory"; -import { - CreateProfileCertificate, - ProfileCertificate, - UpdateProfileCertificate, -} from "../entities/ProfileCertificate"; +import { CreateProfileCertificate, ProfileCertificate } from "../entities/ProfileCertificate"; import { ProfileCertificateHistory } from "../entities/ProfileCertificateHistory"; +import permission from "../interfaces/permission"; @Route("api/v1/org/command") @Tags("Command") @@ -129,11 +106,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, "SYS_ORG"); + } + 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("command.createdUserId = :createdUserId", { - createdUserId: request.user.sub, - }) + .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)" @@ -2063,18 +2136,32 @@ export class CommandController extends Controller { 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 }))) { + 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 }))) { + 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) { + 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); + 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, @@ -2101,8 +2188,8 @@ export class CommandController extends Controller { await this.profileRepository.save(profile); setLogDataDiff(req, { before, after: profile }); } - - if(profile && profile.id) { + + if (profile && profile.id) { //Educations await Promise.all( item.bodyEducations.map(async (education) => { @@ -2124,7 +2211,7 @@ export class CommandController extends Controller { Object.assign(profileCer, { ...cer, ...meta }); const cerHistory = new ProfileCertificateHistory(); Object.assign(cerHistory, { ...profileCer, id: undefined }); - profileCer.profileId = profile.id + profileCer.profileId = profile.id; await this.certificateRepo.save(profileCer, { data: req }); setLogDataDiff(req, { before, after: profileCer }); cerHistory.profileCertificateId = profileCer.id; @@ -2140,8 +2227,8 @@ export class CommandController extends Controller { 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 + (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; @@ -2150,7 +2237,7 @@ export class CommandController extends Controller { const posMaster = await this.posMasterRepository.findOne({ where: { id: item.bodyPosition.posmasterId }, }); - if (posMaster == null) + if (posMaster == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้"); const posMasterOld = await this.posMasterRepository.findOne({ @@ -2201,7 +2288,7 @@ export class CommandController extends Controller { profile.posLevelId = positionNew.posLevelId; profile.posTypeId = positionNew.posTypeId; profile.position = positionNew.positionName; - await this.profileRepository.save(profile, { data: req }); + await this.profileRepository.save(profile, { data: req }); setLogDataDiff(req, { before, after: profile }); await this.positionRepository.save(positionNew, { data: req }); } diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index b4005ffc..31ac3043 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -1433,7 +1433,11 @@ export class OrganizationController extends Controller { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล"); } if (!request.user.role.includes("SUPER_ADMIN")) { - _data = await new permission().PermissionOrgList(request, "SYS_ORG"); + 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 orgRootData = await AppDataSource.getRepository(OrgRoot) @@ -6528,9 +6532,9 @@ export class OrganizationController extends Controller { return new HttpSuccess(formattedData); } /** - * API เช็คสกจในระบบ + * API เช็ค org ในระบบ * - * @summary - เช็คสกจในระบบ (ADMIN) + * @summary - เช็ค org ในระบบ (ADMIN) * */ @Get("check/child1/{id}") @@ -6545,4 +6549,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/PermissionOrgController.ts b/src/controllers/PermissionOrgController.ts index 3fffe3b6..0644a19a 100644 --- a/src/controllers/PermissionOrgController.ts +++ b/src/controllers/PermissionOrgController.ts @@ -65,11 +65,10 @@ export class PermissionOrgController extends Controller { if (!orgRevisionActive) { return new HttpSuccess([]); } - let _data: any = [null]; + let _data: any = null; if (!request.user.role.includes("SUPER_ADMIN")) { _data = await this.listAuthSysOrgFuncByRevisionId(request, "SYS_ORG", orgRevisionActive.id); } - console.log(_data); const data = await AppDataSource.getRepository(OrgRoot) .createQueryBuilder("orgRoot") .where("orgRoot.orgRevisionId = :id", { id: orgRevisionActive.id }) @@ -529,13 +528,9 @@ export class PermissionOrgController extends Controller { let profile = await this.profileRepo.findOne({ where: { keycloak: request.user.sub, - // current_holders: { orgRevisionId: revisionId }, }, relations: ["next_holders", "next_holders.authRole", "next_holders.authRole.authRoles"], }); - console.log(request.user.sub); - console.log(revisionId); - console.log(profile); if (!profile) { return [null]; } @@ -551,8 +546,6 @@ export class PermissionOrgController extends Controller { orgRevisionId: revisionId, }, }); - console.log(posMaster); - console.log(attrOwnership); if (!posMaster) { return [null]; } else if (attrOwnership == "OWNER") { diff --git a/src/interfaces/permission.ts b/src/interfaces/permission.ts index b69afce3..e063de6b 100644 --- a/src/interfaces/permission.ts +++ b/src/interfaces/permission.ts @@ -83,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, @@ -111,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; From 07858809b92662a413f0bebe6b7b1c55cc32f115 Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 11:15:33 +0700 Subject: [PATCH 12/41] no message --- src/controllers/CommandController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index d83831a8..3fa3cc56 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -126,7 +126,7 @@ export class CommandController extends Controller { child4: null, }; if (!request.user.role.includes("SUPER_ADMIN")) { - _data = await new permission().PermissionOrgList(request, "SYS_ORG"); + _data = await new permission().PermissionOrgList(request, "COMMAND"); } const profiles = await this.profileRepository .createQueryBuilder("profile") From 8eb643c435f8f0820e478e8de24c53a02e17fbbf Mon Sep 17 00:00:00 2001 From: Bright Date: Thu, 10 Oct 2024 13:07:10 +0700 Subject: [PATCH 13/41] no message --- src/controllers/CommandController.ts | 216 ++++++++++++++------------- 1 file changed, 113 insertions(+), 103 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index f0ba1287..6b158ee7 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -2039,13 +2039,13 @@ export class CommandController extends Controller { body: { data: { bodyProfile: CreateProfileAllFields; - bodyEducations: CreateProfileEducation[]; - bodyCertificates: CreateProfileCertificate[]; - bodySalarys: CreateProfileSalary; - bodyPosition: { + bodyEducations?: CreateProfileEducation[]; + bodyCertificates?: CreateProfileCertificate[]; + bodySalarys?: CreateProfileSalary | null; + bodyPosition?: { posmasterId: string; positionId: string; - }; + } | null; }[]; }, ) { @@ -2101,109 +2101,119 @@ export class CommandController extends Controller { await this.profileRepository.save(profile); setLogDataDiff(req, { before, after: profile }); } - if(profile && profile.id) { //Educations - 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 }); - }), - ); + 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 - 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 }); - }), - ); + 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 - 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 }); + 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 - 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 }); + 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 }); + } } } }), From 7c8b5d70ed2fd8659aefbcb15312a048153a969c Mon Sep 17 00:00:00 2001 From: Bright Date: Thu, 10 Oct 2024 13:48:20 +0700 Subject: [PATCH 14/41] no message --- src/controllers/CommandController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 846b3e66..32ddde5b 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -2232,8 +2232,8 @@ export class CommandController extends Controller { 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); + 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; From 5df50e673ccda9675635968d5907eb14a29eef12 Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 13:50:34 +0700 Subject: [PATCH 15/41] =?UTF-8?q?=E0=B8=82=E0=B8=AD=E0=B9=81=E0=B8=81?= =?UTF-8?q?=E0=B9=89=E0=B9=84=E0=B8=82=E0=B9=80=E0=B8=9E=E0=B8=B4=E0=B9=88?= =?UTF-8?q?=E0=B8=A1=E0=B9=80=E0=B8=A5=E0=B8=82=E0=B8=9A=E0=B8=B1=E0=B8=95?= =?UTF-8?q?=E0=B8=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/ProfileEditController.ts | 1 + src/controllers/ProfileEditEmployeeController.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/controllers/ProfileEditController.ts b/src/controllers/ProfileEditController.ts index fac2767d..60e95207 100644 --- a/src/controllers/ProfileEditController.ts +++ b/src/controllers/ProfileEditController.ts @@ -122,6 +122,7 @@ export class ProfileEditController extends Controller { .getManyAndCount(); const _data = getProfileEdit.map((item) => ({ id: item.id, + idcard: item.profile.citizenId, topic: item.topic, detail: item.detail, status: item.status, diff --git a/src/controllers/ProfileEditEmployeeController.ts b/src/controllers/ProfileEditEmployeeController.ts index d4cdda23..1792700c 100644 --- a/src/controllers/ProfileEditEmployeeController.ts +++ b/src/controllers/ProfileEditEmployeeController.ts @@ -129,6 +129,7 @@ export class ProfileEditEmployeeController extends Controller { const _data = getProfileEdit.map((item) => ({ id: item.id, + idcard: item.profile.citizenId, topic: item.topic, detail: item.detail, status: item.status, From de8944dbc98d789d5cf239d7ae3c516a67846139 Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 14:35:26 +0700 Subject: [PATCH 16/41] no message --- src/controllers/CommandController.ts | 19 +++++++++---------- src/controllers/UserController.ts | 1 - src/keycloak/index.ts | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 32ddde5b..d3d312e4 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -2166,7 +2166,6 @@ export class CommandController extends Controller { firstName: profile.firstName, lastName: profile.lastName, email: profile.email, - requiredActions: ["UPDATE_PASSWORD"], }); if (typeof userKeycloakId !== "string") { throw new Error(userKeycloakId.errorMessage); @@ -2188,9 +2187,9 @@ export class CommandController extends Controller { await this.profileRepository.save(profile); setLogDataDiff(req, { before, after: profile }); } - if(profile && profile.id) { + if (profile && profile.id) { //Educations - if(item.bodyEducations && item.bodyEducations.length > 0) { + if (item.bodyEducations && item.bodyEducations.length > 0) { await Promise.all( item.bodyEducations.map(async (education) => { const profileEdu = new ProfileEducation(); @@ -2205,9 +2204,9 @@ export class CommandController extends Controller { }), ); } - + //Certificates - if(item.bodyCertificates && item.bodyCertificates.length > 0) { + if (item.bodyCertificates && item.bodyCertificates.length > 0) { await Promise.all( item.bodyCertificates.map(async (cer) => { const profileCer = new ProfileCertificate(); @@ -2223,7 +2222,7 @@ export class CommandController extends Controller { ); } //Salary - if(item.bodySalarys && item.bodySalarys != null) { + if (item.bodySalarys && item.bodySalarys != null) { const dest_item = await this.salaryRepo.findOne({ where: { profileId: profile.id }, order: { order: "DESC" }, @@ -2232,7 +2231,7 @@ export class CommandController extends Controller { 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.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 }); @@ -2240,11 +2239,11 @@ export class CommandController extends Controller { await this.salaryHistoryRepo.save(salaryHistory, { data: req }); } //Position - if(item.bodyPosition && item.bodyPosition != null) { + if (item.bodyPosition && item.bodyPosition != null) { const posMaster = await this.posMasterRepository.findOne({ where: { id: item.bodyPosition.posmasterId }, }); - if (posMaster == null) + if (posMaster == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้"); const posMasterOld = await this.posMasterRepository.findOne({ @@ -2295,7 +2294,7 @@ export class CommandController extends Controller { profile.posLevelId = positionNew.posLevelId; profile.posTypeId = positionNew.posTypeId; profile.position = positionNew.positionName; - await this.profileRepository.save(profile, { data: req }); + await this.profileRepository.save(profile, { data: req }); setLogDataDiff(req, { before, after: profile }); await this.positionRepository.save(positionNew, { data: req }); } diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 911a4762..456de900 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -98,7 +98,6 @@ export class KeycloakController extends Controller { firstName: body.firstName, lastName: body.lastName, email: body.email, - requiredActions: ["UPDATE_PASSWORD"], }); if (typeof userId !== "string") { diff --git a/src/keycloak/index.ts b/src/keycloak/index.ts index 19856b99..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, }), From ec036d4c59d89224cde735dfe2efb36ac404d4fb Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 14:50:52 +0700 Subject: [PATCH 17/41] no message --- src/controllers/OrganizationController.ts | 81 +++++++++++------------ 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index 31ac3043..e4261393 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -25,7 +25,6 @@ import { OrgChild3 } from "../entities/OrgChild3"; import { OrgChild4 } from "../entities/OrgChild4"; import { PosMaster } from "../entities/PosMaster"; import { Position } from "../entities/Position"; -import CallAPI from "../interfaces/call-api"; import { ProfileSalary } from "../entities/ProfileSalary"; import { Profile } from "../entities/Profile"; import { RequestWithUser } from "../middlewares/user"; @@ -1475,16 +1474,16 @@ export class OrganizationController extends Controller { ? await AppDataSource.getRepository(OrgChild1) .createQueryBuilder("orgChild1") .where("orgChild1.orgRootId IN (:...ids)", { ids: orgRootIds }) - .andWhere( - _data.child1 != undefined && _data.child1 != null - ? _data.child1[0] != null - ? `orgChild1.id IN (:...node)` - : `orgChild1.id is null` - : "1=1", - { - node: _data.child1, - }, - ) + // .andWhere( + // _data.child1 != undefined && _data.child1 != null + // ? _data.child1[0] != null + // ? `orgChild1.id IN (:...node)` + // : `orgChild1.id is null` + // : "1=1", + // { + // node: _data.child1, + // }, + // ) .select([ "orgChild1.id", "orgChild1.isOfficer", @@ -1510,16 +1509,16 @@ export class OrganizationController extends Controller { ? await AppDataSource.getRepository(OrgChild2) .createQueryBuilder("orgChild2") .where("orgChild2.orgChild1Id IN (:...ids)", { ids: orgChild1Ids }) - .andWhere( - _data.child2 != undefined && _data.child2 != null - ? _data.child2[0] != null - ? `orgChild2.id IN (:...node)` - : `orgChild2.id is null` - : "1=1", - { - node: _data.child2, - }, - ) + // .andWhere( + // _data.child2 != undefined && _data.child2 != null + // ? _data.child2[0] != null + // ? `orgChild2.id IN (:...node)` + // : `orgChild2.id is null` + // : "1=1", + // { + // node: _data.child2, + // }, + // ) .select([ "orgChild2.id", "orgChild2.orgChild2Name", @@ -1545,16 +1544,16 @@ export class OrganizationController extends Controller { ? await AppDataSource.getRepository(OrgChild3) .createQueryBuilder("orgChild3") .where("orgChild3.orgChild2Id IN (:...ids)", { ids: orgChild2Ids }) - .andWhere( - _data.child3 != undefined && _data.child3 != null - ? _data.child3[0] != null - ? `orgChild3.id IN (:...node)` - : `orgChild3.id is null` - : "1=1", - { - node: _data.child3, - }, - ) + // .andWhere( + // _data.child3 != undefined && _data.child3 != null + // ? _data.child3[0] != null + // ? `orgChild3.id IN (:...node)` + // : `orgChild3.id is null` + // : "1=1", + // { + // node: _data.child3, + // }, + // ) .select([ "orgChild3.id", "orgChild3.orgChild3Name", @@ -1580,16 +1579,16 @@ export class OrganizationController extends Controller { ? await AppDataSource.getRepository(OrgChild4) .createQueryBuilder("orgChild4") .where("orgChild4.orgChild3Id IN (:...ids)", { ids: orgChild3Ids }) - .andWhere( - _data.child4 != undefined && _data.child4 != null - ? _data.child4[0] != null - ? `orgChild4.id IN (:...node)` - : `orgChild4.id is null` - : "1=1", - { - node: _data.child4, - }, - ) + // .andWhere( + // _data.child4 != undefined && _data.child4 != null + // ? _data.child4[0] != null + // ? `orgChild4.id IN (:...node)` + // : `orgChild4.id is null` + // : "1=1", + // { + // node: _data.child4, + // }, + // ) .select([ "orgChild4.id", "orgChild4.orgChild4Name", From 439564f04e640e783cf3653f56fc1e6044f774ab Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 15:22:47 +0700 Subject: [PATCH 18/41] =?UTF-8?q?=E0=B9=81=E0=B8=81=E0=B9=89=E0=B8=AA?= =?UTF-8?q?=E0=B8=B4=E0=B8=94=20admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/OrganizationController.ts | 114 ++++++++---------- src/controllers/PermissionOrgController.ts | 37 +++--- src/controllers/ProfileEditController.ts | 1 + .../ProfileEditEmployeeController.ts | 1 + 4 files changed, 70 insertions(+), 83 deletions(-) diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index e4261393..0d7ffbbc 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -25,6 +25,7 @@ import { OrgChild3 } from "../entities/OrgChild3"; import { OrgChild4 } from "../entities/OrgChild4"; import { PosMaster } from "../entities/PosMaster"; import { Position } from "../entities/Position"; +import CallAPI from "../interfaces/call-api"; import { ProfileSalary } from "../entities/ProfileSalary"; import { Profile } from "../entities/Profile"; import { RequestWithUser } from "../middlewares/user"; @@ -1419,39 +1420,62 @@ export class OrganizationController extends Controller { */ @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, - }; + // 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, "ไม่พบข้อมูล"); - } + // 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")) { - 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 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( - _data.root != undefined && _data.root != null - ? _data.root[0] != null - ? `orgRoot.id IN (:...node)` - : `orgRoot.id is null` - : "1=1", - { - node: _data.root, - }, - ) + .andWhere(rootId != null ? `orgRoot.id = :rootId` : "1=1", { + rootId: rootId, + }) .select([ "orgRoot.id", "orgRoot.orgRootName", @@ -1474,16 +1498,6 @@ export class OrganizationController extends Controller { ? await AppDataSource.getRepository(OrgChild1) .createQueryBuilder("orgChild1") .where("orgChild1.orgRootId IN (:...ids)", { ids: orgRootIds }) - // .andWhere( - // _data.child1 != undefined && _data.child1 != null - // ? _data.child1[0] != null - // ? `orgChild1.id IN (:...node)` - // : `orgChild1.id is null` - // : "1=1", - // { - // node: _data.child1, - // }, - // ) .select([ "orgChild1.id", "orgChild1.isOfficer", @@ -1509,16 +1523,6 @@ export class OrganizationController extends Controller { ? await AppDataSource.getRepository(OrgChild2) .createQueryBuilder("orgChild2") .where("orgChild2.orgChild1Id IN (:...ids)", { ids: orgChild1Ids }) - // .andWhere( - // _data.child2 != undefined && _data.child2 != null - // ? _data.child2[0] != null - // ? `orgChild2.id IN (:...node)` - // : `orgChild2.id is null` - // : "1=1", - // { - // node: _data.child2, - // }, - // ) .select([ "orgChild2.id", "orgChild2.orgChild2Name", @@ -1544,16 +1548,6 @@ export class OrganizationController extends Controller { ? await AppDataSource.getRepository(OrgChild3) .createQueryBuilder("orgChild3") .where("orgChild3.orgChild2Id IN (:...ids)", { ids: orgChild2Ids }) - // .andWhere( - // _data.child3 != undefined && _data.child3 != null - // ? _data.child3[0] != null - // ? `orgChild3.id IN (:...node)` - // : `orgChild3.id is null` - // : "1=1", - // { - // node: _data.child3, - // }, - // ) .select([ "orgChild3.id", "orgChild3.orgChild3Name", @@ -1579,16 +1573,6 @@ export class OrganizationController extends Controller { ? await AppDataSource.getRepository(OrgChild4) .createQueryBuilder("orgChild4") .where("orgChild4.orgChild3Id IN (:...ids)", { ids: orgChild3Ids }) - // .andWhere( - // _data.child4 != undefined && _data.child4 != null - // ? _data.child4[0] != null - // ? `orgChild4.id IN (:...node)` - // : `orgChild4.id is null` - // : "1=1", - // { - // node: _data.child4, - // }, - // ) .select([ "orgChild4.id", "orgChild4.orgChild4Name", diff --git a/src/controllers/PermissionOrgController.ts b/src/controllers/PermissionOrgController.ts index 0644a19a..1e17ac8e 100644 --- a/src/controllers/PermissionOrgController.ts +++ b/src/controllers/PermissionOrgController.ts @@ -56,32 +56,33 @@ 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) { - return new HttpSuccess([]); - } - let _data: any = null; + if (!orgRevisionActive) return new HttpSuccess([]); + let rootId: any = null; if (!request.user.role.includes("SUPER_ADMIN")) { - _data = await this.listAuthSysOrgFuncByRevisionId(request, "SYS_ORG", orgRevisionActive.id); + const profile = await this.profileRepo.findOne({ + where: { + keycloak: request.user.sub, + }, + }); + if (profile == null) return new HttpSuccess([]); + + 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( - _data != undefined && _data != null - ? _data[0] != null - ? `orgRoot.id IN (:...node)` - : `orgRoot.id is null` - : "1=1", - { - node: _data, - }, - ) + .andWhere(rootId != null ? `orgRoot.id = :rootId` : "1=1", { + rootId: rootId, + }) .orderBy("orgRoot.orgRootOrder", "ASC") .getMany(); return new HttpSuccess(data); diff --git a/src/controllers/ProfileEditController.ts b/src/controllers/ProfileEditController.ts index 60e95207..5c0e0e17 100644 --- a/src/controllers/ProfileEditController.ts +++ b/src/controllers/ProfileEditController.ts @@ -123,6 +123,7 @@ export class ProfileEditController 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/ProfileEditEmployeeController.ts b/src/controllers/ProfileEditEmployeeController.ts index 1792700c..7d8ef83e 100644 --- a/src/controllers/ProfileEditEmployeeController.ts +++ b/src/controllers/ProfileEditEmployeeController.ts @@ -130,6 +130,7 @@ 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, From ee3975c93485f0c92609691ada15b681a26c7e8e Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 17:42:20 +0700 Subject: [PATCH 19/41] no message --- src/controllers/CommandController.ts | 68 +++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index d3d312e4..3da04c79 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -89,6 +89,7 @@ export class CommandController extends Controller { private profileEducationHistoryRepo = AppDataSource.getRepository(ProfileEducationHistory); private certificateRepo = AppDataSource.getRepository(ProfileCertificate); private certificateHistoryRepo = AppDataSource.getRepository(ProfileCertificateHistory); + private orgRevisionRepository = AppDataSource.getRepository(OrgRevision); /** * API list รายการคำสั่ง @@ -367,7 +368,6 @@ export class CommandController extends Controller { commandAffectDate: Date | null; commandExcecuteDate: Date | null; isBangkok: string | null; - isAttachment: boolean | null; }, @Request() request: RequestWithUser, ) { @@ -1085,9 +1085,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: false, orgRevisionIsDraft: true }, + 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.next_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, @@ -1104,6 +1128,9 @@ export class CommandController extends Controller { : Extension.ToThaiNumber(Extension.ToThaiFullDate2(command.commandExcecuteDate)), name: "...................................", position: "...................................", + authorizedUserFullName: "...................................", + authorizedPosition: "...................................", + commandAffectDate: "...................................", }; return new HttpSuccess({ template: command.commandType.fileCover, @@ -1132,7 +1159,24 @@ export class CommandController extends Controller { let _command: any = []; const path = this.commandTypePath(command.commandType.code); if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ"); - + console.log( + command.commandRecives + .filter((x) => x.refId != null) + .map((x) => ({ + refId: x.refId, + Sequence: x.order, + CitizenId: x.citizenId, + Prefix: x.prefix, + FirstName: x.firstName, + LastName: x.lastName, + Amount: x.amount, + PositionSalaryAmount: x.positionSalaryAmount, + MouthSalaryAmount: x.mouthSalaryAmount, + RemarkHorizontal: x.remarkHorizontal, + RemarkVertical: x.remarkVertical, + CommandYear: command.commandYear, + })), + ); await new CallAPI() .PostData(request, path + "/attachment", { refIds: command.commandRecives @@ -1160,7 +1204,7 @@ export class CommandController extends Controller { return new HttpSuccess({ template: command.commandType.fileAttachment, reportName: "xlsx-report", - data: _command, + data: { data: _command }, }); } @@ -2446,6 +2490,12 @@ 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(); } @@ -2476,6 +2526,12 @@ 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/report/attachment") @@ -2624,7 +2680,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": From b7ae2e35a45b560e014c92a4a7b2e1c37a1af0c3 Mon Sep 17 00:00:00 2001 From: Bright Date: Thu, 10 Oct 2024 17:58:34 +0700 Subject: [PATCH 20/41] fix #656, #657 --- .../DevelopmentRequestController.ts | 22 +++---- .../ProfileDevelopmentController.ts | 60 ++++++++++++++++--- 2 files changed, 64 insertions(+), 18 deletions(-) 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/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}") From fd0c421dd9ec61d180271028f1344f78d7fa46bb Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 20:05:25 +0700 Subject: [PATCH 21/41] no message --- src/controllers/CommandController.ts | 66 ++++++++++++++++++---------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 3da04c79..7888c0f4 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -1093,7 +1093,7 @@ export class CommandController extends Controller { : null; if (issue == null) { const orgRevisionActive = await this.orgRevisionRepository.findOne({ - where: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true }, + where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, relations: ["posMasters", "posMasters.orgRoot"], }); if (orgRevisionActive != null) { @@ -1104,8 +1104,8 @@ export class CommandController extends Controller { }); if (profile != null) { issue = - orgRevisionActive?.posMasters?.filter((x) => x.next_holderId == profile.id)[0]?.orgRoot - ?.orgRootName || null; + orgRevisionActive?.posMasters?.filter((x) => x.current_holderId == profile.id)[0] + ?.orgRoot?.orgRootName || null; } } } @@ -1159,24 +1159,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, "ไม่พบประเภทคำสั่งนี้ในระบบ"); - console.log( - command.commandRecives - .filter((x) => x.refId != null) - .map((x) => ({ - refId: x.refId, - Sequence: x.order, - CitizenId: x.citizenId, - Prefix: x.prefix, - FirstName: x.firstName, - LastName: x.lastName, - Amount: x.amount, - PositionSalaryAmount: x.positionSalaryAmount, - MouthSalaryAmount: x.mouthSalaryAmount, - RemarkHorizontal: x.remarkHorizontal, - RemarkVertical: x.remarkVertical, - CommandYear: command.commandYear, - })), - ); await new CallAPI() .PostData(request, path + "/attachment", { refIds: command.commandRecives @@ -1201,10 +1183,47 @@ export class CommandController extends Controller { }) .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: { 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)), + }, }); } @@ -2602,8 +2621,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, From 87a69017bcdf8b2c11cb8bfbe10a34ce709b7417 Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 10 Oct 2024 20:50:21 +0700 Subject: [PATCH 22/41] no message --- src/controllers/CommandController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 7888c0f4..dc1fd73b 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -1024,7 +1024,7 @@ export class CommandController extends Controller { payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, - receiveDate: command.commandExcecuteDate, + isSendNotification: true, }) .catch((error) => { console.error("Error calling API:", error); From d10c38d1b921e7c2453b4b974d0ae6daba1cb2d9 Mon Sep 17 00:00:00 2001 From: kittapath Date: Fri, 11 Oct 2024 10:10:50 +0700 Subject: [PATCH 23/41] no message --- src/controllers/CommandController.ts | 44 ++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index dc1fd73b..8206e076 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -2517,6 +2517,22 @@ export class CommandController extends Controller { 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(); + } @Post("command40/officer/report/excecute") public async command40SalaryOfficerExcecute( @@ -2545,12 +2561,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); + // 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") From fac7d762aa5a1bc03f9b15cf3e770a55a7063211 Mon Sep 17 00:00:00 2001 From: kittapath Date: Fri, 11 Oct 2024 10:17:44 +0700 Subject: [PATCH 24/41] no message --- src/controllers/WorkflowController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 139cc11a..45de5fa2 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -193,7 +193,7 @@ export class WorkflowController extends Controller { payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, - receiveDate: new Date(), + isSendNotification: true, }) .catch((error) => { console.error("Error calling API:", error); @@ -210,7 +210,7 @@ export class WorkflowController extends Controller { payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, - receiveDate: new Date(), + isSendNotification: true, }) .catch((error) => { console.error("Error calling API:", error); From 2e406b14ab7d89083d69eca4be93132342df21f3 Mon Sep 17 00:00:00 2001 From: Bright Date: Fri, 11 Oct 2024 10:37:53 +0700 Subject: [PATCH 25/41] =?UTF-8?q?fix=20Error=20=E0=B8=A3=E0=B8=B2=E0=B8=A2?= =?UTF-8?q?=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=84=E0=B8=B3=E0=B8=A3=E0=B9=89?= =?UTF-8?q?=E0=B8=AD=E0=B8=87=E0=B8=82=E0=B8=AD=E0=B9=81=E0=B8=81=E0=B9=89?= =?UTF-8?q?=E0=B9=84=E0=B8=82=20#658?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/ProfileEditController.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/ProfileEditController.ts b/src/controllers/ProfileEditController.ts index 5c0e0e17..f1b9d7c8 100644 --- a/src/controllers/ProfileEditController.ts +++ b/src/controllers/ProfileEditController.ts @@ -153,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) { From 2af5598aae09572f32203adad0f80b0ac88ec813 Mon Sep 17 00:00:00 2001 From: kittapath Date: Fri, 11 Oct 2024 10:47:15 +0700 Subject: [PATCH 26/41] migrate workflow --- src/entities/MetaState.ts | 46 +++++++++++++++++++ src/entities/MetaStateOperator.ts | 74 +++++++++++++++++++++++++++++++ src/entities/MetaWorkflow.ts | 52 ++++++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 src/entities/MetaState.ts create mode 100644 src/entities/MetaStateOperator.ts create mode 100644 src/entities/MetaWorkflow.ts 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[]; +} From 608c8967bc709adcad628852e87c55f31b8fbe86 Mon Sep 17 00:00:00 2001 From: AdisakKanthawilang Date: Fri, 11 Oct 2024 11:05:31 +0700 Subject: [PATCH 27/41] rabbitMQ command --- package-lock.json | 109 +++++++++++++++++++++++ package.json | 2 + src/app.ts | 24 +++++ src/controllers/CommandController.ts | 119 +++++++++++++++++-------- src/interfaces/call-api.ts | 7 +- src/interfaces/utils.ts | 90 +++++++++++++++++++ src/services/rabbitmq.ts | 126 +++++++++++++++++++++++++++ 7 files changed, 440 insertions(+), 37 deletions(-) create mode 100644 src/services/rabbitmq.ts diff --git a/package-lock.json b/package-lock.json index e4afc853..c8c77e5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@elastic/elasticsearch": "^8.14.0", "@nestjs/platform-express": "^10.3.9", "@tsoa/runtime": "^6.0.0", + "amqplib": "^0.10.4", "axios": "^1.7.2", "cors": "^2.8.5", "csv-parser": "^3.0.0", @@ -32,6 +33,7 @@ "xlsx": "^0.20.2" }, "devDependencies": { + "@types/amqplib": "^0.10.5", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/node": "^20.11.5", @@ -43,6 +45,45 @@ "typescript": "^5.3.3" } }, + "node_modules/@acuminous/bitsyntax": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz", + "integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==", + "dependencies": { + "buffer-more-ints": "~1.0.0", + "debug": "^4.3.4", + "safe-buffer": "~5.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/@acuminous/bitsyntax/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@acuminous/bitsyntax/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/@acuminous/bitsyntax/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -392,6 +433,15 @@ "yarn": ">=1.9.4" } }, + "node_modules/@types/amqplib": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.5.tgz", + "integrity": "sha512-/cSykxROY7BWwDoi4Y4/jLAuZTshZxd8Ey1QYa/VaXriMotBDoou7V/twJiOSHzU6t1Kp1AHAUXGCgqq+6DNeg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -568,6 +618,41 @@ "node": ">=0.10.0" } }, + "node_modules/amqplib": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.4.tgz", + "integrity": "sha512-DMZ4eCEjAVdX1II2TfIUpJhfKAuoCeDIo/YyETbfAqehHTXxxs7WOOd+N1Xxr4cKhx12y23zk8/os98FxlZHrw==", + "dependencies": { + "@acuminous/bitsyntax": "^0.1.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "url-parse": "~1.5.10" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/amqplib/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/amqplib/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/amqplib/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" + }, "node_modules/ansi-escapes": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", @@ -860,6 +945,11 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/buffer-more-ints": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -3508,6 +3598,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -3653,6 +3748,11 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, "node_modules/restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -4967,6 +5067,15 @@ "node": ">= 0.8" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index e0606931..6a8cbda2 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "author": "", "license": "ISC", "devDependencies": { + "@types/amqplib": "^0.10.5", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/node": "^20.11.5", @@ -30,6 +31,7 @@ "@elastic/elasticsearch": "^8.14.0", "@nestjs/platform-express": "^10.3.9", "@tsoa/runtime": "^6.0.0", + "amqplib": "^0.10.4", "axios": "^1.7.2", "cors": "^2.8.5", "csv-parser": "^3.0.0", diff --git a/src/app.ts b/src/app.ts index 40c284ac..d4906096 100644 --- a/src/app.ts +++ b/src/app.ts @@ -5,11 +5,14 @@ import express from "express"; import swaggerUi from "swagger-ui-express"; import swaggerDocument from "./swagger.json"; import * as cron from "node-cron"; +import { init as rabbitmqInit } from './services/rabbitmq'; import error from "./middlewares/error"; import { AppDataSource } from "./database/data-source"; import { RegisterRoutes } from "./routes"; import { OrganizationController } from "./controllers/OrganizationController"; import logMiddleware from "./middlewares/logs"; +import { run } from "node:test"; +import { CommandController } from "./controllers/CommandController"; async function main() { await AppDataSource.initialize(); @@ -43,6 +46,17 @@ async function main() { } }); + const cronTime_command = "0 2 * * * *"; + // const cronTime_command = "*/10 * * * * *"; + cron.schedule(cronTime_command, async () => { + try { + const commandController = new CommandController(); + await commandController.cronjobCommand(); + } catch (error) { + console.error("Error executing function from controller:", error); + } + }); + // app.listen(APP_PORT, APP_HOST, () => console.log(`Listening on: http://localhost:${APP_PORT}`)); app.listen( APP_PORT, @@ -52,6 +66,16 @@ async function main() { console.log(`[APP] Swagger on: http://localhost:${APP_PORT}/api-docs`) ), ); + async function runMessageQueue() { + try { + await rabbitmqInit(); + } catch (e) { + console.log(e); + setTimeout(runMessageQueue, 1000); + } + } + + runMessageQueue() } main(); diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index d8b3c62f..8bb79865 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -19,7 +19,7 @@ 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 } from "typeorm"; +import { Brackets, LessThan, MoreThan, Double, In, Between } from "typeorm"; import { CommandType } from "../entities/CommandType"; import { CommandSend } from "../entities/CommandSend"; import { Profile } from "../entities/Profile"; @@ -42,6 +42,7 @@ import { EmployeePosMaster } from "../entities/EmployeePosMaster"; import { ProfileDiscipline } from "../entities/ProfileDiscipline"; import { ProfileDisciplineHistory } from "../entities/ProfileDisciplineHistory"; import { PosMasterAct } from "../entities/PosMasterAct"; +import { sendToQueue } from "../services/rabbitmq"; @Route("api/v1/org/command") @Tags("Command") @@ -125,12 +126,9 @@ export class CommandController extends Controller { new Brackets((qb) => { qb.where(keyword != null && keyword != "" ? "command.commandNo LIKE :keyword" : "1=1", { keyword: `%${keyword}%`, - }).orWhere( - keyword != null && keyword != "" ? "command.issue LIKE :keyword" : "1=1", - { - keyword: `%${keyword}%`, - }, - ); + }).orWhere(keyword != null && keyword != "" ? "command.issue LIKE :keyword" : "1=1", { + keyword: `%${keyword}%`, + }); }), ) .orderBy("command.createdAt", "DESC") @@ -900,12 +898,12 @@ export class CommandController extends Controller { .filter((x) => x.profileId != null) .map(async (x) => x.profileId); - await new CallAPI() + await new CallAPI() .PostData(request, "/placement/noti/profiles", { subject: `${command.issue}`, body: `${command.issue}`, receiverUserId: profiles, - payload: "",//แนบไฟล์ + payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, receiveDate: command.commandExcecuteDate, @@ -922,34 +920,86 @@ export class CommandController extends Controller { ) ) { command.status = "WAITING"; + command.lastUpdateUserId = request.user.sub; + command.lastUpdateFullName = request.user.name; + command.lastUpdatedAt = new Date(); + await this.commandRepository.save(command); } else { const path = this.commandTypePath(command.commandType.code); if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ"); - - await new CallAPI() - .PostData(request, path + "/excecute", { - refIds: command.commandRecives - .filter((x) => x.refId != null) - .map((x) => ({ - refId: x.refId, - commandAffectDate: command.commandAffectDate, - commandNo: command.commandNo, - commandYear: command.commandYear, - templateDoc: command.positionDetail, - amount: x.amount, - positionSalaryAmount: x.positionSalaryAmount, - mouthSalaryAmount: x.mouthSalaryAmount, - })), - }) - .then(async (res) => { - command.status = "REPORTED"; - }) - .catch((e) => {}); + const msg = { + data: { + id: command.id, + status: "REPORTED", + lastUpdateUserId: request.user.sub, + lastUpdateFullName: request.user.name, + lastUpdatedAt: new Date(), + }, + user: request.user, + token: request.headers["authorization"], + }; + sendToQueue(msg); } - command.lastUpdateUserId = request.user.sub; - command.lastUpdateFullName = request.user.name; - command.lastUpdatedAt = new Date(); - await this.commandRepository.save(command); + return new HttpSuccess(); + } + + async cronjobCommand(@Request() request?: RequestWithUser) { + console.log(request); + const today = new Date(); + today.setHours(7, 0, 0, 0); //+7 เพื่อให้ตรง local time (อาจจะต้องใช้ moment) + const tomorrow = new Date(today); + tomorrow.setDate(tomorrow.getDate() + 1); + + const command = await this.commandRepository.find({ + relations: ["commandType", "commandRecives"], + where:{ + commandExcecuteDate: Between(today, tomorrow), + status: "WAITING" + } + }); + + const data = { + client_id: "gettoken", + client_secret: process.env.AUTH_ACCOUNT_SECRET, + grant_type: "password", + requested_token_type: "urn:ietf:params:oauth:token-type:refresh_token", + username: process.env.USERNAME_, + password: process.env.PASSWORD_, + }; + let _data: any = null; + await Promise.all([ + await new CallAPI() + .PostDataKeycloak("/realms/bma-ehr/protocol/openid-connect/token", data) + .then(async (x) => { + _data = x; + }) + .catch(async (x) => { + throw new HttpError(HttpStatus.UNAUTHORIZED, "ชื่อผู้ใช้งานหรือรหัสผ่านไม่ถูกต้อง"); + }), + ]); + if (_data == null) { + return new HttpError(HttpStatus.UNAUTHORIZED, "ชื่อผู้ใช้งานหรือรหัสผ่านไม่ถูกต้อง"); + } + + command.forEach(async (x) => { + const path = this.commandTypePath(x.commandType.code); + if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ"); + const msg = { + data: { + id: x.id, + status: "REPORTED", + lastUpdateUserId: "system", + lastUpdateFullName: "system", + // lastUpdateUserId: _data.user.sub, + // lastUpdateFullName: _data.user.name, + lastUpdatedAt: new Date(), + }, + user: _data.user, + token: _data.access_token, + }; + sendToQueue(msg); + }) + return new HttpSuccess(); } @@ -1067,7 +1117,7 @@ export class CommandController extends Controller { commandExcecuteDate?: Date | null; persons: { refId: string; - profileId?: string|null; + profileId?: string | null; citizenId: string; prefix: string; firstName: string; @@ -2280,6 +2330,7 @@ export class CommandController extends Controller { ) { return new HttpSuccess(); } + commandTypePath(commandCode: string) { switch (commandCode) { case "C-PM-01": diff --git a/src/interfaces/call-api.ts b/src/interfaces/call-api.ts index 456c2f80..588ea9c3 100644 --- a/src/interfaces/call-api.ts +++ b/src/interfaces/call-api.ts @@ -41,7 +41,7 @@ class CallAPI { } } //Post - public async PostData(request: any, @Path() path: any, sendData: any) { + public async PostData(request: any, @Path() path: any, sendData: any, log = true) { const token = "Bearer " + request.headers.authorization.replace("Bearer ", ""); const url = process.env.API_URL + path; try { @@ -52,7 +52,7 @@ class CallAPI { api_key: process.env.API_KEY, }, }); - addLogSequence(request, { + if (log) addLogSequence(request, { action: "request", status: "success", description: "connected", @@ -65,7 +65,7 @@ class CallAPI { }); return response.data.result; } catch (error) { - addLogSequence(request, { + if (log) addLogSequence(request, { action: "request", status: "error", description: "unconnected", @@ -80,6 +80,7 @@ class CallAPI { throw error; } } + //Post public async PostDataKeycloak(@Path() path: any, sendData: any) { // const token = request.headers.authorization; diff --git a/src/interfaces/utils.ts b/src/interfaces/utils.ts index 099a237c..d3f9ded0 100644 --- a/src/interfaces/utils.ts +++ b/src/interfaces/utils.ts @@ -209,3 +209,93 @@ export function addLogSequence(req: RequestWithUser, data: LogSequence) { export function editLogSequence(req: RequestWithUser, index: number, data: LogSequence) { req.app.locals.logData.sequence[index] = data; } + +export function commandTypePath(commandCode: string): string | null { + switch (commandCode) { + case "C-PM-01": + return "/placement/recruit/report"; + case "C-PM-02": + return "/placement/candidate/report"; + case "C-PM-03": + return "/placement/appoint/report"; + case "C-PM-04": + return "/placement/move/report"; + case "C-PM-05": + return "/placement/appointment/appoint/report"; + case "C-PM-06": + return "/placement/appointment/slip/report"; + case "C-PM-07": + return "/placement/appointment/move/report"; + case "C-PM-08": + return "/retirement/other/appoint/report"; + case "C-PM-09": + return "/retirement/other/out/report"; + case "C-PM-10": + return "/xxxxxx"; + case "C-PM-11": + return "/probation/report/command11/officer/report"; + case "C-PM-12": + return "/probation/report/command12/officer/report"; + case "C-PM-13": + return "/placement/transfer/command/report"; + case "C-PM-14": + return "/placement/Receive/command/report"; + case "C-PM-15": + return "/placement/officer/command/report"; + case "C-PM-16": + return "/placement/repatriation/command/report"; + case "C-PM-17": + return "/retirement/resign/command/report"; + case "C-PM-18": + return "/retirement/out/command/report"; + case "C-PM-19": + return "/discipline/result/command19/report"; + case "C-PM-20": + return "/discipline/result/command20/report"; + case "C-PM-21": + return "/org/command/command21/employee/report"; + case "C-PM-22": + return "/placement/appointment/employee-appoint/report"; + case "C-PM-23": + return "/retirement/resign/employee/report"; + case "C-PM-24": + return "/placement/appointment/employee-move/report"; + case "C-PM-25": + return "/discipline/result/command25/report"; + case "C-PM-26": + return "/discipline/result/command26/report"; + case "C-PM-27": + return "/discipline/result/command27/report"; + case "C-PM-28": + return "/discipline/result/command28/report"; + case "C-PM-29": + return "/discipline/result/command29/report"; + case "C-PM-30": + return "/discipline/result/command30/report"; + case "C-PM-31": + return "/discipline/result/command31/report"; + case "C-PM-32": + return "/discipline/result/command32/report"; + case "C-PM-33": + return "/salary/report/command/officer/report"; + case "C-PM-34": + return "/salary/report/command/officer/report"; + case "C-PM-35": + return "/salary/report/command/officer/report"; + case "C-PM-36": + return "/salary/report/command/employee/report"; + case "C-PM-37": + return "/salary/report/command/employee/report"; + case "C-PM-38": + return "/org/command/command38/officer/report"; + case "C-PM-39": + return "/placement/slip/report"; + case "C-PM-40": + return "/org/command/command40/officer/report"; + case "C-PM-41": + return "/retirement/resign/leave-cancel/report"; + default: + return null; + } +} + diff --git a/src/services/rabbitmq.ts b/src/services/rabbitmq.ts new file mode 100644 index 00000000..eb482fd6 --- /dev/null +++ b/src/services/rabbitmq.ts @@ -0,0 +1,126 @@ +import amqp from "amqplib"; +import { AppDataSource } from "../database/data-source"; +import { Command } from "../entities/Command"; +import { commandTypePath } from "../interfaces/utils"; +import CallAPI from "../interfaces/call-api"; +import HttpError from "../interfaces/http-error"; +import HttpStatusCode from "../interfaces/http-status"; +import { RequestWithUser } from "../middlewares/user"; + +export let sendToQueue: (payload: any) => void; + +export async function init() { //----> (1) Producer + if (!process.env.AMQ_URL || !process.env.AMQ_QUEUE) return; + + const { AMQ_URL: url, AMQ_QUEUE: queue } = process.env; //----> (1.2) get url and queue from .env + + const connection = await amqp.connect(url); //----> (1.3) set up url with amqp protocol + + const channel = await connection.createChannel(); //----> (1.4) create Channel + + channel.assertQueue(queue, { durable: true }); //----> (1.5) assert queue and set durable (if "true" save to disk on RabbitMQ) + channel.prefetch(1); + + sendToQueue = (payload: any, persistent = true) => { //----> (2) sendQueue To RabbitMQ and set persistent (if "true" redo the failed queue when server run again) + channel.sendToQueue(queue, Buffer.from(JSON.stringify(payload)), { + persistent, + }); + }; + + console.log("[AMQ] Listening for message..."); + + createConsumer(queue, channel, handler); //----> (3) Process Consumer + // createConsumer(queue1, channel, handler1); + // createConsumer(queue2, channel, handler2); +} + +function createConsumer( //----> consumer + queue: string, + channel: amqp.Channel, + handler: (msg: amqp.ConsumeMessage) => Promise | boolean, +) { + channel.consume( + queue, + async (msg) => { + if (!msg) return; + + if (await handler(msg)) return channel.ack(msg); + + return await new Promise((resolve) => setTimeout(() => resolve(channel.nack(msg)), 3000)); + }, + { noAck: false }, + ); +} + +async function handler(msg: amqp.ConsumeMessage): Promise { //----> condition before process consumer + const repo = AppDataSource.getRepository(Command); + const { data, token, user } = JSON.parse(msg.content.toString()); + + const { id, status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt } = data; + + const command = await repo.findOne({ + where: { id: id }, + relations: ["commandType", "commandRecives"], + }); + + if (!command) return true; + + const path = commandTypePath(command.commandType.code); + if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ"); + + return await new CallAPI() + .PostData( + { + headers: { authorization: token }, //time bomb + }, + path + "/excecute", + { + refIds: command.commandRecives + .filter((x) => x.refId != null) + .map((x) => ({ + refId: x.refId, + commandAffectDate: command.commandAffectDate, + commandNo: command.commandNo, + commandYear: command.commandYear, + templateDoc: command.positionDetail, + amount: x.amount, + positionSalaryAmount: x.positionSalaryAmount, + mouthSalaryAmount: x.mouthSalaryAmount, + })), + }, + false, + ) + .then(async (res) => { + console.log("[AMQ] Excecute Command Success"); + Object.assign(command, { status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt }); + const result = await repo.save(command).catch((e) => console.log(e)); + if (result) return true; + return false; + }) + .catch((e) => { + console.error(e); + return false; + }); +} + +// async function handler(msg: amqp.ConsumeMessage): Promise { //----> condition before process consumer +// const repo = AppDataSource.getRepository(Command); + +// const { id, status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt } = JSON.parse( +// msg.content.toString(), +// ); + +// const record = await repo.findOne({ +// where: { id }, +// }); + +// if (!record) return true; + +// Object.assign(record, { status, lastUpdateUserId, lastUpdateFullName, lastUpdatedAt }); + +// const result = await repo.save(record).catch((e) => console.log(e)); + +// if (result) return true; + +// return false; +// } From 4933ce85999411e0707143c1c1445502042b3ee7 Mon Sep 17 00:00:00 2001 From: kittapath Date: Fri, 11 Oct 2024 13:39:41 +0700 Subject: [PATCH 28/41] noti --- src/controllers/CommandController.ts | 9 +++++--- src/controllers/WorkflowController.ts | 4 ++-- .../1728618339457-add_table_workflow4.ts | 22 +++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 src/migration/1728618339457-add_table_workflow4.ts diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 8206e076..82870af9 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -1020,7 +1020,7 @@ export class CommandController extends Controller { .PostData(request, "/placement/noti/profiles", { subject: `${command.issue}`, body: `${command.issue}`, - receiverUserId: profiles, + receiverUserIds: profiles, payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, @@ -1112,8 +1112,11 @@ export class CommandController extends Controller { if (issue == null) issue = "..................................."; const _command = { issue: issue, - commandNo: command.commandNo, - commandYear: command.commandYear, + commandNo: command.commandNo == null ? "" : Extension.ToThaiNumber(command.commandNo), + commandYear: + command.commandYear == null + ? "" + : Extension.ToThaiNumber(Extension.ToThaiYear(command.commandYear).toString()), commandTitle: command.issue, detailHeader: command.detailHeader, detailBody: command.detailBody, diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 45de5fa2..468aa20b 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -189,7 +189,7 @@ export class WorkflowController extends Controller { .PostData(req, "/placement/noti/profiles", { subject: `รายการถูกส่ง`, body: `รายการถูกส่ง`, - receiverUserId: profileNow, + receiverUserIds: profileNow, payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, @@ -206,7 +206,7 @@ export class WorkflowController extends Controller { .PostData(req, "/placement/noti/profiles", { subject: `ได้รับรายการ`, body: `ได้รับรายการ`, - receiverUserId: profileNext, + receiverUserIds: profileNext, payload: "", //แนบไฟล์ isSendMail: true, isSendInbox: true, diff --git a/src/migration/1728618339457-add_table_workflow4.ts b/src/migration/1728618339457-add_table_workflow4.ts new file mode 100644 index 00000000..2d925841 --- /dev/null +++ b/src/migration/1728618339457-add_table_workflow4.ts @@ -0,0 +1,22 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow41728618339457 implements MigrationInterface { + name = 'AddTableWorkflow41728618339457' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE \`metaStateOperator\` (\`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, \`metaStateId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง metaState', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`CREATE TABLE \`metaState\` (\`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\` int NULL COMMENT 'ลำดับ', \`metaWorkflowId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง metaWorkflow', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`CREATE TABLE \`metaWorkflow\` (\`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 'ระบบ', \`sysName\` varchar(100) NULL COMMENT 'ชื่อระบบ', \`posLevelName\` varchar(100) NULL COMMENT 'ชื่อระดับ', \`posTypeName\` varchar(100) NULL COMMENT 'ชื่อประเภท', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`ALTER TABLE \`metaStateOperator\` ADD CONSTRAINT \`FK_b7489ef0f2b87666caecaadeb1e\` FOREIGN KEY (\`metaStateId\`) REFERENCES \`metaState\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`metaState\` ADD CONSTRAINT \`FK_73a4a241baa54b4e454f6914e4a\` FOREIGN KEY (\`metaWorkflowId\`) REFERENCES \`metaWorkflow\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`metaState\` DROP FOREIGN KEY \`FK_73a4a241baa54b4e454f6914e4a\``); + await queryRunner.query(`ALTER TABLE \`metaStateOperator\` DROP FOREIGN KEY \`FK_b7489ef0f2b87666caecaadeb1e\``); + await queryRunner.query(`DROP TABLE \`metaWorkflow\``); + await queryRunner.query(`DROP TABLE \`metaState\``); + await queryRunner.query(`DROP TABLE \`metaStateOperator\``); + } + +} From 5dc3e25aca67f32b0b5b4fc7c02c48f2e457f2ce Mon Sep 17 00:00:00 2001 From: Bright Date: Tue, 15 Oct 2024 13:56:29 +0700 Subject: [PATCH 29/41] =?UTF-8?q?fix=20=E0=B9=81=E0=B8=95=E0=B9=88?= =?UTF-8?q?=E0=B8=87=E0=B8=95=E0=B8=B1=E0=B9=89=E0=B8=87-=E0=B9=80?= =?UTF-8?q?=E0=B8=A5=E0=B8=B7=E0=B9=88=E0=B8=AD=E0=B8=99-=E0=B8=A2?= =?UTF-8?q?=E0=B9=89=E0=B8=B2=E0=B8=A2=20=E0=B9=84=E0=B8=A1=E0=B9=88?= =?UTF-8?q?=E0=B8=AA=E0=B9=88=E0=B8=87=E0=B9=80=E0=B8=87=E0=B8=B4=E0=B8=99?= =?UTF-8?q?=E0=B9=80=E0=B8=94=E0=B8=B7=E0=B8=AD=E0=B8=99=E0=B8=9B=E0=B8=B1?= =?UTF-8?q?=E0=B8=88=E0=B8=88=E0=B8=B8=E0=B8=9A=E0=B8=B1=E0=B8=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/ProfileController.ts | 8 +++++++- src/controllers/ProfileEmployeeController.ts | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/controllers/ProfileController.ts b/src/controllers/ProfileController.ts index 2b06b51d..178f4584 100644 --- a/src/controllers/ProfileController.ts +++ b/src/controllers/ProfileController.ts @@ -3978,7 +3978,12 @@ export class ProfileController extends Controller { // await new permission().PermissionOrgUserGet(request, "SYS_REGISTRY_OFFICER", id);//ไม่แน่ใจOFFปิดไว้ก่อน const profile = await this.profileRepo.findOne({ where: { id: id }, - relations: ["posLevel", "posType", "current_holders", "current_holders.orgRoot"], + relations: ["posLevel", "posType", "current_holders", "current_holders.orgRoot", "profileSalary"], + order: { + profileSalary: { + order: "DESC", + } + } }); if (!profile) { throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลบุคคลนี้ในระบบ"); @@ -4155,6 +4160,7 @@ export class ProfileController extends Controller { posNo: shortName, isPosmasterAct: data.length > 0, posmasterAct: data, + salary: profile && profile.profileSalary.length > 0 ? profile.profileSalary[0].amount : null, }; if (_profile.child4Id != null) { diff --git a/src/controllers/ProfileEmployeeController.ts b/src/controllers/ProfileEmployeeController.ts index f4222790..e3c8ed77 100644 --- a/src/controllers/ProfileEmployeeController.ts +++ b/src/controllers/ProfileEmployeeController.ts @@ -3705,7 +3705,12 @@ export class ProfileEmployeeController extends Controller { async getProfileByProfileid(@Request() request: RequestWithUser, @Path() id: string) { const profile = await this.profileRepo.findOne({ where: { id: id }, - relations: ["posLevel", "posType", "current_holders", "current_holders.orgRoot"], + relations: ["posLevel", "posType", "current_holders", "current_holders.orgRoot", "profileSalarys"], + order: { + profileSalarys: { + order: "DESC" + } + } }); if (!profile) { throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลบุคคลนี้ในระบบ"); @@ -3826,6 +3831,7 @@ export class ProfileEmployeeController extends Controller { node: null, nodeId: null, posNo: shortName, + salary: profile && profile.profileSalarys.length > 0 ? profile.profileSalarys[0].amount : null }; if (_profile.child4Id != null) { From 766888d01ca6d7fc0a8ec73a6e41d05d920d3531 Mon Sep 17 00:00:00 2001 From: AdisakKanthawilang Date: Tue, 15 Oct 2024 16:54:18 +0700 Subject: [PATCH 30/41] =?UTF-8?q?=E0=B9=80=E0=B8=9E=E0=B8=B4=E0=B9=88?= =?UTF-8?q?=E0=B8=A1=E0=B9=80=E0=B8=87=E0=B8=B7=E0=B9=88=E0=B8=AD=E0=B8=99?= =?UTF-8?q?=E0=B9=84=E0=B8=82=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=AA=E0=B8=A3?= =?UTF-8?q?=E0=B9=89=E0=B8=B2=E0=B8=87=E0=B9=81=E0=B8=9A=E0=B8=9A=E0=B8=A3?= =?UTF-8?q?=E0=B9=88=E0=B8=B2=E0=B8=87=E0=B9=82=E0=B8=84=E0=B8=A3=E0=B8=87?= =?UTF-8?q?=E0=B8=AA=E0=B8=A3=E0=B9=89=E0=B8=B2=E0=B8=87=20#1024?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/OrganizationController.ts | 110 +++++++++++++++++++--- 1 file changed, 95 insertions(+), 15 deletions(-) diff --git a/src/controllers/OrganizationController.ts b/src/controllers/OrganizationController.ts index 0d7ffbbc..37339837 100644 --- a/src/controllers/OrganizationController.ts +++ b/src/controllers/OrganizationController.ts @@ -33,6 +33,7 @@ import permission from "../interfaces/permission"; import { PermissionOrg } from "../entities/PermissionOrg"; import FunctionMain from "../interfaces/functionMain"; import { setLogDataDiff } from "../interfaces/utils"; +import { AuthRole } from "../entities/AuthRole"; @Route("api/v1/org") @Tags("Organization") @@ -54,6 +55,7 @@ export class OrganizationController extends Controller { private positionRepository = AppDataSource.getRepository(Position); private salaryRepository = AppDataSource.getRepository(ProfileSalary); private profileRepo = AppDataSource.getRepository(Profile); + private authRoleRepo = AppDataSource.getRepository(AuthRole); /** * API รายการประวัติโครงสร้าง @@ -114,7 +116,7 @@ export class OrganizationController extends Controller { } /** - * API สร้างโครงสร้างระดับ4 + * API สร้างแบบร่างโครงสร้าง * * @summary ORG_022 - สร้างโครงสร้างใหม่ #23 * @@ -124,6 +126,7 @@ export class OrganizationController extends Controller { @Body() requestBody: CreateOrgRevision, @Request() request: RequestWithUser, ) { + console.log("fucntion draft"); //new main revision const before = null; const revision = Object.assign(new OrgRevision(), requestBody) as OrgRevision; @@ -141,7 +144,9 @@ export class OrganizationController extends Controller { if ( requestBody.typeDraft.toUpperCase() == "ORG" || requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || - requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" ) { //cone by revisionId if (requestBody.orgRevisionId == null) @@ -217,10 +222,13 @@ export class OrganizationController extends Controller { where: { orgRevisionId: requestBody.orgRevisionId }, relations: ["positions"], }); + let _orgPosMaster: PosMaster[]; if ( requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || - requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" ) { _orgPosMaster = orgPosMaster.map((x) => ({ ...x, @@ -246,7 +254,9 @@ export class OrganizationController extends Controller { await this.orgRootRepository.save(data); if ( requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || - requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" ) { //create posmaster await Promise.all( @@ -256,12 +266,23 @@ export class OrganizationController extends Controller { delete item.id; const posMaster = Object.assign(new PosMaster(), item); posMaster.positions = []; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { posMaster.next_holderId = item.current_holderId; } else { posMaster.next_holderId = null; posMaster.isSit = false; } + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { + posMaster.authRoleId = item.authRoleId; + } else { + posMaster.authRoleId = null; + } posMaster.current_holderId = null; posMaster.orgRevisionId = revision.id; posMaster.orgRootId = data.id; @@ -278,7 +299,10 @@ export class OrganizationController extends Controller { delete pos.id; const position = Object.assign(new Position(), pos); position.posMasterId = posMaster.id; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + ) { position.positionIsSelected = false; } position.createdUserId = request.user.sub; @@ -321,12 +345,23 @@ export class OrganizationController extends Controller { delete item.id; const posMaster = Object.assign(new PosMaster(), item); posMaster.positions = []; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { posMaster.next_holderId = item.current_holderId; } else { posMaster.next_holderId = null; posMaster.isSit = false; } + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { + posMaster.authRoleId = item.authRoleId; + } else { + posMaster.authRoleId = null; + } posMaster.current_holderId = null; posMaster.orgRevisionId = revision.id; posMaster.orgRootId = data.id; @@ -344,7 +379,10 @@ export class OrganizationController extends Controller { delete pos.id; const position = Object.assign(new Position(), pos); position.posMasterId = posMaster.id; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + ) { position.positionIsSelected = false; } position.createdUserId = request.user.sub; @@ -388,12 +426,23 @@ export class OrganizationController extends Controller { delete item.id; const posMaster = Object.assign(new PosMaster(), item); posMaster.positions = []; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { posMaster.next_holderId = item.current_holderId; } else { posMaster.next_holderId = null; posMaster.isSit = false; } + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { + posMaster.authRoleId = item.authRoleId; + } else { + posMaster.authRoleId = null; + } posMaster.current_holderId = null; posMaster.orgRevisionId = revision.id; posMaster.orgRootId = data.id; @@ -412,7 +461,10 @@ export class OrganizationController extends Controller { delete pos.id; const position = Object.assign(new Position(), pos); position.posMasterId = posMaster.id; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + ) { position.positionIsSelected = false; } position.createdUserId = request.user.sub; @@ -459,12 +511,23 @@ export class OrganizationController extends Controller { delete item.id; const posMaster = Object.assign(new PosMaster(), item); posMaster.positions = []; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { posMaster.next_holderId = item.current_holderId; } else { posMaster.next_holderId = null; posMaster.isSit = false; } + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { + posMaster.authRoleId = item.authRoleId; + } else { + posMaster.authRoleId = null; + } posMaster.current_holderId = null; posMaster.orgRevisionId = revision.id; posMaster.orgRootId = data.id; @@ -484,7 +547,10 @@ export class OrganizationController extends Controller { delete pos.id; const position = Object.assign(new Position(), pos); position.posMasterId = posMaster.id; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + ) { position.positionIsSelected = false; } position.createdUserId = request.user.sub; @@ -529,12 +595,23 @@ export class OrganizationController extends Controller { delete item.id; const posMaster = Object.assign(new PosMaster(), item); posMaster.positions = []; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { posMaster.next_holderId = item.current_holderId; } else { posMaster.next_holderId = null; posMaster.isSit = false; } + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_PERSON_ROLE" + ) { + posMaster.authRoleId = item.authRoleId; + } else { + posMaster.authRoleId = null; + } posMaster.current_holderId = null; posMaster.orgRevisionId = revision.id; posMaster.orgRootId = data.id; @@ -555,7 +632,10 @@ export class OrganizationController extends Controller { delete pos.id; const position = Object.assign(new Position(), pos); position.posMasterId = posMaster.id; - if (requestBody.typeDraft.toUpperCase() == "ORG_POSITION") { + if ( + requestBody.typeDraft.toUpperCase() == "ORG_POSITION" || + requestBody.typeDraft.toUpperCase() == "ORG_POSITION_ROLE" + ) { position.positionIsSelected = false; } position.createdUserId = request.user.sub; @@ -575,7 +655,7 @@ export class OrganizationController extends Controller { }); }); } - + const _orgRevisions = await this.orgRevisionRepository.find({ where: [{ orgRevisionIsDraft: true, id: Not(revision.id) }], }); From ad9727075296b87f5713d0b8199eade5b68a0400 Mon Sep 17 00:00:00 2001 From: Bright Date: Tue, 15 Oct 2024 17:20:25 +0700 Subject: [PATCH 31/41] =?UTF-8?q?fix=20noti=20=E0=B8=95=E0=B8=B4=E0=B8=94?= =?UTF-8?q?=20promise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/CommandController.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 85b2c98e..8f291634 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -1013,9 +1013,11 @@ export class CommandController extends Controller { if (command.commandExcecuteDate == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบวันที่คำสั่งมีผล"); - let profiles = command.commandRecives - .filter((x) => x.profileId != null) - .map(async (x) => x.profileId); + let profiles = command && command.commandRecives.length > 0 + ? command.commandRecives + .filter((x) => x.profileId != null) + .map((x) => x.profileId) + : []; await new CallAPI() .PostData(request, "/placement/noti/profiles", { From 3ea2c7c3b099cb3fdba9c4bcc268c1450936a185 Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 16 Oct 2024 11:55:45 +0700 Subject: [PATCH 32/41] no message --- src/app.ts | 6 +- src/controllers/WorkflowController.ts | 288 ++++++++++++++++-- src/entities/Profile.ts | 8 + src/entities/State.ts | 4 + src/entities/StateOperatorUser.ts | 22 +- src/entities/StateUserComment.ts | 79 +++++ src/entities/Workflow.ts | 8 + .../1729044078594-add_table_workflow5.ts | 14 + .../1729047708690-add_table_workflow6.ts | 26 ++ 9 files changed, 420 insertions(+), 35 deletions(-) create mode 100644 src/entities/StateUserComment.ts create mode 100644 src/migration/1729044078594-add_table_workflow5.ts create mode 100644 src/migration/1729047708690-add_table_workflow6.ts diff --git a/src/app.ts b/src/app.ts index d4906096..360977a7 100644 --- a/src/app.ts +++ b/src/app.ts @@ -5,7 +5,7 @@ import express from "express"; import swaggerUi from "swagger-ui-express"; import swaggerDocument from "./swagger.json"; import * as cron from "node-cron"; -import { init as rabbitmqInit } from './services/rabbitmq'; +import { init as rabbitmqInit } from "./services/rabbitmq"; import error from "./middlewares/error"; import { AppDataSource } from "./database/data-source"; import { RegisterRoutes } from "./routes"; @@ -26,7 +26,7 @@ async function main() { ); app.use(express.json()); app.use(express.urlencoded({ extended: true })); - app.use(logMiddleware); + // app.use(logMiddleware); app.use("/", express.static("static")); app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument)); @@ -75,7 +75,7 @@ async function main() { } } - runMessageQueue() + runMessageQueue(); } main(); diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 468aa20b..ca1d3f03 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -10,18 +10,20 @@ import { StateOperator } from "../entities/StateOperator"; import { StateOperatorUser } from "../entities/StateOperatorUser"; import CallAPI from "../interfaces/call-api"; import { Profile } from "../entities/Profile"; +import { StateUserComment } from "../entities/StateUserComment"; @Route("api/v1/org/workflow") -@Tags("AuthRole") +@Tags("Workflow") @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 stateUserCommentRepo = AppDataSource.getRepository(StateUserComment); private profileRepo = AppDataSource.getRepository(Profile); - @Post("check-workflow") + @Post("add-workflow") public async checkWorkflow( @Request() req: RequestWithUser, @Body() @@ -30,7 +32,7 @@ export class WorkflowController extends Controller { posLevelName: string; posTypeName: string; profiles: { - profile: string; + profileId: string; operator: string; order: number; }[]; @@ -48,7 +50,7 @@ export class WorkflowController extends Controller { await Promise.all( body.profiles.map(async (item) => { const operatoeUser = new StateOperatorUser(); - operatoeUser.profile = item.profile; + operatoeUser.profileId = item.profileId; operatoeUser.operator = item.operator.trim().toLocaleUpperCase(); operatoeUser.order = item.order; operatoeUser.workflowId = workflow.id; @@ -76,18 +78,18 @@ export class WorkflowController extends Controller { body: { workflowId: string; stateId: string; - profile: string; + profileId: string; action: string; }, ) { const stateOperatorUser = await this.stateOperatorUserRepo.findOne({ where: { - profile: body.profile, + profileId: body.profileId, workflowId: body.workflowId, }, }); if (!stateOperatorUser) - throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); + throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในกระบวนการนี้"); const operator = await this.stateOperatorRepo.findOne({ where: { @@ -95,7 +97,7 @@ export class WorkflowController extends Controller { state: { id: body.stateId, workflow: { id: body.workflowId } }, }, }); - if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); let isCan = false; switch (body.action.trim().toLocaleUpperCase()) { @@ -125,13 +127,42 @@ export class WorkflowController extends Controller { } } - @Post("check-iscan-all") - public async checkIsCanAll( + @Post("check-state-now") + public async checkStateNow( + @Request() req: RequestWithUser, + @Body() + body: { + workflowId: string; + }, + ) { + const workflow = await this.workflowRepo.findOne({ + where: { + id: body.workflowId, + }, + relations: ["stateOperatorUsers"], + }); + if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); + + const state = await this.stateRepo.findOne({ + where: { + id: workflow.stateId, + }, + relations: ["stateOperators"], + }); + if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ"); + return new HttpSuccess({ + stateId: state.id, + stateNo: state.order, + stateName: state.name, + }); + } + + @Post("check-user-now") + public async checkUserNow( @Request() req: RequestWithUser, @Body() body: { workflowId: string; - stateId: string; }, ) { const profile = await this.profileRepo.findOne({ @@ -139,24 +170,68 @@ export class WorkflowController extends Controller { keycloak: req.user.sub, }, }); - if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน"); const stateOperatorUser = await this.stateOperatorUserRepo.findOne({ where: { - profile: profile.id, + profileId: profile.id, workflowId: body.workflowId, }, }); if (!stateOperatorUser) - throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); + throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในกระบวนการนี้"); + + const workflow = await this.workflowRepo.findOne({ + where: { + id: body.workflowId, + }, + }); + if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); const operator = await this.stateOperatorRepo.findOne({ where: { operator: stateOperatorUser.operator, - state: { id: body.stateId, workflow: { id: body.workflowId } }, + stateId: workflow.stateId, }, + relations: ["state"], }); - if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); - return new HttpSuccess(operator); + if (!operator) + throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในขั้นตอนนี้"); + return new HttpSuccess({ + stateId: operator.state.id, + stateNo: operator.state.order, + stateName: operator.state.name, + operator: operator.operator, + can_view: operator.canView, + can_update: operator.canUpdate, + can_operate: operator.canOperate, + can_change_state: operator.canChangeState, + can_delete: operator.canDelete, + can_cancel: operator.canCancel, + }); + } + + @Post("check-state-all") + public async checkStateAll( + @Request() req: RequestWithUser, + @Body() + body: { + workflowId: string; + }, + ) { + const state = await this.stateRepo.find({ + where: { + workflowId: body.workflowId, + }, + order: { stateUserComments: { order: "ASC" } }, + relations: ["stateUserComments"], + }); + const _state = state.map((x) => ({ + stateId: x.id, + stateNo: x.order, + stateName: x.name, + stateUserComments: x.stateUserComments, + })); + return new HttpSuccess(_state); } @Post("state-next") @@ -164,16 +239,24 @@ export class WorkflowController extends Controller { @Request() req: RequestWithUser, @Body() body: { - stateId: string; + workflowId: string; }, ) { + const workflow = await this.workflowRepo.findOne({ + where: { + id: body.workflowId, + }, + relations: ["stateOperatorUsers"], + }); + if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); + const state = await this.stateRepo.findOne({ where: { - id: body.stateId, + id: workflow.stateId, }, - relations: ["stateOperators", "workflow", "workflow.stateOperatorUsers"], + relations: ["stateOperators"], }); - if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ"); const _state = await this.stateRepo.findOne({ where: { order: state.order + 1, @@ -182,7 +265,7 @@ export class WorkflowController extends Controller { relations: ["stateOperators"], }); //noti - let profileNow = state.workflow.stateOperatorUsers + let profileNow = workflow.stateOperatorUsers .filter((x) => state.stateOperators.map((s) => s.operator).includes(x.operator)) .map((x) => x.profile); await new CallAPI() @@ -199,7 +282,7 @@ export class WorkflowController extends Controller { console.error("Error calling API:", error); }); if (_state != null) { - let profileNext = state.workflow.stateOperatorUsers + let profileNext = workflow.stateOperatorUsers .filter((x) => _state.stateOperators.map((s) => s.operator).includes(x.operator)) .map((x) => x.profile); await new CallAPI() @@ -215,10 +298,13 @@ export class WorkflowController extends Controller { .catch((error) => { console.error("Error calling API:", error); }); + workflow.stateId = _state.id; + await this.workflowRepo.save(workflow); } return new HttpSuccess({ stateId: _state?.id || null, + stateNo: _state?.order || null, stateName: _state?.name || null, stateType: _state?.type || null, }); @@ -237,7 +323,7 @@ export class WorkflowController extends Controller { id: body.stateId, }, }); - if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล"); + if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ"); const _state = await this.stateRepo.findOne({ where: { order: state.order - 1, @@ -247,8 +333,162 @@ export class WorkflowController extends Controller { return new HttpSuccess({ stateId: _state?.id || null, + stateNo: _state?.order || null, stateName: _state?.name || null, stateType: _state?.type || null, }); } + + @Post("add-step") + public async addStep( + @Request() req: RequestWithUser, + @Body() + body: { + stateId: string; + profileId: string; + isAcceptSetting: boolean; + isApproveSetting: boolean; + isReasonSetting: boolean; + }, + ) { + const profile = await this.profileRepo.findOne({ + where: { + id: body.profileId, + }, + }); + if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบผู้ใช้งานนี้"); + const state = await this.stateRepo.findOne({ + where: { + id: body.stateId, + }, + relations: ["stateUserComments"], + }); + if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ"); + + const stateUserComment = new StateUserComment(); + stateUserComment.order = state.stateUserComments.length + 1; + stateUserComment.stateId = body.stateId; + stateUserComment.profileId = body.profileId; + stateUserComment.isAcceptSetting = body.isAcceptSetting; + stateUserComment.isApproveSetting = body.isApproveSetting; + stateUserComment.isReasonSetting = body.isReasonSetting; + stateUserComment.createdUserId = req.user.sub; + stateUserComment.createdFullName = req.user.name; + stateUserComment.createdAt = new Date(); + stateUserComment.lastUpdateUserId = req.user.sub; + stateUserComment.lastUpdateFullName = req.user.name; + stateUserComment.lastUpdatedAt = new Date(); + await this.stateUserCommentRepo.save(stateUserComment); + + await new CallAPI() + .PostData(req, "/placement/noti/profiles", { + subject: `ได้รับรายการ`, + body: `ได้รับรายการ`, + receiverUserIds: [body.profileId], + payload: "", //แนบไฟล์ + isSendMail: true, + isSendInbox: true, + isSendNotification: true, + }) + .catch((error) => { + console.error("Error calling API:", error); + }); + + return new HttpSuccess(); + } + + @Post("comment") + public async createcomment( + @Request() req: RequestWithUser, + @Body() + body: { + stateId: string; + isAccept?: boolean | null; + isApprove?: boolean | null; + reason?: string | null; + }, + ) { + const profile = await this.profileRepo.findOne({ + where: { + keycloak: req.user.sub, + }, + }); + if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน"); + const state = await this.stateRepo.findOne({ + where: { + id: body.stateId, + }, + }); + if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ"); + let _null: any = null; + const stateUserComment = new StateUserComment(); + stateUserComment.stateId = body.stateId; + stateUserComment.profileId = profile.id; + stateUserComment.isAccept = body.isAccept == null ? _null : body.isAccept; + stateUserComment.isApprove = body.isApprove == null ? _null : body.isAccept; + stateUserComment.reason = body.reason == null ? _null : body.isAccept; + stateUserComment.createdUserId = req.user.sub; + stateUserComment.createdFullName = req.user.name; + stateUserComment.createdAt = new Date(); + stateUserComment.lastUpdateUserId = req.user.sub; + stateUserComment.lastUpdateFullName = req.user.name; + stateUserComment.lastUpdatedAt = new Date(); + await this.stateUserCommentRepo.save(stateUserComment); + + return new HttpSuccess(); + } + + @Post("comment-state") + public async getCommentState( + @Request() req: RequestWithUser, + @Body() + body: { + stateId: string; + }, + ) { + const state = await this.stateRepo.findOne({ + where: { + id: body.stateId, + }, + order: { stateUserComments: { order: "ASC" } }, + relations: ["stateUserComments"], + }); + if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ"); + + return new HttpSuccess(state.stateUserComments); + } + + @Post("comment-state-user") + public async getCommentStateUser( + @Request() req: RequestWithUser, + @Body() + body: { + stateId: string; + }, + ) { + const profile = await this.profileRepo.findOne({ + where: { + keycloak: req.user.sub, + }, + }); + if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน"); + const stateUserComment = await this.stateUserCommentRepo.findOne({ + where: { + profileId: profile.id, + stateId: body.stateId, + }, + }); + + return new HttpSuccess({ + isAccept: stateUserComment?.isAccept || null, + isApprove: stateUserComment?.isApprove || null, + reason: stateUserComment?.reason || null, + isAcceptSetting: stateUserComment?.isAcceptSetting || null, + isApproveSetting: stateUserComment?.isApproveSetting || null, + isReasonSetting: stateUserComment?.isReasonSetting || null, + order: stateUserComment?.order || null, + stateId: stateUserComment?.stateId || null, + profileId: stateUserComment?.profileId || null, + }); + } } diff --git a/src/entities/Profile.ts b/src/entities/Profile.ts index 0978f528..6b1cdec3 100644 --- a/src/entities/Profile.ts +++ b/src/entities/Profile.ts @@ -32,6 +32,8 @@ import { ProfileDevelopment } from "./ProfileDevelopment"; import { PermissionOrg } from "./PermissionOrg"; import { CommandSend } from "./CommandSend"; import { DevelopmentRequest } from "./DevelopmentRequest"; +import { StateOperatorUser } from "./StateOperatorUser"; +import { StateUserComment } from "./StateUserComment"; @Entity("profile") export class Profile extends EntityBase { @@ -378,6 +380,12 @@ export class Profile extends EntityBase { @OneToMany(() => CommandSend, (v) => v.profile) commandSends: CommandSend[]; + @OneToMany(() => StateOperatorUser, (v) => v.profile) + stateOperatorUsers: StateOperatorUser[]; + + @OneToMany(() => StateUserComment, (v) => v.profile) + stateUserComments: StateUserComment[]; + @ManyToOne(() => PosLevel, (posLevel) => posLevel.profiles) @JoinColumn({ name: "posLevelId" }) posLevel: PosLevel; diff --git a/src/entities/State.ts b/src/entities/State.ts index 949f0167..fb16afc9 100644 --- a/src/entities/State.ts +++ b/src/entities/State.ts @@ -2,6 +2,7 @@ import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm"; import { EntityBase } from "./base/Base"; import { StateOperator } from "./StateOperator"; import { Workflow } from "./Workflow"; +import { StateUserComment } from "./StateUserComment"; @Entity("state") export class State extends EntityBase { @@ -42,4 +43,7 @@ export class State extends EntityBase { @OneToMany(() => StateOperator, (stateOperator) => stateOperator.state) stateOperators: StateOperator[]; + + @OneToMany(() => StateUserComment, (stateUserComment) => stateUserComment.state) + stateUserComments: StateUserComment[]; } diff --git a/src/entities/StateOperatorUser.ts b/src/entities/StateOperatorUser.ts index 5c890dd7..d9f2d6a8 100644 --- a/src/entities/StateOperatorUser.ts +++ b/src/entities/StateOperatorUser.ts @@ -2,6 +2,7 @@ import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm"; import { EntityBase } from "./base/Base"; import { StateOperator } from "./StateOperator"; import { Workflow } from "./Workflow"; +import { Profile } from "./Profile"; @Entity("stateOperatorUser") export class StateOperatorUser extends EntityBase { @@ -13,14 +14,6 @@ export class StateOperatorUser extends EntityBase { }) operator: string; - @Column({ - nullable: true, - comment: "", - length: 255, - default: null, - }) - profile: string; - @Column({ nullable: true, comment: "ลำดับ", @@ -47,4 +40,17 @@ export class StateOperatorUser extends EntityBase { @ManyToOne(() => Workflow, (workflow) => workflow.stateOperatorUsers) @JoinColumn({ name: "workflowId" }) workflow: Workflow; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง profile", + type: "uuid", + default: null, + }) + profileId: string; + + @ManyToOne(() => Profile, (profile) => profile.stateOperatorUsers) + @JoinColumn({ name: "profileId" }) + profile: Profile; } diff --git a/src/entities/StateUserComment.ts b/src/entities/StateUserComment.ts new file mode 100644 index 00000000..516ac146 --- /dev/null +++ b/src/entities/StateUserComment.ts @@ -0,0 +1,79 @@ +import { Entity, Column, ManyToOne, JoinColumn } from "typeorm"; +import { EntityBase } from "./base/Base"; +import { State } from "./State"; +import { Profile } from "./Profile"; + +@Entity("stateUserComment") +export class StateUserComment extends EntityBase { + @Column({ + nullable: true, + comment: "เลือกรับทราบ", + default: null, + }) + isAccept: boolean; + + @Column({ + nullable: true, + comment: "เลือกพิจารณา", + default: null, + }) + isApprove: boolean; + + @Column({ + nullable: true, + comment: "แสดงความคิดเห็น", + length: 255, + default: null, + }) + reason: string; + + @Column({ + comment: "เลือกรับทราบ", + default: false, + }) + isAcceptSetting: boolean; + + @Column({ + comment: "เลือกพิจารณา", + default: false, + }) + isApproveSetting: boolean; + + @Column({ + comment: "แสดงความคิดเห็น", + default: false, + }) + isReasonSetting: boolean; + + @Column({ + nullable: true, + comment: "ลำดับ", + default: null, + }) + order: number; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง state", + default: null, + }) + stateId: string; + + @ManyToOne(() => State, (state) => state.stateUserComments) + @JoinColumn({ name: "stateId" }) + state: State; + + @Column({ + nullable: true, + length: 40, + comment: "คีย์นอก(FK)ของตาราง profile", + type: "uuid", + default: null, + }) + profileId: string; + + @ManyToOne(() => Profile, (profile) => profile.stateUserComments) + @JoinColumn({ name: "profileId" }) + profile: Profile; +} diff --git a/src/entities/Workflow.ts b/src/entities/Workflow.ts index c41d442c..fd66bdd1 100644 --- a/src/entities/Workflow.ts +++ b/src/entities/Workflow.ts @@ -40,6 +40,14 @@ export class Workflow extends EntityBase { }) posLevelName: string; + @Column({ + nullable: true, + comment: "id state", + length: 100, + default: null, + }) + stateId: string; + @Column({ nullable: true, comment: "ชื่อประเภท", diff --git a/src/migration/1729044078594-add_table_workflow5.ts b/src/migration/1729044078594-add_table_workflow5.ts new file mode 100644 index 00000000..eaf2f203 --- /dev/null +++ b/src/migration/1729044078594-add_table_workflow5.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow51729044078594 implements MigrationInterface { + name = 'AddTableWorkflow51729044078594' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`stateId\` varchar(100) NULL COMMENT 'id state'`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`stateId\``); + } + +} diff --git a/src/migration/1729047708690-add_table_workflow6.ts b/src/migration/1729047708690-add_table_workflow6.ts new file mode 100644 index 00000000..f50923c2 --- /dev/null +++ b/src/migration/1729047708690-add_table_workflow6.ts @@ -0,0 +1,26 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow61729047708690 implements MigrationInterface { + name = 'AddTableWorkflow61729047708690' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` CHANGE \`profile\` \`profileId\` varchar(255) NULL`); + await queryRunner.query(`CREATE TABLE \`stateUserComment\` (\`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', \`isAccept\` tinyint NULL COMMENT 'เลือกรับทราบ', \`isApprove\` tinyint NULL COMMENT 'เลือกพิจารณา', \`reason\` varchar(255) NULL COMMENT 'แสดงความคิดเห็น', \`isAcceptSetting\` tinyint NOT NULL COMMENT 'เลือกรับทราบ' DEFAULT 0, \`isApproveSetting\` tinyint NOT NULL COMMENT 'เลือกพิจารณา' DEFAULT 0, \`isReasonSetting\` tinyint NOT NULL COMMENT 'แสดงความคิดเห็น' DEFAULT 0, \`order\` int NULL COMMENT 'ลำดับ', \`stateId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง state', \`profileId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง profile', PRIMARY KEY (\`id\`)) ENGINE=InnoDB`); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP COLUMN \`profileId\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD \`profileId\` varchar(40) NULL COMMENT 'คีย์นอก(FK)ของตาราง profile'`); + await queryRunner.query(`ALTER TABLE \`stateUserComment\` ADD CONSTRAINT \`FK_f6ed25f165eb356ea5499484452\` FOREIGN KEY (\`stateId\`) REFERENCES \`state\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`stateUserComment\` ADD CONSTRAINT \`FK_f83cf9aef7ece2cddc2bb7c5a55\` FOREIGN KEY (\`profileId\`) REFERENCES \`profile\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD CONSTRAINT \`FK_f64285e5016ad2932f38c8687a1\` FOREIGN KEY (\`profileId\`) REFERENCES \`profile\`(\`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_f64285e5016ad2932f38c8687a1\``); + await queryRunner.query(`ALTER TABLE \`stateUserComment\` DROP FOREIGN KEY \`FK_f83cf9aef7ece2cddc2bb7c5a55\``); + await queryRunner.query(`ALTER TABLE \`stateUserComment\` DROP FOREIGN KEY \`FK_f6ed25f165eb356ea5499484452\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP COLUMN \`profileId\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD \`profileId\` varchar(255) NULL`); + await queryRunner.query(`DROP TABLE \`stateUserComment\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` CHANGE \`profileId\` \`profile\` varchar(255) NULL`); + } + +} From f67dab02a0cec0fb76ce5158099b061e0c56db6c Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 16 Oct 2024 12:00:22 +0700 Subject: [PATCH 33/41] no message --- src/controllers/WorkflowController.ts | 46 +++++++++++++++++---------- src/entities/Workflow.ts | 16 ++++++++++ 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index ca1d3f03..48e4bf6f 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -132,12 +132,14 @@ export class WorkflowController extends Controller { @Request() req: RequestWithUser, @Body() body: { - workflowId: string; + refId: string; + system: string; }, ) { const workflow = await this.workflowRepo.findOne({ where: { - id: body.workflowId, + refId: body.refId, + system: body.system, }, relations: ["stateOperatorUsers"], }); @@ -162,7 +164,8 @@ export class WorkflowController extends Controller { @Request() req: RequestWithUser, @Body() body: { - workflowId: string; + refId: string; + system: string; }, ) { const profile = await this.profileRepo.findOne({ @@ -171,22 +174,22 @@ export class WorkflowController extends Controller { }, }); if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน"); + const workflow = await this.workflowRepo.findOne({ + where: { + refId: body.refId, + system: body.system, + }, + relations: ["stateOperatorUsers"], + }); + if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); const stateOperatorUser = await this.stateOperatorUserRepo.findOne({ where: { - profileId: profile.id, - workflowId: body.workflowId, + workflowId: workflow.id, }, }); if (!stateOperatorUser) throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในกระบวนการนี้"); - const workflow = await this.workflowRepo.findOne({ - where: { - id: body.workflowId, - }, - }); - if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); - const operator = await this.stateOperatorRepo.findOne({ where: { operator: stateOperatorUser.operator, @@ -215,12 +218,21 @@ export class WorkflowController extends Controller { @Request() req: RequestWithUser, @Body() body: { - workflowId: string; + refId: string; + system: string; }, ) { + const workflow = await this.workflowRepo.findOne({ + where: { + refId: body.refId, + system: body.system, + }, + relations: ["stateOperatorUsers"], + }); + if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); const state = await this.stateRepo.find({ where: { - workflowId: body.workflowId, + workflowId: workflow.id, }, order: { stateUserComments: { order: "ASC" } }, relations: ["stateUserComments"], @@ -239,12 +251,14 @@ export class WorkflowController extends Controller { @Request() req: RequestWithUser, @Body() body: { - workflowId: string; + refId: string; + system: string; }, ) { const workflow = await this.workflowRepo.findOne({ where: { - id: body.workflowId, + refId: body.refId, + system: body.system, }, relations: ["stateOperatorUsers"], }); diff --git a/src/entities/Workflow.ts b/src/entities/Workflow.ts index fd66bdd1..0c6090d6 100644 --- a/src/entities/Workflow.ts +++ b/src/entities/Workflow.ts @@ -5,6 +5,22 @@ import { StateOperatorUser } from "./StateOperatorUser"; @Entity("workflow") export class Workflow extends EntityBase { + @Column({ + nullable: true, + comment: "refIdw", + length: 255, + default: null, + }) + refId: string; + + @Column({ + nullable: true, + comment: "system", + length: 255, + default: null, + }) + system: string; + @Column({ nullable: true, comment: "ชื่อ flow", From 2b9cd85532270b3bfeb64b6cdf5f01a3f2f1e6e4 Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 16 Oct 2024 14:40:37 +0700 Subject: [PATCH 34/41] no message --- src/controllers/WorkflowController.ts | 149 +++++++++++------- src/entities/MetaState.ts | 7 +- src/entities/MetaWorkflow.ts | 2 +- .../1729055668134-add_table_workflow7.ts | 16 ++ 4 files changed, 111 insertions(+), 63 deletions(-) create mode 100644 src/migration/1729055668134-add_table_workflow7.ts diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 48e4bf6f..5e5837aa 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -11,6 +11,9 @@ import { StateOperatorUser } from "../entities/StateOperatorUser"; import CallAPI from "../interfaces/call-api"; import { Profile } from "../entities/Profile"; import { StateUserComment } from "../entities/StateUserComment"; +import { MetaWorkflow } from "../entities/MetaWorkflow"; +import { MetaState } from "../entities/MetaState"; +import { MetaStateOperator } from "../entities/MetaStateOperator"; @Route("api/v1/org/workflow") @Tags("Workflow") @@ -23,52 +26,84 @@ export class WorkflowController extends Controller { private stateUserCommentRepo = AppDataSource.getRepository(StateUserComment); private profileRepo = AppDataSource.getRepository(Profile); + private metaWorkflowRepo = AppDataSource.getRepository(MetaWorkflow); + private metaStateRepo = AppDataSource.getRepository(MetaState); + private metaStateOperatorRepo = AppDataSource.getRepository(MetaStateOperator); + @Post("add-workflow") public async checkWorkflow( @Request() req: RequestWithUser, @Body() body: { + refId: string; sysName: string; posLevelName: string; posTypeName: string; - profiles: { - profileId: string; - operator: string; - order: number; - }[]; }, ) { - const workflow = await this.workflowRepo.findOne({ + const profile = await this.profileRepo.findOne({ + where: { + keycloak: req.user.sub, + }, + }); + if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน"); + + const metaWorkflow = await this.metaWorkflowRepo.findOne({ where: { sysName: body.sysName, posLevelName: body.posLevelName, posTypeName: body.posTypeName, }, - relations: ["states"], }); - if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบกระบวนการนี้ได้"); + if (!metaWorkflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบกระบวนการนี้ได้"); + + 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 workflow = new Workflow(); + Object.assign(workflow, { ...metaWorkflow, id: undefined, ...meta }); + this.workflowRepo.save(workflow); + const metaState = await this.metaStateRepo.find({ + where: { + metaWorkflowId: metaWorkflow.id, + }, + }); + await Promise.all( - body.profiles.map(async (item) => { - const operatoeUser = new StateOperatorUser(); - operatoeUser.profileId = item.profileId; - 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); + metaState.map(async (item) => { + const state = new State(); + Object.assign(state, { ...item, id: undefined, workflowId: workflow.id, ...meta }); + await this.stateRepo.save(state); + const metaStateOperator = await this.metaStateOperatorRepo.find({ + where: { + metaStateId: item.id, + }, + }); + await Promise.all( + metaStateOperator.map(async (item) => { + const stateOperator = new StateOperator(); + Object.assign(stateOperator, { ...item, id: undefined, stateId: state.id, ...meta }); + await this.stateOperatorRepo.save(stateOperator); + }), + ); }), ); - return new HttpSuccess({ + + const stateOperatorUser = new StateOperatorUser(); + Object.assign(stateOperatorUser, { + profileId: profile.id, + operator: "OWNER", + order: 1, 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, + ...meta, }); + await this.stateOperatorUserRepo.save(stateOperatorUser); + return new HttpSuccess(); } @Post("check-iscan") @@ -168,24 +203,17 @@ export class WorkflowController extends Controller { system: string; }, ) { - const profile = await this.profileRepo.findOne({ - where: { - keycloak: req.user.sub, - }, - }); - if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน"); - const workflow = await this.workflowRepo.findOne({ - where: { - refId: body.refId, - system: body.system, - }, - relations: ["stateOperatorUsers"], - }); - if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); const stateOperatorUser = await this.stateOperatorUserRepo.findOne({ where: { - workflowId: workflow.id, + workflow: { + refId: body.refId, + system: body.system, + }, + profile: { + keycloak: req.user.sub, + }, }, + relations: ["workflow"], }); if (!stateOperatorUser) throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในกระบวนการนี้"); @@ -193,7 +221,7 @@ export class WorkflowController extends Controller { const operator = await this.stateOperatorRepo.findOne({ where: { operator: stateOperatorUser.operator, - stateId: workflow.stateId, + stateId: stateOperatorUser.workflow.stateId, }, relations: ["state"], }); @@ -222,19 +250,14 @@ export class WorkflowController extends Controller { system: string; }, ) { - const workflow = await this.workflowRepo.findOne({ - where: { - refId: body.refId, - system: body.system, - }, - relations: ["stateOperatorUsers"], - }); - if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้"); const state = await this.stateRepo.find({ where: { - workflowId: workflow.id, + workflow: { + refId: body.refId, + system: body.system, + }, }, - order: { stateUserComments: { order: "ASC" } }, + order: { order: "ASC", stateUserComments: { order: "ASC" } }, relations: ["stateUserComments"], }); const _state = state.map((x) => ({ @@ -255,6 +278,20 @@ export class WorkflowController extends Controller { system: string; }, ) { + const stateOperatorUser = await this.stateOperatorUserRepo.findOne({ + where: { + workflow: { + refId: body.refId, + system: body.system, + }, + profile: { + keycloak: req.user.sub, + }, + }, + }); + if (!stateOperatorUser) + throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในกระบวนการนี้"); + const workflow = await this.workflowRepo.findOne({ where: { refId: body.refId, @@ -480,15 +517,11 @@ export class WorkflowController extends Controller { stateId: string; }, ) { - const profile = await this.profileRepo.findOne({ - where: { - keycloak: req.user.sub, - }, - }); - if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน"); const stateUserComment = await this.stateUserCommentRepo.findOne({ where: { - profileId: profile.id, + profile: { + keycloak: req.user.sub, + }, stateId: body.stateId, }, }); diff --git a/src/entities/MetaState.ts b/src/entities/MetaState.ts index fa2cf5ec..fbf61ce7 100644 --- a/src/entities/MetaState.ts +++ b/src/entities/MetaState.ts @@ -1,8 +1,7 @@ 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"; +import { MetaWorkflow } from "./MetaWorkflow"; @Entity("metaState") export class MetaState extends EntityBase { @@ -37,9 +36,9 @@ export class MetaState extends EntityBase { }) metaWorkflowId: string; - @ManyToOne(() => metaWorkflow, (metaWorkflow) => metaWorkflow.metaStates) + @ManyToOne(() => MetaWorkflow, (metaWorkflow) => metaWorkflow.metaStates) @JoinColumn({ name: "metaWorkflowId" }) - metaWorkflow: metaWorkflow; + metaWorkflow: MetaWorkflow; @OneToMany(() => MetaStateOperator, (metaStateOperator) => metaStateOperator.metaState) metaStateOperators: MetaStateOperator[]; diff --git a/src/entities/MetaWorkflow.ts b/src/entities/MetaWorkflow.ts index e787457c..defcd6d5 100644 --- a/src/entities/MetaWorkflow.ts +++ b/src/entities/MetaWorkflow.ts @@ -3,7 +3,7 @@ import { EntityBase } from "./base/Base"; import { MetaState } from "./MetaState"; @Entity("metaWorkflow") -export class metaWorkflow extends EntityBase { +export class MetaWorkflow extends EntityBase { @Column({ nullable: true, comment: "ชื่อ flow", diff --git a/src/migration/1729055668134-add_table_workflow7.ts b/src/migration/1729055668134-add_table_workflow7.ts new file mode 100644 index 00000000..d9f4d32f --- /dev/null +++ b/src/migration/1729055668134-add_table_workflow7.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow71729055668134 implements MigrationInterface { + name = 'AddTableWorkflow71729055668134' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`refId\` varchar(255) NULL COMMENT 'refIdw'`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`system\` varchar(255) NULL COMMENT 'system'`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`system\``); + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`refId\``); + } + +} From b60b364b2a502a7b1ac1decbab3b1deb4f6b0cea Mon Sep 17 00:00:00 2001 From: AdisakKanthawilang Date: Wed, 16 Oct 2024 15:11:13 +0700 Subject: [PATCH 35/41] fix type field develop create update function --- src/entities/ProfileDevelopment.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/entities/ProfileDevelopment.ts b/src/entities/ProfileDevelopment.ts index 73b5d6f5..66a79b50 100644 --- a/src/entities/ProfileDevelopment.ts +++ b/src/entities/ProfileDevelopment.ts @@ -192,9 +192,9 @@ export class CreateProfileDevelopment { isDevelopment10: boolean | null; // summary?: number | null; // point?: number | null; - developmentTarget?: number | null; - developmentResults?: number | null; - developmentReport?: number | null; + developmentTarget?: string | null; + developmentResults?: string | null; + developmentReport?: string | null; developmentProjects?: string[]; } @@ -215,9 +215,9 @@ export class CreateProfileEmployeeDevelopment { isDevelopment10: boolean | null; // summary?: number | null; // point?: number | null; - developmentTarget?: number | null; - developmentResults?: number | null; - developmentReport?: number | null; + developmentTarget?: string | null; + developmentResults?: string | null; + developmentReport?: string | null; developmentProjects?: string[]; } @@ -237,8 +237,8 @@ export type UpdateProfileDevelopment = { isDevelopment10: boolean | null; // summary?: number | null; // point?: number | null; - developmentTarget?: number | null; - developmentResults?: number | null; - developmentReport?: number | null; + developmentTarget?: string | null; + developmentResults?: string | null; + developmentReport?: string | null; developmentProjects?: string[]; }; From a0398c93544c070b73e042fd636345c87078127e Mon Sep 17 00:00:00 2001 From: Bright Date: Wed, 16 Oct 2024 16:34:36 +0700 Subject: [PATCH 36/41] =?UTF-8?q?fix=20=E0=B8=AD=E0=B8=AD=E0=B8=81?= =?UTF-8?q?=E0=B8=84=E0=B8=B3=E0=B8=AA=E0=B8=B1=E0=B9=88=E0=B8=87,=20email?= =?UTF-8?q?=20keycloak?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/CommandController.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 8f291634..91a95124 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -2286,7 +2286,7 @@ export class CommandController extends Controller { const userKeycloakId = await createUser(profile.citizenId, profile.citizenId, { firstName: profile.firstName, lastName: profile.lastName, - email: profile.email, + // email: profile.email, }); if (typeof userKeycloakId !== "string") { throw new Error(userKeycloakId.errorMessage); @@ -2305,6 +2305,7 @@ export class CommandController extends Controller { ); if (!result) throw new Error("Failed. Cannot set user's role."); profile.keycloak = userKeycloakId; + profile.email = item.bodyProfile.email; await this.profileRepository.save(profile); setLogDataDiff(req, { before, after: profile }); } @@ -2773,7 +2774,7 @@ export class CommandController extends Controller { case "C-PM-05": return "/placement/appointment/appoint/report"; case "C-PM-06": - return "/placement/appointment/slip/report"; + return "/placement/slip/report"; case "C-PM-07": return "/placement/appointment/move/report"; case "C-PM-08": @@ -2839,7 +2840,7 @@ export class CommandController extends Controller { case "C-PM-38": return "/org/command/command38/officer/report"; case "C-PM-39": - return "/placement/slip/report"; + return "/placement/appointment/slip/report"; case "C-PM-40": return "/org/command/command40/officer/report"; case "C-PM-41": From 238ab9dba2b0578e653656bafb9202e29d1cac6c Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 16 Oct 2024 17:15:55 +0700 Subject: [PATCH 37/41] =?UTF-8?q?=E0=B8=AA=E0=B8=A3=E0=B9=89=E0=B8=B2?= =?UTF-8?q?=E0=B8=87=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/WorkflowController.ts | 68 +++++++++++++++++++++++---- src/entities/StateOperatorUser.ts | 8 ---- src/entities/Workflow.ts | 8 ---- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 5e5837aa..3a261a56 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -14,6 +14,8 @@ import { StateUserComment } from "../entities/StateUserComment"; import { MetaWorkflow } from "../entities/MetaWorkflow"; import { MetaState } from "../entities/MetaState"; import { MetaStateOperator } from "../entities/MetaStateOperator"; +import { PosMasterAssign } from "../entities/PosMasterAssign"; +import { PosMaster } from "../entities/PosMaster"; @Route("api/v1/org/workflow") @Tags("Workflow") @@ -29,6 +31,7 @@ export class WorkflowController extends Controller { private metaWorkflowRepo = AppDataSource.getRepository(MetaWorkflow); private metaStateRepo = AppDataSource.getRepository(MetaState); private metaStateOperatorRepo = AppDataSource.getRepository(MetaStateOperator); + private posMasterRepo = AppDataSource.getRepository(PosMaster); @Post("add-workflow") public async checkWorkflow( @@ -66,12 +69,19 @@ export class WorkflowController extends Controller { lastUpdatedAt: new Date(), }; const workflow = new Workflow(); - Object.assign(workflow, { ...metaWorkflow, id: undefined, ...meta }); - this.workflowRepo.save(workflow); + Object.assign(workflow, { + ...metaWorkflow, + id: undefined, + ...meta, + ...body, + system: body.sysName, + }); + await this.workflowRepo.save(workflow); const metaState = await this.metaStateRepo.find({ where: { metaWorkflowId: metaWorkflow.id, }, + order: { order: "ASC" }, }); await Promise.all( @@ -79,15 +89,19 @@ export class WorkflowController extends Controller { const state = new State(); Object.assign(state, { ...item, id: undefined, workflowId: workflow.id, ...meta }); await this.stateRepo.save(state); + if (state.order == 1) { + workflow.stateId = state.id; + await this.workflowRepo.save(workflow); + } const metaStateOperator = await this.metaStateOperatorRepo.find({ where: { metaStateId: item.id, }, }); await Promise.all( - metaStateOperator.map(async (item) => { + metaStateOperator.map(async (item1) => { const stateOperator = new StateOperator(); - Object.assign(stateOperator, { ...item, id: undefined, stateId: state.id, ...meta }); + Object.assign(stateOperator, { ...item1, id: undefined, stateId: state.id, ...meta }); await this.stateOperatorRepo.save(stateOperator); }), ); @@ -97,12 +111,46 @@ export class WorkflowController extends Controller { const stateOperatorUser = new StateOperatorUser(); Object.assign(stateOperatorUser, { profileId: profile.id, - operator: "OWNER", + operator: "Owner", order: 1, workflowId: workflow.id, ...meta, }); await this.stateOperatorUserRepo.save(stateOperatorUser); + + const profileOfficer = await this.posMasterRepo.find({ + where: { + posMasterAssigns: { assignId: body.sysName }, + orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true }, + }, + relations: ["orgChild1"], + }); + await Promise.all( + profileOfficer.map(async (item, i) => { + if (item.orgChild1 == null || item.orgChild1.isOfficer == false) { + const stateOperatorUser = new StateOperatorUser(); + Object.assign(stateOperatorUser, { + profileId: profile.id, + operator: "Officer", + order: i + 2, + workflowId: workflow.id, + ...meta, + }); + await this.stateOperatorUserRepo.save(stateOperatorUser); + } else { + const stateOperatorUser = new StateOperatorUser(); + Object.assign(stateOperatorUser, { + profileId: profile.id, + operator: "PersonnelOfficer", + order: i + 2, + workflowId: workflow.id, + ...meta, + }); + await this.stateOperatorUserRepo.save(stateOperatorUser); + } + }), + ); + return new HttpSuccess(); } @@ -174,7 +222,7 @@ export class WorkflowController extends Controller { const workflow = await this.workflowRepo.findOne({ where: { refId: body.refId, - system: body.system, + sysName: body.system, }, relations: ["stateOperatorUsers"], }); @@ -207,7 +255,7 @@ export class WorkflowController extends Controller { where: { workflow: { refId: body.refId, - system: body.system, + sysName: body.system, }, profile: { keycloak: req.user.sub, @@ -254,7 +302,7 @@ export class WorkflowController extends Controller { where: { workflow: { refId: body.refId, - system: body.system, + sysName: body.system, }, }, order: { order: "ASC", stateUserComments: { order: "ASC" } }, @@ -282,7 +330,7 @@ export class WorkflowController extends Controller { where: { workflow: { refId: body.refId, - system: body.system, + sysName: body.system, }, profile: { keycloak: req.user.sub, @@ -295,7 +343,7 @@ export class WorkflowController extends Controller { const workflow = await this.workflowRepo.findOne({ where: { refId: body.refId, - system: body.system, + sysName: body.system, }, relations: ["stateOperatorUsers"], }); diff --git a/src/entities/StateOperatorUser.ts b/src/entities/StateOperatorUser.ts index d9f2d6a8..6d5c4294 100644 --- a/src/entities/StateOperatorUser.ts +++ b/src/entities/StateOperatorUser.ts @@ -21,14 +21,6 @@ export class StateOperatorUser extends EntityBase { }) order: number; - @Column({ - nullable: true, - comment: "ผู้ดำเนินการ", - length: 255, - default: null, - }) - refId: string; - @Column({ nullable: true, length: 40, diff --git a/src/entities/Workflow.ts b/src/entities/Workflow.ts index 0c6090d6..e6804bf2 100644 --- a/src/entities/Workflow.ts +++ b/src/entities/Workflow.ts @@ -13,14 +13,6 @@ export class Workflow extends EntityBase { }) refId: string; - @Column({ - nullable: true, - comment: "system", - length: 255, - default: null, - }) - system: string; - @Column({ nullable: true, comment: "ชื่อ flow", From b933666c8d203aea25a4d2feb547ebd3466dbc71 Mon Sep 17 00:00:00 2001 From: kittapath Date: Wed, 16 Oct 2024 17:49:55 +0700 Subject: [PATCH 38/41] delete user in state --- src/controllers/WorkflowController.ts | 8 ++++---- .../1729073909711-add_table_workflow8.ts | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 src/migration/1729073909711-add_table_workflow8.ts diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 3a261a56..a37a95c5 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -16,6 +16,7 @@ import { MetaState } from "../entities/MetaState"; import { MetaStateOperator } from "../entities/MetaStateOperator"; import { PosMasterAssign } from "../entities/PosMasterAssign"; import { PosMaster } from "../entities/PosMaster"; +import { Not } from "typeorm"; @Route("api/v1/org/workflow") @Tags("Workflow") @@ -326,19 +327,18 @@ export class WorkflowController extends Controller { system: string; }, ) { - const stateOperatorUser = await this.stateOperatorUserRepo.findOne({ + const stateOperatorUser = await this.stateOperatorUserRepo.find({ where: { workflow: { refId: body.refId, sysName: body.system, }, profile: { - keycloak: req.user.sub, + keycloak: Not(req.user.sub), }, }, }); - if (!stateOperatorUser) - throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในกระบวนการนี้"); + await this.stateOperatorUserRepo.remove(stateOperatorUser); const workflow = await this.workflowRepo.findOne({ where: { diff --git a/src/migration/1729073909711-add_table_workflow8.ts b/src/migration/1729073909711-add_table_workflow8.ts new file mode 100644 index 00000000..17efd713 --- /dev/null +++ b/src/migration/1729073909711-add_table_workflow8.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddTableWorkflow81729073909711 implements MigrationInterface { + name = 'AddTableWorkflow81729073909711' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`workflow\` DROP COLUMN \`system\``); + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` DROP COLUMN \`refId\``); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`stateOperatorUser\` ADD \`refId\` varchar(255) NULL COMMENT 'ผู้ดำเนินการ'`); + await queryRunner.query(`ALTER TABLE \`workflow\` ADD \`system\` varchar(255) NULL COMMENT 'system'`); + } + +} From 7cada3195d4556f175251eb9b12d53a533dbf2fe Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 17 Oct 2024 09:46:55 +0700 Subject: [PATCH 39/41] =?UTF-8?q?=E0=B8=AB=E0=B8=B2=E0=B8=9C=E0=B8=B9?= =?UTF-8?q?=E0=B9=89=E0=B8=9A=E0=B8=B1=E0=B8=87=E0=B8=84=E0=B8=B1=E0=B8=9A?= =?UTF-8?q?=E0=B8=9A=E0=B8=B1=E0=B8=8D=E0=B8=8A=E0=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/WorkflowController.ts | 50 ++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index a37a95c5..36d65ece 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Post, Request, Route, Security, Tags } from "tsoa"; +import { Body, Controller, Get, Path, Post, Request, Route, Security, Tags } from "tsoa"; import { AppDataSource } from "../database/data-source"; import { RequestWithUser } from "../middlewares/user"; import HttpError from "../interfaces/http-error"; @@ -16,7 +16,7 @@ import { MetaState } from "../entities/MetaState"; import { MetaStateOperator } from "../entities/MetaStateOperator"; import { PosMasterAssign } from "../entities/PosMasterAssign"; import { PosMaster } from "../entities/PosMaster"; -import { Not } from "typeorm"; +import { IsNull, Not } from "typeorm"; @Route("api/v1/org/workflow") @Tags("Workflow") @@ -131,7 +131,7 @@ export class WorkflowController extends Controller { if (item.orgChild1 == null || item.orgChild1.isOfficer == false) { const stateOperatorUser = new StateOperatorUser(); Object.assign(stateOperatorUser, { - profileId: profile.id, + profileId: item.current_holderId, operator: "Officer", order: i + 2, workflowId: workflow.id, @@ -141,7 +141,7 @@ export class WorkflowController extends Controller { } else { const stateOperatorUser = new StateOperatorUser(); Object.assign(stateOperatorUser, { - profileId: profile.id, + profileId: item.current_holderId, operator: "PersonnelOfficer", order: i + 2, workflowId: workflow.id, @@ -266,7 +266,8 @@ export class WorkflowController extends Controller { }); if (!stateOperatorUser) throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในกระบวนการนี้"); - + console.log(stateOperatorUser.operator); + console.log(stateOperatorUser.workflow.stateId); const operator = await this.stateOperatorRepo.findOne({ where: { operator: stateOperatorUser.operator, @@ -586,4 +587,43 @@ export class WorkflowController extends Controller { profileId: stateUserComment?.profileId || null, }); } + + /** + * + * + */ + @Get("commander") + async getProfilePlacement(@Request() req: RequestWithUser) { + const posMasterUser = await this.posMasterRepo.findOne({ + where: { + orgRevision: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true }, + current_holder: { keycloak: req.user.sub }, + }, + }); + if (!posMasterUser || !posMasterUser.orgRootId) + throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบตำแหน่งผู้ใช้งาน"); + + const posMasters = await this.posMasterRepo.find({ + where: { + orgRevision: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true }, + isDirector: true, + current_holderId: Not(IsNull()), + orgRootId: posMasterUser.orgRootId, + }, + relations: ["current_holder", "orgRoot"], + }); + + let _posMasters = posMasters.map((data) => ({ + id: data.current_holderId, + prefix: data.current_holder.prefix, + firstName: data.current_holder.firstName, + lastName: data.current_holder.lastName, + position: data.current_holder.position, + posLevel: data.current_holder.posLevel, + posType: data.current_holder.posType, + orgRoot: data.orgRoot.orgRootName, + })); + + return new HttpSuccess(_posMasters); + } } From 437632f39c1e998f6b02e54e81065f91f92397eb Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 17 Oct 2024 09:55:06 +0700 Subject: [PATCH 40/41] no message --- src/controllers/WorkflowController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 36d65ece..39410525 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -596,7 +596,7 @@ export class WorkflowController extends Controller { async getProfilePlacement(@Request() req: RequestWithUser) { const posMasterUser = await this.posMasterRepo.findOne({ where: { - orgRevision: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true }, + orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, current_holder: { keycloak: req.user.sub }, }, }); @@ -605,7 +605,7 @@ export class WorkflowController extends Controller { const posMasters = await this.posMasterRepo.find({ where: { - orgRevision: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true }, + orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false }, isDirector: true, current_holderId: Not(IsNull()), orgRootId: posMasterUser.orgRootId, From a53cf4212f572e4f2656712c2198060cb3f03950 Mon Sep 17 00:00:00 2001 From: kittapath Date: Thu, 17 Oct 2024 10:38:32 +0700 Subject: [PATCH 41/41] report 10 --- src/controllers/CommandController.ts | 59 +++++++++++++-------------- src/controllers/WorkflowController.ts | 3 +- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/controllers/CommandController.ts b/src/controllers/CommandController.ts index 91a95124..4b030940 100644 --- a/src/controllers/CommandController.ts +++ b/src/controllers/CommandController.ts @@ -19,7 +19,7 @@ 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, Not ,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, CreateProfileAllFields } from "../entities/Profile"; @@ -1013,11 +1013,10 @@ export class CommandController extends Controller { if (command.commandExcecuteDate == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบวันที่คำสั่งมีผล"); - let profiles = command && command.commandRecives.length > 0 - ? command.commandRecives - .filter((x) => x.profileId != null) - .map((x) => x.profileId) - : []; + let profiles = + command && command.commandRecives.length > 0 + ? command.commandRecives.filter((x) => x.profileId != null).map((x) => x.profileId) + : []; await new CallAPI() .PostData(request, "/placement/noti/profiles", { @@ -1073,12 +1072,12 @@ export class CommandController extends Controller { const command = await this.commandRepository.find({ relations: ["commandType", "commandRecives"], - where:{ + where: { commandExcecuteDate: Between(today, tomorrow), - status: "WAITING" - } + status: "WAITING", + }, }); - + const data = { client_id: "gettoken", client_secret: process.env.AUTH_ACCOUNT_SECRET, @@ -1100,27 +1099,27 @@ export class CommandController extends Controller { ]); if (_data == null) { return new HttpError(HttpStatus.UNAUTHORIZED, "ชื่อผู้ใช้งานหรือรหัสผ่านไม่ถูกต้อง"); - } + } command.forEach(async (x) => { - const path = this.commandTypePath(x.commandType.code); - if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ"); - const msg = { - data: { - id: x.id, - status: "REPORTED", - lastUpdateUserId: "system", - lastUpdateFullName: "system", - // lastUpdateUserId: _data.user.sub, - // lastUpdateFullName: _data.user.name, - lastUpdatedAt: new Date(), - }, - user: _data.user, - token: _data.access_token, - }; - sendToQueue(msg); - }) - + const path = this.commandTypePath(x.commandType.code); + if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ"); + const msg = { + data: { + id: x.id, + status: "REPORTED", + lastUpdateUserId: "system", + lastUpdateFullName: "system", + // lastUpdateUserId: _data.user.sub, + // lastUpdateFullName: _data.user.name, + lastUpdatedAt: new Date(), + }, + user: _data.user, + token: _data.access_token, + }; + sendToQueue(msg); + }); + return new HttpSuccess(); } @@ -2782,7 +2781,7 @@ export class CommandController extends Controller { case "C-PM-09": return "/retirement/other/out/report"; case "C-PM-10": - return "/xxxxxx"; + return "/probation/report/command10/officer/report"; case "C-PM-11": return "/probation/report/command11/officer/report"; case "C-PM-12": diff --git a/src/controllers/WorkflowController.ts b/src/controllers/WorkflowController.ts index 39410525..3bbd31dc 100644 --- a/src/controllers/WorkflowController.ts +++ b/src/controllers/WorkflowController.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Path, Post, Request, Route, Security, Tags } from "tsoa"; +import { Body, Controller, Get, Post, Request, Route, Security, Tags } from "tsoa"; import { AppDataSource } from "../database/data-source"; import { RequestWithUser } from "../middlewares/user"; import HttpError from "../interfaces/http-error"; @@ -14,7 +14,6 @@ import { StateUserComment } from "../entities/StateUserComment"; import { MetaWorkflow } from "../entities/MetaWorkflow"; import { MetaState } from "../entities/MetaState"; import { MetaStateOperator } from "../entities/MetaStateOperator"; -import { PosMasterAssign } from "../entities/PosMasterAssign"; import { PosMaster } from "../entities/PosMaster"; import { IsNull, Not } from "typeorm";