GWM : Automation for Survey and iip calculation

This commit is contained in:
Gowtham M 2026-02-03 11:15:35 +05:30
parent 79d71002fa
commit 35c51fc3c3
4 changed files with 277 additions and 0 deletions

View 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
View File

@ -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",

View File

@ -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",

View File

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