fcsc_ipi_backend/app/controllers/dashboard.controller.js
2025-12-17 10:07:04 +05:30

390 lines
11 KiB
JavaScript

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 });
// }
// };