Merge branch 'develop' into adiDev

# Conflicts:
#	src/controllers/CommandController.ts
This commit is contained in:
AdisakKanthawilang 2024-10-11 11:10:04 +07:00
commit 0cc21ebb0f
30 changed files with 2778 additions and 283 deletions

View file

@ -19,10 +19,10 @@ import HttpSuccess from "../interfaces/http-success";
import HttpStatusCode from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
import { Command } from "../entities/Command";
import { Brackets, LessThan, MoreThan, Double, In, Between } from "typeorm";
import { Brackets, LessThan, MoreThan, Double, In, Not ,Between } from "typeorm";
import { CommandType } from "../entities/CommandType";
import { CommandSend } from "../entities/CommandSend";
import { Profile } from "../entities/Profile";
import { Profile, CreateProfileAllFields } from "../entities/Profile";
import { RequestWithUser } from "../middlewares/user";
import { OrgRevision } from "../entities/OrgRevision";
import { CommandSendCC } from "../entities/CommandSendCC";
@ -32,9 +32,14 @@ import HttpStatus from "../interfaces/http-status";
import Extension from "../interfaces/extension";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import CallAPI from "../interfaces/call-api";
import { ProfileSalary } from "../entities/ProfileSalary";
import { ProfileSalary, CreateProfileSalary } from "../entities/ProfileSalary";
import { ProfileSalaryHistory } from "../entities/ProfileSalaryHistory";
import { removeProfileInOrganize, setLogDataDiff } from "../interfaces/utils";
import {
calculateRetireDate,
calculateRetireLaw,
removeProfileInOrganize,
setLogDataDiff,
} from "../interfaces/utils";
import { Position } from "../entities/Position";
import { PosMaster } from "../entities/PosMaster";
import { EmployeePosition } from "../entities/EmployeePosition";
@ -43,6 +48,14 @@ import { ProfileDiscipline } from "../entities/ProfileDiscipline";
import { ProfileDisciplineHistory } from "../entities/ProfileDisciplineHistory";
import { PosMasterAct } from "../entities/PosMasterAct";
import { sendToQueue } from "../services/rabbitmq";
import { PosLevel } from "../entities/PosLevel";
import { PosType } from "../entities/PosType";
import { addUserRoles, createUser, getRoles } from "../keycloak";
import { ProfileEducation, CreateProfileEducation } from "../entities/ProfileEducation";
import { ProfileEducationHistory } from "../entities/ProfileEducationHistory";
import { CreateProfileCertificate, ProfileCertificate } from "../entities/ProfileCertificate";
import { ProfileCertificateHistory } from "../entities/ProfileCertificateHistory";
import permission from "../interfaces/permission";
@Route("api/v1/org/command")
@Tags("Command")
@ -71,6 +84,13 @@ export class CommandController extends Controller {
private disciplineRepository = AppDataSource.getRepository(ProfileDiscipline);
private disciplineHistoryRepository = AppDataSource.getRepository(ProfileDisciplineHistory);
private posMasterActRepository = AppDataSource.getRepository(PosMasterAct);
private posLevelRepo = AppDataSource.getRepository(PosLevel);
private posTypeRepo = AppDataSource.getRepository(PosType);
private profileEducationRepo = AppDataSource.getRepository(ProfileEducation);
private profileEducationHistoryRepo = AppDataSource.getRepository(ProfileEducationHistory);
private certificateRepo = AppDataSource.getRepository(ProfileCertificate);
private certificateHistoryRepo = AppDataSource.getRepository(ProfileCertificateHistory);
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
/**
* API list
@ -80,6 +100,7 @@ export class CommandController extends Controller {
*/
@Get("list")
async GetResult(
@Request() request: RequestWithUser,
@Query("page") page: number = 1,
@Query("pageSize") pageSize: number = 10,
@Query() keyword: string = "",
@ -87,8 +108,107 @@ export class CommandController extends Controller {
@Query() year?: number,
@Query() status?: string | null,
) {
let profilekArray: any = [];
let _profile = await this.profileRepository.findOne({
where: { keycloak: request.user.sub },
relations: ["current_holders", "current_holders.orgRevision"],
});
let isDirector =
_profile?.current_holders?.filter(
(x) =>
x.orgRevision?.orgRevisionIsCurrent == true && x.orgRevision?.orgRevisionIsDraft == false,
)[0]?.isDirector || false;
if (isDirector) {
let _data: any = {
root: null,
child1: null,
child2: null,
child3: null,
child4: null,
};
if (!request.user.role.includes("SUPER_ADMIN")) {
_data = await new permission().PermissionOrgList(request, "COMMAND");
}
const profiles = await this.profileRepository
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.andWhere(
_data.root != undefined && _data.root != null
? _data.root[0] != null
? `current_holders.orgRootId IN (:...root)`
: `current_holders.orgRootId is null`
: "1=1",
{
root: _data.root,
},
)
.andWhere(
_data.child1 != undefined && _data.child1 != null
? _data.child1[0] != null
? `current_holders.orgChild1Id IN (:...child1)`
: `current_holders.orgChild1Id is null`
: "1=1",
{
child1: _data.child1,
},
)
.andWhere(
_data.child2 != undefined && _data.child2 != null
? _data.child2[0] != null
? `current_holders.orgChild2Id IN (:...child2)`
: `current_holders.orgChild2Id is null`
: "1=1",
{
child2: _data.child2,
},
)
.andWhere(
_data.child3 != undefined && _data.child3 != null
? _data.child3[0] != null
? `current_holders.orgChild3Id IN (:...child3)`
: `current_holders.orgChild3Id is null`
: "1=1",
{
child3: _data.child3,
},
)
.andWhere(
_data.child4 != undefined && _data.child4 != null
? _data.child4[0] != null
? `current_holders.orgChild4Id IN (:...child4)`
: `current_holders.orgChild4Id is null`
: "1=1",
{
child4: _data.child4,
},
)
.select("profile.keycloak", "keycloak")
.getRawMany();
profilekArray = profiles.map((p) => p.keycloak);
}
const [commands, total] = await this.commandRepository
.createQueryBuilder("command")
.andWhere(
new Brackets((qb) => {
qb.orWhere(
profilekArray.length > 0
? "command.createdUserId IN (:...profilekArray)"
: "command.createdUserId='1'",
{
profilekArray: profilekArray,
},
).orWhere("command.createdUserId = :createdUserId", {
createdUserId: request.user.sub,
});
}),
)
.andWhere(
status != null && status != undefined && status != ""
? "command.status IN (:...status)"
@ -248,8 +368,7 @@ export class CommandController extends Controller {
detailFooter: string | null;
commandAffectDate: Date | null;
commandExcecuteDate: Date | null;
isBangkok: boolean | null;
isAttachment: boolean | null;
isBangkok: string | null;
},
@Request() request: RequestWithUser,
) {
@ -906,7 +1025,7 @@ export class CommandController extends Controller {
payload: "", //แนบไฟล์
isSendMail: true,
isSendInbox: true,
receiveDate: command.commandExcecuteDate,
isSendNotification: true,
})
.catch((error) => {
console.error("Error calling API:", error);
@ -1019,9 +1138,33 @@ export class CommandController extends Controller {
if (!command) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลคำสั่งนี้");
}
let issue =
command.isBangkok == "OFFICE"
? "สำนักปลัดกรุงเทพมหานคร"
: command.isBangkok == "BANGKOK"
? "กรุงเทพมหานคร"
: null;
if (issue == null) {
const orgRevisionActive = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
relations: ["posMasters", "posMasters.orgRoot"],
});
if (orgRevisionActive != null) {
const profile = await this.profileRepository.findOne({
where: {
keycloak: command.createdUserId.toString(),
},
});
if (profile != null) {
issue =
orgRevisionActive?.posMasters?.filter((x) => x.current_holderId == profile.id)[0]
?.orgRoot?.orgRootName || null;
}
}
}
if (issue == null) issue = "...................................";
const _command = {
issue: "...................................",
issue: issue,
commandNo: command.commandNo,
commandYear: command.commandYear,
commandTitle: command.issue,
@ -1038,6 +1181,9 @@ export class CommandController extends Controller {
: Extension.ToThaiNumber(Extension.ToThaiFullDate2(command.commandExcecuteDate)),
name: "...................................",
position: "...................................",
authorizedUserFullName: "...................................",
authorizedPosition: "...................................",
commandAffectDate: "...................................",
};
return new HttpSuccess({
template: command.commandType.fileCover,
@ -1066,7 +1212,6 @@ export class CommandController extends Controller {
let _command: any = [];
const path = this.commandTypePath(command.commandType.code);
if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ");
await new CallAPI()
.PostData(request, path + "/attachment", {
refIds: command.commandRecives
@ -1087,15 +1232,51 @@ export class CommandController extends Controller {
})),
})
.then(async (res) => {
console.log(res);
_command = res;
})
.catch(() => {});
let issue =
command.isBangkok == "OFFICE"
? "สำนักปลัดกรุงเทพมหานคร"
: command.isBangkok == "BANGKOK"
? "กรุงเทพมหานคร"
: null;
if (issue == null) {
const orgRevisionActive = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
relations: ["posMasters", "posMasters.orgRoot"],
});
if (orgRevisionActive != null) {
const profile = await this.profileRepository.findOne({
where: {
keycloak: command.createdUserId.toString(),
},
});
if (profile != null) {
issue =
orgRevisionActive?.posMasters?.filter((x) => x.current_holderId == profile.id)[0]
?.orgRoot?.orgRootName || null;
}
}
}
if (issue == null) issue = "...................................";
return new HttpSuccess({
template: command.commandType.fileAttachment,
reportName: "xlsx-report",
data: _command,
data: {
data: _command,
issuerOrganizationName: issue,
commandNo: command.commandNo == null ? "" : Extension.ToThaiNumber(command.commandNo),
commandYear:
command.commandYear == null
? ""
: Extension.ToThaiNumber(Extension.ToThaiYear(command.commandYear).toString()),
commandExcecuteDate:
command.commandExcecuteDate == null
? ""
: Extension.ToThaiNumber(Extension.ToThaiFullDate2(command.commandExcecuteDate)),
},
});
}
@ -2040,6 +2221,206 @@ export class CommandController extends Controller {
return new HttpSuccess();
}
@Post("excexute/create-officer-profile")
public async CreateOfficeProfileExcecute(
@Request() req: RequestWithUser,
@Body()
body: {
data: {
bodyProfile: CreateProfileAllFields;
bodyEducations?: CreateProfileEducation[];
bodyCertificates?: CreateProfileCertificate[];
bodySalarys?: CreateProfileSalary | null;
bodyPosition?: {
posmasterId: string;
positionId: string;
} | null;
}[];
},
) {
await Promise.all(
body.data.map(async (item) => {
const before = null;
const meta = {
createdUserId: req.user.sub,
createdFullName: req.user.name,
lastUpdateUserId: req.user.sub,
lastUpdateFullName: req.user.name,
createdAt: new Date(),
lastUpdatedAt: new Date(),
};
const _null: any = null;
if (item.bodyProfile.posLevelId === "") item.bodyProfile.posLevelId = null;
if (item.bodyProfile.posTypeId === "") item.bodyProfile.posTypeId = null;
if (
item.bodyProfile.posLevelId &&
!(await this.posLevelRepo.findOneBy({ id: item.bodyProfile.posLevelId }))
) {
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลระดับตำแหน่งนี้");
}
if (
item.bodyProfile.posTypeId &&
!(await this.posTypeRepo.findOneBy({ id: item.bodyProfile.posTypeId }))
) {
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้");
}
let profile: any = await this.profileRepository.findOneBy({
citizenId: item.bodyProfile.citizenId,
});
if (!profile) {
profile = Object.assign({ ...item.bodyProfile, ...meta });
profile.dateRetire =
item.bodyProfile.birthDate == null
? _null
: calculateRetireDate(item.bodyProfile.birthDate);
profile.dateRetireLaw =
item.bodyProfile.birthDate == null
? _null
: calculateRetireLaw(item.bodyProfile.birthDate);
const userKeycloakId = await createUser(profile.citizenId, profile.citizenId, {
firstName: profile.firstName,
lastName: profile.lastName,
email: profile.email,
});
if (typeof userKeycloakId !== "string") {
throw new Error(userKeycloakId.errorMessage);
}
const list = await getRoles();
if (!Array.isArray(list))
throw new Error("Failed. Cannot get role(s) data from the server.");
const result = await addUserRoles(
userKeycloakId,
list
.filter((v) => v.name === "USER")
.map((x) => ({
id: x.id,
name: x.name,
})),
);
if (!result) throw new Error("Failed. Cannot set user's role.");
profile.keycloak = userKeycloakId;
await this.profileRepository.save(profile);
setLogDataDiff(req, { before, after: profile });
}
if (profile && profile.id) {
//Educations
if (item.bodyEducations && item.bodyEducations.length > 0) {
await Promise.all(
item.bodyEducations.map(async (education) => {
const profileEdu = new ProfileEducation();
Object.assign(profileEdu, { ...education, ...meta });
const eduHistory = new ProfileEducationHistory();
Object.assign(eduHistory, { ...profileEdu, id: undefined });
profileEdu.profileId = profile.id;
await this.profileEducationRepo.save(profileEdu, { data: req });
setLogDataDiff(req, { before, after: profileEdu });
eduHistory.profileEducationId = profileEdu.id;
await this.profileEducationHistoryRepo.save(eduHistory, { data: req });
}),
);
}
//Certificates
if (item.bodyCertificates && item.bodyCertificates.length > 0) {
await Promise.all(
item.bodyCertificates.map(async (cer) => {
const profileCer = new ProfileCertificate();
Object.assign(profileCer, { ...cer, ...meta });
const cerHistory = new ProfileCertificateHistory();
Object.assign(cerHistory, { ...profileCer, id: undefined });
profileCer.profileId = profile.id;
await this.certificateRepo.save(profileCer, { data: req });
setLogDataDiff(req, { before, after: profileCer });
cerHistory.profileCertificateId = profileCer.id;
await this.certificateHistoryRepo.save(cerHistory, { data: req });
}),
);
}
//Salary
if (item.bodySalarys && item.bodySalarys != null) {
const dest_item = await this.salaryRepo.findOne({
where: { profileId: profile.id },
order: { order: "DESC" },
});
const profileSal = new ProfileSalary();
Object.assign(profileSal, { ...item.bodySalarys, ...meta });
const salaryHistory = new ProfileSalaryHistory();
Object.assign(salaryHistory, { ...profileSal, id: undefined });
profileSal.order = dest_item == null ? 1 : dest_item.order + 1;
profileSal.profileId = profile.id;
await this.salaryRepo.save(profileSal, { data: req });
setLogDataDiff(req, { before, after: profileSal });
salaryHistory.profileSalaryId = profileSal.id;
await this.salaryHistoryRepo.save(salaryHistory, { data: req });
}
//Position
if (item.bodyPosition && item.bodyPosition != null) {
const posMaster = await this.posMasterRepository.findOne({
where: { id: item.bodyPosition.posmasterId },
});
if (posMaster == null)
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
const posMasterOld = await this.posMasterRepository.findOne({
where: {
current_holderId: profile.id,
orgRevisionId: posMaster.orgRevisionId,
},
});
if (posMasterOld != null) posMasterOld.current_holderId = null;
const positionOld = await this.positionRepository.findOne({
where: {
posMasterId: posMasterOld?.id,
positionIsSelected: true,
},
});
if (positionOld != null) {
positionOld.positionIsSelected = false;
await this.positionRepository.save(positionOld);
}
const checkPosition = await this.positionRepository.find({
where: {
posMasterId: item.bodyPosition.posmasterId,
positionIsSelected: true,
},
});
if (checkPosition.length > 0) {
const clearPosition = checkPosition.map((positions) => ({
...positions,
positionIsSelected: false,
}));
await this.positionRepository.save(clearPosition);
}
posMaster.current_holderId = profile.id;
if (posMasterOld != null) await this.posMasterRepository.save(posMasterOld);
await this.posMasterRepository.save(posMaster);
const positionNew = await this.positionRepository.findOne({
where: {
id: item.bodyPosition.positionId,
posMasterId: item.bodyPosition.posmasterId,
},
});
if (positionNew != null) {
positionNew.positionIsSelected = true;
profile.posLevelId = positionNew.posLevelId;
profile.posTypeId = positionNew.posTypeId;
profile.position = positionNew.positionName;
await this.profileRepository.save(profile, { data: req });
setLogDataDiff(req, { before, after: profile });
await this.positionRepository.save(positionNew, { data: req });
}
}
}
}),
);
return new HttpSuccess();
}
@Post("command21/employee/report/excecute")
public async command21SalaryEmployeeExcecute(
@Request() req: RequestWithUser,
@ -2181,6 +2562,28 @@ export class CommandController extends Controller {
refIds: string[];
},
) {
const profile = await this.profileEmployeeRepository.find({ where: { id: In(body.refIds) } });
const data = profile.map((_data) => ({
..._data,
statusTemp: "REPORT",
}));
await this.profileEmployeeRepository.save(data);
return new HttpSuccess();
}
@Post("command21/employee/delete")
public async command21SalaryEmployeeDelete(
@Request() req: RequestWithUser,
@Body()
body: {
refIds: string[];
},
) {
const profile = await this.profileEmployeeRepository.find({ where: { id: In(body.refIds) } });
const data = profile.map((_data) => ({
..._data,
statusTemp: "WAITTING",
}));
await this.profileEmployeeRepository.save(data);
return new HttpSuccess();
}
@ -2211,6 +2614,28 @@ export class CommandController extends Controller {
refIds: string[];
},
) {
// const profile = await this.profileEmployeeRepository.find({ where: { id: In(body.refIds) } });
// const data = profile.map((_data) => ({
// ..._data,
// statusTemp: "DONE",
// }));
// await this.profileEmployeeRepository.save(data);
return new HttpSuccess();
}
@Post("command40/officer/delete")
public async command40SalaryOfficerDelete(
@Request() req: RequestWithUser,
@Body()
body: {
refIds: string[];
},
) {
// const profile = await this.profileEmployeeRepository.find({ where: { id: In(body.refIds) } });
// const data = profile.map((_data) => ({
// ..._data,
// statusTemp: "WAITTING",
// }));
// await this.profileEmployeeRepository.save(data);
return new HttpSuccess();
}
@Post("command40/officer/report/attachment")
@ -2281,8 +2706,7 @@ export class CommandController extends Controller {
"" + posMasterAct.posMasterChild?.current_holder?.firstName ??
"" + " " + posMasterAct.posMasterChild?.current_holder?.lastName ??
null,
organization: _organization,
position: posMasterAct.posMasterChild?.current_holder?.position ?? null,
oc: (posMasterAct.posMasterChild?.current_holder?.position ?? null) + "/" + _organization,
postype: posMasterAct.posMasterChild?.current_holder?.posType?.posTypeName ?? null,
poslevel: posMasterAct.posMasterChild?.current_holder?.posLevel?.posLevelName ?? null,
organizationNew: _organizationNew,
@ -2360,7 +2784,7 @@ export class CommandController extends Controller {
case "C-PM-13":
return "/placement/transfer/command/report";
case "C-PM-14":
return "/placement/Receive/command/report";
return "/placement/receive/command/report";
case "C-PM-15":
return "/placement/officer/command/report";
case "C-PM-16":

View file

@ -1,24 +1,68 @@
import {
Controller,
Example,
Get,
Path,
Response,
Route,
Security,
SuccessResponse,
Tags,
} from "tsoa";
import { Controller, Example, Get, Path, Response, Route, SuccessResponse, Tags } from "tsoa";
import { DateTime } from "@elastic/elasticsearch/lib/api/types";
import { Double } from "typeorm";
import { AppDataSource } from "../database/data-source";
import { Profile } from "../entities/Profile";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
import HttpSuccess from "../interfaces/http-success";
interface DPISResponse {
status: number;
message: string;
result?: DPISResult;
}
interface DPISResult {
citizenId: string;
prefix: string;
firstName: string;
lastName: string;
gender: string;
physicalStatus: string;
QualityWorkforce: boolean;
birthDate: DateTime;
dateAppoint: DateTime;
dateStart: DateTime;
dateRetire: DateTime;
isLeave: boolean;
isProbation: boolean;
leaveReason: string;
positionLevel: string;
positionType: string;
educations: ProfileEducationResult[];
leaves: ProfileLeaveResult[];
salaries: ProfileSalaryResult[];
}
interface ProfileLeaveResult {
dateLeaveStart: DateTime;
dateLeaveEnd: DateTime;
leaveType: string;
totalLeave: number;
}
interface ProfileEducationResult {
country: string;
degree: string;
field: string;
institute: string;
educationLevel: string;
}
interface ProfileSalaryResult {
posNo: string;
position: string;
positionType: string;
positionLevel: string;
amount: Double;
positionSalaryAmount: Double;
monthSalaryAmount: Double;
}
@Route("api/v1/dpis")
@Tags("DPIS")
@Security("bearerAuth")
// @Security("bearerAuth")
@Response(
HttpStatus.INTERNAL_SERVER_ERROR,
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
@ -28,179 +72,86 @@ export class DPISController extends Controller {
private profileRepo = AppDataSource.getRepository(Profile);
/**
* 1. API Get Profile
*
*
* @summary 1. API Get Profile
* @summary
*
* @param {string} citizenId
*
* @returns
* @returns
*/
@Get("{citizenId}")
@Example({
id: "08dc4c9f-2710-4e98-8340-c9f2a65467db",
avatar: null,
avatarName: null,
rank: null,
prefix: "นาย",
firstName: "สุรศักดิ์",
lastName: "จันทร์ศรี",
citizenId: "1103700765894",
position: "เจ้าพนักงานสาธารณสุข",
posLevelId: "1526d9d3-d8b1-43ab-81b5-a84dfbe08262",
email: "userUat43@test.test",
phone: null,
keycloak: "bac99314-8163-4671-9af6-cf994167e939",
isProbation: false,
isLeave: false,
leaveReason: null,
dateRetire: "2055-05-06T17:00:00.000Z",
dateAppoint: "2022-11-24T17:00:00.000Z",
dateRetireLaw: "2055-09-29T17:00:00.000Z",
dateStart: "2022-11-24T17:00:00.000Z",
govAgeAbsent: 0,
govAgePlus: 0,
birthDate: "1995-05-06T17:00:00.000Z",
reasonSameDate: null,
telephoneNumber: "990686659",
nationality: "ไทย",
gender: "หญิง",
relationship: "โสด",
religion: "พุทธ",
bloodGroup: null,
registrationAddress: "21/1 หมู่ที่ 2",
registrationProvinceId: "24bf701c-33d6-436e-ad49-6f82bb3ae029",
registrationDistrictId: "34bf701c-33d6-436e-ad49-6f82bb3b0642",
registrationSubDistrictId: "44bf701c-33d6-436e-ad49-6f82bb3b3427",
registrationZipCode: "22110",
currentAddress: "21/1 หมู่ที่ 2",
currentProvinceId: "24bf701c-33d6-436e-ad49-6f82bb3ae029",
currentSubDistrictId: "44bf701c-33d6-436e-ad49-6f82bb3b3427",
currentZipCode: "22110",
dutyTimeId: null,
dutyTimeEffectiveDate: null,
posLevel: {
id: "1526d9d3-d8b1-43ab-81b5-a84dfbe08262",
createdAt: "2024-01-26T05:42:53.761Z",
createdUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0",
lastUpdatedAt: "2024-01-26T05:42:53.761Z",
lastUpdateUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0",
createdFullName: "สาวิตรี ศรีสมัย",
lastUpdateFullName: "สาวิตรี ศรีสมัย",
posLevelName: "ปฏิบัติงาน",
posLevelRank: 1,
posLevelAuthority: null,
posTypeId: "1526d9d3-d8b1-43ab-81b5-a84dfbe08061",
status: 200,
message: "Success",
result: {
citizenId: "1103700765894",
prefix: "นาย",
firstName: "สุรศักดิ์",
lastName: "จันทร์ศรี",
gender: "หญิง",
physicalStatus: "ปกติ",
QualityWorkforce: true,
birthDate: "1995-05-06T17:00:00.000Z",
dateAppoint: "2022-11-24T17:00:00.000Z",
dateStart: "2022-11-24T17:00:00.000Z",
dateRetire: "2055-05-06T17:00:00.000Z",
isLeave: false,
isProbation: false,
leaveReason: null,
positionLevel: "ปฏิบัติงาน",
positionType: "ทั่วไป",
educations: [],
salaries: [
{
posNo: "ขพน.65",
position: "เจ้าพนักงานสาธารณสุข",
positionType: "ทั่วไป",
positionLevel: "ปฏิบัติงาน",
amount: 11860,
positionSalaryAmount: 0,
monthSalaryAmount: 0,
},
{
posNo: "ขพน.65",
position:
"เจ้าพนักงานสาธารณสุขปฏิบัติงาน ฝ่ายสิ่งแวดล้อมและสุขาภิบาล สำนักงานเขตพระนคร\n(ทดลองปฏิบัติหน้าที่ราชการ)",
positionType: "ทั่วไป",
positionLevel: "ปฏิบัติงาน",
amount: 11860,
positionSalaryAmount: 0,
monthSalaryAmount: 0,
},
{
posNo: "ขพน.65",
position:
"เจ้าพนักงานสาธารณสุขปฏิบัติงาน ฝ่ายสิ่งแวดล้อมและสุขาภิบาล สำนักงานเขตพระนคร\n(ทดลองปฏิบัติหน้าที่ราชการ)",
positionType: "ทั่วไป",
positionLevel: "ปฏิบัติงาน",
amount: 11500,
positionSalaryAmount: 0,
monthSalaryAmount: 0,
},
],
leaves: [],
},
posType: {
id: "1526d9d3-d8b1-43ab-81b5-a84dfbe08061",
createdAt: "2024-01-26T05:42:53.761Z",
createdUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0",
lastUpdatedAt: "2024-08-25T09:41:14.000Z",
lastUpdateUserId: "01378019-5286-4e1d-ae43-826b648af4aa",
createdFullName: "สาวิตรี ศรีสมัย",
lastUpdateFullName: "Super Admin",
posTypeName: "ทั่วไป",
posTypeRank: 1,
},
profileSalary: [
{
id: "eef6d0b6-ef64-4389-b497-c74a62e5f334",
createdAt: "2024-08-22T02:23:57.193Z",
createdUserId: "94ba986d-f871-46a2-be92-46c0cbf0bc56",
lastUpdatedAt: "2024-08-22T02:23:57.193Z",
lastUpdateUserId: "94ba986d-f871-46a2-be92-46c0cbf0bc56",
createdFullName: "กานต์พิชชา นาคศรี",
lastUpdateFullName: "กานต์พิชชา นาคศรี",
profileId: "08dc4c9f-2710-4e98-8340-c9f2a65467db",
profileEmployeeId: null,
date: "2024-08-22T09:23:18.000Z",
posNo: "ขพน.65",
position: "เจ้าพนักงานสาธารณสุข",
positionLine: "ปฏิบัติงานสาธารณสุข",
positionPathSide: null,
positionExecutive: null,
positionType: "ทั่วไป",
positionLevel: "ปฏิบัติงาน",
amount: 11860,
positionSalaryAmount: 0,
mouthSalaryAmount: 0,
refCommandNo: null,
templateDoc: "ปรับโครงสร้าง",
order: 3,
},
{
id: "916fcf0c-f0d5-4efb-af46-0f1942de5c19",
createdAt: "2024-06-27T22:01:25.959Z",
createdUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0",
lastUpdatedAt: "2024-06-27T23:24:50.219Z",
lastUpdateUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0",
createdFullName: "โกศล สิงหนาท",
lastUpdateFullName: "โกศล สิงหนาท",
profileId: "08dc4c9f-2710-4e98-8340-c9f2a65467db",
profileEmployeeId: null,
date: "2023-03-31T17:00:00.000Z",
posNo: "ขพน.65",
position:
"เจ้าพนักงานสาธารณสุขปฏิบัติงาน ฝ่ายสิ่งแวดล้อมและสุขาภิบาล สำนักงานเขตพระนคร\n(ทดลองปฏิบัติหน้าที่ราชการ)",
positionLine: null,
positionPathSide: null,
positionExecutive: null,
positionType: "ทั่วไป",
positionLevel: "ปฏิบัติงาน",
amount: 11860,
positionSalaryAmount: 0,
mouthSalaryAmount: 0,
refCommandNo: null,
templateDoc: "เลื่อนขั้นเงินเดือน คำสั่ง ขพน.ที่ 159/2566 ลว. 6 มิ.ย. 2566",
order: 2,
},
{
id: "161bea25-0451-4eff-bbfd-709e88a1700f",
createdAt: "2024-06-27T22:01:25.881Z",
createdUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0",
lastUpdatedAt: "2024-06-27T23:24:50.219Z",
lastUpdateUserId: "59134ef9-9e62-41d0-aac5-339be727f2b0",
createdFullName: "โกศล สิงหนาท",
lastUpdateFullName: "โกศล สิงหนาท",
profileId: "08dc4c9f-2710-4e98-8340-c9f2a65467db",
profileEmployeeId: null,
date: "2022-11-24T17:00:00.000Z",
posNo: "ขพน.65",
position:
"เจ้าพนักงานสาธารณสุขปฏิบัติงาน ฝ่ายสิ่งแวดล้อมและสุขาภิบาล สำนักงานเขตพระนคร\n(ทดลองปฏิบัติหน้าที่ราชการ)",
positionLine: null,
positionPathSide: null,
positionExecutive: null,
positionType: "ทั่วไป",
positionLevel: "ปฏิบัติงาน",
amount: 11500,
positionSalaryAmount: 0,
mouthSalaryAmount: 0,
refCommandNo: null,
templateDoc:
"บรรจุและแต่งตั้งผู้สอบแข่งขันได้ คำสั่ง ขพน.ที่ 374/2565 ลว. 29 พ.ย. 2565 โดยมีเงื่อนไขว่าต้องปฏิบัติงานให้กรุงเทพมหานครเป็นระยะเวลาไม่น้อยกว่า 5 ปี นับแต่วันที่ได้รับการบรรจุและแต่งตั้ง \nโดยห้ามโอนไปหน่วยงานหรือส่วนราชการอื่น เว้นแต่ลาออกจากราชการ\n",
order: 1,
},
],
profileInsignia: [],
})
async GetProfileCitizenIdAsync(@Path() citizenId: string) {
async GetProfileCitizenIdAsync(@Path() citizenId: string): Promise<DPISResponse> {
const profile = await this.profileRepo.findOne({
relations: {
posLevel: true,
posType: true,
profileSalary: true,
profileInsignias: true,
profileEducations: true,
profileLeaves: true,
},
where: { citizenId: citizenId },
order: {
profileSalary: {
date: "DESC",
},
profileInsignias: {
receiveDate: "DESC",
profileLeaves: {
dateLeaveStart: "ASC",
},
profileEducations: {
degree: "ASC",
@ -209,45 +160,61 @@ export class DPISController extends Controller {
});
if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
const mapProfile = {
const mapProfile: DPISResult = {
citizenId: profile.citizenId,
prefix: profile.prefix,
firstName: profile.firstName,
lastName: profile.lastName,
rank: profile.rank,
position: profile.position,
isProbation: profile.isProbation,
isLeave: profile.isLeave,
leaveReason: profile.leaveReason,
dateRetire: profile.dateRetire,
dateAppoint: profile.dateAppoint,
dateRetireLaw: profile.dateRetireLaw,
dateStart: profile.dateStart,
birthDate: profile.birthDate,
telephoneNumber: profile.telephoneNumber,
nationality: profile.nationality,
gender: profile.gender,
relationship: profile.relationship,
religion: profile.religion,
bloodGroup: profile.bloodGroup,
registrationAddress: profile.registrationAddress,
registrationProvinceId: profile.registrationProvinceId,
registrationDistrictId: profile.registrationDistrictId,
registrationSubDistrictId: profile.registrationSubDistrictId,
registrationZipCode: profile.registrationZipCode,
currentAddress: profile.currentAddress,
currentProvinceId: profile.currentProvinceId,
currentSubDistrictId: profile.currentSubDistrictId,
currentZipCode: profile.currentZipCode,
dutyTimeId: profile.dutyTimeId,
dutyTimeEffectiveDate: profile.dutyTimeEffectiveDate,
posLevel: profile.posLevel ? profile.posLevel : null,
posType: profile.posType ? profile.posType : null,
profileSalary: profile.profileSalary,
profileInsignia: profile.profileInsignias,
profileEducation: profile.profileEducations,
physicalStatus: "ปกติ",
QualityWorkforce: true,
birthDate: profile.birthDate,
dateAppoint: profile.dateAppoint,
dateStart: profile.dateStart,
dateRetire: profile.dateRetire,
isLeave: profile.isLeave,
isProbation: profile.isProbation,
leaveReason: profile.leaveReason,
positionLevel: profile.posLevel ? profile.posLevel.posLevelName : "",
positionType: profile.posType ? profile.posType.posTypeName : "",
// educations
educations: profile.profileEducations.map((item) => {
return {
country: item.country,
degree: item.degree,
field: item.field,
institute: item.institute,
educationLevel: item.educationLevel,
};
}),
salaries: profile.profileSalary.map((item) => {
return {
posNo: item.posNo,
position: item.position,
positionType: item.positionType,
positionLevel: item.positionLevel,
amount: item.amount,
positionSalaryAmount: item.positionSalaryAmount,
monthSalaryAmount: item.mouthSalaryAmount,
};
}),
leaves: profile.profileLeaves.map((item) => {
return {
dateLeaveStart: item.dateLeaveStart,
dateLeaveEnd: item.dateLeaveEnd,
leaveType: item.leaveType ? item.leaveType.name : "",
totalLeave: item.totalLeave,
};
}),
};
return new HttpSuccess(mapProfile);
return {
status: 200,
message: "Success",
result: mapProfile,
};
}
}

View file

@ -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);
}

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -25,6 +25,10 @@ import { RequestWithUser } from "../middlewares/user";
import { PermissionOrg } from "../entities/PermissionOrg";
import { Profile } from "../entities/Profile";
import HttpStatus from "../interfaces/http-status";
import permission from "../interfaces/permission";
import { PosMaster } from "../entities/PosMaster";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
import { ProfileEmployee } from "../entities/ProfileEmployee";
@Route("api/v1/org/permission-org")
@Tags("PermissionOrg")
@ -39,6 +43,10 @@ export class PermissionOrgController extends Controller {
private profileRepository = AppDataSource.getRepository(Profile);
private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
private permissionOrgRepository = AppDataSource.getRepository(PermissionOrg);
private posMasterRepository = AppDataSource.getRepository(PosMaster);
private posMasterEmpRepository = AppDataSource.getRepository(EmployeePosMaster);
private profileRepo = AppDataSource.getRepository(Profile);
private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee);
/**
* API
@ -48,22 +56,35 @@ export class PermissionOrgController extends Controller {
*/
@Get()
async GetActiveRootIdAdmin(@Request() request: RequestWithUser) {
// if (!request.user.role.includes("SUPER_ADMIN")) {
// throw new HttpError(HttpStatus.FORBIDDEN, "ไม่มีสิทธิ์ใช้งานระบบนี้");
// }
const orgRevisionActive = await this.orgRevisionRepository.findOne({
where: { orgRevisionIsCurrent: false, orgRevisionIsDraft: true },
relations: ["posMasters"],
});
if (!orgRevisionActive) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่แบบร่างอยู่ตอนนี้");
}
if (!orgRevisionActive) return new HttpSuccess([]);
let rootId: any = null;
if (!request.user.role.includes("SUPER_ADMIN")) {
const profile = await this.profileRepo.findOne({
where: {
keycloak: request.user.sub,
},
});
if (profile == null) return new HttpSuccess([]);
const data = await this.orgRootRepository.find({
where: { orgRevisionId: orgRevisionActive.id },
order: {
orgRootOrder: "ASC",
},
});
if (!request.user.role.includes("SUPER_ADMIN")) {
rootId =
orgRevisionActive?.posMasters?.filter((x) => x.next_holderId == profile.id)[0]
?.orgRootId || null;
if (!rootId) return new HttpSuccess([]);
}
}
const data = await AppDataSource.getRepository(OrgRoot)
.createQueryBuilder("orgRoot")
.where("orgRoot.orgRevisionId = :id", { id: orgRevisionActive.id })
.andWhere(rootId != null ? `orgRoot.id = :rootId` : "1=1", {
rootId: rootId,
})
.orderBy("orgRoot.orgRootOrder", "ASC")
.getMany();
return new HttpSuccess(data);
}
@ -500,4 +521,38 @@ export class PermissionOrgController extends Controller {
await this.permissionOrgRepository.delete(_delPermissionOrg.id);
return new HttpSuccess();
}
public async listAuthSysOrgFuncByRevisionId(
request: RequestWithUser,
system: string,
revisionId: string,
) {
let profile = await this.profileRepo.findOne({
where: {
keycloak: request.user.sub,
},
relations: ["next_holders", "next_holders.authRole", "next_holders.authRole.authRoles"],
});
if (!profile) {
return [null];
}
let attrOwnership =
profile?.next_holders
.filter((x) => x.orgRevisionId == revisionId)[0]
?.authRole?.authRoles?.filter((x) => x.authSysId == system)[0]?.attrOwnership || null;
const posMaster = await this.posMasterRepository.findOne({
where: {
next_holderId: profile.id,
orgRevisionId: revisionId,
},
});
if (!posMaster) {
return [null];
} else if (attrOwnership == "OWNER") {
return null;
} else {
return [posMaster.orgRootId];
}
}
}

View file

@ -63,6 +63,7 @@ import { updateName } from "../keycloak";
import permission from "../interfaces/permission";
import { PosMasterAct } from "../entities/PosMasterAct";
import axios from "axios";
import { OrgChild1 } from "../entities/OrgChild1";
@Route("api/v1/org/profile")
@Tags("Profile")
@Security("bearerAuth")
@ -101,6 +102,7 @@ export class ProfileController extends Controller {
private disciplineHistoryRepository = AppDataSource.getRepository(ProfileDisciplineHistory);
private profileLeaveRepository = AppDataSource.getRepository(ProfileLeave);
private posMasterActRepository = AppDataSource.getRepository(PosMasterAct);
private orgChild1Repository = AppDataSource.getRepository(OrgChild1);
/**
* report
@ -934,6 +936,91 @@ export class ProfileController extends Controller {
return new HttpSuccess({ caregiver, commander, chairman });
}
/**
* API
*
* @summary API
*
*/
@Get("admin-keycloak")
async listProfileIdByorg(@Request() request: RequestWithUser) {
let _data: any = {
root: null,
child1: null,
child2: null,
child3: null,
child4: null,
};
if (!request.user.role.includes("SUPER_ADMIN")) {
_data = await new permission().PermissionOrgList(request, "SYS_ORG");
}
const profiles = await this.profileRepo
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.current_holders", "current_holders")
.leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
.leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
.leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
.leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
.leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
.andWhere(
_data.root != undefined && _data.root != null
? _data.root[0] != null
? `current_holders.orgRootId IN (:...root)`
: `current_holders.orgRootId is null`
: "1=1",
{
root: _data.root,
},
)
.andWhere(
_data.child1 != undefined && _data.child1 != null
? _data.child1[0] != null
? `current_holders.orgChild1Id IN (:...child1)`
: `current_holders.orgChild1Id is null`
: "1=1",
{
child1: _data.child1,
},
)
.andWhere(
_data.child2 != undefined && _data.child2 != null
? _data.child2[0] != null
? `current_holders.orgChild2Id IN (:...child2)`
: `current_holders.orgChild2Id is null`
: "1=1",
{
child2: _data.child2,
},
)
.andWhere(
_data.child3 != undefined && _data.child3 != null
? _data.child3[0] != null
? `current_holders.orgChild3Id IN (:...child3)`
: `current_holders.orgChild3Id is null`
: "1=1",
{
child3: _data.child3,
},
)
.andWhere(
_data.child4 != undefined && _data.child4 != null
? _data.child4[0] != null
? `current_holders.orgChild4Id IN (:...child4)`
: `current_holders.orgChild4Id is null`
: "1=1",
{
child4: _data.child4,
},
)
.andWhere({ keycloak: Not(IsNull()) })
.andWhere({ keycloak: Not("") })
.select("profile.keycloak", "keycloak")
.getRawMany();
const keycloakArray = profiles.map((p) => p.keycloak);
return new HttpSuccess(keycloakArray);
}
/**
*
*
@ -3407,6 +3494,32 @@ export class ProfileController extends Controller {
return new HttpSuccess(_profile);
}
/**
* API
*
* @summary
*
*/
@Get("keycloak/idofficer")
async getIsOfficerByKeycloak(@Request() request: RequestWithUser) {
const posMasters = await this.posMasterRepo.findOne({
where: {
current_holder: {
keycloak: request.user.sub,
},
orgRevision: {
orgRevisionIsCurrent: true,
orgRevisionIsDraft: false,
},
},
relations: ["orgChild1"],
});
if (posMasters == null || posMasters.orgRoot == null) {
return new HttpSuccess(false);
}
return new HttpSuccess(posMasters);
}
/**
* API keycloakid
*
@ -4800,6 +4913,7 @@ export class ProfileController extends Controller {
const isProbation: boolean = true;
const [findProfile, total] = await AppDataSource.getRepository(Profile)
.createQueryBuilder("profile")
.leftJoinAndSelect("profile.profileSalary", "profileSalary")
.leftJoinAndSelect("profile.posLevel", "posLevel")
.leftJoinAndSelect("profile.posType", "posType")
.leftJoinAndSelect("profile.current_holders", "current_holders")
@ -4914,9 +5028,13 @@ export class ProfileController extends Controller {
lastName: item.lastName,
position: item.position,
idcard: item.citizenId,
refCommandNo:
item.profileSalary.sort((a, b) => b.order - a.order).length == 0
? null
: item.profileSalary.sort((a, b) => b.order - a.order)[0].refCommandNo,
posLevelName: item.posLevel == null ? null : item.posLevel.posLevelName,
posTypeName: item.posType == null ? null : item.posType.posTypeName,
posNo: `${posMaster == null ? null : posMaster.posMasterNo}${shortName}`,
posNo: posMaster == null ? null : `${posMaster.posMasterNo}${shortName}`,
positionField: position == null ? null : position.positionField,
positionArea: position == null ? null : position.positionArea,
posExecutiveName: posExecutive,

View file

@ -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}")

View file

@ -122,6 +122,8 @@ export class ProfileEditController extends Controller {
.getManyAndCount();
const _data = getProfileEdit.map((item) => ({
id: item.id,
idcard: item.profile.citizenId,
profileId: item.profile.id,
topic: item.topic,
detail: item.detail,
status: item.status,
@ -151,10 +153,10 @@ export class ProfileEditController extends Controller {
// return new HttpSuccess(getProfileEdit);
// }
@Get("{profileId}")
public async detailProfileEdit(@Path() profileId: string) {
@Get("{id}")
public async detailProfileEdit(@Path() id: string) {
const getProfileEdit = await this.profileEditRepo.findOne({
where: { profileId: profileId },
where: { id: id },
relations: ["profile"],
});
if (!getProfileEdit) {

View file

@ -129,6 +129,8 @@ export class ProfileEditEmployeeController extends Controller {
const _data = getProfileEdit.map((item) => ({
id: item.id,
idcard: item.profile.citizenId,
profileId: item.profile.id,
topic: item.topic,
detail: item.detail,
status: item.status,

View file

@ -30,11 +30,15 @@ import {
getRoleMappings,
getUserCount,
enableStatus,
getUserCountOrg,
getUserListOrg,
} from "../keycloak";
import { AppDataSource } from "../database/data-source";
import { Profile } from "../entities/Profile";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import { IsNull } from "typeorm";
import { IsNull, Not } from "typeorm";
import { RequestWithUser } from "../middlewares/user";
import permission from "../interfaces/permission";
// import * as io from "../lib/websocket";
// import elasticsearch from "../elasticsearch";
// import { StorageFolder } from "../interfaces/storage-fs";
@ -94,7 +98,6 @@ export class KeycloakController extends Controller {
firstName: body.firstName,
lastName: body.lastName,
email: body.email,
requiredActions: ["UPDATE_PASSWORD"],
});
if (typeof userId !== "string") {
@ -239,7 +242,89 @@ export class KeycloakController extends Controller {
}
@Get("user")
async getUserList(@Query() first = "", @Query() max = "", @Query() search = "") {
async getUserList(
@Request() request: RequestWithUser,
@Query() first = "",
@Query() max = "",
@Query() search = "",
) {
// let _data: any = {
// root: null,
// child1: null,
// child2: null,
// child3: null,
// child4: null,
// };
// if (!request.user.role.includes("SUPER_ADMIN")) {
// _data = await new permission().PermissionOrgList(request, "SYS_ORG");
// }
// const profiles = await this.profileRepo
// .createQueryBuilder("profile")
// .leftJoinAndSelect("profile.current_holders", "current_holders")
// .leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
// .leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
// .leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
// .leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
// .leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
// .andWhere(
// _data.root != undefined && _data.root != null
// ? _data.root[0] != null
// ? `current_holders.orgRootId IN (:...root)`
// : `current_holders.orgRootId is null`
// : "1=1",
// {
// root: _data.root,
// },
// )
// .andWhere(
// _data.child1 != undefined && _data.child1 != null
// ? _data.child1[0] != null
// ? `current_holders.orgChild1Id IN (:...child1)`
// : `current_holders.orgChild1Id is null`
// : "1=1",
// {
// child1: _data.child1,
// },
// )
// .andWhere(
// _data.child2 != undefined && _data.child2 != null
// ? _data.child2[0] != null
// ? `current_holders.orgChild2Id IN (:...child2)`
// : `current_holders.orgChild2Id is null`
// : "1=1",
// {
// child2: _data.child2,
// },
// )
// .andWhere(
// _data.child3 != undefined && _data.child3 != null
// ? _data.child3[0] != null
// ? `current_holders.orgChild3Id IN (:...child3)`
// : `current_holders.orgChild3Id is null`
// : "1=1",
// {
// child3: _data.child3,
// },
// )
// .andWhere(
// _data.child4 != undefined && _data.child4 != null
// ? _data.child4[0] != null
// ? `current_holders.orgChild4Id IN (:...child4)`
// : `current_holders.orgChild4Id is null`
// : "1=1",
// {
// child4: _data.child4,
// },
// )
// .andWhere({ keycloak: Not(IsNull()) })
// .andWhere({ keycloak: Not("") })
// .select("profile.keycloak", "keycloak")
// .getRawMany();
// let keycloakArray = profiles.map((p) => p.keycloak);
// const total = await getUserCountOrg(first, max, search, keycloakArray);
// const result = await getUserListOrg(first, max, search, keycloakArray);
const total = await getUserCount(first, max, search);
const result = await getUserList(first, max, search);

View file

@ -0,0 +1,254 @@
import { Body, Controller, Post, Request, Route, Security, Tags } from "tsoa";
import { AppDataSource } from "../database/data-source";
import { RequestWithUser } from "../middlewares/user";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
import HttpSuccess from "../interfaces/http-success";
import { Workflow } from "../entities/Workflow";
import { State } from "../entities/State";
import { StateOperator } from "../entities/StateOperator";
import { StateOperatorUser } from "../entities/StateOperatorUser";
import CallAPI from "../interfaces/call-api";
import { Profile } from "../entities/Profile";
@Route("api/v1/org/workflow")
@Tags("AuthRole")
@Security("bearerAuth")
export class WorkflowController extends Controller {
private workflowRepo = AppDataSource.getRepository(Workflow);
private stateRepo = AppDataSource.getRepository(State);
private stateOperatorRepo = AppDataSource.getRepository(StateOperator);
private stateOperatorUserRepo = AppDataSource.getRepository(StateOperatorUser);
private profileRepo = AppDataSource.getRepository(Profile);
@Post("check-workflow")
public async checkWorkflow(
@Request() req: RequestWithUser,
@Body()
body: {
sysName: string;
posLevelName: string;
posTypeName: string;
profiles: {
profile: string;
operator: string;
order: number;
}[];
},
) {
const workflow = await this.workflowRepo.findOne({
where: {
sysName: body.sysName,
posLevelName: body.posLevelName,
posTypeName: body.posTypeName,
},
relations: ["states"],
});
if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบกระบวนการนี้ได้");
await Promise.all(
body.profiles.map(async (item) => {
const operatoeUser = new StateOperatorUser();
operatoeUser.profile = item.profile;
operatoeUser.operator = item.operator.trim().toLocaleUpperCase();
operatoeUser.order = item.order;
operatoeUser.workflowId = workflow.id;
operatoeUser.createdUserId = req.user.sub;
operatoeUser.createdFullName = req.user.name;
operatoeUser.createdAt = new Date();
operatoeUser.lastUpdateUserId = req.user.sub;
operatoeUser.lastUpdateFullName = req.user.name;
operatoeUser.lastUpdatedAt = new Date();
await this.stateOperatorUserRepo.save(operatoeUser);
}),
);
return new HttpSuccess({
workflowId: workflow.id,
stateId: workflow.states.sort((a, b) => a.order - b.order)[0].id,
// stateName: workflow.states.sort((a, b) => a.order - b.order)[0].name,
// stateType: workflow.states.sort((a, b) => a.order - b.order)[0].type,
});
}
@Post("check-iscan")
public async checkIsCan(
@Request() req: RequestWithUser,
@Body()
body: {
workflowId: string;
stateId: string;
profile: string;
action: string;
},
) {
const stateOperatorUser = await this.stateOperatorUserRepo.findOne({
where: {
profile: body.profile,
workflowId: body.workflowId,
},
});
if (!stateOperatorUser)
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้");
const operator = await this.stateOperatorRepo.findOne({
where: {
operator: stateOperatorUser.operator,
state: { id: body.stateId, workflow: { id: body.workflowId } },
},
});
if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
let isCan = false;
switch (body.action.trim().toLocaleUpperCase()) {
case "VIEW":
isCan = operator.canView;
case "UPDATE":
isCan = operator.canUpdate;
case "DELETE":
isCan = operator.canDelete;
case "CANCEL":
isCan = operator.canCancel;
case "OPERATE":
isCan = operator.canOperate;
case "CHANGESTATE":
isCan = operator.canChangeState;
case "COMMENT":
isCan = operator.canComment;
case "SIGN":
isCan = operator.canSign;
default:
isCan = false;
}
if (isCan == false) {
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการได้");
} else {
return new HttpSuccess();
}
}
@Post("check-iscan-all")
public async checkIsCanAll(
@Request() req: RequestWithUser,
@Body()
body: {
workflowId: string;
stateId: string;
},
) {
const profile = await this.profileRepo.findOne({
where: {
keycloak: req.user.sub,
},
});
if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
const stateOperatorUser = await this.stateOperatorUserRepo.findOne({
where: {
profile: profile.id,
workflowId: body.workflowId,
},
});
if (!stateOperatorUser)
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้");
const operator = await this.stateOperatorRepo.findOne({
where: {
operator: stateOperatorUser.operator,
state: { id: body.stateId, workflow: { id: body.workflowId } },
},
});
if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
return new HttpSuccess(operator);
}
@Post("state-next")
public async stateNext(
@Request() req: RequestWithUser,
@Body()
body: {
stateId: string;
},
) {
const state = await this.stateRepo.findOne({
where: {
id: body.stateId,
},
relations: ["stateOperators", "workflow", "workflow.stateOperatorUsers"],
});
if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
const _state = await this.stateRepo.findOne({
where: {
order: state.order + 1,
workflowId: state.workflowId,
},
relations: ["stateOperators"],
});
//noti
let profileNow = state.workflow.stateOperatorUsers
.filter((x) => state.stateOperators.map((s) => s.operator).includes(x.operator))
.map((x) => x.profile);
await new CallAPI()
.PostData(req, "/placement/noti/profiles", {
subject: `รายการถูกส่ง`,
body: `รายการถูกส่ง`,
receiverUserId: profileNow,
payload: "", //แนบไฟล์
isSendMail: true,
isSendInbox: true,
isSendNotification: true,
})
.catch((error) => {
console.error("Error calling API:", error);
});
if (_state != null) {
let profileNext = state.workflow.stateOperatorUsers
.filter((x) => _state.stateOperators.map((s) => s.operator).includes(x.operator))
.map((x) => x.profile);
await new CallAPI()
.PostData(req, "/placement/noti/profiles", {
subject: `ได้รับรายการ`,
body: `ได้รับรายการ`,
receiverUserId: profileNext,
payload: "", //แนบไฟล์
isSendMail: true,
isSendInbox: true,
isSendNotification: true,
})
.catch((error) => {
console.error("Error calling API:", error);
});
}
return new HttpSuccess({
stateId: _state?.id || null,
stateName: _state?.name || null,
stateType: _state?.type || null,
});
}
@Post("state-back")
public async stateBack(
@Request() req: RequestWithUser,
@Body()
body: {
stateId: string;
},
) {
const state = await this.stateRepo.findOne({
where: {
id: body.stateId,
},
});
if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
const _state = await this.stateRepo.findOne({
where: {
order: state.order - 1,
workflowId: state.workflowId,
},
});
return new HttpSuccess({
stateId: _state?.id || null,
stateName: _state?.name || null,
stateType: _state?.type || null,
});
}
}

View file

@ -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: "สถานะบัญชีแนบท้าย",

View file

@ -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 {

46
src/entities/MetaState.ts Normal file
View file

@ -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[];
}

View file

@ -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;
}

View file

@ -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[];
}

View file

@ -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 {

View file

@ -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 {

45
src/entities/State.ts Normal file
View file

@ -0,0 +1,45 @@
import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm";
import { EntityBase } from "./base/Base";
import { StateOperator } from "./StateOperator";
import { Workflow } from "./Workflow";
@Entity("state")
export class State extends EntityBase {
@Column({
nullable: true,
comment: "ชื่อประเภทขั้นตอน",
length: 255,
default: null,
})
name: string;
@Column({
nullable: true,
comment: "ประเภทขั้นตอน",
length: 255,
default: null,
})
type: string;
@Column({
nullable: true,
comment: "ลำดับ",
default: null,
})
order: number;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง workflow",
default: null,
})
workflowId: string;
@ManyToOne(() => Workflow, (workflow) => workflow.states)
@JoinColumn({ name: "workflowId" })
workflow: Workflow;
@OneToMany(() => StateOperator, (stateOperator) => stateOperator.state)
stateOperators: StateOperator[];
}

View file

@ -0,0 +1,75 @@
import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm";
import { EntityBase } from "./base/Base";
import { State } from "./State";
import { StateOperatorUser } from "./StateOperatorUser";
@Entity("stateOperator")
export class StateOperator extends EntityBase {
@Column({
nullable: true,
comment: "ผู้ดำเนินการ",
length: 255,
default: null,
})
operator: string;
@Column({
comment: "ดูเอกสาร",
default: false,
})
canView: boolean;
@Column({
comment: "แก้ไขเอกสาร",
default: false,
})
canUpdate: boolean;
@Column({
comment: "ลบเอกสาร",
default: false,
})
canDelete: boolean;
@Column({
comment: "ยกเลิกเอกสาร",
default: false,
})
canCancel: boolean;
@Column({
comment: "ดำเนินการเอกสาร",
default: false,
})
canOperate: boolean;
@Column({
comment: "เปลี่ยนสถานะเอกสาร",
default: false,
})
canChangeState: boolean;
@Column({
comment: "แสดงความเห็นเอกสาร",
default: false,
})
canComment: boolean;
@Column({
comment: "ลงนามอนุมัติ",
default: false,
})
canSign: boolean;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง state",
default: null,
})
stateId: string;
@ManyToOne(() => State, (state) => state.stateOperators)
@JoinColumn({ name: "stateId" })
state: State;
}

View file

@ -0,0 +1,50 @@
import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from "typeorm";
import { EntityBase } from "./base/Base";
import { StateOperator } from "./StateOperator";
import { Workflow } from "./Workflow";
@Entity("stateOperatorUser")
export class StateOperatorUser extends EntityBase {
@Column({
nullable: true,
comment: "ผู้ดำเนินการ",
length: 255,
default: null,
})
operator: string;
@Column({
nullable: true,
comment: "",
length: 255,
default: null,
})
profile: string;
@Column({
nullable: true,
comment: "ลำดับ",
default: null,
})
order: number;
@Column({
nullable: true,
comment: "ผู้ดำเนินการ",
length: 255,
default: null,
})
refId: string;
@Column({
nullable: true,
length: 40,
comment: "คีย์นอก(FK)ของตาราง workflow",
default: null,
})
workflowId: string;
@ManyToOne(() => Workflow, (workflow) => workflow.stateOperatorUsers)
@JoinColumn({ name: "workflowId" })
workflow: Workflow;
}

53
src/entities/Workflow.ts Normal file
View file

@ -0,0 +1,53 @@
import { Entity, Column, OneToMany } from "typeorm";
import { EntityBase } from "./base/Base";
import { State } from "./State";
import { StateOperatorUser } from "./StateOperatorUser";
@Entity("workflow")
export class Workflow extends EntityBase {
@Column({
nullable: true,
comment: "ชื่อ flow",
length: 255,
default: null,
})
name: string;
@Column({
nullable: true,
comment: "ระบบ", //PLACEMENT
length: 255,
default: null,
})
category: string;
@OneToMany(() => State, (state) => state.workflow)
states: State[];
@Column({
nullable: true,
comment: "ชื่อระบบ", //สอบคัดเลือก
length: 100,
default: null,
})
sysName: string;
@Column({
nullable: true,
comment: "ชื่อระดับ",
length: 100,
default: null,
})
posLevelName: string;
@Column({
nullable: true,
comment: "ชื่อประเภท",
length: 100,
default: null,
})
posTypeName: string;
@OneToMany(() => StateOperatorUser, (stateOperatorUser) => stateOperatorUser.workflow)
stateOperatorUsers: StateOperatorUser[];
}

View file

@ -76,7 +76,6 @@ class CallAPI {
response: JSON.stringify(error),
},
});
console.log(error);
throw error;
}
}

View file

@ -53,7 +53,6 @@ class CheckAuth {
return await new CallAPI()
.GetData(req, `/org/permission/org/${system}/${action}`)
.then(async (x) => {
console.log(x);
let privilege = x.privilege;
// if (action.trim().toLocaleUpperCase() == "CREATE")
// privilege = await this.PermissionCreate(req, system);
@ -84,7 +83,16 @@ class CheckAuth {
} else if (x.orgChild4Id == null) {
node = 3;
}
if (privilege == "ROOT") {
if (privilege == "OWNER") {
data = {
root: null,
child1: null,
child2: null,
child3: null,
child4: null,
privilege: "OWNER",
};
} else if (privilege == "ROOT") {
data = {
root: [x.orgRootId],
child1: null,
@ -112,15 +120,6 @@ class CheckAuth {
privilege: "NORMAL",
};
} else if (privilege == "SPECIFIC") {
} else if (privilege == "OWNER") {
data = {
root: null,
child1: null,
child2: null,
child3: null,
child4: null,
privilege: "OWNER",
};
}
return data;

View file

@ -75,7 +75,7 @@ export async function createUser(username: string, password: string, opts?: Reco
method: "POST",
body: JSON.stringify({
enabled: true,
credentials: [{ type: "password", value: password }],
credentials: [{ type: "password", value: password ,temporary: false,}],
username,
...opts,
}),
@ -168,6 +168,69 @@ export async function getUserCount(first = "", max = "", search = "") {
return await res.json();
}
/**
* Get keycloak user list
*
* Client must have permission to manage realm's user
*
* @returns user list if success, false otherwise.
*/
export async function getUserListOrg(first = "", max = "", search = "", userIds: string[] = []) {
const userIdsParam = userIds.join(",");
const res = await fetch(
// `${KC_URL}/admin/realms/${KC_REALM}/users`.concat(!!search ? `?search=${search}` : ""),
`${KC_URL}/admin/realms/${KC_REALM}/users?first=${first || "0"}&max=${max || "-1"}${search ? `&search=${search}` : ""}${userIdsParam ? `&id=${userIdsParam}` : ""}`,
{
// prettier-ignore
headers: {
"authorization": `Bearer ${await getToken()}`,
"content-type": `application/json`,
},
},
).catch((e) => console.log("Keycloak Error: ", e));
if (!res) return false;
if (!res.ok) {
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
}
return ((await res.json()) as any[]).map((v: Record<string, string>) => ({
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
*

View file

@ -0,0 +1,28 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddTableWorkflow1728399911271 implements MigrationInterface {
name = 'AddTableWorkflow1728399911271'
public async up(queryRunner: QueryRunner): Promise<void> {
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<void> {
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\``);
}
}

View file

@ -0,0 +1,30 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddTableWorkflow11728442861469 implements MigrationInterface {
name = 'AddTableWorkflow11728442861469'
public async up(queryRunner: QueryRunner): Promise<void> {
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<void> {
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`);
}
}

View file

@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddTableWorkflow21728456793035 implements MigrationInterface {
name = 'AddTableWorkflow21728456793035'
public async up(queryRunner: QueryRunner): Promise<void> {
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<void> {
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 'ชื่อระบบ'`);
}
}

View file

@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddTableWorkflow31728465477520 implements MigrationInterface {
name = 'AddTableWorkflow31728465477520'
public async up(queryRunner: QueryRunner): Promise<void> {
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<void> {
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`);
}
}