GWM
This commit is contained in:
parent
064084b0c5
commit
38f97d197f
@ -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 });
|
||||
}
|
||||
};
|
||||
@ -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",
|
||||
|
||||
@ -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 {
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user