diff --git a/app/controllers/auth.controller.js b/app/controllers/auth.controller.js index 5088191..ecff636 100644 --- a/app/controllers/auth.controller.js +++ b/app/controllers/auth.controller.js @@ -2,6 +2,7 @@ const db = require("../models"); const bcrypt = require("bcryptjs"); const jwt = require("jsonwebtoken"); require("dotenv").config(); +const sanitize = require("sanitize-html"); const User = db.user; const EstablishmentUser = db.EstablishmentUser; @@ -115,10 +116,18 @@ exports.logout = (req, res) => { }); }; +const sanitizeStringValue = (value) => + typeof value === "string" + ? sanitize(value, { allowedTags: [], allowedAttributes: {} }) + : value; + // Register new user exports.register = async (req, res) => { try { - const { name, email, password } = req.body; + const name = sanitizeStringValue(req.body.name); + const email = sanitizeStringValue(req.body.email); + const password = req.body.password; + if (!name || !email || !password) return res.status(400).send({ status: "error", @@ -141,8 +150,7 @@ exports.register = async (req, res) => { return res.status(201).send({ status: "ok", code: "REGISTERED", - message: "User registered successfully", - data: newUser + message: "User registered successfully" }); } catch (err) { diff --git a/app/controllers/establishment.controller.js b/app/controllers/establishment.controller.js index f10e08d..0c6ae81 100644 --- a/app/controllers/establishment.controller.js +++ b/app/controllers/establishment.controller.js @@ -19,6 +19,12 @@ const path = require("path"); const { version } = require("os"); const sequelize = db.sequelize; const { sanitizeForLog } = require("../utils/sanitize"); +const sanitize = require("sanitize-html"); + +const sanitizeStringValue = (value) => + typeof value === "string" + ? sanitize(value, { allowedTags: [], allowedAttributes: {} }) + : value; exports.testEmail = async (req, res) => { placeHolderData = { @@ -137,39 +143,39 @@ exports.createEstablishment = async (req, res) => { // Create establishment record const establishment = await Establishment.create({ - establishment_code, - factory_name, - permanent_factory_code: permanent_factory_code || null, - industry_code: industry_code || null, - industry_code_production: industry_code_production || null, - industry_code_mismatch_remarks, - license_number, - isic_code, - description, - establishment_address, + establishment_code: sanitizeStringValue(establishment_code), + factory_name: sanitizeStringValue(factory_name), + permanent_factory_code: sanitizeStringValue(permanent_factory_code), + industry_code: sanitizeStringValue(industry_code), + industry_code_production: sanitizeStringValue(industry_code_production), + industry_code_mismatch_remarks: sanitizeStringValue(industry_code_mismatch_remarks), + license_number: sanitizeStringValue(license_number), + isic_code: sanitizeStringValue(isic_code), + description: sanitizeStringValue(description), + establishment_address: sanitizeStringValue(establishment_address), establishment_city_town_id, establishment_emirate_id, - establishment_postal_code, - establishment_po_box, - establishment_makani_number, - establishment_contact_person_name, - establishment_contact_person_designation, - establishment_mobile_number, - establishment_contact_email, - establishment_website, + establishment_postal_code: sanitizeStringValue(establishment_postal_code), + establishment_po_box: sanitizeStringValue(establishment_po_box), + establishment_makani_number: sanitizeStringValue(establishment_makani_number), + establishment_contact_person_name: sanitizeStringValue(establishment_contact_person_name), + establishment_contact_person_designation: sanitizeStringValue(establishment_contact_person_designation), + establishment_mobile_number: sanitizeStringValue(establishment_mobile_number), + establishment_contact_email: sanitizeStringValue(establishment_contact_email), + establishment_website: sanitizeStringValue(establishment_website), corporate_same_as_establishment, - corporate_name, - corporate_address, + corporate_name: sanitizeStringValue(corporate_name), + corporate_address: sanitizeStringValue(corporate_address), corporate_city_town_id, corporate_emirate_id, - corporate_postal_code, - corporate_po_box, - corporate_makani_number, - corporate_contact_person_name, - corporate_contact_person_designation, - corporate_mobile_number, - corporate_email, - corporate_website, + corporate_postal_code: sanitizeStringValue(corporate_postal_code), + corporate_po_box: sanitizeStringValue(corporate_po_box), + corporate_makani_number: sanitizeStringValue(corporate_makani_number), + corporate_contact_person_name: sanitizeStringValue(corporate_contact_person_name), + corporate_contact_person_designation: sanitizeStringValue(corporate_contact_person_designation), + corporate_mobile_number: sanitizeStringValue(corporate_mobile_number), + corporate_email: sanitizeStringValue(corporate_email), + corporate_website: sanitizeStringValue(corporate_website), emirati_male, emirati_female, non_emirati_male, @@ -179,7 +185,6 @@ exports.createEstablishment = async (req, res) => { created_by: req.body.created_by || req.user.id, created_at: new Date(), }); - // Hash password const hashedPassword = await bcrypt.hash(establishment_user.password, 10); @@ -194,46 +199,15 @@ exports.createEstablishment = async (req, res) => { //send email to user placeHolderData = { - contact_name : sanitizeForLog(establishment_user.name), + contact_name : sanitizeStringValue(establishment_user.name), portal_url : process.env.FE_BASE_URL, - username : sanitizeForLog(establishment_user.email), + username : sanitizeStringValue(establishment_user.email), password : establishment_user.password, support_email : process.env.SUPPORT_EMAIL, support_phone : process.env.SUPPORT_PHONE, } - await sendEmailService(sanitizeForLog(establishment_user.email), 'establishment_user_creation_to_user', placeHolderData); - - // insert establishment_products - // if (Array.isArray(establishment_products) && establishment_products.length > 0) { - - // // remove duplicates from request itself - // let uniqueProducts = [...new Set(establishment_products.map(x => x.product_id))]; - // // now check which already exist for this establishment - // const existing = await EstablishmentProduct.findAll({ - // where: { - // establishment_id: establishment.id, - // product_id: uniqueProducts - // }, - // attributes: ['product_id'] - // }); - - // const existingIds = existing.map(x => x.product_id); - - // // filter only new ones (not existing) - // const newProducts = uniqueProducts - // .filter(pid => !existingIds.includes(pid)) - // .map(pid => ({ - // establishment_id: establishment.id, - // product_id: pid, - // created_at: new Date(), - // })); - - // // only insert if have new ones - // if (newProducts.length) { - // await EstablishmentProduct.bulkCreate(newProducts); - // } - // } + await sendEmailService(sanitizeStringValue(establishment_user.email), 'establishment_user_creation_to_user', placeHolderData); // insert establishment_products if (Array.isArray(establishment_products) && establishment_products.length > 0) @@ -273,14 +247,15 @@ exports.createEstablishment = async (req, res) => { await EstablishmentProduct.bulkCreate(insertData); } } - - //Return success response return res.status(201).send({ status: "success", message: "Establishment and linked user created successfully", - data: { - establishment, + data: { + establishment:{ + id:establishment.id, + establishment_code: establishment.establishment_code, + }, user: { id: user.id, name: user.name, @@ -290,18 +265,14 @@ exports.createEstablishment = async (req, res) => { }); } catch (err) { - if (err.name === "SequelizeUniqueConstraintError") { - - // extract exact field - const field = err.errors[0].path; // <-- this gives the column name + const field = err.errors[0].path; return res.status(400).json({ status: "failed", message: `${field} already exists` }); } - - return res.status(500).send({status: "failed",message: err.message || "Internal server error",}); + return res.status(500).send({status: "failed",message: err.message,}); } }; @@ -807,7 +778,29 @@ exports.getAllEmirates = async (req, res) => { exports.getAllCityTowns = async (req, res) => { try { - const { emirate_id } = req.query; + let { emirate_id } = req.query; + + if (emirate_id) { + + emirate_id = Number(emirate_id); + if (isNaN(emirate_id)) { + return res.status(400).send({ + status: "failed", + message: "Invalid emirate_id" + }); + } + + const emirateExists = await Emirate.findOne({ + where: { id: emirate_id } + }); + + if (!emirateExists) { + return res.status(404).send({ + status: "failed", + message: "Emirate not found" + }); + } + } const whereClause = {}; if (emirate_id) { @@ -819,8 +812,13 @@ exports.getAllCityTowns = async (req, res) => { attributes: ["id", "name", "emirate_id"], order: [["name", "ASC"]], }); + const sanitizedCities = cities.map(city => ({ + id: city.id, + name: sanitizeStringValue(city.name), + emirate_id: city.emirate_id, + })); - return res.status(200).send({status: "success", message: "City/Town fetched successfully", data: cities, }); + return res.status(200).send({status: "success", message: "City/Town fetched successfully", data: sanitizedCities, }); } catch (err) { return res.status(500).send({ status: "failed", message: err.message || "Internal server error", }); diff --git a/app/controllers/establishment_products.controller.js b/app/controllers/establishment_products.controller.js index 4375ba1..c50510d 100644 --- a/app/controllers/establishment_products.controller.js +++ b/app/controllers/establishment_products.controller.js @@ -8,16 +8,69 @@ const UnitMaster = db.UnitMaster; exports.createEstablishmentProduct = async (req, res) => { try { - const { establishment_id , product_id, action_done_by , created_by } = req.body; + let { establishment_id , product_id, action_done_by , created_by } = req.body; + + if (establishment_id === undefined) { + return res.status(400).json({ + status: "failed", + message: "establishment_id is required" + }); + } + establishment_id = Number(establishment_id); + if (!Number.isInteger(establishment_id) || establishment_id <= 0) { + return res.status(400).json({ + status: "failed", + message: "Invalid establishment_id" + }); + } + if (product_id === undefined) { + return res.status(400).json({ + status: "failed", + message: "product_id is required" + }); + } + product_id = Number(product_id); + if (!Number.isInteger(product_id) || (product_id <= 0 && product_id > 10)) { + return res.status(400).json({ + status: "failed", + message: "Invalid product_id" + }); + } + if (action_done_by === undefined) { + return res.status(400).json({ + status: "failed", + message: "action_done_by is required" + }); + } + if (typeof action_done_by !== "string" || action_done_by.trim().length === 0) { + return res.status(400).json({ + status: "failed", + message: "Invalid action_done_by" + }); + } + action_done_by = action_done_by.trim(); + + const existingMapping = await EstablishmentProduct.findOne({ + where: { + establishment_id, + product_id + } + }); + + if (existingMapping) { + return res.status(409).json({ + status: "failed", + message: "This product is already mapped to the establishment" + }); + } const data = await EstablishmentProduct.create({ establishment_id, product_id, action_done_by, created_by: created_by || req.user?.id || null, }); - - res.status(201).send({'status':"success",'message':"Creation successful",'data': data }); + res.status(201).send({'status':"success",'message':"Establishment Product Created successfully."}); } catch (err) { res.status(500).send({'status':"failed",'message':err.message }); @@ -28,8 +81,16 @@ exports.getAllEstablishmentProducts = async (req, res) => { try { const whereClause = {}; - if (req.query.establishment_id) { - whereClause.establishment_id = req.query.establishment_id; + if (typeof req.query.establishment_id !== "undefined") { + const establishmentId = parseInt(req.query.establishment_id, 10); + + if (!Number.isInteger(establishmentId) || establishmentId <= 0) { + return res.status(400).json({ + status: "failed", + message: "Invalid establishment_id" + }); + } + whereClause.establishment_id = establishmentId; } const data = await EstablishmentProduct.findAll({ diff --git a/app/controllers/establishment_user.controller.js b/app/controllers/establishment_user.controller.js index 4e64c82..1b19893 100644 --- a/app/controllers/establishment_user.controller.js +++ b/app/controllers/establishment_user.controller.js @@ -1,6 +1,7 @@ const db = require("../models"); const bcrypt = require("bcryptjs"); const EstablishmentUser = db.EstablishmentUser; +const Establishment = db.Establishment; const { sendEmailService } = require("../services/email.service"); const { sanitizeForLog } = require("../utils/sanitize"); @@ -8,64 +9,110 @@ const { sanitizeForLog } = require("../utils/sanitize"); // Create User exports.createUser = async (req, res) => { try { - - const { establishment_id, name, email, password , gender} = req.body; - const hashed = await bcrypt.hash(password, 10); - - email = sanitizeForLog(email || ""); - name = sanitizeForLog(name || ""); - gender = sanitizeForLog(gender || ""); - - if (!establishment_id || !email) { - return res.status(400).send({ + let { establishment_id, name, email, password, gender } = req.body; + establishment_id = Number(establishment_id); + if (!Number.isInteger(establishment_id) || establishment_id <= 0) { + return res.status(400).json({ status: "error", - code: "MISSING_FIELDS", - message: "establishment_id and email are required" + message: "Invalid establishment_id" }); } - - const existing = await EstablishmentUser.findOne({ where: { email, is_active: true } }); - if (existing) { - return res.status(400).send({ + const establishment = await Establishment.findByPk(establishment_id); + if (!establishment) { + return res.status(404).json({ + status: "error", + message: "Establishment not found" + }); + } + if (typeof email !== "string" || email.trim().length === 0) { + return res.status(400).json({ + status: "error", + message: "Email is required" + }); + } + email = email.trim().toLowerCase(); + if (typeof password !== "string" || password.length < 6) { + return res.status(400).json({ + status: "error", + message: "Password must be at least 6 characters long" + }); + } + name = typeof name === "string" ? name.trim() : null; + + if (gender) { + gender = gender.toString().toLowerCase(); + if (!["male", "female", "other"].includes(gender)) { + return res.status(400).json({ + status: "error", + message: "Invalid gender" + }); + } + gender = gender.charAt(0).toUpperCase() + gender.slice(1); + } + const existingUser = await EstablishmentUser.findOne({ + where: { email, is_active: true } + }); + + if (existingUser) { + return res.status(409).json({ status: "error", - code: "EMAIL_EXISTS", message: "Email already exists" }); } + const hashedPassword = await bcrypt.hash(password, 10); const user = await EstablishmentUser.create({ establishment_id, name, email, - password: hashed, + password: hashedPassword, gender, - created_by: req.user.id, + created_by: req.user.id }); - //send email to user - placeHolderData = { - contact_name : name, - portal_url : process.env.FE_BASE_URL, - username : email, - password : password, - support_email : process.env.SUPPORT_EMAIL, - support_phone : process.env.SUPPORT_PHONE, - - } - await sendEmailService(email, 'establishment_user_creation_to_user', placeHolderData); + await sendEmailService(email, "establishment_user_creation_to_user", { + contact_name: name, + portal_url: process.env.FE_BASE_URL, + username: email, + password, + support_email: process.env.SUPPORT_EMAIL, + support_phone: process.env.SUPPORT_PHONE + }); - return res.status(201).send({'status':"ok", 'message':"Creation successful",'data': user }); - - } catch (err) { - return res.status(500).send({'status':"error",'message':err.message }); + return res.status(201).json({ + status: "success", + message: "Establishment User created successfully", + data: { + name: user.name, + email: user.email, + } + }); + } catch (error) { + return res.status(500).json({ + status: "error", + message: error.message + }); } }; + // Get all users exports.getAllUsers = async (req, res) => { - try { + try { + let users; + if (typeof req.query.establishment_id !== 'undefined') { + const establishmentId = parseInt(req.query.establishment_id, 10); + if (Number.isNaN(establishmentId)) { + return res.status(400).json({ + status: "failed", + message: "Invalid establishment_id" + }); + } + users = await EstablishmentUser.findAll({ where:{ establishment_id : establishmentId} }); + }else{ + users = await EstablishmentUser.findAll(); + } - const users = await EstablishmentUser.findAll({ where:{ establishment_id : req.query.establishment_id} }); return res.status(200).send({'status':"success",'message':"Fetched successfully",'data': users }); } catch (err) { diff --git a/app/controllers/establishment_users_auth.controller.js b/app/controllers/establishment_users_auth.controller.js index 2c6d7c5..0ef06be 100644 --- a/app/controllers/establishment_users_auth.controller.js +++ b/app/controllers/establishment_users_auth.controller.js @@ -1,12 +1,19 @@ const bcrypt = require("bcryptjs"); const jwt = require("jsonwebtoken"); const db = require("../models"); +const sanitize = require("sanitize-html"); const EstablishmentUser = db.EstablishmentUser; +const sanitizeStringValue = (value) => + typeof value === "string" + ? sanitize(value, { allowedTags: [], allowedAttributes: {} }) + : value; + // User Login exports.login = async (req, res) => { try { - const { email, password } = req.body; + const email = sanitizeStringValue(req.body.email); + const password = req.body.password; if (!email || !password) return res.status(400).send({'status':"failed",'message':"Email and password required",'data': ""}); @@ -16,11 +23,17 @@ exports.login = async (req, res) => { const validPassword = await bcrypt.compare(password, user.password); if (!validPassword) return res.status(401).json({ message: "Invalid password" }); - // Create JWT token - const token = jwt.sign({ id: user.id, email: user.email , name: user.name, establishment_id: user.establishment_id }, process.env.JWT_SECRET, { - expiresIn: "6h", - }); + const token = jwt.sign( + { + id: user.id, + email: sanitizeStringValue(user.email), + name: sanitizeStringValue(user.name), + establishment_id: user.establishment_id + }, + process.env.JWT_SECRET, + { expiresIn: "6h" } + ); res.status(200).send({'status':"success",'message':"Login successful",'data': token }); diff --git a/app/controllers/products.controller.js b/app/controllers/products.controller.js index f337f82..ba08d3e 100644 --- a/app/controllers/products.controller.js +++ b/app/controllers/products.controller.js @@ -5,12 +5,20 @@ const db = require("../models"); const { Sequelize } = require("sequelize"); const Product = db.Product; const UnitMaster = db.UnitMaster; +const sanitize = require("sanitize-html"); - +const cleanString = (value) => + typeof value === "string" + ? sanitize(value, { allowedTags: [], allowedAttributes: {} }) + : value; exports.createProduct = async (req, res) => { try { - const { product_name, hs_code, hs_description } = req.body; + const product_name = cleanString(req.body.product_name); + const hs_description = cleanString(req.body.hs_description); + const hs_code = req.body.hs_code; + const unit_id = req.body.unit_id; + if (hs_description && hs_description.length > 1000) { return res.status(400).json({ status: "failed", @@ -51,9 +59,16 @@ exports.createProduct = async (req, res) => { message: `HS Code '${hs_code}' already exists.` }); } - req.body.created_by = req.user.id; - const data = await Product.create(req.body); - res.status(201).send({'status':"success",'message':"created successfully",'data': data }); + + await Product.create({ + product_name, + hs_code, + hs_description, + unit_id, + created_by: req.user.id + }); + + res.status(201).send({'status':"success",'message':"created successfully." }); } catch (error) { res.status(500).send({'status':"failed",'message':error.message }); } diff --git a/app/controllers/quarterlyWindowsConfiguration.controller.js b/app/controllers/quarterlyWindowsConfiguration.controller.js index 4c0d09d..c005145 100644 --- a/app/controllers/quarterlyWindowsConfiguration.controller.js +++ b/app/controllers/quarterlyWindowsConfiguration.controller.js @@ -5,6 +5,7 @@ const QuarterlyWindowsConfiguration = db.QuarterlyWindowsConfiguration; const Establishment = db.Establishment; const EstablishmentUser = db.EstablishmentUser; const { sendEmailService } = require("../services/email.service"); +const sanitize = require("sanitize-html"); // Create new configuration @@ -23,13 +24,31 @@ exports.createConfig = async (req, res) => { // get active establishment count const assignedCount = await Establishment.count({ where: { is_active: true } - }); - - // set auto values before inserting - req.body.assigned = assignedCount; - req.body.responded = 0; - req.body.not_responded = assignedCount; - req.body.created_by = req.body.created_by || req.user.id; + }); + + function sanitizeValue(value) { + if (typeof value === "string") { + return sanitize(value, { + allowedTags: [], + allowedAttributes: {}, + }); + } + if (Array.isArray(value)) { + return value.map(sanitizeValue); + }} + + const payload = { + survey_name: sanitizeValue(req.body.survey_name), + quarter: sanitizeValue(req.body.quarter), + year: req.body.year, + start_date: req.body.start_date, + end_date: req.body.end_date, + grace_periods_days: req.body.grace_periods_days, + assigned: assignedCount, + responded: 0, + not_responded: assignedCount, + created_by: req.user.id, + }; const placeholder = { survey_name: survey_name, @@ -42,11 +61,10 @@ exports.createConfig = async (req, res) => { support_phone: process.env.SUPPORT_PHONE }; - const data = await QuarterlyWindowsConfiguration.create(req.body); + const data = await QuarterlyWindowsConfiguration.create(payload); res.status(201).send({ status: "success", - message: "Quarterly window configuration created successfully", - data, + message: "Quarterly window configuration created successfully" }); sendEmailsToEstablishments(placeholder); } catch (err) { diff --git a/app/controllers/unitMasterController.js b/app/controllers/unitMasterController.js index 84d33fb..9abf72b 100644 --- a/app/controllers/unitMasterController.js +++ b/app/controllers/unitMasterController.js @@ -5,11 +5,26 @@ const { UnitMaster } = require("../models"); const fs = require("fs"); const csv = require("csv-parser"); const path = require("path"); +const sanitize = require("sanitize-html"); + +const sanitizeStringValue = (value) => + typeof value === "string" + ? sanitize(value, { allowedTags: [], allowedAttributes: {} }).trim() + : value; -// Create new Unit exports.createUnit = async (req, res) => { try { - const { uom } = req.body; + let { + uom, + description, + is_base_unit, + base_unit_id, + factor + } = req.body; + + uom = sanitizeStringValue(uom); + description = sanitizeStringValue(description); + factor = sanitizeStringValue(factor); if (!uom || typeof uom !== "string" || !uom.trim()) { return res.status(400).json({ @@ -17,27 +32,47 @@ exports.createUnit = async (req, res) => { message: "UOM (Unit Name) is required and must be a non-empty string.", }); } - const cleaned = uom.replace(/[^a-zA-Z]/g, "").toUpperCase(); + if (!description) { + return res.status(400).json({ + status: "error", + message: "Description is required and must be a non-empty string.", + }); + } + const cleaned = uom.replace(/[^A-Za-z]/g, "").toUpperCase(); + if (!cleaned) { return res.status(400).json({ status: "error", - message: "UOM must contain at least one letter (A-Z).", + message: "UOM must contain at least one alphabetic character.", }); } + is_base_unit = Boolean(is_base_unit); + + if (base_unit_id !== null && base_unit_id !== undefined) { + base_unit_id = Number(base_unit_id); + if (Number.isNaN(base_unit_id)) { + return res.status(400).json({ + status: "error", + message: "base_unit_id must be a valid number." + }); + } + } + + // SAFE: no Sequelize.where, no SQL functions const existingUOM = await UnitMaster.findOne({ - where: Sequelize.where( - Sequelize.fn("LOWER", Sequelize.col("uom")), - uom.toLowerCase() - ), + where: { + uom: cleaned + } }); - if (existingUOM) + if (existingUOM) { return res.status(400).json({ status: "error", - message: `Unit '${uom}' already exists with short key '${existingUOM.uom_short_name}'.`, + message: `Unit '${cleaned}' already exists with short key '${existingUOM.uom_short_name}'.`, }); + } - //Generate short name (same rule as CSV) + // Abbreviation map const abbreviationMap = { METER: "MT", METRE: "MT", @@ -58,44 +93,51 @@ exports.createUnit = async (req, res) => { UNIT: "UNT", }; - let uomShort; + let uomShort = + cleaned.length <= 5 + ? cleaned + : (abbreviationMap[cleaned] || cleaned.substring(0, 3)) + + Math.random().toString(36).substring(2, 4).toUpperCase(); - if (cleaned.length <= 5) { - uomShort = cleaned; - } else { - // If >5 letters, use abbreviation or auto-generate - const baseShort = abbreviationMap[cleaned] || cleaned.substring(0, 3); - const randomLetters = () => - Array.from({ length: 2 }, () => - String.fromCharCode(65 + Math.floor(Math.random() * 26)) - ).join(""); - uomShort = `${baseShort}${randomLetters()}`.substring(0, 5); - } + uomShort = uomShort.substring(0, 5); let exists = await UnitMaster.findOne({ - where: Sequelize.where( - Sequelize.fn("LOWER", Sequelize.col("uom_short_name")), - uomShort.toLowerCase() - ), + where: { + uom_short_name: uomShort + } }); while (exists) { - const randomSuffix = Math.random().toString(36).substring(2, 3).toUpperCase(); - uomShort = (uomShort.substring(0, 4) + randomSuffix).substring(0, 5); + const suffix = Math.random().toString(36).substring(2, 3).toUpperCase(); + uomShort = (uomShort.substring(0, 4) + suffix).substring(0, 5); + exists = await UnitMaster.findOne({ - where: Sequelize.where( - Sequelize.fn("LOWER", Sequelize.col("uom_short_name")), - uomShort.toLowerCase() - ), + where: { + uom_short_name: uomShort + } }); } - req.body.uom_short_name = uomShort; - req.body.created_by = req.body.created_by || req.user.id; - - const unit = await UnitMaster.create(req.body); - res.status(201).json({ status: "success", data: unit }); + + const unit = await UnitMaster.create({ + uom: cleaned, + uom_short_name: uomShort, + description, + is_base_unit, + base_unit_id, + factor: factor || null, + created_by: req.body.created_by || req.user.id + }); + + return res.status(201).json({ + status: "success", + message: "Unit created successfully." + }); + } catch (err) { - res.status(400).json({ status: "error", message: err.message }); + return res.status(400).json({ + status: "error", + message: err.message + }); } }; @@ -385,19 +427,16 @@ exports.uploadUnitMasterFromCSV = async (req, res) => { let uomShort = row._generatedShort; const description = row._description; + const normalizedUom = sanitizeStringValue(uom).toUpperCase(); + const normalizedShort = uomShort.toUpperCase(); + const existing = await UnitMaster.findOne({ where: { [Op.or]: [ - Sequelize.where( - Sequelize.fn("LOWER", Sequelize.col("uom")), - uom.toLowerCase() - ), - Sequelize.where( - Sequelize.fn("LOWER", Sequelize.col("uom_short_name")), - uomShort.toLowerCase() - ), - ], - }, + { uom: normalizedUom }, + { uom_short_name: normalizedShort } + ] + } }); if (existing) { diff --git a/app/controllers/variationReasonMaster.controller.js b/app/controllers/variationReasonMaster.controller.js index dc3cc0c..4bddd15 100644 --- a/app/controllers/variationReasonMaster.controller.js +++ b/app/controllers/variationReasonMaster.controller.js @@ -5,15 +5,43 @@ const VariationReasonMaster = db.VariationReasonMaster; // Create exports.createReason = async (req, res) => { try { - const { reason, high_or_low } = req.body; + let { reason, high_or_low } = req.body; + if (typeof reason !== "string" || reason.trim().length === 0) { + return res.status(400).json({ + status: "failed", + message: "Reason is required" + }); + } + reason = reason.trim(); - if (!reason) - return res.status(400).send({ status: "failed", message: "Reason is required" }); + if (high_or_low) { + high_or_low = high_or_low.toString().toLowerCase(); + + if (!["low", "high"].includes(high_or_low)) { + return res.status(400).json({ + status: "failed", + message: "Invalid high_or_low value" + }); + } + high_or_low = high_or_low === "low" ? "Low" : "High"; + } + + const newReason = await VariationReasonMaster.create({ + reason, + high_or_low, + created_by: req.body.created_by || req.user.id + }); + + return res.status(201).json({ + status: "success", + message: "Reason created successfully" + }); - const newReason = await VariationReasonMaster.create({ reason, high_or_low, created_by: req.body.created_by || req.user.id }); - res.status(201).send({ status: "success", message: "Reason created successfully", data: newReason }); } catch (err) { - res.status(500).send({ status: "failed", message: err.message }); + return res.status(500).json({ + status: "failed", + message: "Internal server error" + }); } }; diff --git a/app/controllers/zeroTargetReasonMaster.controller.js b/app/controllers/zeroTargetReasonMaster.controller.js index 9a6632a..cdbc761 100644 --- a/app/controllers/zeroTargetReasonMaster.controller.js +++ b/app/controllers/zeroTargetReasonMaster.controller.js @@ -4,11 +4,20 @@ const ZeroTargetReasonMaster = db.ZeroTargetReasonMaster; // Create exports.create = async (req, res) => { try { - const { reason, is_active } = req.body; - if (!reason) return res.status(400).send({ status: "failed", message: "Reason is required" }); + let { reason, is_active } = req.body; + if (typeof reason !== "string" || reason.trim().length === 0) { + return res.status(400).json({ + status: "failed", + message: "Reason is required" + }); + } + reason = reason.trim(); + if (typeof is_active !== "boolean") { + is_active = true; + } const data = await ZeroTargetReasonMaster.create({ reason, is_active, created_by: req.user.id }); - res.status(201).send({ status: "success", data }); + res.status(201).send({ status: "success", message: "Record created successfully",}); } catch (err) { res.status(500).send({ status: "failed", message: err.message }); }