576 lines
20 KiB
TypeScript
576 lines
20 KiB
TypeScript
import {
|
||
Controller,
|
||
Post,
|
||
Put,
|
||
Patch,
|
||
Delete,
|
||
Route,
|
||
Security,
|
||
Tags,
|
||
Body,
|
||
Path,
|
||
Request,
|
||
Response,
|
||
Get,
|
||
Query,
|
||
} from "tsoa";
|
||
import { AppDataSource } from "../database/data-source";
|
||
import HttpStatus from "../interfaces/http-status";
|
||
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, IsNull, Not, Any } from "typeorm";
|
||
import { CommandType } from "../entities/CommandType";
|
||
import { Profile, CreateProfileAllFields } from "../entities/Profile";
|
||
import { RequestWithUser, RequestWithUserWebService } from "../middlewares/user";
|
||
import { OrgRevision } from "../entities/OrgRevision";
|
||
import { ProfileEmployee } from "../entities/ProfileEmployee";
|
||
import { PosMaster } from "../entities/PosMaster";
|
||
import permission from "../interfaces/permission";
|
||
import { viewCurrentTenureOfficer } from "../entities/view/viewCurrentTenureOfficer";
|
||
import { CommandController } from "./CommandController";
|
||
import Extension from "../interfaces/extension";
|
||
import { viewRegistryOfficer } from "../entities/view/viewRegistryOfficer";
|
||
import { viewRegistryEmployee } from "../entities/view/viewRegistryEmployee";
|
||
import { Registry } from "../entities/Registry";
|
||
import { RegistryEmployee } from "../entities/RegistryEmployee";
|
||
import { TenurePositionOfficer } from "../entities/TenurePositionOfficer";
|
||
import { PosMasterAssign, PosMasterAssignDTO } from "../entities/PosMasterAssign";
|
||
import { PermissionProfile } from "../entities/PermissionProfile";
|
||
import { OrgRoot } from "../entities/OrgRoot";
|
||
import { MetaWorkflow } from "../entities/MetaWorkflow";
|
||
import { MetaState } from "../entities/MetaState";
|
||
import { MetaStateOperator } from "../entities/MetaStateOperator";
|
||
import { Workflow } from "../entities/Workflow";
|
||
import { State } from "../entities/State";
|
||
import { StateOperator } from "../entities/StateOperator";
|
||
import { StateOperatorUser } from "../entities/StateOperatorUser";
|
||
import {
|
||
commandTypePath,
|
||
calculateGovAge,
|
||
calculateAge,
|
||
calculateRetireDate,
|
||
calculateRetireLaw,
|
||
removeProfileInOrganize,
|
||
setLogDataDiff,
|
||
} from "../interfaces/utils";
|
||
import CallAPI from "../interfaces/call-api";
|
||
import { PostRetireToExprofile } from "./ExRetirementController"
|
||
import { Position } from "../entities/Position";
|
||
import { PosLevel } from "../entities/PosLevel";
|
||
import { TenureLevelOfficer } from "../entities/TenureLevelOfficer";
|
||
import { TenurePositionEmployee } from "../entities/TenurePositionEmployee";
|
||
import { TenureLevelEmployee } from "../entities/TenureLevelEmployee";
|
||
import { TenurePositionExecutiveOfficer } from "../entities/TenurePositionExecutiveOfficer";
|
||
|
||
@Route("api/v1/org/DevTest")
|
||
@Tags("DevTest")
|
||
@Security("bearerAuth")
|
||
@Response(
|
||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
|
||
)
|
||
export class DevTestController extends Controller {
|
||
private commandRepository = AppDataSource.getRepository(Command);
|
||
private commandTypeRepository = AppDataSource.getRepository(CommandType);
|
||
private orgRevisionRepo = AppDataSource.getRepository(OrgRevision);
|
||
private orgRootRepo = AppDataSource.getRepository(OrgRoot);
|
||
private posMasterRepo = AppDataSource.getRepository(PosMaster);
|
||
private profileRepo = AppDataSource.getRepository(Profile);
|
||
private profileEmpRepo = AppDataSource.getRepository(ProfileEmployee);
|
||
private registryRepo = AppDataSource.getRepository(Registry);
|
||
private registryEmployeeRepo = AppDataSource.getRepository(RegistryEmployee);
|
||
private posMasterAssignRepository = AppDataSource.getRepository(PosMasterAssign);
|
||
private permissionProfilesRepository = AppDataSource.getRepository(PermissionProfile);
|
||
private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee);
|
||
private metaWorkflowRepo = AppDataSource.getRepository(MetaWorkflow);
|
||
private metaStateRepo = AppDataSource.getRepository(MetaState);
|
||
private metaStateOperatorRepo = AppDataSource.getRepository(MetaStateOperator);
|
||
private workflowRepo = AppDataSource.getRepository(Workflow);
|
||
private stateRepo = AppDataSource.getRepository(State);
|
||
private stateOperatorRepo = AppDataSource.getRepository(StateOperator);
|
||
private stateOperatorUserRepo = AppDataSource.getRepository(StateOperatorUser);
|
||
private positionRepository = AppDataSource.getRepository(Position);
|
||
private positionOfficerRepo = AppDataSource.getRepository(TenurePositionOfficer);
|
||
private positionEmployeeRepo = AppDataSource.getRepository(TenurePositionEmployee);
|
||
private levelOfficerRepo = AppDataSource.getRepository(TenureLevelOfficer);
|
||
private levelEmployeeRepo = AppDataSource.getRepository(TenureLevelEmployee);
|
||
private positionExecutiveOfficerRepo = AppDataSource.getRepository(
|
||
TenurePositionExecutiveOfficer,
|
||
);
|
||
|
||
@Patch("tick-officer-registry")
|
||
public async calculateOfficerPosition(
|
||
@Request() req: RequestWithUser,
|
||
@Body()
|
||
body: {
|
||
profileIds: string[];
|
||
},
|
||
) {
|
||
|
||
console.log("1.")
|
||
/**
|
||
* ===============================
|
||
* PREPARE DATA
|
||
* ===============================
|
||
*/
|
||
const profile = await this.profileRepo.find({
|
||
where: { id: In(body.profileIds) },
|
||
relations: {
|
||
posLevel: true,
|
||
posType: true,
|
||
},
|
||
});
|
||
|
||
if (!profile.length) return;
|
||
|
||
const [{ today }] = await AppDataSource.query(
|
||
"SELECT CURRENT_DATE() as today",
|
||
);
|
||
|
||
const orgRevision = await this.orgRevisionRepo.findOne({
|
||
select: ["id"],
|
||
where: {
|
||
orgRevisionIsDraft: false,
|
||
orgRevisionIsCurrent: true,
|
||
},
|
||
});
|
||
|
||
/**
|
||
* ===============================
|
||
* TRANSACTION
|
||
* ===============================
|
||
*/
|
||
const queryRunner = AppDataSource.createQueryRunner();
|
||
await queryRunner.connect();
|
||
await queryRunner.startTransaction();
|
||
console.log("2.")
|
||
try {
|
||
/**
|
||
* ===============================
|
||
* RESULT BUFFERS (SAVE ARRAY)
|
||
* ===============================
|
||
*/
|
||
const positionOfficerBulk: any[] = [];
|
||
const levelOfficerBulk: any[] = [];
|
||
const executiveOfficerBulk: any[] = [];
|
||
console.log("3.")
|
||
/**
|
||
* ===============================
|
||
* MAIN LOOP (SINGLE LOOP)
|
||
* ===============================
|
||
*/
|
||
for (const x of profile) {
|
||
const currentDate =
|
||
x.isLeave && x.leaveDate
|
||
? Extension.toDateOnlyString(x.leaveDate)
|
||
: today;
|
||
/**
|
||
* ====================================
|
||
* PARALLEL STORED PROCEDURES
|
||
* ====================================
|
||
*/
|
||
const [
|
||
positionResult,
|
||
levelResult,
|
||
executiveResult,
|
||
] = await Promise.all([
|
||
AppDataSource.query("CALL GetProfileSalaryPosition(?, ?)", [
|
||
x.id,
|
||
currentDate,
|
||
]),
|
||
AppDataSource.query("CALL GetProfileSalaryLevel(?, ?)", [
|
||
x.id,
|
||
currentDate,
|
||
]),
|
||
AppDataSource.query("CALL GetProfileSalaryExecutive(?, ?)", [
|
||
x.id,
|
||
currentDate,
|
||
]),
|
||
]);
|
||
console.log("4.",x.id)
|
||
/**
|
||
* ====================================
|
||
* POSITION
|
||
* ====================================
|
||
*/
|
||
const posRows = positionResult?.[0] ?? [];
|
||
const posMap =
|
||
posRows.length > 1
|
||
? posRows.slice(1).map((r: any, i: number) => ({
|
||
days_diff: Number(r.days_diff) || 0,
|
||
positionName: posRows[i]?.positionName,
|
||
}))
|
||
: [];
|
||
|
||
const posCal = posMap
|
||
.filter((p:any) => p.positionName === x.position)
|
||
.reduce(
|
||
(a:any, c:any) => ({
|
||
days_diff: a.days_diff + c.days_diff,
|
||
positionName: c.positionName,
|
||
}),
|
||
{ days_diff: 0, positionName: null },
|
||
);
|
||
|
||
positionOfficerBulk.push({
|
||
profileId: x.id,
|
||
positionName: posCal.positionName,
|
||
days_diff: posCal.days_diff,
|
||
Years: Math.floor(posCal.days_diff / 365.2524),
|
||
Months: Math.floor((posCal.days_diff / 30.4375) % 12),
|
||
Days: Math.floor(posCal.days_diff % 30.4375),
|
||
});
|
||
console.log("5.",x.id)
|
||
/**
|
||
* ====================================
|
||
* 2️⃣ POSITION LEVEL
|
||
* ====================================
|
||
*/
|
||
const lvlRows = levelResult?.[0] ?? [];
|
||
const lvlMap =
|
||
lvlRows.length > 1
|
||
? lvlRows.slice(1).map((r: any, i: number) => ({
|
||
days_diff: Number(r.days_diff) || 0,
|
||
positionType: lvlRows[i]?.positionType,
|
||
positionLevel: lvlRows[i]?.positionLevel,
|
||
positionCee: lvlRows[i]?.positionCee,
|
||
}))
|
||
: [];
|
||
|
||
const lvlCal = lvlMap
|
||
.filter(
|
||
(l:any) =>
|
||
l.positionLevel === x.posLevel?.posLevelName &&
|
||
l.positionType === x.posType?.posTypeName,
|
||
)
|
||
.reduce(
|
||
(a:any, c:any) => ({
|
||
days_diff: a.days_diff + c.days_diff,
|
||
positionType: c.positionType,
|
||
positionLevel: c.positionLevel,
|
||
positionCee: c.positionCee,
|
||
}),
|
||
{
|
||
days_diff: 0,
|
||
positionType: null,
|
||
positionLevel: null,
|
||
positionCee: null,
|
||
},
|
||
);
|
||
|
||
levelOfficerBulk.push({
|
||
profileId: x.id,
|
||
positionType: lvlCal.positionType,
|
||
positionLevel: lvlCal.positionLevel,
|
||
positionCee: lvlCal.positionCee,
|
||
days_diff: lvlCal.days_diff,
|
||
Years: x.posLevel ? (lvlCal.days_diff / 365.2524).toFixed(4) : 0,
|
||
Months: x.posLevel ? ((lvlCal.days_diff / 30.4375) % 12).toFixed(4) : 0,
|
||
Days: x.posLevel ? (lvlCal.days_diff % 30.4375).toFixed(4) : 0,
|
||
});
|
||
console.log("6.",x.id)
|
||
/**
|
||
* ====================================
|
||
* 3️⃣ POSITION EXECUTIVE
|
||
* ====================================
|
||
*/
|
||
const exeRows = executiveResult?.[0] ?? [];
|
||
const exeMap =
|
||
exeRows.length > 1
|
||
? exeRows.slice(1).map((r: any, i: number) => ({
|
||
days_diff: Number(r.days_diff) || 0,
|
||
positionExecutive: exeRows[i]?.positionExecutive,
|
||
}))
|
||
: [];
|
||
|
||
const position = await this.positionRepository.findOne({
|
||
where: {
|
||
positionIsSelected: true,
|
||
posMaster: {
|
||
orgRevisionId: orgRevision?.id,
|
||
current_holderId: x.id,
|
||
},
|
||
},
|
||
order: { createdAt: "DESC" },
|
||
relations: {
|
||
posExecutive: true,
|
||
},
|
||
});
|
||
|
||
const exeName = position?.posExecutive?.posExecutiveName;
|
||
|
||
const exeCal = exeMap
|
||
.filter((e:any) => exeName && e.positionExecutive === exeName)
|
||
.reduce(
|
||
(a:any, c:any) => ({
|
||
days_diff: a.days_diff + c.days_diff,
|
||
positionExecutive: c.positionExecutive,
|
||
}),
|
||
{ days_diff: 0, positionExecutive: null },
|
||
);
|
||
|
||
executiveOfficerBulk.push({
|
||
profileId: x.id,
|
||
positionExecutiveName: exeCal.positionExecutive,
|
||
days_diff: exeCal.days_diff,
|
||
Years: (exeCal.days_diff / 365.2524).toFixed(4),
|
||
Months: ((exeCal.days_diff / 30.4375) % 12).toFixed(4),
|
||
Days: (exeCal.days_diff % 30.4375).toFixed(4),
|
||
});
|
||
}
|
||
console.log("7.")
|
||
/**
|
||
* ===============================
|
||
* CLEAR ALL DATA AND SAVE ARRAY (BULK)
|
||
* ===============================
|
||
*/
|
||
await queryRunner.manager
|
||
.createQueryBuilder()
|
||
.delete()
|
||
.from(this.positionOfficerRepo.target)
|
||
.execute();
|
||
|
||
await queryRunner.manager
|
||
.createQueryBuilder()
|
||
.delete()
|
||
.from(this.levelOfficerRepo.target)
|
||
.execute();
|
||
|
||
await queryRunner.manager
|
||
.createQueryBuilder()
|
||
.delete()
|
||
.from(this.positionExecutiveOfficerRepo.target)
|
||
.execute();
|
||
console.log("8.")
|
||
await queryRunner.manager.save(this.positionOfficerRepo.target, positionOfficerBulk);
|
||
await queryRunner.manager.save(this.levelOfficerRepo.target, levelOfficerBulk);
|
||
await queryRunner.manager.save(this.positionExecutiveOfficerRepo.target,executiveOfficerBulk);
|
||
console.log("9.")
|
||
/**
|
||
* ===============================
|
||
* REGISTRY OFFICER (SYNC VIEW)
|
||
* ===============================
|
||
*/
|
||
const allRegis = await queryRunner.manager
|
||
.getRepository(viewRegistryOfficer)
|
||
.createQueryBuilder("registryOfficer")
|
||
.where("registryOfficer.profileId IN (:...profileIds)", {
|
||
profileIds: new Set(profile.map((p) => p.id))
|
||
})
|
||
.getMany();
|
||
|
||
const mapRegistryData = allRegis.map((x) => ({
|
||
...x,
|
||
isProbation: Boolean(x.isProbation),
|
||
isLeave: Boolean(x.isLeave),
|
||
isRetirement: Boolean(x.isRetirement),
|
||
Educations: x.Educations ? JSON.stringify(x.Educations) : "",
|
||
}));
|
||
console.log("10.")
|
||
|
||
await queryRunner.manager
|
||
.createQueryBuilder()
|
||
.delete()
|
||
.from(this.registryRepo.target)
|
||
.execute();
|
||
|
||
if (mapRegistryData.length > 0) {
|
||
await queryRunner.manager.save(this.registryRepo.target, mapRegistryData);
|
||
}
|
||
console.log("11.")
|
||
/**
|
||
* ===============================
|
||
* COMMIT
|
||
* ===============================
|
||
*/
|
||
await queryRunner.commitTransaction();
|
||
} catch (error) {
|
||
await queryRunner.rollbackTransaction();
|
||
throw error;
|
||
} finally {
|
||
await queryRunner.release();
|
||
}
|
||
}
|
||
|
||
@Post("getDNA")
|
||
public async GetData(
|
||
@Request() req: RequestWithUser
|
||
){
|
||
let _data: any = {
|
||
root: null,
|
||
child1: null,
|
||
child2: null,
|
||
child3: null,
|
||
child4: null,
|
||
};
|
||
|
||
_data = await new permission().PermissionOrgList(req, "COMMAND");
|
||
return new HttpSuccess(_data);
|
||
}
|
||
|
||
@Post("calculateGovAge")
|
||
public async calculateGovAge(
|
||
@Request() req: RequestWithUser,
|
||
@Body()
|
||
body: {
|
||
profileId: string;
|
||
},
|
||
){
|
||
return new HttpSuccess(await calculateGovAge(body.profileId, "OFFICER"));
|
||
}
|
||
|
||
/**
|
||
* @summary Test Job กวาดออกคำสั่ง ทำงานทุกๆตี2
|
||
*/
|
||
@Post("cronjobCommand")
|
||
async CronjobCommand() {
|
||
const commandController = new CommandController();
|
||
await commandController.cronjobCommand();
|
||
}
|
||
|
||
/**
|
||
* @summary payload & Endpoint ออกคำสั่ง
|
||
*/
|
||
@Put("path-excec/{id}")
|
||
async Bright(
|
||
@Path() id: string,
|
||
@Request() request: RequestWithUser,
|
||
) {
|
||
const command = await this.commandRepository.findOne({
|
||
where: { id: id },
|
||
relations: ["commandType", "commandRecives", "commandSends", "commandSends.commandSendCCs"],
|
||
});
|
||
if (!command) {
|
||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลคำสั่งนี้");
|
||
}
|
||
const path = commandTypePath(command.commandType.code);
|
||
return new HttpSuccess({
|
||
path: path + "/excecute",
|
||
refIds: command.commandRecives
|
||
.filter((x) => x.refId != null)
|
||
.map((x) => ({
|
||
refId: x.refId,
|
||
commandNo: command.commandNo,
|
||
commandYear: command.commandYear,
|
||
commandId: command.id,
|
||
remark: command.positionDetail,
|
||
amount: x.amount,
|
||
amountSpecial: x.amountSpecial,
|
||
positionSalaryAmount: x.positionSalaryAmount,
|
||
mouthSalaryAmount: x.mouthSalaryAmount,
|
||
commandCode: command.commandType.commandCode,
|
||
commandName: command.commandType.name,
|
||
commandDateAffect: command.commandExcecuteDate,
|
||
commandDateSign: command.commandAffectDate,
|
||
})),
|
||
});
|
||
}
|
||
|
||
/**
|
||
* API รายละเอียดรายการคำสั่ง tab4 แนบท้าย
|
||
* @summary API รายละเอียดรายการคำสั่ง tab4 แนบท้าย
|
||
* @param {string} id Id คำสั่ง
|
||
* @param {string} profileId profileId
|
||
*/
|
||
@Get("tab4/attachment/{id}/{profileId}")
|
||
async GetByIdTab4Attachment(
|
||
@Path() id: string,
|
||
@Path() profileId: string,
|
||
@Request() request: RequestWithUser
|
||
) {
|
||
await new permission().PermissionGet(request, "COMMAND");
|
||
|
||
let profile: Profile | ProfileEmployee | null = null;
|
||
profile = await this.profileRepo.findOne({ where: { id: profileId } });
|
||
if (!profile) {
|
||
profile = await this.profileEmpRepo.findOne({ where: { id: profileId } });
|
||
if (!profile)
|
||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลบุคคลากรนี้");
|
||
}
|
||
|
||
const command = await this.commandRepository.findOne({
|
||
where: { id },
|
||
relations: ["commandType", "commandRecives"],
|
||
});
|
||
if (!command) {
|
||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลคำสั่งนี้");
|
||
}
|
||
|
||
let _command: any = [];
|
||
const path = commandTypePath(command.commandType.code);
|
||
if (path == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบประเภทคำสั่งนี้ในระบบ");
|
||
await new CallAPI()
|
||
.PostData(request, path + "/attachment", {
|
||
refIds: command.commandRecives
|
||
.filter((x) =>
|
||
x.refId != null &&
|
||
x.profileId != null && x.profileId == profileId
|
||
)
|
||
.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,
|
||
CommandExcecuteDate: command.commandExcecuteDate,
|
||
})),
|
||
})
|
||
.then(async (res) => {
|
||
_command = res;
|
||
})
|
||
.catch(() => {});
|
||
|
||
let issue =
|
||
command.isBangkok == "OFFICE"
|
||
? "สำนักปลัดกรุงเทพมหานคร"
|
||
: command.isBangkok == "BANGKOK"
|
||
? "กรุงเทพมหานคร"
|
||
: null;
|
||
if (issue == null) {
|
||
const orgRevisionActive = await this.orgRevisionRepo.findOne({
|
||
where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
|
||
relations: ["posMasters", "posMasters.orgRoot"],
|
||
});
|
||
if (orgRevisionActive != null) {
|
||
const profile = await this.profileRepo.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,
|
||
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)),
|
||
},
|
||
});
|
||
}
|
||
|
||
}
|