242 lines
6.7 KiB
JavaScript
242 lines
6.7 KiB
JavaScript
|
||
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
|
||
|
||
// --- 1️⃣ 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 } },
|
||
});
|
||
|
||
// --- 2️⃣ 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,
|
||
});
|
||
|
||
// --- 3️⃣ 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 });
|
||
}
|
||
}; |