This commit is contained in:
Gowtham M 2025-10-29 11:38:32 +05:30
parent 064084b0c5
commit 38f97d197f
4 changed files with 292 additions and 43 deletions

View File

@ -1,9 +1,6 @@
const db = require("../models");
const { Op } = require("sequelize");
const { Sequelize } = require("sequelize");
const Submission = db.Submission;
const SubmissionProduct = db.SubmissionProduct;
const SubmissionDeadline = db.SubmissionDeadline;
const { Sequelize, Op } = require("sequelize");
const { Establishment, Submission, Emirate, EstablishmentUser, SubmissionProduct, SubmissionDeadline } = require("../models");
function getQuarter(date) {
const month = date.getMonth() + 1;
@ -76,12 +73,7 @@ exports.getEstablishmentDashboard = async (req, res) => {
const today = new Date();
const quarters = getPrevCurrNextQuarter(today);
// Last 5 submissions
// const submission_history = await Submission.findAll({
// where: { establishment_id },
// order: [["created_at", "DESC"]],
// limit: 5,
// });
const submission_history = await Submission.findAll({
where: { establishment_id },
@ -99,12 +91,7 @@ exports.getEstablishmentDashboard = async (req, res) => {
],
],
},
// include: [
// {
// model: SubmissionProduct,
// as: "products", // ✅ use your actual alias here
// },
// ],
});
@ -164,3 +151,92 @@ exports.getEstablishmentDashboard = async (req, res) => {
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 });
}
};

View File

@ -241,7 +241,7 @@ exports.getAllEstablishments = async (req, res) => {
...(exportType ? {} : { limit, offset }), // pagination only when not exporting
});
// 📦 If export = excel → generate file
// If export = excel → generate file
if (exportType && exportType.toLowerCase() === "excel") {
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Establishments");
@ -302,7 +302,7 @@ exports.getAllEstablishments = async (req, res) => {
return res.end();
}
// Otherwise return JSON (paginated)
// Otherwise return JSON (paginated)
const totalCount = await Establishment.count({ where: whereClause });
return res.status(200).json({
status: "success",

View File

@ -7,6 +7,9 @@ const UnitMaster = db.UnitMaster;
const VariationReasonMaster = db.VariationReasonMaster;
const ZeroTargetReasonMaster = db.ZeroTargetReasonMaster;
const Product = db.Product;
const CityTown = db.CityTown;
const Emirate = db.Emirate;
const ExcelJS = require("exceljs");
const { Op } = require("sequelize");
const { Sequelize } = require("sequelize");
const { sendEmail } = require("../services/email.service");
@ -204,41 +207,147 @@ exports.submissionHistory = async (req, res) => {
};
// exports.submissionList = async (req, res) => {
// try {
// const data = await Submission.findAll({
// include: [
// {
// model: Establishment,
// as: "establishment" ,
// attributes: ["factory_name","establishment_code"],
// 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: [["id", "DESC"]],
// });
// res.status(200).json({ status: "success", data });
// } catch (err) {
// res.status(500).json({ status: "failed", message: err.message });
// }
// };
exports.submissionList = async (req, res) => {
try {
const {
page = 1,
limit = 10,
search = "",
quarter,
year,
status,
emirate_id,
export_excel = false,
} = req.query;
const data = await Submission.findAll({
const offset = (page - 1) * limit;
const where = {};
// 🔹 Filters
if (year) where.year = year;
if (quarter) where.quarter = quarter;
if (status) where.status = status;
// 🔹 Search — establishment name or code or submitted user
const establishmentWhere = {};
if (search) {
establishmentWhere[Op.or] = [
{ factory_name: { [Op.like]: `%${search}%` } },
{ establishment_code: { [Op.like]: `%${search}%` } },
];
}
// 🔹 Emirate filter
if (emirate_id) establishmentWhere.establishment_emirate_id = emirate_id;
// 🔹 Query
const { rows, count } = await Submission.findAndCountAll({
where,
include: [
{
model: Establishment,
as: "establishment" ,
attributes: ["factory_name","establishment_code","emirate"],
},
{
model: EstablishmentUser,
as: "created_user",
attributes: ["name", "email"],
},
],
{
model: Establishment,
as: "establishment",
attributes: ["factory_name", "establishment_code"],
where: establishmentWhere,
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",
],
],
},
include: [
[
Sequelize.literal(`(
SELECT COUNT(*) FROM submission_products AS sp
WHERE sp.submission_id = submission.id
)`),
"product_count",
],
],
},
order: [["id", "DESC"]],
offset: parseInt(offset),
limit: parseInt(limit),
});
res.status(200).json({ status: "success", data });
// 🔹 Export to Excel
if (export_excel && export_excel === "true") {
const excelData = rows.map((s) => ({
Establishment: s.establishment?.factory_name,
Emirate: s.establishment?.establishment_emirate?.name,
Year: s.year,
Quarter: s.quarter,
Products: s.dataValues.product_count,
Status: s.status,
Submitted_By: s.created_user?.name,
Submission_Date: s.created_at,
}));
const filePath = await exportToExcel("Submission_List", excelData);
return res.download(filePath);
}
// 🔹 Paginated Response
return res.status(200).json({
status: "success",
message: "Fetched successfully",
pagination: {
total: count,
page: Number(page),
limit: Number(limit),
totalPages: Math.ceil(count / limit),
},
data: rows,
});
} catch (err) {
console.error(err);
res.status(500).json({ status: "failed", message: err.message });
}
};
exports.viewSubmissionDetails = async (req, res) => {
try {

View File

@ -1767,14 +1767,45 @@ router.get("/submissions/history/:establishment_id",[verifySignature, verifyToke
* @swagger
* /api/submissions:
* get:
* summary: Get all submissions
* summary: Get submissions list with pagination, filters, search, and export
* tags: [Submissions]
* security:
* - appSignature: []
* - bearerAuth: []
* parameters:
* - in: query
* name: page
* schema: { type: integer, default: 1 }
* description: Page number
* - in: query
* name: limit
* schema: { type: integer, default: 10 }
* description: Items per page
* - in: query
* name: search
* schema: { type: string }
* description: Search by establishment name or code
* - in: query
* name: quarter
* schema: { type: string }
* - in: query
* name: year
* schema: { type: integer }
* - in: query
* name: status
* schema: { type: string }
* - in: query
* name: emirate_id
* schema: { type: integer }
* - in: query
* name: export_excel
* schema: { type: boolean }
* description: If true, exports data to Excel file
* responses:
* 200:
* description: All submissions
* description: Submission list retrieved successfully
* 500:
* description: Server error
*/
router.get("/submissions",[verifySignature, verifyToken], submissionController.submissionList);
@ -2011,6 +2042,39 @@ router.post("/submission_deadlines",[verifySignature, verifyToken], ConfigContro
router.get("/establishment_dashboard",[verifySignature, verifyToken],dashboardController.getEstablishmentDashboard);
/**
* @swagger
* /api/admin_dashboard:
* get:
* summary: Get dashboard data for admin user
* tags: [Dashboard]
* security:
* - appSignature: []
* - bearerAuth: []
* parameters:
* - in: query
* name: quarter
* required: true
* schema:
* type: string
* - in: query
* name: year
* required: true
* schema:
* type: integer
* responses:
* 200:
* description: Dashboard data fetched successfully
* 400:
* description: Bad request
* 403:
* description: Invalid signature
* 401:
* description: Unauthorized
* 500:
* description: Server error
*/
router.get("/admin_dashboard",[verifySignature, verifyToken], dashboardController.adminDashboard);