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",
|
"morgan": "^1.10.1",
|
||||||
"multer": "^2.0.2",
|
"multer": "^2.0.2",
|
||||||
"mysql2": "^3.15.2",
|
"mysql2": "^3.15.2",
|
||||||
|
"node-cron": "^4.2.1",
|
||||||
"nodemailer": "^7.0.10",
|
"nodemailer": "^7.0.10",
|
||||||
"nodemon": "^3.1.10",
|
"nodemon": "^3.1.10",
|
||||||
"sanitize-html": "^2.17.0",
|
"sanitize-html": "^2.17.0",
|
||||||
@ -2237,6 +2238,14 @@
|
|||||||
"node": ">= 0.6"
|
"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": {
|
"node_modules/nodemailer": {
|
||||||
"version": "7.0.10",
|
"version": "7.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.10.tgz",
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
"morgan": "^1.10.1",
|
"morgan": "^1.10.1",
|
||||||
"multer": "^2.0.2",
|
"multer": "^2.0.2",
|
||||||
"mysql2": "^3.15.2",
|
"mysql2": "^3.15.2",
|
||||||
|
"node-cron": "^4.2.1",
|
||||||
"nodemailer": "^7.0.10",
|
"nodemailer": "^7.0.10",
|
||||||
"nodemon": "^3.1.10",
|
"nodemon": "^3.1.10",
|
||||||
"sanitize-html": "^2.17.0",
|
"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 verifySignature = require("./app/middleware/app.middleware");
|
||||||
const authController = require("./app/controllers/auth.controller");
|
const authController = require("./app/controllers/auth.controller");
|
||||||
const establishmentController = require("./app/controllers/establishment.controller");
|
const establishmentController = require("./app/controllers/establishment.controller");
|
||||||
|
const AutomatedSchedulerService = require('./app/services/scheduler.service');
|
||||||
|
|
||||||
require("dotenv").config();
|
require("dotenv").config();
|
||||||
|
|
||||||
const csrf = require("csurf");
|
const csrf = require("csurf");
|
||||||
@ -297,6 +299,27 @@ app.get("/api/test", (req, res) => {
|
|||||||
const deploymentController = require("./app/controllers/deployment.controller");
|
const deploymentController = require("./app/controllers/deployment.controller");
|
||||||
app.post("/deploy", deploymentController.deployment);
|
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
|
* START SERVER
|
||||||
@ -305,4 +328,5 @@ app.post("/deploy", deploymentController.deployment);
|
|||||||
const PORT = process.env.PORT || 5000;
|
const PORT = process.env.PORT || 5000;
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`🚀 Server running on port ${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