const { Sequelize, Op } = require("sequelize"); const { Establishment, Submission, Emirate, EstablishmentUser, SubmissionProduct, SubmissionDeadline, QuarterlyWindowsConfiguration } = require("../models"); function getQuarterDates(quarter, year) { switch (quarter) { case "Q1": return { start: new Date(year, 3, 1), end: new Date(year, 5, 30) }; case "Q2": return { start: new Date(year, 6, 1), end: new Date(year, 8, 30) }; case "Q3": return { start: new Date(year, 9, 1), end: new Date(year, 11, 31) }; case "Q4": return { start: new Date(year, 0, 1), end: new Date(year, 2, 31) }; default: return {}; } } function getPrevCurrNextQuarter(date) { const month = date.getMonth() + 1; // 1-12 const year = date.getFullYear(); const quarters = ["Q1", "Q2", "Q3", "Q4"]; const getQuarterIndex = (m) => { if (m >= 1 && m <= 3) return 0; // Jan-Mar -> Q1 if (m >= 4 && m <= 6) return 1; // Apr-Jun -> Q2 if (m >= 7 && m <= 9) return 2; // Jul-Sep -> Q3 if (m >= 10 && m <=12) return 3; // Oct-Dec -> Q4 }; const currentIndex = getQuarterIndex(month); const currentQuarter = quarters[currentIndex]; const previousIndex = (currentIndex - 1 + 4) % 4; const nextIndex = (currentIndex + 1) % 4; const previousQuarter = quarters[previousIndex]; const nextQuarter = quarters[nextIndex]; const previousQuarterYear = (currentIndex === 1) ? year - 1 : year; const nextQuarterYear = (currentIndex === 3) ? year + 1 : year; return { previous_quarter: previousQuarter, previous_quarter_year: previousQuarterYear, current_quarter: currentQuarter, current_quarter_year: year, next_quarter: nextQuarter, next_quarter_year: nextQuarterYear, }; } exports.getEstablishmentDashboard = async (req, res) => { try { const establishment_id = req.query.establishment_id; if (!establishment_id) { return res.status(400).json({ status: "failed", message: "establishment_id required" }); } const today = new Date(); const quarters = getPrevCurrNextQuarter(today); const submission_history = await Submission.findAll({ where: { establishment_id }, order: [["created_at", "DESC"]], limit: 5, attributes: { include: [ [ Sequelize.literal(`( SELECT COUNT(*) FROM submission_products AS sp WHERE sp.submission_id = submission.id )`), "product_count", ], [ Sequelize.literal(`( SELECT survey_name FROM quarterly_windows_configuration_master AS QW WHERE QW.quarter = submission.quarter AND QW.year = submission.year limit 1 )`), "survey_name", ], ], }, }); // Submission status for current quarter const currentQuarterDates = getQuarterDates(quarters.current_quarter, quarters.current_quarter_year); const currentSubmission = await Submission.findOne({ where: { establishment_id, quarter: quarters.current_quarter, year: quarters.current_quarter_year, }, order: [["created_at", "DESC"]], }); // Get submission deadline (assuming only one row) const deadline = await SubmissionDeadline.findByPk(1); let nextDeadline = null; let submissionStatus = "Pending"; if (deadline) { const quarterEnd = currentQuarterDates.end; const deadlineDate = new Date(quarterEnd); deadlineDate.setDate(deadlineDate.getDate() + deadline.deadline_days_after_quarter_end); nextDeadline = deadlineDate; if (currentSubmission) { submissionStatus = "Submitted"; } } let lastSubmissionInfo = null; if (submission_history.length > 0) { const last = submission_history[0]; lastSubmissionInfo = { quarter: last.quarter, year: last.year, submitted_on: last.created_at, }; } let surveyReady = []; const activeQuarters = await QuarterlyWindowsConfiguration.findAll({ where: { is_active: true }, order: [["created_at", "DESC"]], }); if (activeQuarters?.length > 0) { for (const q of activeQuarters) { const submissionMatch = await Submission.findOne({ where: { year: q.year, quarter: q.quarter, establishment_id: establishment_id } }); // if not submitted yet → add for start survey if (!submissionMatch) { surveyReady.push({ survey_name:q.survey_name, year: q.year, quarter: q.quarter, start_date: q.start_date, end_date: q.end_date, grace_periods_days: q.grace_periods_days, }); } } } res.status(200).json({ status: "success", data: { ...quarters, submission_status: submissionStatus, next_deadline: nextDeadline, last_submission: lastSubmissionInfo, survey_ready: surveyReady, submission_history, }, }); } catch (err) { console.error(err); res.status(500).json({ status: "failed", message: err.message }); } }; exports.adminDashboard = async (req, res) => { try { let { quarter, year } = req.query; // if quarter/year not passed → take latest open config // if (!quarter || !year) { // const lastConfig = await QuarterlyWindowsConfiguration.findOne({ // order: [ // ['year', 'DESC'], // ['quarter', 'DESC'] // ] // }); // if (lastConfig) { // quarter = lastConfig.quarter; // year = lastConfig.year; // } // } let whereCond = {}; if (quarter === 'All') quarter = null; if (year === 'All') year = null; if (quarter) whereCond.quarter = quarter; if (year) whereCond.year = year; const quarterlyWindows = await QuarterlyWindowsConfiguration.findOne({ where: whereCond }); const totalEstablishments = await Establishment.count(); const submittedCount = await Submission.count({ where: { ...whereCond, status: "Submitted" } }); const approvedCount = await Submission.count({ where: { ...whereCond, status: "Approved" } }); const rejectedCount = await Submission.count({ where: { ...whereCond, status: "Rejected" } }); const pendingCount = await Submission.count({ where: { ...whereCond, status: "Pending" } }); // only when query param not used → not started count let notStartedCount = 0; const startedEstIds = await Submission.findAll({ where: whereCond, attributes: [[Sequelize.fn("DISTINCT", Sequelize.col("establishment_id")), "id"]], raw: true, }); const startedIds = startedEstIds.map(e => e.id); notStartedCount = await Establishment.count({ where: { id: { [Op.notIn]: startedIds } }, }); const recentSubmissions = await Submission.findAll({ where: whereCond, include: [ { model: Establishment, as: "establishment", attributes: ["factory_name"], include: [ { model: Emirate, as: "establishment_emirate", attributes: ["name"] }, ], }, { model: EstablishmentUser, as: "created_user", attributes: ["name"] }, ], attributes: { include: [ [ Sequelize.literal(`( SELECT COUNT(*) FROM submission_products AS sp WHERE sp.submission_id = submission.id )`), "product_count", ], [ Sequelize.literal(`( SELECT eu.name FROM establishment_users eu WHERE eu.id = submission.created_by LIMIT 1 )`), "created_by_name" ], [ Sequelize.literal(`( SELECT au.name FROM admin_users au WHERE au.id = submission.approve_or_reject_by LIMIT 1 )`), "reviewer_name" ], ], }, order: [["created_at", "DESC"]], limit: 10, }); return res.status(200).json({ status: "success", selected_quarter: quarter, selected_year: year, summary: { total_establishments: totalEstablishments, submitted: submittedCount, approved: approvedCount, rejected: rejectedCount, pending: pendingCount, not_started: notStartedCount, }, quarterly_windows : quarterlyWindows, recent_submissions: recentSubmissions, }); } catch (err) { console.error(err); return res.status(500).json({ status: "failed", message: err.message }); } }; // exports.adminDashboard = async (req, res) => { // try { // const { quarter, year } = req.query; // e.g., Q1, 2025 // // --- Summary Counts --- // const [ // totalEstablishments, // submittedCount, // approvedCount, // rejectedCount, // pendingCount // ] = await Promise.all([ // Establishment.count(), // Submission.count(), // Submission.count({ where: { status: "Approved" } }), // Submission.count({ where: { status: "Rejected" } }), // Submission.count({ where: { status: "Pending" } }), // ]); // // Not Started = total establishments - those that have any submission // const startedEstIds = await Submission.findAll({ // attributes: [[Sequelize.fn("DISTINCT", Sequelize.col("establishment_id")), "id"]], // raw: true, // }); // const startedIds = startedEstIds.map(e => e.id); // const notStartedCount = await Establishment.count({ // where: { id: { [Op.notIn]: startedIds } }, // }); // // --- Recent 10 submissions for given quarter & year --- // const whereCond = {}; // if (quarter) whereCond.quarter = quarter; // if (year) whereCond.year = year; // const recentSubmissions = await Submission.findAll({ // where: whereCond, // include: [ // { // model: Establishment, // as: "establishment", // attributes: ["factory_name"], // include: [ // { model: Emirate, as: "establishment_emirate", attributes: ["name"] }, // ], // }, // { // model: EstablishmentUser, // as: "created_user", // attributes: ["name"], // }, // ], // attributes: { // include: [ // [ // Sequelize.literal(`( // SELECT COUNT(*) // FROM submission_products AS sp // WHERE sp.submission_id = submission.id // )`), // "product_count", // ], // ], // }, // order: [["created_at", "DESC"]], // limit: 10, // }); // // --- Send Response --- // return res.status(200).json({ // status: "success", // summary: { // total_establishments: totalEstablishments, // submitted: submittedCount, // approved: approvedCount, // rejected: rejectedCount, // pending: pendingCount, // not_started: notStartedCount, // }, // recent_submissions: recentSubmissions, // }); // } catch (err) { // console.error(err); // return res.status(500).json({ status: "failed", message: err.message }); // } // };