Initial commit : GowthamManavalan
This commit is contained in:
commit
b236ca3ba9
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
.env
|
||||
app/writable/logs/*
|
||||
app/writable/uploads/*
|
||||
15
app/config/db.config.js
Normal file
15
app/config/db.config.js
Normal file
@ -0,0 +1,15 @@
|
||||
require('dotenv').config();
|
||||
|
||||
module.exports = {
|
||||
HOST: process.env.DB_HOST,
|
||||
USER: process.env.DB_USER,
|
||||
PASSWORD: process.env.DB_PASSWORD,
|
||||
DB: process.env.DB_NAME,
|
||||
dialect: process.env.DB_DIALECT || 'mysql',
|
||||
pool: {
|
||||
max: 5,
|
||||
min: 0,
|
||||
acquire: 30000,
|
||||
idle: 10000
|
||||
}
|
||||
};
|
||||
47
app/controllers/auth.controller.js
Normal file
47
app/controllers/auth.controller.js
Normal file
@ -0,0 +1,47 @@
|
||||
const db = require("../models");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const jwt = require("jsonwebtoken");
|
||||
require("dotenv").config();
|
||||
|
||||
const User = db.user;
|
||||
|
||||
// Register new user
|
||||
exports.register = async (req, res) => {
|
||||
try {
|
||||
const { name, email, password } = req.body;
|
||||
if (!name || !email || !password)
|
||||
return res.status(400).send({'status':"failed",'message':"All fields required",'data': ""});
|
||||
|
||||
const existing = await User.findOne({ where: { email } });
|
||||
if (existing) res.status(400).send({'status':"failed",'message':"Email already used",'data': ""});
|
||||
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
const newUser = await User.create({ name, email, password: hashedPassword });
|
||||
|
||||
res.status(201).send({'status':"success",'message':"User registered successfully",'data': newUser });
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Login user
|
||||
exports.login = async (req, res) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
|
||||
const user = await User.findOne({ where: { email } });
|
||||
if (!user) res.status(404).send({'status':"failed",'message':"User not found",'data': ""});
|
||||
|
||||
const validPass = await bcrypt.compare(password, user.password);
|
||||
if (!validPass) res.status(401).send({'status':"failed",'message':"Invalid password",'data': ""});
|
||||
|
||||
const token = jwt.sign({ id: user.id, email: user.email }, process.env.JWT_SECRET, {
|
||||
expiresIn: "6h",
|
||||
});
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Login successful",'data': token });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
118
app/controllers/establishment.controller.js
Normal file
118
app/controllers/establishment.controller.js
Normal file
@ -0,0 +1,118 @@
|
||||
const db = require("../models");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const Establishment = db.establishment;
|
||||
const EstablishmentUser = db.establishment_user;
|
||||
|
||||
// Create Establishment + linked user
|
||||
exports.createEstablishment = async (req, res) => {
|
||||
try {
|
||||
|
||||
const { establishment_code, factory_name, email, permanent_factory_code, industry_code, license_number, isic_code, emirate, total_employment, establishment_user, } = req.body;
|
||||
|
||||
if ( !establishment_code || !factory_name || !email || !establishment_user?.name || !establishment_user?.email || !establishment_user?.password )
|
||||
{
|
||||
res.status(400).send({'status':"failed",'message':"Missing required fields",'data': "" });
|
||||
}
|
||||
|
||||
// Create Establishment
|
||||
const establishment = await Establishment.create({
|
||||
establishment_code,
|
||||
factory_name,
|
||||
email,
|
||||
permanent_factory_code,
|
||||
industry_code,
|
||||
license_number,
|
||||
isic_code,
|
||||
emirate,
|
||||
total_employment,
|
||||
});
|
||||
|
||||
// Hash password for user
|
||||
const hashedPassword = await bcrypt.hash(establishment_user.password, 10);
|
||||
|
||||
// Create related Establishment User
|
||||
const user = await EstablishmentUser.create({
|
||||
establishment_id: establishment.id,
|
||||
name: establishment_user.name,
|
||||
email: establishment_user.email,
|
||||
password: hashedPassword,
|
||||
});
|
||||
|
||||
|
||||
res.status(201).send({'status':"success",'message':"Establishment and linked user created successfully",'data': { establishment, user } });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Get all establishments (with user details)
|
||||
exports.getAllEstablishments = async (req, res) => {
|
||||
try {
|
||||
|
||||
const data = await Establishment.findAll({
|
||||
include: [
|
||||
{
|
||||
model: EstablishmentUser,
|
||||
as: "users",
|
||||
attributes: ["id", "name", "email", "is_active"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': data });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get one establishment
|
||||
exports.getEstablishmentById = async (req, res) => {
|
||||
try {
|
||||
|
||||
const data = await Establishment.findByPk(req.params.id, {
|
||||
include: [{ model: EstablishmentUser, as: "users" }],
|
||||
});
|
||||
|
||||
if (!data) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': data });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Update establishment
|
||||
exports.updateEstablishment = async (req, res) => {
|
||||
try {
|
||||
|
||||
const [updated] = await Establishment.update(req.body, {
|
||||
where: { id: req.params.id },
|
||||
});
|
||||
|
||||
if (!updated) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Updated successfully",'data': "" });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Delete establishment
|
||||
exports.deleteEstablishment = async (req, res) => {
|
||||
try {
|
||||
|
||||
const deleted = await Establishment.destroy({ where: { id: req.params.id } });
|
||||
|
||||
if (!deleted) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Deleted successfully",'data': "" });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
83
app/controllers/establishment_products.controller.js
Normal file
83
app/controllers/establishment_products.controller.js
Normal file
@ -0,0 +1,83 @@
|
||||
const { where } = require("sequelize");
|
||||
const db = require("../models");
|
||||
const EstablishmentProduct = db.EstablishmentProduct;
|
||||
const Product = db.Product;
|
||||
|
||||
exports.createEstablishmentProduct = async (req, res) => {
|
||||
try {
|
||||
|
||||
const data = await EstablishmentProduct.create(req.body);
|
||||
res.status(201).send({'status':"success",'message':"Creation successful",'data': data });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.getAllEstablishmentProducts = async (req, res) => {
|
||||
try {
|
||||
|
||||
const whereClause = {};
|
||||
if (req.query.establishment_id) {
|
||||
whereClause.establishment_id = req.query.establishment_id;
|
||||
}
|
||||
|
||||
const data = await EstablishmentProduct.findAll({
|
||||
raw: true ,
|
||||
where: whereClause,
|
||||
include: [
|
||||
{
|
||||
model: Product,
|
||||
as: "product",
|
||||
attributes: ["product_name", "hs_code", "hs_description"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': data });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.getEstablishmentProductById = async (req, res) => {
|
||||
try {
|
||||
|
||||
const data = await EstablishmentProduct.findByPk(req.params.id);
|
||||
|
||||
if (!data) res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': data });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateEstablishmentProduct = async (req, res) => {
|
||||
try {
|
||||
const [updated] = await EstablishmentProduct.update(req.body, { where: { id: req.params.id } });
|
||||
|
||||
if (!updated) res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Record updated successfully",'data': "" });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteEstablishmentProduct = async (req, res) => {
|
||||
try {
|
||||
|
||||
const deleted = await EstablishmentProduct.destroy({ where: { id: req.params.id } });
|
||||
|
||||
if (!deleted) res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Record deleted successfully",'data': "" });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
90
app/controllers/establishment_user.controller.js
Normal file
90
app/controllers/establishment_user.controller.js
Normal file
@ -0,0 +1,90 @@
|
||||
const db = require("../models");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const EstablishmentUser = db.establishment_user;
|
||||
|
||||
// Create User
|
||||
exports.createUser = async (req, res) => {
|
||||
try {
|
||||
|
||||
const { establishment_id, name, email, password } = req.body;
|
||||
const hashed = await bcrypt.hash(password, 10);
|
||||
|
||||
const user = await EstablishmentUser.create({
|
||||
establishment_id,
|
||||
name,
|
||||
email,
|
||||
password: hashed,
|
||||
});
|
||||
|
||||
res.status(201).send({'status':"success",'message':"Creation successful",'data': user });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get all users
|
||||
exports.getAllUsers = async (req, res) => {
|
||||
try {
|
||||
|
||||
const users = await EstablishmentUser.findAll({ where:{ establishment_id : req.query.establishment_id} });
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': users });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get user by id
|
||||
exports.getUserById = async (req, res) => {
|
||||
try {
|
||||
|
||||
const user = await EstablishmentUser.findByPk(req.params.id);
|
||||
|
||||
if (!user) res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': user });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Update user
|
||||
exports.updateUser = async (req, res) => {
|
||||
try {
|
||||
|
||||
const { name, email, password, is_active } = req.body;
|
||||
const data = {};
|
||||
if (name) data.name = name;
|
||||
if (email) data.email = email;
|
||||
if (is_active !== undefined) data.is_active = is_active;
|
||||
if (password) data.password = await bcrypt.hash(password, 10);
|
||||
|
||||
const [updated] = await EstablishmentUser.update(data, {
|
||||
where: { id: req.params.id },
|
||||
});
|
||||
|
||||
if (!updated) res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Record updated successfully",'data': "" });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Delete user
|
||||
exports.deleteUser = async (req, res) => {
|
||||
try {
|
||||
|
||||
const deleted = await EstablishmentUser.destroy({ where: { id: req.params.id } });
|
||||
|
||||
if (!deleted) res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Record deleted successfully",'data': "" });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
41
app/controllers/establishment_users_auth.controller.js
Normal file
41
app/controllers/establishment_users_auth.controller.js
Normal file
@ -0,0 +1,41 @@
|
||||
const bcrypt = require("bcryptjs");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const { EstablishmentUser } = require("../models");
|
||||
|
||||
// User Login
|
||||
exports.login = async (req, res) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
if (!email || !password)
|
||||
return res.status(400).send({'status':"failed",'message':"Email and password required",'data': ""});
|
||||
|
||||
const user = await EstablishmentUser.findOne({ where: { email } });
|
||||
if (!user) res.status(404).send({'status':"failed",'message':"User not found",'data': ""});
|
||||
|
||||
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",
|
||||
});
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Login successful",'data': token });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// User Logout (JWT-based — just a client-side operation)
|
||||
exports.logout = async (req, res) => {
|
||||
try {
|
||||
// For JWT, logout is handled on the client (by deleting token)
|
||||
// But you can still log or blacklist token if needed
|
||||
res.status(200).send({'status':"success",'message':"Logout successful",'data': "" });
|
||||
res.status(200).json({ message: "Logout successful (client should discard token)" });
|
||||
} catch (err) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
68
app/controllers/products.controller.js
Normal file
68
app/controllers/products.controller.js
Normal file
@ -0,0 +1,68 @@
|
||||
const db = require("../models");
|
||||
const Product = db.Product;
|
||||
|
||||
exports.createProduct = async (req, res) => {
|
||||
try {
|
||||
|
||||
const data = await Product.create(req.body);
|
||||
|
||||
res.status(201).send({'status':"success",'message':"created successfully",'data': data });
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.getAllProducts = async (req, res) => {
|
||||
try {
|
||||
|
||||
const data = await Product.findAll();
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': data });
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.getProductById = async (req, res) => {
|
||||
try {
|
||||
|
||||
const data = await Product.findByPk(req.params.id);
|
||||
|
||||
if (!data) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': data });
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateProduct = async (req, res) => {
|
||||
try {
|
||||
|
||||
const [updated] = await Product.update(req.body, { where: { id: req.params.id } });
|
||||
|
||||
if (!updated) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Updated successfully",'data': "" });
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteProduct = async (req, res) => {
|
||||
try {
|
||||
|
||||
const deleted = await Product.destroy({ where: { id: req.params.id } });
|
||||
|
||||
if (!deleted) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Deleted successfully",'data': "" });
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
150
app/controllers/submission.controller.js
Normal file
150
app/controllers/submission.controller.js
Normal file
@ -0,0 +1,150 @@
|
||||
const db = require("../models");
|
||||
const Submission = db.Submission;
|
||||
const SubmissionProduct = db.SubmissionProduct;
|
||||
const Product = db.Product;
|
||||
const { Op } = require("sequelize");
|
||||
|
||||
|
||||
|
||||
exports.createSubmission = async (req, res) => {
|
||||
try {
|
||||
|
||||
const { products = [], ...submissionData } = req.body;
|
||||
|
||||
if (products.length > 10)
|
||||
return res.status(400).json({ status: "failed", message: "Max 10 products allowed" });
|
||||
|
||||
const submission = await Submission.create(submissionData);
|
||||
if (products.length) {
|
||||
products.forEach((p) => (p.submission_id = submission.id));
|
||||
await SubmissionProduct.bulkCreate(products);
|
||||
}
|
||||
|
||||
const result = await Submission.findByPk(submission.id, {
|
||||
include: [{ model: SubmissionProduct, as: "products" }],
|
||||
});
|
||||
|
||||
res.status(201).json({ status: "success", data: result });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).json({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateSubmission = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { products = [], ...submissionData } = req.body;
|
||||
|
||||
// Check submission exists
|
||||
const submission = await Submission.findByPk(id);
|
||||
if (!submission)
|
||||
return res.status(404).json({ status: "failed", message: "Submission not found" });
|
||||
|
||||
// Update submission main data
|
||||
await submission.update(submissionData);
|
||||
|
||||
// Process products
|
||||
for (const product of products) {
|
||||
if (product.id) {
|
||||
// If product ID exists, update
|
||||
const existingProduct = await SubmissionProduct.findOne({
|
||||
where: { id: product.id, submission_id: id },
|
||||
});
|
||||
|
||||
if (existingProduct) {
|
||||
await existingProduct.update(product);
|
||||
} else {
|
||||
// fallback: if given ID not found, create new
|
||||
product.submission_id = id;
|
||||
await SubmissionProduct.create(product);
|
||||
}
|
||||
} else {
|
||||
// If product has no ID → create new record
|
||||
product.submission_id = id;
|
||||
await SubmissionProduct.create(product);
|
||||
}
|
||||
}
|
||||
|
||||
// Get updated full record
|
||||
const updatedSubmission = await Submission.findByPk(id, {
|
||||
include: [{ model: SubmissionProduct, as: "products" }],
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
status: "success",
|
||||
message: "Submission updated successfully",
|
||||
data: updatedSubmission,
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
exports.submissionHistory = async (req, res) => {
|
||||
try {
|
||||
|
||||
const { establishment_id } = req.params;
|
||||
|
||||
const data = await Submission.findAll({
|
||||
where: { establishment_id },
|
||||
order: [["id", "DESC"]],
|
||||
});
|
||||
|
||||
res.status(200).json({ status: "success", data });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).json({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.submissionList = async (req, res) => {
|
||||
try {
|
||||
|
||||
const data = await Submission.findAll({
|
||||
// include: [{ model: SubmissionProduct, as: "products" }],
|
||||
order: [["id", "DESC"]],
|
||||
});
|
||||
|
||||
res.status(200).json({ status: "success", data });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).json({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.viewSubmissionDetails = async (req, res) => {
|
||||
try {
|
||||
|
||||
const { id } = req.params;
|
||||
|
||||
const data = await Submission.findByPk(id, {
|
||||
include: [
|
||||
{
|
||||
model: SubmissionProduct, as: "products" ,
|
||||
include: [
|
||||
{
|
||||
model: Product,
|
||||
as: "product",
|
||||
attributes: ["product_name", "hs_code", "hs_description"],
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
if (!data) return res.status(404).json({ status: "failed", message: "Not found" });
|
||||
|
||||
res.status(200).json({ status: "success", data });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).json({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
59
app/controllers/unitMasterController.js
Normal file
59
app/controllers/unitMasterController.js
Normal file
@ -0,0 +1,59 @@
|
||||
// controllers/unitMasterController.js
|
||||
const { UnitMaster } = require("../models");
|
||||
|
||||
// Create new Unit
|
||||
exports.createUnit = async (req, res) => {
|
||||
try {
|
||||
const unit = await UnitMaster.create(req.body);
|
||||
res.status(201).json({ status: "success", data: unit });
|
||||
} catch (err) {
|
||||
res.status(400).json({ status: "error", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get all Units
|
||||
exports.getAllUnits = async (req, res) => {
|
||||
try {
|
||||
const units = await UnitMaster.findAll();
|
||||
res.status(200).json({ status: "success", data: units });
|
||||
} catch (err) {
|
||||
res.status(500).json({ status: "error", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get Unit by ID
|
||||
exports.getUnitById = async (req, res) => {
|
||||
try {
|
||||
const unit = await UnitMaster.findByPk(req.params.id);
|
||||
if (!unit) return res.status(404).json({ status: "error", message: "Unit not found" });
|
||||
res.status(200).json({ status: "success", data: unit });
|
||||
} catch (err) {
|
||||
res.status(500).json({ status: "error", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Update Unit
|
||||
exports.updateUnit = async (req, res) => {
|
||||
try {
|
||||
const unit = await UnitMaster.findByPk(req.params.id);
|
||||
if (!unit) return res.status(404).json({ status: "error", message: "Unit not found" });
|
||||
|
||||
await unit.update(req.body);
|
||||
res.status(200).json({ status: "success", data: unit });
|
||||
} catch (err) {
|
||||
res.status(400).json({ status: "error", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Delete Unit
|
||||
exports.deleteUnit = async (req, res) => {
|
||||
try {
|
||||
const unit = await UnitMaster.findByPk(req.params.id);
|
||||
if (!unit) return res.status(404).json({ status: "error", message: "Unit not found" });
|
||||
|
||||
await unit.destroy();
|
||||
res.status(200).json({ status: "success", message: "Unit deleted successfully" });
|
||||
} catch (err) {
|
||||
res.status(500).json({ status: "error", message: err.message });
|
||||
}
|
||||
};
|
||||
94
app/controllers/user.controller.js
Normal file
94
app/controllers/user.controller.js
Normal file
@ -0,0 +1,94 @@
|
||||
const db = require("../models");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const logger = require("../services/logger");
|
||||
require("dotenv").config();
|
||||
|
||||
const User = db.user;
|
||||
|
||||
// Create User
|
||||
exports.createUser = async (req, res) => {
|
||||
try {
|
||||
|
||||
const { name, email, password } = req.body;
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
const user = await User.create({ name, email, password: hashedPassword });
|
||||
|
||||
logger.info(`User created: ${email}`);
|
||||
|
||||
res.status(201).send({'status':"success",'message':"created successfully",'data': user });
|
||||
|
||||
} catch (err) {
|
||||
logger.error(err.message);
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get All Users
|
||||
exports.getAllUsers = async (req, res) => {
|
||||
try {
|
||||
|
||||
const users = await User.findAll();
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': users });
|
||||
|
||||
} catch (err) {
|
||||
logger.error(err.message);
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get User by ID
|
||||
exports.getUserById = async (req, res) => {
|
||||
try {
|
||||
|
||||
const user = await User.findByPk(req.params.id);
|
||||
|
||||
if (!user) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
|
||||
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': user });
|
||||
|
||||
} catch (err) {
|
||||
logger.error(err.message);
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Update User
|
||||
exports.updateUser = async (req, res) => {
|
||||
try {
|
||||
|
||||
const { name, email } = req.body;
|
||||
const [updated] = await User.update({ name, email }, { where: { id: req.params.id } });
|
||||
|
||||
if (updated) {
|
||||
const updatedUser = await User.findByPk(req.params.id);
|
||||
res.status(200).send({'status':"success",'message':"Updated successfully",'data': updatedUser });
|
||||
} else {
|
||||
res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.error(err.message);
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Delete User
|
||||
exports.deleteUser = async (req, res) => {
|
||||
try {
|
||||
|
||||
const deleted = await User.destroy({ where: { id: req.params.id } });
|
||||
|
||||
if (deleted) {
|
||||
res.status(200).send({'status':"success",'message':"Deleted successfully",'data': "" });
|
||||
} else {
|
||||
res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.error(err.message);
|
||||
res.status(500).send({'status':"failed",'message':err.message });
|
||||
}
|
||||
};
|
||||
66
app/controllers/variationReasonMaster.controller.js
Normal file
66
app/controllers/variationReasonMaster.controller.js
Normal file
@ -0,0 +1,66 @@
|
||||
// app/controllers/variationReasonMaster.controller.js
|
||||
const db = require("../models");
|
||||
const VariationReasonMaster = db.VariationReasonMaster;
|
||||
|
||||
// Create
|
||||
exports.createReason = async (req, res) => {
|
||||
try {
|
||||
const { reason, high_or_low } = req.body;
|
||||
|
||||
if (!reason)
|
||||
return res.status(400).send({ status: "failed", message: "Reason is required" });
|
||||
|
||||
const newReason = await VariationReasonMaster.create({ reason, high_or_low });
|
||||
res.status(201).send({ status: "success", message: "Reason created successfully", data: newReason });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get all
|
||||
exports.getAllReasons = async (req, res) => {
|
||||
try {
|
||||
const data = await VariationReasonMaster.findAll();
|
||||
res.status(200).send({ status: "success", message: "Fetched successfully", data });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Get by ID
|
||||
exports.getReasonById = async (req, res) => {
|
||||
try {
|
||||
const data = await VariationReasonMaster.findByPk(req.params.id);
|
||||
if (!data) return res.status(404).send({ status: "failed", message: "Reason not found" });
|
||||
res.status(200).send({ status: "success", message: "Fetched successfully", data });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Update
|
||||
exports.updateReason = async (req, res) => {
|
||||
try {
|
||||
const { reason, high_or_low, is_active } = req.body;
|
||||
const updated = await VariationReasonMaster.update(
|
||||
{ reason, high_or_low, is_active, updated_at: new Date(), updated_on: new Date() },
|
||||
{ where: { id: req.params.id } }
|
||||
);
|
||||
|
||||
if (updated[0] === 0) return res.status(404).send({ status: "failed", message: "Reason not found" });
|
||||
res.status(200).send({ status: "success", message: "Updated successfully" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// Delete
|
||||
exports.deleteReason = async (req, res) => {
|
||||
try {
|
||||
const deleted = await VariationReasonMaster.destroy({ where: { id: req.params.id } });
|
||||
if (!deleted) return res.status(404).send({ status: "failed", message: "Reason not found" });
|
||||
res.status(200).send({ status: "success", message: "Deleted successfully" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
62
app/controllers/zeroTargetReasonMaster.controller.js
Normal file
62
app/controllers/zeroTargetReasonMaster.controller.js
Normal file
@ -0,0 +1,62 @@
|
||||
const db = require("../models");
|
||||
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" });
|
||||
|
||||
const data = await ZeroTargetReasonMaster.create({ reason, is_active });
|
||||
res.status(201).send({ status: "success", data });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// ✅ Get All
|
||||
exports.getAll = async (req, res) => {
|
||||
try {
|
||||
const data = await ZeroTargetReasonMaster.findAll();
|
||||
res.status(200).send({ status: "success", data });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// ✅ Get By ID
|
||||
exports.getById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const data = await ZeroTargetReasonMaster.findByPk(id);
|
||||
if (!data) return res.status(404).send({ status: "failed", message: "Not found" });
|
||||
res.status(200).send({ status: "success", data });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// ✅ Update
|
||||
exports.update = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const [updated] = await ZeroTargetReasonMaster.update(req.body, { where: { id } });
|
||||
if (!updated) return res.status(404).send({ status: "failed", message: "Not found" });
|
||||
const data = await ZeroTargetReasonMaster.findByPk(id);
|
||||
res.status(200).send({ status: "success", data });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
// ✅ Delete
|
||||
exports.delete = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const deleted = await ZeroTargetReasonMaster.destroy({ where: { id } });
|
||||
if (!deleted) return res.status(404).send({ status: "failed", message: "Not found" });
|
||||
res.status(200).send({ status: "success", message: "Deleted successfully" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ status: "failed", message: err.message });
|
||||
}
|
||||
};
|
||||
12
app/middleware/app.middleware.js
Normal file
12
app/middleware/app.middleware.js
Normal file
@ -0,0 +1,12 @@
|
||||
require("dotenv").config();
|
||||
|
||||
module.exports = function (req, res, next) {
|
||||
|
||||
const APP_SIGNATURE = req.headers["APP_SIGNATURE"];
|
||||
|
||||
if(APP_SIGNATURE != process.env.APP_SIGNATURE)
|
||||
{
|
||||
return res.status(403).json({ message: "Access denied, SIGNATURE missing" });
|
||||
}
|
||||
|
||||
};
|
||||
15
app/middleware/auth.middleware.js
Normal file
15
app/middleware/auth.middleware.js
Normal file
@ -0,0 +1,15 @@
|
||||
const jwt = require("jsonwebtoken");
|
||||
require("dotenv").config();
|
||||
|
||||
module.exports = function (req, res, next) {
|
||||
const authHeader = req.headers["authorization"];
|
||||
const token = authHeader && authHeader.split(" ")[1]; // Expect "Bearer <token>"
|
||||
|
||||
if (!token) return res.status(403).json({ message: "Access denied, token missing" });
|
||||
|
||||
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
|
||||
if (err) return res.status(401).json({ message: "Invalid or expired token" });
|
||||
req.user = decoded;
|
||||
next();
|
||||
});
|
||||
};
|
||||
54
app/models/UnitMaster.model.js
Normal file
54
app/models/UnitMaster.model.js
Normal file
@ -0,0 +1,54 @@
|
||||
// models/UnitMaster.js
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const UnitMaster = sequelize.define(
|
||||
"UnitMaster",
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
uom_short_name: {
|
||||
type: DataTypes.STRING(20),
|
||||
allowNull: false,
|
||||
},
|
||||
uom: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
},
|
||||
is_base_unit: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
},
|
||||
base_unit_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
factor: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
created_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
tableName: "unit_master",
|
||||
timestamps: true,
|
||||
createdAt: "created_at",
|
||||
updatedAt: "updated_at",
|
||||
}
|
||||
);
|
||||
|
||||
return UnitMaster;
|
||||
};
|
||||
|
||||
74
app/models/establishment.model.js
Normal file
74
app/models/establishment.model.js
Normal file
@ -0,0 +1,74 @@
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const Establishment = sequelize.define(
|
||||
"establishments",
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
establishment_code: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
factory_name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
email: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
permanent_factory_code: {
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
industry_code: {
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
license_number: {
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
isic_code: {
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
emirate: {
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
emirati_male: DataTypes.INTEGER,
|
||||
emirati_female: DataTypes.INTEGER,
|
||||
non_emirati_male: DataTypes.INTEGER,
|
||||
non_emirati_female: DataTypes.INTEGER,
|
||||
total_emirati: DataTypes.INTEGER,
|
||||
total_employees: {
|
||||
type: DataTypes.INTEGER,
|
||||
},
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
},
|
||||
created_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: false,
|
||||
tableName: "establishments",
|
||||
}
|
||||
);
|
||||
|
||||
return Establishment;
|
||||
};
|
||||
|
||||
51
app/models/establishmentProduct.model.js
Normal file
51
app/models/establishmentProduct.model.js
Normal file
@ -0,0 +1,51 @@
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const EstablishmentProduct = sequelize.define("establishment_products", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
establishment_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
product_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
},
|
||||
created_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
}, {
|
||||
tableName: "establishment_products",
|
||||
timestamps: false,
|
||||
});
|
||||
|
||||
EstablishmentProduct.associate = (models) => {
|
||||
EstablishmentProduct.belongsTo(models.Product, { // 'Product' with capital P
|
||||
foreignKey: "product_id",
|
||||
as: "product",
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
return EstablishmentProduct;
|
||||
};
|
||||
|
||||
56
app/models/establishment_user.model.js
Normal file
56
app/models/establishment_user.model.js
Normal file
@ -0,0 +1,56 @@
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const EstablishmentUser = sequelize.define(
|
||||
"establishment_users",
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
establishment_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
email: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
},
|
||||
created_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: false,
|
||||
tableName: "establishment_users",
|
||||
}
|
||||
);
|
||||
|
||||
return EstablishmentUser;
|
||||
};
|
||||
|
||||
46
app/models/index.js
Normal file
46
app/models/index.js
Normal file
@ -0,0 +1,46 @@
|
||||
const dbConfig = require("../config/db.config.js");
|
||||
const { Sequelize, DataTypes } = require("sequelize");
|
||||
|
||||
const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, {
|
||||
host: dbConfig.HOST,
|
||||
dialect: dbConfig.dialect,
|
||||
pool: dbConfig.pool,
|
||||
logging: false,
|
||||
});
|
||||
|
||||
const db = {};
|
||||
db.Sequelize = Sequelize;
|
||||
db.sequelize = sequelize;
|
||||
|
||||
db.user = require("./user.model.js")(sequelize, DataTypes);
|
||||
db.establishment = require("./establishment.model")(sequelize, DataTypes);
|
||||
db.establishment_user = require("./establishment_user.model")(sequelize, DataTypes);
|
||||
db.Product = require("./product.model.js")(sequelize, DataTypes);
|
||||
db.EstablishmentProduct = require("./establishmentProduct.model")(sequelize, DataTypes);
|
||||
db.VariationReasonMaster = require("./variationReasonMaster.model")(sequelize, DataTypes);
|
||||
db.ZeroTargetReasonMaster = require("./zeroTargetReason.model")(sequelize, DataTypes);
|
||||
db.Submission = require("./submission.model")(sequelize, DataTypes);
|
||||
db.SubmissionProduct = require("./submissionProduct.model")(sequelize, DataTypes);
|
||||
db.UnitMaster = require("./UnitMaster.model")(sequelize, DataTypes);
|
||||
|
||||
|
||||
// Associations
|
||||
db.establishment.hasMany(db.establishment_user, {
|
||||
foreignKey: "establishment_id",
|
||||
as: "users",
|
||||
});
|
||||
|
||||
db.establishment_user.belongsTo(db.establishment, {
|
||||
foreignKey: "establishment_id",
|
||||
as: "establishment",
|
||||
});
|
||||
|
||||
// **Call associate methods defined in models**
|
||||
Object.keys(db).forEach((modelName) => {
|
||||
if (db[modelName].associate) {
|
||||
db[modelName].associate(db);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = db;
|
||||
61
app/models/product.model.js
Normal file
61
app/models/product.model.js
Normal file
@ -0,0 +1,61 @@
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const Product = sequelize.define("products", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
product_name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
hs_code: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
hs_description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
},
|
||||
created_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
}, {
|
||||
tableName: "products",
|
||||
timestamps: false,
|
||||
});
|
||||
|
||||
Product.associate = (models) => {
|
||||
Product.hasMany(models.EstablishmentProduct, {
|
||||
foreignKey: "product_id",
|
||||
as: "establishment_products",
|
||||
});
|
||||
};
|
||||
|
||||
Product.associate = (models) => {
|
||||
Product.hasMany(models.SubmissionProduct, {
|
||||
foreignKey: "product_id",
|
||||
as: "submission_products",
|
||||
});
|
||||
};
|
||||
|
||||
return Product;
|
||||
};
|
||||
|
||||
73
app/models/submission.model.js
Normal file
73
app/models/submission.model.js
Normal file
@ -0,0 +1,73 @@
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const Submission = sequelize.define("submission", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
establishment_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
quarter: {
|
||||
type: DataTypes.ENUM("Q1", "Q2", "Q3", "Q4"),
|
||||
allowNull: false,
|
||||
},
|
||||
year: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
emirati_male: DataTypes.INTEGER,
|
||||
emirati_female: DataTypes.INTEGER,
|
||||
non_emirati_male: DataTypes.INTEGER,
|
||||
non_emirati_female: DataTypes.INTEGER,
|
||||
total_emirati: DataTypes.INTEGER,
|
||||
total_employees: DataTypes.INTEGER,
|
||||
edit_request: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
},
|
||||
edit_access: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
},
|
||||
edit_access_close_date: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: true,
|
||||
},
|
||||
created_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
},
|
||||
updated_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
}, {
|
||||
tableName: "submission",
|
||||
timestamps: false,
|
||||
});
|
||||
|
||||
Submission.associate = (models) => {
|
||||
Submission.hasMany(models.SubmissionProduct, {
|
||||
foreignKey: "submission_id",
|
||||
as: "products",
|
||||
onDelete: "CASCADE",
|
||||
});
|
||||
};
|
||||
|
||||
return Submission;
|
||||
};
|
||||
|
||||
61
app/models/submissionProduct.model.js
Normal file
61
app/models/submissionProduct.model.js
Normal file
@ -0,0 +1,61 @@
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const SubmissionProduct = sequelize.define("submission_products", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
submission_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
product_id: DataTypes.INTEGER,
|
||||
unit_id: DataTypes.INTEGER,
|
||||
annual_installed_capacity: DataTypes.STRING(100),
|
||||
previous_quantity: DataTypes.STRING(100),
|
||||
previous_cost: DataTypes.STRING(100),
|
||||
current_quantity: DataTypes.STRING(100),
|
||||
current_cost: DataTypes.STRING(100),
|
||||
forecast_quantity: DataTypes.STRING(100),
|
||||
forecast_cost: DataTypes.STRING(100),
|
||||
variation_reason_master_id: DataTypes.INTEGER,
|
||||
other_variation_reason: DataTypes.STRING(255),
|
||||
zero_target_reason_master_id: DataTypes.INTEGER,
|
||||
other_zero_target_reason: DataTypes.STRING(255),
|
||||
remarks: DataTypes.STRING(255),
|
||||
created_by: DataTypes.INTEGER,
|
||||
updated_by: DataTypes.INTEGER,
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
},
|
||||
updated_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
}, {
|
||||
tableName: "submission_products",
|
||||
timestamps: false,
|
||||
});
|
||||
|
||||
SubmissionProduct.associate = (models) => {
|
||||
SubmissionProduct.belongsTo(models.Submission, {
|
||||
foreignKey: "submission_id",
|
||||
as: "submission",
|
||||
});
|
||||
};
|
||||
|
||||
SubmissionProduct.associate = (models) => {
|
||||
SubmissionProduct.belongsTo(models.Product, { // 'Product' with capital P
|
||||
foreignKey: "product_id",
|
||||
as: "product",
|
||||
});
|
||||
};
|
||||
|
||||
return SubmissionProduct;
|
||||
};
|
||||
|
||||
25
app/models/user.model.js
Normal file
25
app/models/user.model.js
Normal file
@ -0,0 +1,25 @@
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const User = sequelize.define("admin_users", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
email: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
});
|
||||
|
||||
return User;
|
||||
};
|
||||
|
||||
44
app/models/variationReasonMaster.model.js
Normal file
44
app/models/variationReasonMaster.model.js
Normal file
@ -0,0 +1,44 @@
|
||||
// app/models/variationReasonMaster.model.js
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const VariationReasonMaster = sequelize.define("variation_reason_master", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
reason: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
},
|
||||
high_or_low: {
|
||||
type: DataTypes.STRING(20),
|
||||
allowNull: true,
|
||||
},
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
},
|
||||
created_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
}, {
|
||||
tableName: "variation_reason_master",
|
||||
timestamps: false,
|
||||
});
|
||||
|
||||
return VariationReasonMaster;
|
||||
};
|
||||
|
||||
39
app/models/zeroTargetReason.model.js
Normal file
39
app/models/zeroTargetReason.model.js
Normal file
@ -0,0 +1,39 @@
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
const ZeroTargetReasonMaster = sequelize.define("zero_target_reason_master", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
reason: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
},
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
},
|
||||
created_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
updated_by: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
}, {
|
||||
tableName: "zero_target_reason_master",
|
||||
timestamps: false,
|
||||
});
|
||||
|
||||
return ZeroTargetReasonMaster;
|
||||
};
|
||||
|
||||
1423
app/routes/routes.js
Normal file
1423
app/routes/routes.js
Normal file
File diff suppressed because it is too large
Load Diff
15
app/services/logger.js
Normal file
15
app/services/logger.js
Normal file
@ -0,0 +1,15 @@
|
||||
const { createLogger, transports, format } = require('winston');
|
||||
const path = require('path');
|
||||
|
||||
const logger = createLogger({
|
||||
format: format.combine(
|
||||
format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`)
|
||||
),
|
||||
transports: [
|
||||
new transports.File({ filename: path.join(__dirname, '../writable/logs/app.log') }),
|
||||
new transports.Console()
|
||||
]
|
||||
});
|
||||
|
||||
module.exports = logger;
|
||||
2186
package-lock.json
generated
Normal file
2186
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
package.json
Normal file
30
package.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "fcsc_ipi_backend",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"dev": "nodemon server.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^3.0.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.3",
|
||||
"express": "^5.1.0",
|
||||
"express-validator": "^7.2.1",
|
||||
"helmet": "^8.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"morgan": "^1.10.1",
|
||||
"multer": "^2.0.2",
|
||||
"mysql2": "^3.15.2",
|
||||
"nodemon": "^3.1.10",
|
||||
"sequelize": "^6.37.7",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"winston": "^3.18.3"
|
||||
}
|
||||
}
|
||||
64
server.js
Normal file
64
server.js
Normal file
@ -0,0 +1,64 @@
|
||||
const express = require("express");
|
||||
const cors = require("cors");
|
||||
const helmet = require("helmet");
|
||||
const morgan = require("morgan");
|
||||
const swaggerUi = require("swagger-ui-express");
|
||||
const swaggerJsdoc = require("swagger-jsdoc");
|
||||
const routes = require("./app/routes/routes");
|
||||
const db = require("./app/models");
|
||||
require("dotenv").config();
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
app.use(cors());
|
||||
app.use(helmet());
|
||||
app.use(morgan("dev"));
|
||||
|
||||
// Swagger setup
|
||||
const swaggerOptions = {
|
||||
definition: {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "FCSC IPI Survey",
|
||||
version: "1.0.0",
|
||||
description: "User management + Auth API using Sequelize and Swagger",
|
||||
},
|
||||
components: {
|
||||
securitySchemes: {
|
||||
bearerAuth: {
|
||||
type: "http",
|
||||
scheme: "bearer",
|
||||
bearerFormat: "JWT",
|
||||
},
|
||||
},
|
||||
},
|
||||
security: [
|
||||
{
|
||||
bearerAuth: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
apis: ["./app/routes/*.js"],
|
||||
};
|
||||
const swaggerDocs = swaggerJsdoc(swaggerOptions);
|
||||
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
|
||||
|
||||
|
||||
// Routes
|
||||
app.use("/api", routes);
|
||||
|
||||
|
||||
|
||||
// Sync DB
|
||||
db.sequelize.sync({ alter: true }).then(() => {
|
||||
console.log("✅ Database connected & synced.");
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Start server
|
||||
const PORT = process.env.PORT || 5000;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🚀 Server running on port ${PORT}`);
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user