From 0915843ef4354fc2b199cbc75fab638acee080ea Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Fri, 17 Oct 2025 15:37:38 +0530 Subject: [PATCH] Added some api's : GWM --- app/controllers/config.controller.js | 52 ++++++++ app/controllers/dashboard.controller.js | 140 ++++++++++++++++++++ app/controllers/establishment.controller.js | 30 ++--- app/models/index.js | 1 + app/models/submission.model.js | 6 - app/models/submissionDeadline.model.js | 51 +++++++ app/routes/routes.js | 112 ++++++++++++++++ 7 files changed, 371 insertions(+), 21 deletions(-) create mode 100644 app/controllers/config.controller.js create mode 100644 app/controllers/dashboard.controller.js create mode 100644 app/models/submissionDeadline.model.js diff --git a/app/controllers/config.controller.js b/app/controllers/config.controller.js new file mode 100644 index 0000000..1846ae5 --- /dev/null +++ b/app/controllers/config.controller.js @@ -0,0 +1,52 @@ +const db = require("../models"); +const SubmissionDeadline = db.SubmissionDeadline; + + + +// POST /api/submission-deadlines +exports.updateDeadlineData = async (req, res) => { + try { + const { + deadline_days_after_quarter_end, + grace_periods_days_after_deadline, + first_reminder_days_before_deadline, + second_reminder_days_before_deadline, + created_by, + updated_by, + } = req.body; + + // Try to find existing record (id=1) + let existing = await SubmissionDeadline.findByPk(1); + + if (existing) { + // Update + await existing.update({ + deadline_days_after_quarter_end, + grace_periods_days_after_deadline, + first_reminder_days_before_deadline, + second_reminder_days_before_deadline, + updated_at: new Date(), + updated_by, + }); + + res.status(200).json({ status: "success", message: "Deadline updated successfully", data: existing }); + } else { + // Create new (set id = 1 manually) + const newRecord = await SubmissionDeadline.create({ + id: 1, + deadline_days_after_quarter_end, + grace_periods_days_after_deadline, + first_reminder_days_before_deadline, + second_reminder_days_before_deadline, + created_at: new Date(), + created_by, + }); + + res.status(201).json({ status: "success", message: "Deadline created successfully", data: newRecord }); + } + + } catch (err) { + console.error(err); + res.status(500).json({ status: "failed", message: err.message }); + } +}; diff --git a/app/controllers/dashboard.controller.js b/app/controllers/dashboard.controller.js new file mode 100644 index 0000000..1c0e230 --- /dev/null +++ b/app/controllers/dashboard.controller.js @@ -0,0 +1,140 @@ +const db = require("../models"); +const { Op } = require("sequelize"); + +const Submission = db.Submission; +const SubmissionDeadline = db.SubmissionDeadline; + +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); + + // Last 5 submissions + const submission_history = await Submission.findAll({ + where: { establishment_id }, + order: [["created_at", "DESC"]], + limit: 5, + }); + + // 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 }); + } +}; diff --git a/app/controllers/establishment.controller.js b/app/controllers/establishment.controller.js index 428d459..2da42ca 100644 --- a/app/controllers/establishment.controller.js +++ b/app/controllers/establishment.controller.js @@ -6,13 +6,13 @@ const EstablishmentUser = db.establishment_user; // Create Establishment + linked user exports.createEstablishment = async (req, res) => { try { - - const { establishment_code, factory_name, email, permanent_factory_code, industry_code, license_number, isic_code, emirate, total_employment, establishment_user, } = req.body; + + const { establishment_code, factory_name, email, permanent_factory_code, industry_code, license_number, isic_code, emirate, emirati_male,emirati_female,non_emirati_male,non_emirati_female,total_emirati,total_employees, establishment_user, } = req.body; - if ( !establishment_code || !factory_name || !email || !establishment_user?.name || !establishment_user?.email || !establishment_user?.password ) - { - res.status(400).send({'status':"failed",'message':"Missing required fields",'data': "" }); - } + // if ( !establishment_code || !factory_name || !email || !establishment_user?.name || !establishment_user?.email || !establishment_user?.password ) + // { + // res.status(400).send({'status':"failed",'message':"Missing required fields",'data': "" }); + // } // Create Establishment const establishment = await Establishment.create({ @@ -24,22 +24,22 @@ exports.createEstablishment = async (req, res) => { license_number, isic_code, emirate, - total_employment, + emirati_male,emirati_female,non_emirati_male,non_emirati_female,total_emirati,total_employees, }); // Hash password for user - const hashedPassword = await bcrypt.hash(establishment_user.password, 10); + // const hashedPassword = await bcrypt.hash(establishment_user.password, 10); // Create related Establishment User - const user = await EstablishmentUser.create({ - establishment_id: establishment.id, - name: establishment_user.name, - email: establishment_user.email, - password: hashedPassword, - }); + // const user = await EstablishmentUser.create({ + // establishment_id: establishment.id, + // name: establishment_user.name, + // email: establishment_user.email, + // password: hashedPassword, + // }); - res.status(201).send({'status':"success",'message':"Establishment and linked user created successfully",'data': { establishment, user } }); + res.status(201).send({'status':"success",'message':"Establishment and linked user created successfully",'data': { establishment } }); } catch (err) { res.status(500).send({'status':"failed",'message':err.message }); diff --git a/app/models/index.js b/app/models/index.js index 0ddd233..145af64 100644 --- a/app/models/index.js +++ b/app/models/index.js @@ -22,6 +22,7 @@ db.ZeroTargetReasonMaster = require("./zeroTargetReason.model")(sequelize, DataT db.Submission = require("./submission.model")(sequelize, DataTypes); db.SubmissionProduct = require("./submissionProduct.model")(sequelize, DataTypes); db.UnitMaster = require("./UnitMaster.model")(sequelize, DataTypes); +db.SubmissionDeadline = require("./submissionDeadline.model")(sequelize, DataTypes); // Associations diff --git a/app/models/submission.model.js b/app/models/submission.model.js index d776e05..8c50223 100644 --- a/app/models/submission.model.js +++ b/app/models/submission.model.js @@ -17,12 +17,6 @@ module.exports = (sequelize, DataTypes) => { type: DataTypes.INTEGER, allowNull: false, }, - emirati_male: DataTypes.INTEGER, - emirati_female: DataTypes.INTEGER, - non_emirati_male: DataTypes.INTEGER, - non_emirati_female: DataTypes.INTEGER, - total_emirati: DataTypes.INTEGER, - total_employees: DataTypes.INTEGER, edit_request: { type: DataTypes.BOOLEAN, defaultValue: false, diff --git a/app/models/submissionDeadline.model.js b/app/models/submissionDeadline.model.js new file mode 100644 index 0000000..750b374 --- /dev/null +++ b/app/models/submissionDeadline.model.js @@ -0,0 +1,51 @@ +module.exports = (sequelize, DataTypes) => { + const SubmissionDeadline = sequelize.define( + "submission_deadlines", + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + deadline_days_after_quarter_end: { + type: DataTypes.INTEGER, + allowNull: false, + }, + grace_periods_days_after_deadline: { + type: DataTypes.INTEGER, + allowNull: false, + }, + first_reminder_days_before_deadline: { + type: DataTypes.INTEGER, + allowNull: false, + }, + second_reminder_days_before_deadline: { + type: DataTypes.INTEGER, + allowNull: false, + }, + created_at: { + type: DataTypes.DATE, + defaultValue: DataTypes.NOW, + }, + updated_at: { + type: DataTypes.DATE, + allowNull: true, + }, + created_by: { + type: DataTypes.INTEGER, + allowNull: true, + }, + updated_by: { + type: DataTypes.INTEGER, + allowNull: true, + }, + }, + { + tableName: "submission_deadlines", + timestamps: false, + } + ); + + return SubmissionDeadline; + }; + \ No newline at end of file diff --git a/app/routes/routes.js b/app/routes/routes.js index 7995eff..d6ab49f 100644 --- a/app/routes/routes.js +++ b/app/routes/routes.js @@ -13,6 +13,8 @@ const variationReasonMasterController = require("../controllers/variationReasonM const zeroTargetReasonMasterController = require("../controllers/zeroTargetReasonMaster.controller"); const unitMasterController = require("../controllers/unitMasterController"); const submissionController = require("../controllers/submission.controller"); +const ConfigController = require("../controllers/config.controller"); +const dashboardController = require("../controllers/dashboard.controller"); @@ -41,6 +43,10 @@ const submissionController = require("../controllers/submission.controller"); * description: Manage Unit Master entries * - name: Submissions * description: Manage establishment submissions + * - name: Config + * description: Sumbission config + * - name: Dashboard + * description: */ @@ -1664,4 +1670,110 @@ router.put("/approveOrRejectSubmission/:id",[verifySignature, verifyToken], subm + + + + + + + + + + +/** + * @swagger + * /api/submission_deadlines: + * post: + * summary: Create or update submission deadline configuration (only one record allowed) + * tags: [Config] + * security: + * - appSignature: [] + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * deadline_days_after_quarter_end: + * type: integer + * example: 30 + * grace_periods_days_after_deadline: + * type: integer + * example: 7 + * first_reminder_days_before_deadline: + * type: integer + * example: 5 + * second_reminder_days_before_deadline: + * type: integer + * example: 2 + * created_by: + * type: integer + * example: 1 + * updated_by: + * type: integer + * example: 1 + * responses: + * 200: + * description: Deadline data updated successfully + * 201: + * description: Deadline data created successfully + * 500: + * description: Server error + */ +router.post("/submission_deadlines",[verifySignature, verifyToken], ConfigController.updateDeadlineData); + + + + + + + + + + + + + + +/** + * @swagger + * /api/establishment_dashboard: + * get: + * summary: Get dashboard data for establishment user + * tags: [Dashboard] + * parameters: + * - in: query + * name: establishment_id + * required: true + * schema: + * type: integer + * description: ID of the establishment + * responses: + * 200: + * description: Dashboard data fetched successfully + * 400: + * description: Bad request + * 403: + * description: Invalid signature + * 401: + * description: Unauthorized + * 500: + * description: Server error + */ +router.get("/establishment_dashboard",dashboardController.getEstablishmentDashboard); + + + + + + + + + + + + + module.exports = router;