const db = require("../models"); const logger = require("../services/logger"); const IPICalculationService = require("../services/ipi_calculation_service"); const SubmissionAutoFillService = require("../services/auto_fill_missing_quarterly_submissions_service"); const CalculationLog = db.CalculationLog; // 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 } }; // SELECT // p.id AS product_id, // p.hs_code AS product_hs_code, // s.year, // u.uom_short_name AS unit, // -- Q1 // SUM(CASE WHEN s.quarter = 'Q1' THEN sp.current_quantity_period_one END) AS Jan, // SUM(CASE WHEN s.quarter = 'Q1' THEN sp.current_quantity_period_two END) AS Feb, // SUM(CASE WHEN s.quarter = 'Q1' THEN sp.current_quantity_period_three END)AS Mar, // -- Q2 // SUM(CASE WHEN s.quarter = 'Q2' THEN sp.current_quantity_period_one END) AS Apr, // SUM(CASE WHEN s.quarter = 'Q2' THEN sp.current_quantity_period_two END) AS May, // SUM(CASE WHEN s.quarter = 'Q2' THEN sp.current_quantity_period_three END)AS Jun, // -- Q3 // SUM(CASE WHEN s.quarter = 'Q3' THEN sp.current_quantity_period_one END) AS Jul, // SUM(CASE WHEN s.quarter = 'Q3' THEN sp.current_quantity_period_two END) AS Aug, // SUM(CASE WHEN s.quarter = 'Q3' THEN sp.current_quantity_period_three END)AS Sep, // -- Q4 // SUM(CASE WHEN s.quarter = 'Q4' THEN sp.current_quantity_period_one END) AS Oct, // SUM(CASE WHEN s.quarter = 'Q4' THEN sp.current_quantity_period_two END) AS Nov, // SUM(CASE WHEN s.quarter = 'Q4' THEN sp.current_quantity_period_three END)AS `Dec`, // -- Average (A.M.) Base Year Production // ROUND( // ( // COALESCE(SUM(CASE WHEN s.quarter='Q1' THEN sp.current_quantity_period_one END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q1' THEN sp.current_quantity_period_two END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q1' THEN sp.current_quantity_period_three END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q2' THEN sp.current_quantity_period_one END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q2' THEN sp.current_quantity_period_two END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q2' THEN sp.current_quantity_period_three END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q3' THEN sp.current_quantity_period_one END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q3' THEN sp.current_quantity_period_two END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q3' THEN sp.current_quantity_period_three END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q4' THEN sp.current_quantity_period_one END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q4' THEN sp.current_quantity_period_two END),0) + // COALESCE(SUM(CASE WHEN s.quarter='Q4' THEN sp.current_quantity_period_three END),0) // ) / 12, // 2) AS avg_by_production // FROM submission_products sp // JOIN submission s ON s.id = sp.submission_id // JOIN products p ON p.id = sp.product_id // LEFT JOIN unit_master u ON u.id = p.unit_id -- if you have units table // WHERE // s.year = 2022 -- base year // AND sp.is_active = 1 // AND s.status = 'Approved' -- optional, recommended // GROUP BY // p.id; // 1. Calculate Base Year Production (Run once for base year 2022) exports.calculate_base_year = async (req, res) => { try { const { baseYear = 2022, forceRecalculate = false } = req.body; const service = new IPICalculationService(dbConfig); const result = await service.calculateBaseYearProduction(baseYear , forceRecalculate); await service.close(); res.json({ success: true, message: `Base year ${baseYear} production calculated successfully (quarter-based)`, data: result }); } catch (error) { console.error('Error:', error); res.status(500).json({ success: false, message: 'Error calculating base year production', error: error.message }); } }; // 2. Calculate IPI for Specific Quarter exports.calculate_month = async (req, res) => { try { const { year, quarter } = req.body; if (!year || !quarter) { return res.status(400).json({ success: false, message: 'Year and quarter are required' }); } if (!['Q1', 'Q2', 'Q3', 'Q4'].includes(quarter)) { return res.status(400).json({ success: false, message: 'Quarter must be one of Q1, Q2, Q3, Q4' }); } const service = new IPICalculationService(dbConfig); const result = await service.runCompleteCalculation(year, quarter); await service.close(); res.json({ success: true, message: `IPI calculated for ${year}-${quarter}`, data: result }); } catch (error) { console.error('Error:', error); res.status(500).json({ success: false, message: 'Error calculating IPI', error: error.message }); } }; // 3. Calculate IPI for quarter exports.calculate_quarter = async (req, res) => { try { const { year, quarter } = req.body; if (!year || !quarter) { return res.status(400).json({ success: false, message: 'Year and quarter are required' }); } if (!['Q1', 'Q2', 'Q3', 'Q4'].includes(quarter)) { return res.status(400).json({ success: false, message: 'Invalid quarter. Accepted values: Q1, Q2, Q3, Q4' }); } const service = new IPICalculationService(dbConfig); const result = await service.runCompleteCalculation(year, quarter); await service.close(); res.json({ success: true, message: `IPI calculated for ${year} ${quarter}`, data: result }); } catch (error) { console.error('Error:', error); res.status(500).json({ success: false, message: 'Error calculating IPI range', error: error.message }); } }; // 4. Get Calculation Status/Log exports.calculation_log = async (req, res) => { try { const { year, month, type } = req.query; const service = new IPICalculationService(dbConfig); const connection = await service.pool.getConnection(); let query = ` SELECT * FROM calculation_log WHERE 1=1 `; const params = []; if (year) { query += ` AND reference_year = ?`; params.push(year); } if (month) { query += ` AND reference_month = ?`; params.push(month); } if (type) { query += ` AND calculation_type = ?`; params.push(type); } query += ` ORDER BY started_at DESC LIMIT 100`; const [results] = await connection.query(query, params); connection.release(); await service.close(); res.json({ success: true, data: results}); } catch (error) { console.error('Error:', error); res.status(500).json({ success: false, message: 'Error fetching calculation log', error: error.message }); } }; const validateYearQuarter = (year, quarter) => { if (!year || !quarter) { return { ok: false, message: "Year and quarter are required" }; } if (!["Q1", "Q2", "Q3", "Q4"].includes(quarter)) { return { ok: false, message: "Invalid quarter. Accepted values: Q1, Q2, Q3, Q4", }; } return { ok: true }; }; async function runSurveyAutoSubmit(year, quarter) { const autoSubmissionService = new SubmissionAutoFillService(dbConfig); const autoFillMissingSubmissions = await autoSubmissionService.autoFillMissingSubmissions(year, quarter); const verifyCompleteness = await autoSubmissionService.verifyCompleteness(year, quarter); return { autoFillMissingSubmissions, verifyCompleteness }; } async function runQuarterCalculation(year, quarter) { const service = new IPICalculationService(dbConfig); try { const data = await service.runCompleteCalculation(year, quarter); return { message: `IPI calculated for ${year} ${quarter}`, data }; } finally { await service.close(); } } // 5. Survey Auto Submit exports.survey_auto_submit = async (req, res) => { try { const { year, quarter } = req.body; const validation = validateYearQuarter(year, quarter); if (!validation.ok) { return res.status(400).json({ success: false, message: validation.message }); } const result = await runSurveyAutoSubmit(year, quarter); res.json({ success: true, ...result }); } catch (error) { console.error("Error:", error); res.status(500).json({ success: false, message: "Error during survey auto submit", error: error.message, }); } }; // 6. Auto submit missing surveys, then run quarterly IPI calculation exports.survey_auto_submit_and_calculate = async (req, res) => { try { const { year, quarter } = req.body; const validation = validateYearQuarter(year, quarter); if (!validation.ok) { return res.status(400).json({ success: false, message: validation.message }); } const autoSubmitResult = await runSurveyAutoSubmit(year, quarter); const calculationResult = await runQuarterCalculation(year, quarter); res.json({ success: true, message: `Auto submit and IPI calculation completed for ${year} ${quarter}`, year, quarter, steps: { survey_auto_submit: autoSubmitResult, calculate_quarter: calculationResult, }, }); } catch (error) { console.error("Error:", error); res.status(500).json({ success: false, message: "Error during auto submit and quarterly calculation", error: error.message, }); } }; exports.getCalculationLogsByYearMonth = async (req, res) => { try { const { year, quarter, month } = req.query; if (!year) { return res.status(400).json({ message: "Year is required", }); } const resolvedQuarter = quarter || (month ? (month <= 3 ? "Q1" : month <= 6 ? "Q2" : month <= 9 ? "Q3" : "Q4") : null); if (!resolvedQuarter) { return res.status(400).json({ message: "Quarter (or month to derive quarter) is required", }); } const logs = await CalculationLog.findAll({ where: { reference_year: year, reference_month: resolvedQuarter, }, order: [["started_at", "DESC"]], }); if (!logs.length) { return res.status(404).json({ message: "No calculation logs found", }); } return res.status(200).json({ message: "Calculation logs fetched successfully", data: logs, }); } catch (err) { logger.error(`Error getting calculation logs: ${err.message }`); logger.error(`Stack trace: ${err.stack}`); return res.status(500).json({ message: "Server error", }); } };