GWM : Automation for Survey and iip calculation
This commit is contained in:
parent
79d71002fa
commit
35c51fc3c3
243
app/services/scheduler.service.js
Normal file
243
app/services/scheduler.service.js
Normal file
@ -0,0 +1,243 @@
|
||||
const cron = require('node-cron');
|
||||
const mysql = require('mysql2/promise');
|
||||
const SubmissionAutoFillService = require('./auto_fill_missing_quarterly_submissions_service'); // Adjust path
|
||||
const IPICalculationService = require('./ipi_calculation_service');
|
||||
|
||||
// Database configuration
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
dialect: process.env.DB_DIALECT || 'mysql',
|
||||
pool: {
|
||||
max: 5,
|
||||
min: 0,
|
||||
acquire: 30000,
|
||||
idle: 10000
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AutomatedSchedulerService {
|
||||
|
||||
|
||||
constructor() {
|
||||
this.isRunning = false;
|
||||
this.pool = mysql.createPool(dbConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the latest entry from quarterly_windows_configuration_master table
|
||||
*/
|
||||
async getLatestQuarterlyWindow() {
|
||||
const connection = await this.pool.getConnection();
|
||||
try {
|
||||
const query = `
|
||||
SELECT
|
||||
year,
|
||||
quarter,
|
||||
end_date,
|
||||
start_date
|
||||
FROM quarterly_windows_configuration_master
|
||||
ORDER BY year DESC,
|
||||
CASE quarter
|
||||
WHEN 'Q1' THEN 1
|
||||
WHEN 'Q2' THEN 2
|
||||
WHEN 'Q3' THEN 3
|
||||
WHEN 'Q4' THEN 4
|
||||
END DESC
|
||||
LIMIT 1
|
||||
`;
|
||||
|
||||
// const query = `
|
||||
// SELECT
|
||||
// year,
|
||||
// quarter,
|
||||
// end_date,
|
||||
// start_date
|
||||
// FROM quarterly_windows_configuration_master
|
||||
// ORDER BY id DESC
|
||||
// LIMIT 1
|
||||
// `;
|
||||
|
||||
const [rows] = await connection.query(query);
|
||||
return rows[0] || null;
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute survey auto submit logic
|
||||
*/
|
||||
async executeSurveyAutoSubmit(year, quarter) {
|
||||
console.log(`[${new Date().toISOString()}] Starting survey_auto_submit for ${year} ${quarter}`);
|
||||
|
||||
try {
|
||||
const autoSubmissionService = new SubmissionAutoFillService(dbConfig);
|
||||
|
||||
// Auto-fill missing submissions for specific year and quarter
|
||||
const result = await autoSubmissionService.autoFillMissingSubmissions(year, quarter);
|
||||
|
||||
// Verify completeness for specific quarter
|
||||
const result3 = await autoSubmissionService.verifyCompleteness(year, quarter);
|
||||
|
||||
console.log(`[${new Date().toISOString()}] survey_auto_submit completed successfully`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
autoFillMissingSubmissions: result,
|
||||
verifyCompleteness: result3
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`[${new Date().toISOString()}] Error in survey_auto_submit:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute calculate quarter logic
|
||||
*/
|
||||
async executeCalculateQuarter(year, quarter) {
|
||||
console.log(`[${new Date().toISOString()}] Starting calculate_quarter for ${year} ${quarter}`);
|
||||
|
||||
try {
|
||||
// Quarter to month mapping
|
||||
const quarterMap = {
|
||||
Q1: { startMonth: 1, endMonth: 3 },
|
||||
Q2: { startMonth: 4, endMonth: 6 },
|
||||
Q3: { startMonth: 7, endMonth: 9 },
|
||||
Q4: { startMonth: 10, endMonth: 12 },
|
||||
};
|
||||
|
||||
const selectedQuarter = quarterMap[quarter];
|
||||
|
||||
if (!selectedQuarter) {
|
||||
throw new Error('Invalid quarter. Accepted values: Q1, Q2, Q3, Q4');
|
||||
}
|
||||
|
||||
const { startMonth, endMonth } = selectedQuarter;
|
||||
const service = new IPICalculationService(dbConfig);
|
||||
const results = [];
|
||||
|
||||
for (let month = startMonth; month <= endMonth; month++) {
|
||||
const result = await service.runCompleteCalculation(year, month);
|
||||
results.push({
|
||||
month,
|
||||
...result
|
||||
});
|
||||
}
|
||||
|
||||
await service.close();
|
||||
|
||||
console.log(`[${new Date().toISOString()}] calculate_quarter completed successfully`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `IPI calculated for ${year} months ${startMonth}-${endMonth}`,
|
||||
data: results
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`[${new Date().toISOString()}] Error in calculate_quarter:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main scheduler logic - runs daily
|
||||
*/
|
||||
async runScheduledTask() {
|
||||
// Prevent concurrent execution
|
||||
if (this.isRunning) {
|
||||
console.log(`[${new Date().toISOString()}] Scheduler already running, skipping this execution`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.isRunning = true;
|
||||
|
||||
try {
|
||||
console.log(`[${new Date().toISOString()}] ========================================`);
|
||||
console.log(`[${new Date().toISOString()}] Starting scheduled task execution`);
|
||||
|
||||
// Step 1: Get latest quarterly window configuration
|
||||
const latestWindow = await this.getLatestQuarterlyWindow();
|
||||
|
||||
if (!latestWindow) {
|
||||
console.log(`[${new Date().toISOString()}] No quarterly window configuration found`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[${new Date().toISOString()}] Latest window: Year=${latestWindow.year}, Quarter=${latestWindow.quarter}, End Date=${latestWindow.end_date}`);
|
||||
|
||||
// Step 2: Check if current date is greater than end_date
|
||||
const currentDate = new Date();
|
||||
const endDate = new Date(latestWindow.end_date);
|
||||
|
||||
console.log(`[${new Date().toISOString()}] Current Date: ${currentDate.toISOString()}`);
|
||||
console.log(`[${new Date().toISOString()}] End Date: ${endDate.toISOString()}`);
|
||||
|
||||
if (currentDate < endDate) {
|
||||
console.log(`[${new Date().toISOString()}] Current date is not greater than end_date. Skipping execution.`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[${new Date().toISOString()}] Current date is greater than end_date. Proceeding with execution.`);
|
||||
|
||||
// Step 3: Execute survey_auto_submit
|
||||
const surveyResult = await this.executeSurveyAutoSubmit(
|
||||
latestWindow.year,
|
||||
latestWindow.quarter
|
||||
);
|
||||
|
||||
// Step 4: Execute calculate_quarter after survey_auto_submit completes
|
||||
const calculationResult = await this.executeCalculateQuarter(
|
||||
latestWindow.year,
|
||||
latestWindow.quarter
|
||||
);
|
||||
|
||||
console.log(`[${new Date().toISOString()}] ========================================`);
|
||||
console.log(`[${new Date().toISOString()}] All scheduled tasks completed successfully`);
|
||||
console.log(`[${new Date().toISOString()}] Survey Result:`, JSON.stringify(surveyResult, null, 2));
|
||||
console.log(`[${new Date().toISOString()}] Calculation Result:`, JSON.stringify(calculationResult, null, 2));
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[${new Date().toISOString()}] Error in scheduled task:`, error);
|
||||
// You might want to send an alert/notification here
|
||||
} finally {
|
||||
this.isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the scheduler
|
||||
* Runs every day at 2:00 AM (you can adjust the time)
|
||||
*/
|
||||
start() {
|
||||
console.log(`[${new Date().toISOString()}] Starting automated scheduler...`);
|
||||
|
||||
// Run every day at 2:00 AM
|
||||
// Format: minute hour day month weekday
|
||||
// '0 2 * * *' = At 2:00 AM every day
|
||||
cron.schedule('0 2 * * *', () => {
|
||||
this.runScheduledTask();
|
||||
});
|
||||
|
||||
console.log(`[${new Date().toISOString()}] Scheduler started successfully. Will run daily at 2:00 AM.`);
|
||||
|
||||
// Optional: Run immediately on startup for testing
|
||||
// Uncomment the line below if you want to test immediately
|
||||
// this.runScheduledTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual trigger for testing
|
||||
*/
|
||||
async manualTrigger() {
|
||||
console.log(`[${new Date().toISOString()}] Manual trigger initiated...`);
|
||||
await this.runScheduledTask();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AutomatedSchedulerService;
|
||||
9
package-lock.json
generated
9
package-lock.json
generated
@ -24,6 +24,7 @@
|
||||
"morgan": "^1.10.1",
|
||||
"multer": "^2.0.2",
|
||||
"mysql2": "^3.15.2",
|
||||
"node-cron": "^4.2.1",
|
||||
"nodemailer": "^7.0.10",
|
||||
"nodemon": "^3.1.10",
|
||||
"sanitize-html": "^2.17.0",
|
||||
@ -2237,6 +2238,14 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cron": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.2.1.tgz",
|
||||
"integrity": "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "7.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.10.tgz",
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"morgan": "^1.10.1",
|
||||
"multer": "^2.0.2",
|
||||
"mysql2": "^3.15.2",
|
||||
"node-cron": "^4.2.1",
|
||||
"nodemailer": "^7.0.10",
|
||||
"nodemon": "^3.1.10",
|
||||
"sanitize-html": "^2.17.0",
|
||||
|
||||
24
server.js
24
server.js
@ -12,6 +12,8 @@ const sanitizeInput = require("./app/utils/sanitizeInput");
|
||||
const verifySignature = require("./app/middleware/app.middleware");
|
||||
const authController = require("./app/controllers/auth.controller");
|
||||
const establishmentController = require("./app/controllers/establishment.controller");
|
||||
const AutomatedSchedulerService = require('./app/services/scheduler.service');
|
||||
|
||||
require("dotenv").config();
|
||||
|
||||
const csrf = require("csurf");
|
||||
@ -297,6 +299,27 @@ app.get("/api/test", (req, res) => {
|
||||
const deploymentController = require("./app/controllers/deployment.controller");
|
||||
app.post("/deploy", deploymentController.deployment);
|
||||
|
||||
|
||||
/**
|
||||
* =========================
|
||||
* Auto Submission and iip calculation Automation
|
||||
* =========================
|
||||
*/
|
||||
const scheduler = new AutomatedSchedulerService();
|
||||
scheduler.start();
|
||||
// manual trigger endpoint
|
||||
app.post('/api/admin/trigger-scheduler', async (req, res) => {
|
||||
try {
|
||||
await scheduler.manualTrigger();
|
||||
res.json({ success: true, message: 'Scheduler triggered successfully' });
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Error triggering scheduler',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
/**
|
||||
* =========================
|
||||
* START SERVER
|
||||
@ -305,4 +328,5 @@ app.post("/deploy", deploymentController.deployment);
|
||||
const PORT = process.env.PORT || 5000;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🚀 Server running on port ${PORT}`);
|
||||
console.log(`Automated scheduler is active and will run daily at 2:00 AM`);
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user