cronjob ส่งข้อมูลผู้เกษียณไปให้ระบบพ้นราชการ #2330
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m17s
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m17s
This commit is contained in:
parent
e6c3e80a3d
commit
93d4857ea1
4 changed files with 175 additions and 12 deletions
12
src/app.ts
12
src/app.ts
|
|
@ -19,6 +19,7 @@ import { ScriptProfileOrgController } from "./controllers/ScriptProfileOrgContro
|
|||
import { DateSerializer } from "./interfaces/date-serializer";
|
||||
|
||||
import { initWebSocket } from "./services/webSocket";
|
||||
import { RetirementService } from "./services/RetirementService";
|
||||
|
||||
async function main() {
|
||||
await AppDataSource.initialize();
|
||||
|
|
@ -114,6 +115,17 @@ async function main() {
|
|||
}
|
||||
});
|
||||
|
||||
// Cron job for posting retirement data to Exprofile - every day at 04:30:00 on the 1st of October
|
||||
const cronTime_PostRetire = "0 30 4 1 10 *";
|
||||
cron.schedule(cronTime_PostRetire, async () => {
|
||||
try {
|
||||
const retirementService = new RetirementService();
|
||||
await retirementService.cronjobPostRetireToExprofile();
|
||||
} catch (error) {
|
||||
console.error("[Cronjob] Error executing cronjobPostRetireToExprofile:", error);
|
||||
}
|
||||
});
|
||||
|
||||
// app.listen(APP_PORT, APP_HOST, () => console.log(`Listening on: http://localhost:${APP_PORT}`));
|
||||
const server = app.listen(
|
||||
APP_PORT,
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ import { PostRetireToExprofile } from "./ExRetirementController";
|
|||
import { LeaveType } from "../entities/LeaveType";
|
||||
import { KeycloakAttributeService } from "../services/KeycloakAttributeService";
|
||||
import { reOrderCommandRecivesAndDelete } from "../services/CommandService";
|
||||
import { RetirementService } from "../services/RetirementService";
|
||||
@Route("api/v1/org/command")
|
||||
@Tags("Command")
|
||||
@Security("bearerAuth")
|
||||
|
|
@ -1608,8 +1609,7 @@ export class CommandController extends Controller {
|
|||
|
||||
return new HttpSuccess();
|
||||
}
|
||||
// @Get("XXX")
|
||||
async cronjobUpdateRetirementStatus(/*@Request() request: RequestWithUser*/) {
|
||||
async cronjobUpdateRetirementStatus() {
|
||||
const adminToken = (await getToken()) ?? "";
|
||||
const today = new Date();
|
||||
today.setUTCHours(0, 0, 0, 0);
|
||||
|
|
@ -1887,6 +1887,21 @@ export class CommandController extends Controller {
|
|||
return new HttpSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* API ทดสอบ cronjobPostRetireToExprofile
|
||||
* @summary ทดสอบส่งข้อมูลผู้เกษียณไปยังระบบพ้นราชการ (Exprofile)
|
||||
*/
|
||||
@Get("cronjob/cronjobPostRetireToExprofile")
|
||||
async runCronjobPostRetireToExprofile() {
|
||||
try {
|
||||
const retirementService = new RetirementService();
|
||||
const result = await retirementService.cronjobPostRetireToExprofile();
|
||||
return new HttpSuccess(result);
|
||||
} catch (error: any) {
|
||||
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, error.message || "เกิดข้อผิดพลาด");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* API รายละเอียดรายการคำสั่ง tab4 คำสั่ง
|
||||
*
|
||||
|
|
|
|||
|
|
@ -237,16 +237,19 @@ export async function PostRetireToExprofile(
|
|||
continue;
|
||||
}
|
||||
|
||||
addLogSequence(request, {
|
||||
action: "request",
|
||||
status: "error",
|
||||
description: "unconnected to exprofile api",
|
||||
request: {
|
||||
method: "POST",
|
||||
url: API_URL_BANGKOK + "/importData",
|
||||
response: JSON.stringify(error),
|
||||
},
|
||||
});
|
||||
// เช็ค request ก่อนเรียก addLogSequence (สำหรับ cronjob ที่ส่ง null)
|
||||
if (request) {
|
||||
addLogSequence(request, {
|
||||
action: "request",
|
||||
status: "error",
|
||||
description: "unconnected to exprofile api",
|
||||
request: {
|
||||
method: "POST",
|
||||
url: API_URL_BANGKOK + "/importData",
|
||||
response: JSON.stringify(error),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถติดต่อ API ได้");
|
||||
}
|
||||
|
|
|
|||
133
src/services/RetirementService.ts
Normal file
133
src/services/RetirementService.ts
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import { AppDataSource } from "../database/data-source";
|
||||
import { Profile } from "../entities/Profile";
|
||||
import { PostRetireToExprofile } from "../controllers/ExRetirementController";
|
||||
import { Between, MoreThanOrEqual } from "typeorm";
|
||||
|
||||
const BATCH_SIZE = 100;
|
||||
const CONCURRENT_PER_BATCH = 10; // ส่ง parallel ทีละ 10 คนในแต่ละ batch
|
||||
|
||||
export class RetirementService {
|
||||
private profileRepository = AppDataSource.getRepository(Profile);
|
||||
|
||||
/**
|
||||
* Cronjob สำหรับส่งข้อมูลผู้เกษียณไปยังระบบพ้นราชการ (Exprofile)
|
||||
* ทำงานเวลา 04:30:00 ของทุกวันที่ 1 ตุลาคม
|
||||
*
|
||||
* รายละเอียด:
|
||||
* - Query profiles ที่ leaveDate = วันที่ 1 ตุลาคมของปีนั้น และ leaveType = "RETIRE"
|
||||
* - Batch ทีละ 100 records
|
||||
* - Concurrent ทีละ 10 คน (parallel) ในแต่ละ batch
|
||||
* - ถ้า fail ให้ log error แล้วทำคนต่อไป
|
||||
*/
|
||||
async cronjobPostRetireToExprofile(): Promise<{
|
||||
success: number;
|
||||
failed: number;
|
||||
failedProfiles: Array<{ id: string; name: string; error: string }>;
|
||||
}> {
|
||||
const result = {
|
||||
success: 0,
|
||||
failed: 0,
|
||||
failedProfiles: [] as Array<{ id: string; name: string; error: string }>,
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
// หาวันที่ 1 ตุลาคมของปีปัจจุบัน
|
||||
const now = new Date();
|
||||
const currentYear = now.getFullYear();
|
||||
|
||||
// สร้างวันที่ 1 ตุลาคมของปีปัจจุบัน (เวลา 00:00:00)
|
||||
const startDate = new Date(currentYear, 9, 1, 0, 0, 0); // Month 9 = October (0-indexed)
|
||||
const endDate = new Date(currentYear, 9, 1, 23, 59, 59);
|
||||
|
||||
// Query profiles ที่ leaveDate อยู่ในวันที่ 1 ตุลาคม และ leaveType = "RETIRE"
|
||||
const profiles = await this.profileRepository.find({
|
||||
where: [
|
||||
{ leaveDate: Between(startDate, endDate), leaveType: "RETIRE" as any },
|
||||
{ leaveDate: MoreThanOrEqual(startDate), leaveType: "RETIRE" as any },
|
||||
],
|
||||
relations: ["posLevel", "posType"],
|
||||
});
|
||||
|
||||
// Filter เอาเฉพาะวันที่ 1 ตุลาคมเท่านั้น
|
||||
const filteredProfiles = profiles.filter(p => {
|
||||
if (!p.leaveDate) return false;
|
||||
const leaveDate = new Date(p.leaveDate);
|
||||
return (
|
||||
leaveDate.getFullYear() === currentYear &&
|
||||
leaveDate.getMonth() === 9 && // October
|
||||
leaveDate.getDate() === 1
|
||||
);
|
||||
});
|
||||
|
||||
if (filteredProfiles.length === 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// แบ่ง batch ทีละ 100 records
|
||||
for (let i = 0; i < filteredProfiles.length; i += BATCH_SIZE) {
|
||||
const batch = filteredProfiles.slice(i, i + BATCH_SIZE);
|
||||
|
||||
// แบ่งเป็น chunk เล็กๆ ทีละ CONCURRENT_PER_BATCH เพื่อส่ง parallel
|
||||
for (let j = 0; j < batch.length; j += CONCURRENT_PER_BATCH) {
|
||||
const chunk = batch.slice(j, j + CONCURRENT_PER_BATCH);
|
||||
|
||||
// ส่ง parallel ในแต่ละ chunk
|
||||
await Promise.all(
|
||||
chunk.map(async (profile) => {
|
||||
try {
|
||||
await this.postSingleProfileToExprofile(profile);
|
||||
result.success++;
|
||||
} catch (error: any) {
|
||||
result.failed++;
|
||||
const errorInfo = {
|
||||
id: profile.id,
|
||||
name: `${profile.prefix}${profile.firstName} ${profile.lastName}`,
|
||||
error: error.message || String(error),
|
||||
};
|
||||
result.failedProfiles.push(errorInfo);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ส่งข้อมูล profile ไปยัง Exprofile
|
||||
*/
|
||||
private async postSingleProfileToExprofile(profile: Profile): Promise<void> {
|
||||
if (!profile.leaveDate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!profile.citizenId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const retireYear = profile.leaveDate.getFullYear();
|
||||
const retireDate = new Date(profile.leaveDate);
|
||||
|
||||
// ส่งไปยัง Exprofile
|
||||
PostRetireToExprofile(
|
||||
null,
|
||||
profile.citizenId,
|
||||
profile.prefix || "",
|
||||
profile.firstName || "",
|
||||
profile.lastName || "",
|
||||
retireYear.toString(),
|
||||
profile.position || "",
|
||||
profile.posType?.posTypeName || "",
|
||||
profile.posLevel?.posLevelName || "",
|
||||
retireDate,
|
||||
profile.org || "",
|
||||
profile.leaveReason || "เกษียณอายุราชการ"
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue