const express = require("express"); const router = express.Router(); const verifyToken = require("../middleware/auth.middleware"); const verifySignature = require("../middleware/app.middleware"); const adminUserController = require("../controllers/user.controller"); const authController = require("../controllers/auth.controller"); const establishmentController = require("../controllers/establishment.controller"); const establishmentUserController = require("../controllers/establishment_user.controller"); const establishmentUserAuthController = require("../controllers/establishment_users_auth.controller"); const productController = require("../controllers/products.controller"); const establishmentProductController = require("../controllers/establishment_products.controller"); const variationReasonMasterController = require("../controllers/variationReasonMaster.controller"); 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"); const notificationTemplateController = require("../controllers/notificationTemplate.controller"); const quarterlyWindowsController = require("../controllers/quarterlyWindowsConfiguration.controller"); const calculationController = require("../controllers/calculation.controller"); const ManufacturingIpiController = require("../controllers/manufacturingIPI.controller") const testController = require("../controllers/test.controller"); const exportController = require("../controllers/export.controller"); const fs = require("fs"); const path = require("path"); const multer = require("multer"); const { UPLOAD_DIR } = require("../config/upload.config"); const upload = multer({ dest: UPLOAD_DIR }); const { handleCsvUpload } = require("../middleware/csvUpload.middleware"); /** * @swagger * /api/calculate_base_year: * post: * summary: Base year calculation 2022 * tags: [IIP Calculation] * security: * - appSignature: [] * - CSRF: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - baseYear * - forceRecalculate * properties: * baseYear: * type: integer * example: 2022 * forceRecalculate: * type: string * example: false * responses: * 200: * description: Base year production calculated successfully */ router.post("/calculate_base_year",[] , calculationController.calculate_base_year); /** * @swagger * /api/survey_auto_submit: * post: * summary: Auto survey submission for Quarter * tags: [IIP Calculation] * security: * - appSignature: [] * - CSRF: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - year * - quarter * properties: * year: * type: integer * example: 2025 * quarter: * type: string * enum: [Q1, Q2, Q3, Q4] * example: Q2 * responses: * 200: * description: Auto survey completed successfully */ router.post("/survey_auto_submit",[] , calculationController.survey_auto_submit); /** * @swagger * /api/calculate_quarter: * post: * summary: Calculate IPI for a selected year and quarter (Quarter → Month mapping) * tags: [IIP Calculation] * security: * - appSignature: [] * - CSRF: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - year * - quarter * properties: * year: * type: integer * example: 2025 * quarter: * type: string * enum: [Q1, Q2, Q3, Q4] * example: Q2 * description: | * Quarter to month mapping: * - Q1 → Jan to Mar (1 - 3) * - Q2 → Apr to Jun (4 - 6) * - Q3 → Jul to Sep (7 - 9) * - Q4 → Oct to Dec (10 - 12) * responses: * 200: * description: Quarterly IPI calculation completed successfully */ router.post("/calculate_quarter",[] , calculationController.calculate_quarter); /** * @swagger * /api/survey_auto_submit_and_calculate: * post: * summary: Auto submit missing surveys, then calculate IPI for the quarter * description: | * Runs in sequence: * 1. survey_auto_submit — auto-fill missing submissions and verify completeness * 2. calculate_quarter — run IPI calculation for the same year and quarter * tags: [IIP Calculation] * security: * - appSignature: [] * - CSRF: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - year * - quarter * properties: * year: * type: integer * example: 2025 * quarter: * type: string * enum: [Q1, Q2, Q3, Q4] * example: Q2 * responses: * 200: * description: Auto submit and quarterly calculation completed successfully * 400: * description: Invalid year or quarter * 500: * description: Server error */ router.post( "/survey_auto_submit_and_calculate", [], calculationController.survey_auto_submit_and_calculate ); router.get("/calculate_month",[] , calculationController.calculate_month); /** * @swagger * tags: * - name: Admin And Establishments User Auth * description: Authentication * - name: Admin Users * description: User management APIs * - name: Establishments * description: CRUD APIs for managing Establishments * - name: Establishment Users * description: CRUD APIs for managing Establishment Users * - name: Products * description: CRUD APIs for managing Products * - name: Establishment Products * description: CRUD APIs for linking establishments and products * - name: Variation Reason Master * description: Manage variation reason master data * - name: Zero Target Reasons * description: API for managing zero target reasons * - name: Unit Master * description: Manage Unit Master entries * - name: Submissions * description: Manage establishment submissions * - name: Config * description: Sumbission config * - name: Dashboard * description: * - name: Notification Templates * description: Manage notification templates * - name: Quarterly Windows Configuration * description: Manage quarterly windows configuration master data * - name: Establishment Pwd Reset Requests * description: Manage Establishment Pwd Reset Requests * - name: Master * description: */ /** * @swagger * components: * securitySchemes: * bearerAuth: * type: http * scheme: bearer * bearerFormat: JWT * description: "key to identify authorized user" * appSignature: * type: apiKey * in: header * name: APP_SIGNATURE * description: "Signature key to identify authorized application" * CSRF: * type: apiKey * in: header * name: X-CSRF-Token * description: "Signature key to identify authorized application" */ /** * @swagger * /api/auth/admin_register: * post: * summary: Register new Admin-user (For testing purpose only) * tags: [Admin And Establishments User Auth] * security: * - appSignature: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - name * - email * - password * properties: * name: * type: string * example: John Doe * email: * type: string * example: john@example.com * password: * type: string * example: "" * responses: * 201: * description: User registered successfully * 400: * description: Missing fields or duplicate email * 500: * description: Server error */ router.post("/auth/admin_register",[verifySignature], authController.register); /** * @swagger * /api/auth/login: * post: * summary: Login Admin-user / Establishments-user and get JWT token * tags: [Admin And Establishments User Auth] * security: * - appSignature: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - email * - password * properties: * email: * type: string * example: john@example.com * password: * type: string * example: "" * responses: * 201: * description: User verifyed successfully * 404: * description: Missing email * 500: * description: Server error */ router.post("/auth/login",[verifySignature], authController.login); /** * @swagger * /api/auth/logout: * get: * summary: Logout Admin-user / Establishments-user * tags: [Admin And Establishments User Auth] * security: * - appSignature: [] */ router.get("/auth/logout",[verifySignature], authController.logout); /** * @swagger * /api/admin_users: * get: * summary: Get all users (Protected) * tags: [Admin Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 201: * description: Fetched successfully * 404: * description: Missing Data * 500: * description: Server error */ router.get("/admin_users", [verifySignature , verifyToken], adminUserController.getAllUsers); /** * @swagger * /api/admin_users/{id}: * get: * summary: Get user by ID (Protected) * tags: [Admin Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: User ID * responses: * 201: * description: Fetched successfully * 404: * description: Missing Data * 500: * description: Server error */ router.get("/admin_users/:id", [verifySignature, verifyToken], adminUserController.getUserById); /** * @swagger * /api/admin_users: * post: * summary: Create a user * tags: [Admin Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * name: { type: string } * email: { type: string } * password: * type: string * example: "" * responses: * 201: * description: created successfully * 404: * description: Missing Data * 500: * description: Server error */ router.post("/admin_users",[verifySignature, verifyToken], adminUserController.createUser); /** * @swagger * /api/admin_users/{id}: * put: * summary: Update user * tags: [Admin Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: User ID * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * name: { type: string } * email: { type: string } * is_active: { type: boolean } * responses: * 201: * description: updated successfully * 404: * description: Missing Data * 500: * description: Server error */ router.put("/admin_users/:id",[verifySignature, verifyToken], adminUserController.updateUser); /** * @swagger * /api/admin_users/{id}: * delete: * summary: Delete user * tags: [Admin Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: User ID * responses: * 201: * description: deleted successfully * 404: * description: Missing Data * 500: * description: Server error */ router.delete("/admin_users/:id",[verifySignature, verifyToken], adminUserController.deleteUser); /** * @swagger * /api/admin_users/{id}/change-password: * put: * summary: Change Admin User Password * description: Allows an Admin user to change their password after verifying the old password. * tags: [Admin Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * description: ID of the admin user * schema: * type: integer * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - old_password * - new_password * - confirm_password * properties: * old_password: * type: string * example: "OldPassword@123" * new_password: * type: string * example: "ExamplePassword123!" * confirm_password: * type: string * example: "ExamplePassword123!" * responses: * 200: * description: Password updated successfully * 400: * description: Validation or password mismatch error * 404: * description: User not found * 500: * description: Internal server error */ router.put("/admin_users/:id/change-password",[verifySignature, verifyToken], adminUserController.changeAdminUserPassword); router.get("/testEmail", establishmentController.testEmail); /** * @swagger * /api/test/submissions-with-products: * post: * summary: Create test submission and submission-products for multiple quarters * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: array * items: * type: object * required: * - year * - establishment_id * - product_id * - data * properties: * year: * type: integer * example: 2022 * establishment_id: * type: integer * example: 2 * product_id: * type: integer * example: 3 * data: * type: array * items: * type: object * required: * - quarter * - qty * - cost * properties: * quarter: * type: string * enum: [Q1, Q2, Q3, Q4] * example: Q1 * qty: * type: number * example: 456573559 * cost: * type: number * example: 40566560717 * example: * - year: 2022 * establishment_id: 2 * product_id: 3 * data: * - quarter: Q1 * qty: 456573559 * cost: 40566560717 * - quarter: Q2 * qty: 8755776 * cost: 7654656 * - quarter: Q3 * qty: 7465465 * cost: 865454 * - quarter: Q4 * qty: 656465465 * cost: 98776 * - year: 2022 * establishment_id: 2 * product_id: 3 * data: * - quarter: Q1 * qty: 456573559 * cost: 40566560717 * - quarter: Q2 * qty: 8755776 * cost: 7654656 * - quarter: Q3 * qty: 7465465 * cost: 865454 * - quarter: Q4 * qty: 656465465 * cost: 98776 * responses: * 201: * description: Submission and products processed successfully * 400: * description: Validation error * 500: * description: Server error */ router.post("/test/submissions-with-products",[verifySignature], testController.createSubmissionWithProducts); /** * @swagger * /api/establishments: * post: * summary: Create a new Establishment with linked user * tags: [Establishments] * security: * - appSignature: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - establishment_code * - factory_name * - email * - establishment_user * properties: * establishment_code: { type: string } * factory_name: { type: string } * permanent_factory_code: { type: string } * industry_code: { type: string } * industry_code_mismatch_remarks: { type: string } * license_number: { type: string } * isic_code: { type: string } * description: { type: string } * establishment_address: { type: string } * establishment_city_town_id: { type: integer, description: "FK from city_towns" } * establishment_emirate_id: { type: integer, description: "FK from emirates" } * establishment_postal_code: { type: string } * establishment_po_box: { type: string } * establishment_makani_number: { type: string } * establishment_contact_person_name: { type: string } * establishment_contact_person_designation: { type: string } * establishment_mobile_number: { type: string } * establishment_contact_email: { type: string } * establishment_website: { type: string } * corporate_same_as_establishment: { type: boolean } * corporate_name: { type: string } * corporate_address: { type: string } * corporate_city_town_id: { type: integer, description: "FK from city_towns" } * corporate_emirate_id: { type: integer, description: "FK from emirates" } * corporate_postal_code: { type: string } * corporate_po_box: { type: string } * corporate_makani_number: { type: string } * corporate_contact_person_name: { type: string } * corporate_contact_person_designation: { type: string } * corporate_mobile_number: { type: string } * corporate_email: { type: string } * corporate_website: { type: string } * emirati_male: { type: integer } * emirati_female: { type: integer } * non_emirati_male: { type: integer } * non_emirati_female: { type: integer } * total_emirati: { type: integer } * total_employees: { type: integer } * ERN: { type: string } * zone: { type: string, description: "Establishment zone (optional)" } * created_by: { type: integer } * establishment_user: * type: object * required: * - name * - email * - password * properties: * name: { type: string } * email: { type: string } * password: * type: string * example: "" * establishment_products: * type: array * items: * type: object * required: * - product_id * properties: * product_id: { type: integer } * created_by: { type: integer } * updated_by: { type: integer } * action_done_by: { type: string } * responses: * 201: * description: Establishment and linked user created successfully * 400: * description: Missing required fields * 500: * description: Server error */ router.post("/establishments",[verifySignature, verifyToken], establishmentController.createEstablishment); /** * @swagger * /api/establishments: * get: * summary: Get all Establishments with pagination, filters, and sorting * tags: [Establishments] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: page * schema: { type: integer, default: 1 } * description: Current page number * - in: query * name: limit * schema: { type: integer, default: 10 } * description: Number of records per page * - in: query * name: search * schema: { type: string } * description: Search by Establishment name, email, or code * - in: query * name: emirate_id * schema: { type: integer } * description: Filter by Emirate ID * - in: query * name: isic_code * schema: { type: string } * description: Filter by ISIC code * - in: query * name: status * schema: { type: string, enum: [active, inactive] } * description: Filter by active/inactive status * - in: query * name: sort_by * schema: { type: string, default: created_at } * description: Column to sort by (e.g. name, created_at) * - in: query * name: sort_order * schema: { type: string, enum: [ASC, DESC], default: DESC } * description: Sorting order * - in: query * name: export * schema: { type: string, enum: [excel] } * description: Set "excel" to download as Excel file * responses: * 200: * description: Fetched establishments successfully * 500: * description: Internal server error */ router.get("/establishments",[verifySignature, verifyToken], establishmentController.getAllEstablishments); /** * @swagger * /api/establishments/{id}: * get: * summary: Get an Establishment by ID * tags: [Establishments] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: Establishment ID * responses: * 200: * description: Establishment details * 404: * description: Establishment not found */ router.get("/establishments/:id",[verifySignature, verifyToken], establishmentController.getEstablishmentById); /** * @swagger * /api/establishments/{id}: * put: * summary: Update an Establishment by ID * tags: [Establishments] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: Establishment ID * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * establishment_code: { type: string } * factory_name: { type: string } * permanent_factory_code: { type: string } * industry_code: { type: string } * industry_code_mismatch_remarks: { type: string } * license_number: { type: string } * isic_code: { type: string } * description: { type: string } * establishment_address: { type: string } * establishment_city_town_id: { type: integer, description: "FK from city_towns" } * establishment_emirate_id: { type: integer, description: "FK from emirates" } * establishment_postal_code: { type: string } * establishment_po_box: { type: string } * establishment_makani_number: { type: string } * establishment_contact_person_name: { type: string } * establishment_contact_person_designation: { type: string } * establishment_mobile_number: { type: string } * establishment_contact_email: { type: string } * establishment_website: { type: string } * corporate_same_as_establishment: { type: boolean } * corporate_name: { type: string } * corporate_address: { type: string } * corporate_city_town_id: { type: integer, description: "FK from city_towns" } * corporate_emirate_id: { type: integer, description: "FK from emirates" } * corporate_postal_code: { type: string } * corporate_po_box: { type: string } * corporate_makani_number: { type: string } * corporate_contact_person_name: { type: string } * corporate_contact_person_designation: { type: string } * corporate_mobile_number: { type: string } * corporate_email: { type: string } * corporate_website: { type: string } * emirati_male: { type: integer } * emirati_female: { type: integer } * non_emirati_male: { type: integer } * non_emirati_female: { type: integer } * total_emirati: { type: integer } * total_employees: { type: integer } * ERN: { type: string } * zone: { type: string, description: "Establishment zone (optional)" } * updated_by: { type: integer } * establishment_products: * type: array * items: * type: object * required: * - product_id * properties: * product_id: { type: integer } * created_by: { type: integer } * updated_by: { type: integer } * action_done_by: { type: string } * responses: * 200: * description: Establishment updated successfully * 400: * description: Invalid data * 404: * description: Establishment not found */ router.put("/establishments/:id",[verifySignature, verifyToken], establishmentController.updateEstablishment); /** * @swagger * /api/establishments/{id}: * delete: * summary: Delete an Establishment by ID * tags: [Establishments] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: Establishment ID * responses: * 200: * description: Establishment deleted successfully * 404: * description: Establishment not found */ router.delete("/establishments/:id",[verifySignature, verifyToken], establishmentController.deleteEstablishment); /** * @swagger * /api/establishments/uploadCSV: * post: * summary: Upload Establishment data in bulk using CSV file * description: This API accepts CSV file and inserts multiple Establishment in bulk. CSV header columns must match Establishment table columns. * tags: [Establishments] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * multipart/form-data: * schema: * type: object * properties: * file: * type: string * format: binary * description: CSV file to upload * responses: * 200: * description: Customer Profiles inserted successfully. * 400: * description: No file uploaded * 500: * description: Server error */ router.post("/establishments/uploadCSV",[verifySignature, verifyToken, upload.single("file")], establishmentController.establishmentBulkUpload); /** * @swagger * /api/searchIsicMaster: * get: * summary: Get all Isic Master data * tags: [Establishments] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: code * schema: { type: string } * - in: query * name: description * schema: { type: string } * responses: * 200: * description: Fetched successfully * 500: * description: Internal server error */ router.get("/searchIsicMaster",[verifySignature, verifyToken], establishmentController.searchIsicMaster); /** * @swagger * /api/establishment-users: * post: * summary: Create a new Establishment User * tags: [Establishment Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - establishment_id * - name * - email * - password * properties: * establishment_id: * type: integer * example: 1 * name: * type: string * example: Gem Watson * email: * type: string * example: gem@alpha.com * password: * type: string * example: "" * gender: * type: string * example: male * is_active: * type: boolean * example: true * responses: * 201: * description: Establishment User created successfully * 400: * description: Missing or invalid fields * 500: * description: Server error */ router.post("/establishment-users",[verifySignature, verifyToken], establishmentUserController.createUser); /** * @swagger * /api/establishment-users: * get: * summary: Get all Establishment Users * tags: [Establishment Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: establishment_id * schema: * type: integer * required: false * description: Filter products by establishment ID * example: 1 * responses: * 200: * description: List of establishment users */ router.get("/establishment-users",[verifySignature, verifyToken], establishmentUserController.getAllUsers); /** * @swagger * /api/establishment-users/{id}: * get: * summary: Get an Establishment User by ID * tags: [Establishment Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: Establishment User ID * responses: * 200: * description: Establishment User details * 404: * description: User not found */ router.get("/establishment-users/:id",[verifySignature, verifyToken], establishmentUserController.getUserById); /** * @swagger * /api/establishment-users/{id}: * put: * summary: Update an Establishment User * tags: [Establishment Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: Establishment User ID * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * name: * type: string * example: Gem Watson Updated * email: * type: string * example: gem.updated@alpha.com * password: * type: string * example: "" * gender: * type: string * example: male * is_active: * type: boolean * example: true * responses: * 200: * description: Establishment User updated successfully * 400: * description: Invalid data * 404: * description: User not found */ router.put("/establishment-users/:id",[verifySignature, verifyToken], establishmentUserController.updateUser); /** * @swagger * /api/establishment-users/{id}/change-password: * put: * summary: Change Establishment User Password * description: Allows an establishment user to change their password after verifying the old password. * tags: [Establishment Users] * security: * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * description: ID of the establishment user * schema: * type: integer * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - old_password * - new_password * - confirm_password * properties: * old_password: * type: string * example: "OldPassword@123" * new_password: * type: string * example: "ExamplePassword123!" * confirm_password: * type: string * example: "ExamplePassword123!" * responses: * 200: * description: Password updated successfully * 400: * description: Validation or password mismatch error * 404: * description: User not found * 500: * description: Internal server error */ router.put("/establishment-users/:id/change-password",[verifySignature, verifyToken], establishmentUserController.changeUserPassword); /** * @swagger * /api/establishment-users/{id}: * delete: * summary: Delete an Establishment User * tags: [Establishment Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: Establishment User ID * responses: * 200: * description: Establishment User deleted successfully * 404: * description: User not found */ router.delete("/establishment-users/:id",[verifySignature, verifyToken], establishmentUserController.deleteUser); /** * @swagger * /api/trigger-establishment-users-welcome-email: * post: * summary: Sending Establishment User Welcome Email * tags: [Establishment Users] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - establishment_id * properties: * establishment_id: * type: integer * example: 1 * responses: * 200: * description: Email send success * 400: * description: Missing or invalid fields * 500: * description: Server error */ router.post("/trigger-establishment-users-welcome-email",[verifySignature, verifyToken], establishmentUserController.triggerEstablishmentUsersWelcomeEmail); /** * @swagger * /api/products: * post: * summary: Create a new Product * tags: [Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * required: [product_name] * properties: * product_name: * type: string * example: "Laptop" * hs_code: * type: string * example: "8471.30" * hs_description: * type: string * example: "Portable automatic data processing machines" * unit_id: * type: integer * example: "select data from unit master" * weight_in_ib: * type: number * description: Optional weight used in IPI weighting (decimal, DECIMAL(18,10) in DB). * example: 100.655214 * is_active: * type: boolean * example: true * responses: * 201: * description: Product created successfully */ router.post("/products",[verifySignature, verifyToken], productController.createProduct); /** * @swagger * /api/products: * get: * summary: Get all Products * tags: [Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: List of products */ router.get("/products",[verifySignature, verifyToken], productController.getAllProducts); /** * @swagger * /api/products/{id}: * get: * summary: Get Product by ID * tags: [Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * responses: * 200: * description: Product found * 404: * description: Product not found */ router.get("/products/:id", [verifySignature, verifyToken],productController.getProductById); /** * @swagger * /api/products/{id}: * put: * summary: Update a Product * tags: [Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * requestBody: * content: * application/json: * schema: * type: object * properties: * product_name: * type: string * example: "Laptop" * hs_code: * type: string * example: "8471.30" * hs_description: * type: string * example: "Portable automatic data processing machines" * unit_id: * type: integer * example: "select data from unit master" * weight_in_ib: * type: number * description: Optional weight used in IPI weighting (decimal). Omit to leave unchanged; send null to clear. * example: 100.655214 * is_active: * type: boolean * example: true * responses: * 200: * description: Product updated successfully * 404: * description: Product not found */ router.put("/products/:id",[verifySignature, verifyToken], productController.updateProduct); /** * @swagger * /api/products/{id}: * delete: * summary: Delete a Product * tags: [Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * responses: * 200: * description: Product deleted successfully * 404: * description: Product not found */ router.delete("/products/:id",[verifySignature, verifyToken], productController.deleteProduct); /** * @swagger * /api/products/uploadCSV: * post: * summary: Upload products in bulk using CSV file * description: This API accepts CSV file and inserts multiple products in bulk. CSV header columns must match Product table columns. * tags: [Products] * security: * - bearerAuth: [] * appSignature: [] * requestBody: * required: true * content: * multipart/form-data: * schema: * type: object * required: * - file * properties: * file: * type: string * format: binary * description: CSV file — form field name must be "file" * responses: * 201: * description: Products uploaded successfully * 400: * description: Missing file, wrong form field, or validation error * 403: * description: Missing or invalid APP_SIGNATURE or auth token * 500: * description: Server error */ router.post( "/products/uploadCSV", [verifySignature, verifyToken, handleCsvUpload], productController.uploadProductsFromCSV ); /** * @swagger * /api/download-sample-product-upload-file: * get: * summary: Download sample CSV template for bulk product upload * tags: [Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: Sample CSV file downloaded successfully * content: * text/csv: * schema: * type: string * format: binary * 404: * description: File not found * 500: * description: Server error */ router.get("/download-sample-product-upload-file",[verifySignature, verifyToken], productController.downloadProductSample); /** * @swagger * /api/establishment-products: * post: * summary: Create a new EstablishmentProduct (link establishment with product) * tags: [Establishment Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - establishment_id * - product_id * properties: * establishment_id: * type: integer * example: 1 * product_id: * type: integer * example: 10 * action_done_by: * type: string * example: admin_users * created_by: * type: integer * example: 1 * responses: * 201: * description: EstablishmentProduct created successfully * 400: * description: Missing or invalid fields * 500: * description: Server error */ router.post("/establishment-products",[verifySignature, verifyToken], establishmentProductController.createEstablishmentProduct); /** * @swagger * /api/establishment-products: * get: * summary: Get all EstablishmentProducts * tags: [Establishment Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: establishment_id * schema: * type: integer * required: false * description: Filter products by establishment ID * example: 1 * responses: * 200: * description: List of establishment-product links * 500: * description: Server error */ router.get("/establishment-products",[verifySignature, verifyToken], establishmentProductController.getAllEstablishmentProducts); /** * @swagger * /api/establishment-products/{id}: * get: * summary: Get an EstablishmentProduct by ID * tags: [Establishment Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: EstablishmentProduct ID * responses: * 200: * description: EstablishmentProduct details * 404: * description: Record not found * 500: * description: Server error */ router.get("/establishment-products/:id",[verifySignature, verifyToken], establishmentProductController.getEstablishmentProductById); /** * @swagger * /api/establishment-products/{id}: * put: * summary: Update an EstablishmentProduct by ID * tags: [Establishment Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: EstablishmentProduct ID * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * establishment_id: * type: integer * example: 1 * product_id: * type: integer * example: 10 * action_done_by: * type: string * example: admin_users * updated_by: * type: integer * example: 1 * responses: * 200: * description: Record updated successfully * 400: * description: Invalid data * 404: * description: Record not found * 500: * description: Server error */ router.put("/establishment-products/:id",[verifySignature, verifyToken], establishmentProductController.updateEstablishmentProduct); /** * @swagger * /api/establishment-products/{id}: * delete: * summary: Delete an EstablishmentProduct by ID * tags: [Establishment Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * description: EstablishmentProduct ID * responses: * 200: * description: Record deleted successfully * 404: * description: Record not found * 500: * description: Server error */ router.delete("/establishment-products/:id",[verifySignature, verifyToken], establishmentProductController.deleteEstablishmentProduct); /** * @swagger * /api/variation_reasons: * post: * summary: Create a new variation reason * tags: [Variation Reason Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * required: [reason] * properties: * reason: * type: string * example: "Unexpected delay" * high_or_low: * type: string * example: "High" * responses: * 201: * description: Reason created successfully */ router.post("/variation_reasons",[verifySignature, verifyToken], variationReasonMasterController.createReason); /** * @swagger * /api/variation_reasons: * get: * summary: Get all variation reasons * tags: [Variation Reason Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: List of reasons */ router.get("/variation_reasons",[verifySignature, verifyToken], variationReasonMasterController.getAllReasons); /** * @swagger * /api/variation_reasons/{id}: * get: * summary: Get a reason by ID * tags: [Variation Reason Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * schema: * type: integer * required: true * description: Reason ID * responses: * 200: * description: Reason fetched successfully * 404: * description: Reason not found */ router.get("/variation_reasons/:id",[verifySignature, verifyToken], variationReasonMasterController.getReasonById); /** * @swagger * /api/variation_reasons/{id}: * put: * summary: Update a variation reason * tags: [Variation Reason Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * schema: * type: integer * required: true * description: Reason ID * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * reason: * type: string * example: "Price fluctuation" * high_or_low: * type: string * example: "Low" * is_active: * type: boolean * example: true * responses: * 200: * description: Updated successfully * 404: * description: Reason not found */ router.put("/variation_reasons/:id",[verifySignature, verifyToken], variationReasonMasterController.updateReason); /** * @swagger * /api/variation_reasons/{id}: * delete: * summary: Delete a variation reason * tags: [Variation Reason Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * schema: * type: integer * required: true * description: Reason ID * responses: * 200: * description: Deleted successfully * 404: * description: Reason not found */ router.delete("/variation_reasons/:id",[verifySignature, verifyToken], variationReasonMasterController.deleteReason); /** * @swagger * /api/zero_target_reason: * get: * summary: Get all zero target reasons * tags: [Zero Target Reasons] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: List of reasons */ router.get("/zero_target_reason/",[verifySignature, verifyToken], zeroTargetReasonMasterController.getAll); /** * @swagger * /api/zero_target_reason/{id}: * get: * summary: Get zero target reason by ID * tags: [Zero Target Reasons] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * schema: * type: integer * responses: * 200: * description: Reason found */ router.get("/zero_target_reason/:id",[verifySignature, verifyToken], zeroTargetReasonMasterController.getById); /** * @swagger * /api/zero_target_reason: * post: * summary: Create a new zero target reason * tags: [Zero Target Reasons] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * reason: * type: string * is_active: * type: boolean * responses: * 201: * description: Created successfully */ router.post("/zero_target_reason/",[verifySignature, verifyToken], zeroTargetReasonMasterController.create); /** * @swagger * /api/zero_target_reason/{id}: * put: * summary: Update zero target reason * tags: [Zero Target Reasons] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * reason: * type: string * is_active: * type: boolean * responses: * 200: * description: Updated successfully */ router.put("/zero_target_reason/:id",[verifySignature, verifyToken], zeroTargetReasonMasterController.update); /** * @swagger * /api/zero_target_reason/{id}: * delete: * summary: Delete zero target reason * tags: [Zero Target Reasons] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * responses: * 200: * description: Deleted successfully */ router.delete("/zero_target_reason/:id",[verifySignature, verifyToken], zeroTargetReasonMasterController.delete); /** * @swagger * /api/unit_master: * get: * summary: Get all units * tags: [Unit Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: List of units */ router.get("/unit_master",[verifySignature, verifyToken], unitMasterController.getAllUnits); /** * @swagger * /api/unit_master/{id}: * get: * summary: Get unit by ID * tags: [Unit Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * responses: * 200: * description: Unit details */ router.get("/unit_master/:id",[verifySignature, verifyToken], unitMasterController.getUnitById); /** * @swagger * /api/unit_master: * post: * summary: Create a new unit * tags: [Unit Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * uom: { type: string } * is_base_unit: { type : boolean } * base_unit_id: { type : integer } * factor: { type : string } * description: { type : string } * responses: * 201: * description: Unit created successfully */ router.post("/unit_master",[verifySignature, verifyToken], unitMasterController.createUnit); /** * @swagger * /api/unit_master/{id}: * put: * summary: Update a unit * tags: [Unit Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * uom: { type: string } * uom_short_name: { type: string } * is_base_unit: { type : boolean } * base_unit_id: { type : integer } * factor: { type : string } * description: { type : string } * is_active: { type : boolean } * responses: * 200: * description: Unit updated successfully */ router.put("/unit_master/:id",[verifySignature, verifyToken], unitMasterController.updateUnit); /** * @swagger * /api/unit_master/{id}: * delete: * summary: Delete a unit * tags: [Unit Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: path * name: id * required: true * schema: * type: integer * responses: * 200: * description: Unit deleted successfully */ router.delete("/unit_master/:id",[verifySignature, verifyToken], unitMasterController.deleteUnit); /** * @swagger * /api/unit_master/uploadCSV: * post: * summary: Upload products in bulk using CSV file * description: This API accepts CSV file and inserts multiple products in bulk. CSV header columns must match Product table columns. * tags: [Unit Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * multipart/form-data: * schema: * type: object * properties: * file: * type: string * format: binary * description: CSV file to upload * responses: * 201: * description: Unit Master file uploaded successfully * 400: * description: No file uploaded * 500: * description: Server error */ router.post("/unit_master/uploadCSV",[ verifySignature, verifyToken, upload.single("file")], unitMasterController.uploadUnitMasterFromCSV); /** * @swagger * /api/submissions: * post: * summary: Create submission with up to 10 products * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * establishment_id: { type: integer } * quarter: { type: string, enum: [Q1, Q2, Q3, Q4] } * year: { type: integer } * emirati_male: { type: integer } * emirati_female: { type: integer } * non_emirati_male: { type: integer } * non_emirati_female: { type: integer } * total_emirati: { type: integer } * total_employees: { type: integer } * created_by: { type: integer } * products: * type: array * items: * type: object * properties: * product_id: { type: integer } * unit_id: { type: integer } * annual_installed_capacity: { type: string } * previous_quantity_period_one: { type: string } * previous_quantity_period_two: { type: string } * previous_quantity_period_three: { type: string } * previous_cost_period_one: { type: string } * previous_cost_period_two: { type: string } * previous_cost_period_three: { type: string } * current_quantity_period_one: { type: string } * current_quantity_period_two: { type: string } * current_quantity_period_three: { type: string } * current_cost_period_one: { type: string } * current_cost_period_two: { type: string } * current_cost_period_three: { type: string } * forecast_quantity_period_one: { type: string } * forecast_quantity_period_two: { type: string } * forecast_quantity_period_three: { type: string } * forecast_cost_period_one: { type: string } * forecast_cost_period_two: { type: string } * forecast_cost_period_three: { type: string } * previous_quantity: { type: string } * previous_cost: { type: string } * current_quantity: { type: string } * current_cost: { type: string } * forecast_quantity: { type: string } * forecast_cost: { type: string } * variation_reason_master_id: { type: string } * other_variation_reason: { type: string } * zero_target_reason_master_id: { type: string } * other_zero_target_reason: { type: string } * remarks: { type: string } * responses: * 201: * description: Submission created */ router.post("/submissions",[verifySignature, verifyToken], submissionController.createSubmission); /** * @swagger * /api/submissions/{id}: * put: * summary: Update submission with products * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * establishment_id: { type: integer } * quarter: { type: string, enum: [Q1, Q2, Q3, Q4] } * year: { type: integer } * emirati_male: { type: integer } * emirati_female: { type: integer } * non_emirati_male: { type: integer } * non_emirati_female: { type: integer } * total_emirati: { type: integer } * total_employees: { type: integer } * updated_by: { type: integer } * products: * type: array * items: * type: object * properties: * id: { type: integer } * product_id: { type: integer } * unit_id: { type: integer } * annual_installed_capacity: { type: string } * previous_quantity_period_one: { type: string } * previous_quantity_period_two: { type: string } * previous_quantity_period_three: { type: string } * previous_cost_period_one: { type: string } * previous_cost_period_two: { type: string } * previous_cost_period_three: { type: string } * current_quantity_period_one: { type: string } * current_quantity_period_two: { type: string } * current_quantity_period_three: { type: string } * current_cost_period_one: { type: string } * current_cost_period_two: { type: string } * current_cost_period_three: { type: string } * forecast_quantity_period_one: { type: string } * forecast_quantity_period_two: { type: string } * forecast_quantity_period_three: { type: string } * forecast_cost_period_one: { type: string } * forecast_cost_period_two: { type: string } * forecast_cost_period_three: { type: string } * previous_quantity: { type: string } * previous_cost: { type: string } * current_quantity: { type: string } * current_cost: { type: string } * forecast_quantity: { type: string } * forecast_cost: { type: string } * variation_reason_master_id: { type: string } * other_variation_reason: { type: string } * zero_target_reason_master_id: { type: string } * other_zero_target_reason: { type: string } * remarks: { type: string } * responses: * 200: * description: Updated successfully */ router.put("/submissions/:id",[verifySignature, verifyToken], submissionController.updateSubmission); /** * @swagger * /api/submissions/history/{establishment_id}: * get: * summary: Get submission history for establishment * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: establishment_id * in: path * required: true * responses: * 200: * description: History list */ router.get("/submissions/history/:establishment_id",[verifySignature, verifyToken], submissionController.submissionHistory); /** * @swagger * /api/submissions: * get: * summary: Get submissions list with pagination, filters, search, and export * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * 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: Submission list retrieved successfully * 500: * description: Server error */ router.get("/submissions",[verifySignature, verifyToken], submissionController.submissionList); /** * @swagger * /api/exports/annex-ii: * get: * summary: Export Annex II establishment quarterly data (quantity and value) * tags: [Exports] * security: * - appSignature: [] * - bearerAuth: [] * parameters: * - in: query * name: years * schema: { type: string, example: "2022,2025,2026" } * description: Comma-separated years to include (defaults to all years with data) * - in: query * name: status * schema: { type: string, example: "Approved" } * description: Comma-separated submission statuses (default Approved,Submitted,Resubmitted) * - in: query * name: emirate_id * schema: { type: integer } * - in: query * name: establishment_id * schema: { type: integer } * responses: * 200: * description: Excel file download * 404: * description: No data found */ router.get( "/exports/annex-ii", [verifySignature, verifyToken], exportController.exportAnnexII ); /** * @swagger * /api/exports/annex-iii-quantity: * get: * summary: Export Annex III item-level quantity data * tags: [Exports] * security: * - appSignature: [] * - bearerAuth: [] * parameters: * - in: query * name: years * schema: { type: string, example: "2022,2025" } * - in: query * name: status * schema: { type: string, example: "Approved" } * - in: query * name: emirate_id * schema: { type: integer } * - in: query * name: establishment_id * schema: { type: integer } * responses: * 200: * description: Excel file download */ router.get( "/exports/annex-iii-quantity", [verifySignature, verifyToken], exportController.exportAnnexIIIQuantity ); /** * @swagger * /api/exports/annex-iii-values: * get: * summary: Export Annex III item-level value (cost) data * tags: [Exports] * security: * - appSignature: [] * - bearerAuth: [] * parameters: * - in: query * name: years * schema: { type: string, example: "2022,2025" } * - in: query * name: status * schema: { type: string, example: "Approved" } * - in: query * name: emirate_id * schema: { type: integer } * - in: query * name: establishment_id * schema: { type: integer } * responses: * 200: * description: Excel file download */ router.get( "/exports/annex-iii-values", [verifySignature, verifyToken], exportController.exportAnnexIIIValues ); /** * @swagger * /api/submissions/view/{id}: * get: * summary: Get submission details by ID or by (establishment_id, year, quarter) * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: false * description: Submission ID (optional if using query combination) * schema: * type: integer * - name: establishment_id * in: query * required: false * schema: * type: integer * - name: year * in: query * required: false * schema: * type: integer * - name: quarter * in: query * required: false * schema: * type: string * responses: * 200: * description: Submission details retrieved successfully * 404: * description: Submission not found * 500: * description: Server error */ router.get("/submissions/view/:id",[verifySignature, verifyToken], submissionController.viewSubmissionDetails); /** * @swagger * /api/submissionEditRequest/{id}: * put: * summary: Update request for submission products * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * edit_request: { type: integer } * responses: * 200: * description: Updated successfully */ router.put("/submissionEditRequest/:id",[verifySignature, verifyToken], submissionController.submissionEditRequest); /** * @swagger * /api/enableOrDisableSubmissionEditAccess/{id}: * put: * summary: Allow or deny the edit request of submission products * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * edit_access: * type: integer * description: 1 for Enable, 0 for Disable * responses: * 200: * description: Updated successfully */ router.put("/enableOrDisableSubmissionEditAccess/:id",[verifySignature, verifyToken], submissionController.enableOrDisableSubmissionEditAccess); /** * @swagger * /api/approveOrRejectSubmission/{id}: * put: * summary: Approve or Reject the submission * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * approve_reject_status: * type: integer * description: 1 for Approve, 2 for Reject * reject_reason: * type: string * description: rejection reason * approve_or_reject_by: * type: integer * description: logged admin user primary id * responses: * 200: * description: Updated successfully */ router.put("/approveOrRejectSubmission/:id",[verifySignature, verifyToken], submissionController.approveOrRejectSubmission); /** * @swagger * /api/getQuarterPeriods: * post: * summary: get Quarter Periods based on current quarter and year * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * current_year: { type: integer } * current_quarter: { type: string } * responses: * 200: * description: Updated successfully */ router.post("/getQuarterPeriods",[verifySignature, verifyToken], submissionController.getQuarterPeriods); /** * @swagger * /api/submissions/getPreviousForecastData: * get: * summary: Get Previous and Forecast Data based on Establishment + Quarter + Year + Product * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: establishment_id * required: true * schema: { type: integer } * - in: query * name: quarter * required: true * schema: { type: string, enum: [Q1, Q2, Q3, Q4] } * - in: query * name: year * required: true * schema: { type: integer } * - in: query * name: product_id * required: true * schema: { type: integer } * responses: * 200: * description: Previous forecast data fetched successfully * 404: * description: Not found * 500: * description: Server error */ router.get("/submissions/getPreviousForecastData",[verifySignature, verifyToken], submissionController.getPreviousForecastData); /** * @swagger * /api/submissions/getBeforePreviousData: * get: * summary: compute the quarter two steps before (before-previous) based on Establishment + current_quarter + current_year + Product * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: establishment_id * required: true * schema: { type: integer } * - in: query * name: current_quarter * required: true * schema: { type: string, enum: [Q1, Q2, Q3, Q4] } * - in: query * name: current_year * required: true * schema: { type: integer } * - in: query * name: product_id * required: true * schema: { type: integer } * responses: * 200: * description: Previous forecast data fetched successfully * 404: * description: Not found * 500: * description: Server error */ router.get("/submissions/getBeforePreviousData",[verifySignature, verifyToken], submissionController.getBeforePreviousData); /** * @swagger * /api/submissions/getProductSubmissionHistory: * get: * summary: Get Product submission history data based on Establishment + Product * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: establishment_id * required: true * schema: { type: integer } * - in: query * name: product_id * required: true * schema: { type: integer } * responses: * 200: * description: Product submission history data fetched successfully * 404: * description: Not found * 500: * description: Server error */ router.get("/submissions/getProductSubmissionHistory",[verifySignature, verifyToken], submissionController.getProductSubmissionHistory); /** * @swagger * /api/submission-audit-history: * get: * summary: Get submission product update history (merged view) * description: Returns submission history with submission + product level change history merged. If no filters passed → returns entire history list. * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: establishment_id * schema: * type: integer * required: true * description: Filter by establishment_id * - in: query * name: year * schema: * type: integer * required: false * description: Filter by year * - in: query * name: quarter * schema: * type: string * enum: [Q1, Q2, Q3, Q4] * required: false * description: Filter by quarter * - in: query * name: product_id * schema: * type: integer * required: false * description: Filter by product_id * responses: * 200: * description: Merged submission history list retrieved successfully * 500: * description: Server error */ router.get("/submission-audit-history",[verifySignature, verifyToken], submissionController.getSubmissionHistory); /** * @swagger * /api/submissions/deleteDraftSubmissionData: * get: * summary: Delete submission (hard delete) * tags: [Submissions] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: id * required: true * schema: { type: integer } * responses: * 200: * description: successfully Deleted * 404: * description: Not found * 500: * description: Server error */ router.get("/submissions/deleteDraftSubmissionData",[verifySignature, verifyToken], submissionController.deleteDraftSubmissionData); /** * @swagger * /api/submission_deadlines: * post: * summary: Create or update submission deadline configuration (only one record allowed) * tags: [Config] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * 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] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * 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",[verifySignature, verifyToken],dashboardController.getEstablishmentDashboard); /** * @swagger * /api/admin_dashboard: * get: * summary: Get dashboard data for admin user * tags: [Dashboard] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: quarter * required: false * schema: * type: string * - in: query * name: year * required: false * 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); /** * @swagger * /api/notification_templates: * get: * summary: Get all notification templates * tags: [Notification Templates] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: Fetched successfully */ router.get("/notification_templates",[verifySignature, verifyToken], notificationTemplateController.getAllTemplates); /** * @swagger * /api/notification_templates/{id}: * get: * summary: Get a single notification template * tags: [Notification Templates] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * responses: * 200: * description: Fetched successfully */ router.get("/notification_templates/:id",[verifySignature, verifyToken], notificationTemplateController.getTemplateById); /** * @swagger * /api/notification_templates/{id}: * put: * summary: Update a notification template * tags: [Notification Templates] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * title: { type: string } * subject: { type: string } * body_html: { type: string } * placeholders: { type: array, items: { type: string } } * responses: * 200: * description: Updated successfully */ router.put("/notification_templates/:id",[verifySignature, verifyToken], notificationTemplateController.updateTemplate); /** * @swagger * /api/quarterly_windows: * post: * summary: Create new quarterly configuration * tags: [Quarterly Windows Configuration] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * survey_name: { type: string, example: "Test"} * year: { type: integer } * quarter: { type: string, example: "Q1" } * start_date: { type: string, format: date } * end_date: { type: string, format: date } * grace_periods_days: { type: integer } * is_active: { type: boolean } * responses: * 201: * description: Created successfully */ router.post("/quarterly_windows",[verifySignature, verifyToken], quarterlyWindowsController.createConfig); /** * @swagger * /api/quarterly_windows: * get: * summary: Get all quarterly configurations * tags: [Quarterly Windows Configuration] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: Fetched successfully */ router.get("/quarterly_windows",[verifySignature, verifyToken], quarterlyWindowsController.getAllConfigs); /** * @swagger * /api/quarterly_windows/{id}: * get: * summary: Get configuration by ID * tags: [Quarterly Windows Configuration] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * responses: * 200: * description: Fetched successfully */ router.get("/quarterly_windows/:id",[verifySignature, verifyToken], quarterlyWindowsController.getConfigById); /** * @swagger * /api/quarterly_windows/{id}: * put: * summary: Update configuration by ID * tags: [Quarterly Windows Configuration] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - name: id * in: path * required: true * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * survey_name: { type: string, example: "Test"} * year: { type: integer } * quarter: { type: string, example: "Q1" } * start_date: { type: string, format: date } * end_date: { type: string, format: date } * grace_periods_days: { type: integer } * is_active: { type: boolean } * responses: * 200: * description: Updated successfully */ router.put("/quarterly_windows/:id",[verifySignature, verifyToken], quarterlyWindowsController.updateConfig); /** * @swagger * /api/password-reset-requests: * get: * summary: Get all establishment password reset requests * tags: [Establishment Reset Requests] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] * responses: * 200: * description: List of all reset requests * 500: * description: Internal server error */ router.get("/password-reset-requests", establishmentController.getAllRequests); /** * @swagger * /api/password-reset-requests: * post: * summary: Create a new establishment reset request * tags: [Establishment Reset Requests] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - establishment_name * - establishment_code * - registered_email * properties: * establishment_name: * type: string * example: "ABC Industries" * establishment_code: * type: string * example: "EST1234" * registered_email: * type: string * example: "contact@abcindustries.com" * contact_person_name: * type: string * example: "John Doe" * contact_phone: * type: string * example: "+971501234567" * additional_notes: * type: string * example: "Forgot credentials and need account reset." * responses: * 201: * description: Reset request created successfully * 400: * description: Validation failed or mismatch between establishment and email * 404: * description: Establishment or user not found * 500: * description: Internal server error */ router.post("/password-reset-requests", establishmentController.createRequest); /** * @swagger * /api/forgot-password/request-otp: * post: * summary: Request OTP for establishment user pwd reset * tags: [Establishment Pwd Reset Requests] * security: * - appSignature: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - establishment_name * - establishment_code * - registered_email * properties: * establishment_name: { type: string, example: "ABC Industries" } * establishment_code: { type: string, example: "EST1234" } * registered_email: { type: string, example: "contact@abcindustries.com" } * user_type: {type: string, example: "establishment_user"} * responses: * 200: * description: OTP sent successfully * 400: * description: Missing or invalid data * 404: * description: Establishment or user not found * 500: * description: Server error */ router.post("/forgot-password/request-otp",[verifySignature], establishmentController.forgotPasswordRequestOTP); /** * @swagger * /api/forgot-password/verify-otp: * post: * summary: Verify OTP and reset establishment user Pwd * tags: [Establishment Pwd Reset Requests] * security: * - appSignature: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - registered_email * - otp * - password * - confirm_password * properties: * registered_email: { type: string, example: "contact@abcindustries.com" } * otp: { type: string, example: "123456" } * password: { type: string, example: "" } * confirm_password: { type: string, example: "" } * responses: * 200: * description: Password reset successfully * 400: * description: Invalid OTP or password mismatch * 404: * description: User or OTP not found * 500: * description: Server error */ router.post("/forgot-password/verify-otp",[verifySignature], establishmentController.forgotPasswordVerifyOTP); /** * @swagger * /api/emirates: * get: * summary: Get all Emirates * tags: [Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: Emirates fetched successfully * 500: * description: Server error */ router.get("/emirates", [verifySignature, verifyToken], establishmentController.getAllEmirates); /** * @swagger * /api/city-towns: * get: * summary: Get all City/Town (optional filter by emirate_id) * tags: [Master] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: emirate_id * schema: * type: integer * description: Filter cities by emirate_id * responses: * 200: * description: City/Town fetched successfully * 500: * description: Server error */ router.get("/city-towns", [verifySignature, verifyToken], establishmentController.getAllCityTowns); /** * @swagger * /api/establishment/download-sample-file: * get: * summary: Download sample CSV template for bulk company profile upload * tags: [Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: Sample CSV file downloaded successfully * content: * text/csv: * schema: * type: string * format: binary * 404: * description: File not found * 500: * description: Server error */ router.get("/establishment/download-sample-file",[verifySignature, verifyToken], establishmentController.downloadCompanyProfileSample); /** * @swagger * /api/unit_master_download_sample_file: * get: * summary: Download sample CSV template for bulk Unit Master upload * tags: [Products] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: Sample CSV file downloaded successfully * content: * text/csv: * schema: * type: string * format: binary * 404: * description: File not found * 500: * description: Server error */ router.get("/unit_master_download_sample_file",[verifySignature, verifyToken], unitMasterController.downloadUnitMasterFile); /** * @swagger * /api/manufacturing/getManufacturingIndex: * get: * summary: Get all Manufacturing IPI Index list * tags: [ManufacturingIPI] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * responses: * 200: * description: ManufacturingIpi Index details fetched successfully * 404: * description: Not found * 500: * description: Server error */ router.get("/manufacturing/getManufacturingIndex",[verifySignature, verifyToken], ManufacturingIpiController.getAllManufacturingIndexDetails); /** * @swagger * /api/manufacturing/getManufacturingMonthlyOverview: * get: * summary: Get Manufacturing IPI Overview by year and quarter * tags: [ManufacturingIPI] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] # or bearerAuth: [] if you use Authorization header * parameters: * - in: query * name: year * required: true * schema: * type: integer * description: Year (e.g., 2025) * - in: query * name: quarter * required: true * schema: * type: string * enum: [Q1, Q2, Q3, Q4] * description: Quarter (Q1-Q4) * responses: * 200: * description: Manufacturing IPI Overview fetched successfully * 400: * description: Invalid parameters * 404: * description: Data not found * 500: * description: Server error */ router.get("/manufacturing/getManufacturingMonthlyOverview", [verifySignature, verifyToken], ManufacturingIpiController.getManufacturingMonthlyOverviewByYearMonth); /** * @swagger * /api/auth/request-otp: * post: * summary: Request OTP for login Admin or Establishment User * tags: [Admin And Establishments User Auth] * security: * - appSignature: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - registered_email * properties: * registered_email: { type: string, example: "contact@abcindustries.com" } * responses: * 200: * description: OTP sent successfully * 400: * description: Missing or invalid data * 404: * description: Establishment or user not found * 500: * description: Server error */ router.post("/auth/request-otp",[verifySignature], establishmentController.requestOTPForLogin); /** * @swagger * /api/auth/verify-otp: * post: * summary: Verify OTP to signin * tags: [Admin And Establishments User Auth] * security: * - appSignature: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - registered_email * - otp * properties: * registered_email: { type: string, example: "contact@abcindustries.com" } * otp: { type: string, example: "123456" } * responses: * 200: * description: Otp verified successfully * 400: * description: Invalid OTP * 404: * description: User or OTP not found * 500: * description: Server error */ router.post("/auth/verify-otp",[verifySignature], establishmentController.verifyOTPForLogin); /** * @swagger * /api/calculation-log/getCalculationLogs: * get: * summary: Get calculation logs by reference year and month * tags: [CalculationLog] * security: * - appSignature: [] * - CSRF: [] * cookieAuth: [] * parameters: * - in: query * name: year * required: true * schema: * type: integer * example: 2025 * description: Reference year * - in: query * name: month * required: true * schema: * type: integer * example: 4 * description: Reference month (1-12) * responses: * 200: * description: Calculation log details fetched successfully * 400: * description: Year and month are required * 404: * description: No records found * 500: * description: Server error */ router.get( "/calculation-log/getCalculationLogs", [verifySignature, verifyToken], calculationController.getCalculationLogsByYearMonth); module.exports = router;