const { Sequelize, Op } = require("sequelize"); const { Establishment, Submission, Emirate, EstablishmentUser, SubmissionProduct, SubmissionDeadline } = require("../models"); function getQuarter(date) { const month = date.getMonth() + 1; if (month >= 4 && month <= 6) return "Q1"; if (month >= 7 && month <= 9) return "Q2"; if (month >= 10 && month <= 12) return "Q3"; return "Q4"; // Jan-Mar } 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"]; // map month -> index: 0=Q1(Apr-Jun),1=Q2(Jul-Sep),2=Q3(Oct-Dec),3=Q4(Jan-Mar) const getQuarterIndex = (m) => { if (m >= 4 && m <= 6) return 0; // Apr-Jun -> Q1 if (m >= 7 && m <= 9) return 1; // Jul-Sep -> Q2 if (m >= 10 && m <= 12) return 2; // Oct-Dec -> Q3 return 3; // Jan-Mar -> 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 === 3) ? year - 1 : year; const nextQuarterYear = (currentIndex === 2) ? 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", ], ], }, }); // 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, }; } res.status(200).json({ status: "success", data: { ...quarters, submission_status: submissionStatus, next_deadline: nextDeadline, last_submission: lastSubmissionInfo, submission_history, }, }); } catch (err) { console.error(err); 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 }); } };