450 lines
14 KiB
JavaScript
450 lines
14 KiB
JavaScript
const db = require("../models");
|
|
const Submission = db.Submission;
|
|
const SubmissionProduct = db.SubmissionProduct;
|
|
const Establishment = db.Establishment;
|
|
const EstablishmentUser = db.EstablishmentUser;
|
|
const UnitMaster = db.UnitMaster;
|
|
const VariationReasonMaster = db.VariationReasonMaster;
|
|
const ZeroTargetReasonMaster = db.ZeroTargetReasonMaster;
|
|
const Product = db.Product;
|
|
const { Op } = require("sequelize");
|
|
const { Sequelize } = require("sequelize");
|
|
const { sendEmail } = require("../services/email.service");
|
|
const { getQuarterPeriods } = require("../services/quarterService");
|
|
|
|
|
|
|
|
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);
|
|
|
|
// Process products before insert
|
|
const processedProducts = products.map((p) => {
|
|
const num = (v) => (isNaN(parseFloat(v)) ? 0 : parseFloat(v)); // safe number conversion
|
|
|
|
// Calculate totals for each section
|
|
const previous_quantity =
|
|
num(p.previous_quantity_period_one) +
|
|
num(p.previous_quantity_period_two) +
|
|
num(p.previous_quantity_period_three);
|
|
|
|
const previous_cost =
|
|
num(p.previous_cost_period_one) +
|
|
num(p.previous_cost_period_two) +
|
|
num(p.previous_cost_period_three);
|
|
|
|
const current_quantity =
|
|
num(p.current_quantity_period_one) +
|
|
num(p.current_quantity_period_two) +
|
|
num(p.current_quantity_period_three);
|
|
|
|
const current_cost =
|
|
num(p.current_cost_period_one) +
|
|
num(p.current_cost_period_two) +
|
|
num(p.current_cost_period_three);
|
|
|
|
const forecast_quantity =
|
|
num(p.forecast_quantity_period_one) +
|
|
num(p.forecast_quantity_period_two) +
|
|
num(p.forecast_quantity_period_three);
|
|
|
|
const forecast_cost =
|
|
num(p.forecast_cost_period_one) +
|
|
num(p.forecast_cost_period_two) +
|
|
num(p.forecast_cost_period_three);
|
|
|
|
return {
|
|
...p,
|
|
submission_id: submission.id,
|
|
previous_quantity: previous_quantity.toString(),
|
|
previous_cost: previous_cost.toString(),
|
|
current_quantity: current_quantity.toString(),
|
|
current_cost: current_cost.toString(),
|
|
forecast_quantity: forecast_quantity.toString(),
|
|
forecast_cost: forecast_cost.toString(),
|
|
};
|
|
});
|
|
|
|
// Bulk insert products
|
|
await SubmissionProduct.bulkCreate(processedProducts);
|
|
|
|
}
|
|
|
|
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.updateSubmission = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { products = [], ...submissionData } = req.body;
|
|
|
|
// Check if submission exists
|
|
const submission = await Submission.findByPk(id);
|
|
if (!submission)
|
|
return res.status(404).json({ status: "failed", message: "Submission not found" });
|
|
|
|
// Update main submission record
|
|
await submission.update(submissionData);
|
|
|
|
// Helper: safe numeric conversion
|
|
const num = (v) => (isNaN(parseFloat(v)) ? 0 : parseFloat(v));
|
|
|
|
// Loop through products
|
|
for (const p of products) {
|
|
// --- Auto-calculate totals ---
|
|
const previous_quantity =
|
|
num(p.previous_quantity_period_one) +
|
|
num(p.previous_quantity_period_two) +
|
|
num(p.previous_quantity_period_three);
|
|
|
|
const previous_cost =
|
|
num(p.previous_cost_period_one) +
|
|
num(p.previous_cost_period_two) +
|
|
num(p.previous_cost_period_three);
|
|
|
|
const current_quantity =
|
|
num(p.current_quantity_period_one) +
|
|
num(p.current_quantity_period_two) +
|
|
num(p.current_quantity_period_three);
|
|
|
|
const current_cost =
|
|
num(p.current_cost_period_one) +
|
|
num(p.current_cost_period_two) +
|
|
num(p.current_cost_period_three);
|
|
|
|
const forecast_quantity =
|
|
num(p.forecast_quantity_period_one) +
|
|
num(p.forecast_quantity_period_two) +
|
|
num(p.forecast_quantity_period_three);
|
|
|
|
const forecast_cost =
|
|
num(p.forecast_cost_period_one) +
|
|
num(p.forecast_cost_period_two) +
|
|
num(p.forecast_cost_period_three);
|
|
|
|
// Attach calculated fields
|
|
const updatedProductData = {
|
|
...p,
|
|
submission_id: id,
|
|
previous_quantity: previous_quantity.toString(),
|
|
previous_cost: previous_cost.toString(),
|
|
current_quantity: current_quantity.toString(),
|
|
current_cost: current_cost.toString(),
|
|
forecast_quantity: forecast_quantity.toString(),
|
|
forecast_cost: forecast_cost.toString(),
|
|
};
|
|
|
|
// --- Update or Create ---
|
|
if (p.id) {
|
|
const existingProduct = await SubmissionProduct.findOne({
|
|
where: { id: p.id, submission_id: id },
|
|
});
|
|
|
|
if (existingProduct) {
|
|
await existingProduct.update(updatedProductData);
|
|
} else {
|
|
await SubmissionProduct.create(updatedProductData);
|
|
}
|
|
} else {
|
|
await SubmissionProduct.create(updatedProductData);
|
|
}
|
|
}
|
|
|
|
// Fetch updated data with associations
|
|
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: Establishment,
|
|
as: "establishment" ,
|
|
attributes: ["factory_name","establishment_code","emirate"],
|
|
},
|
|
{
|
|
model: EstablishmentUser,
|
|
as: "created_user",
|
|
attributes: ["name", "email"],
|
|
},
|
|
],
|
|
attributes: {
|
|
include: [
|
|
[
|
|
Sequelize.literal(`(SELECT COUNT(*) FROM submission_products AS sp WHERE sp.submission_id = submission.id )`),
|
|
"product_count",
|
|
],
|
|
],
|
|
},
|
|
order: [["id", "DESC"]],
|
|
});
|
|
|
|
res.status(200).json({ status: "success", data });
|
|
|
|
} catch (err) {
|
|
res.status(500).json({ status: "failed", message: err.message });
|
|
}
|
|
};
|
|
|
|
|
|
exports.viewSubmissionDetails = async (req, res) => {
|
|
try {
|
|
|
|
const { id } = req.params;
|
|
|
|
const data = await Submission.findByPk(id, {
|
|
include: [
|
|
{
|
|
model: Establishment,
|
|
as: "establishment" ,
|
|
},
|
|
{
|
|
model: SubmissionProduct,
|
|
as: "products",
|
|
include: [
|
|
{
|
|
model: Product,
|
|
as: "product",
|
|
attributes: ["id", "product_name", "hs_code", "hs_description"],
|
|
},
|
|
{
|
|
model: UnitMaster,
|
|
as: "unit",
|
|
attributes: ["uom"],
|
|
},
|
|
{
|
|
model: VariationReasonMaster,
|
|
as: "variation_reason",
|
|
attributes: ["reason"],
|
|
},
|
|
{
|
|
model: ZeroTargetReasonMaster,
|
|
as: "zero_target_reason",
|
|
attributes: ["reason"],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
});
|
|
|
|
const quarter_periods = getQuarterPeriods(Number(data.year), data.quarter);
|
|
|
|
|
|
if (!data) return res.status(404).json({ status: "failed", message: "Not found" });
|
|
|
|
res.status(200).json({ status: "success", data , quarter_periods });
|
|
|
|
} catch (err) {
|
|
res.status(500).json({ status: "failed", message: err.message });
|
|
}
|
|
};
|
|
|
|
|
|
|
|
exports.submissionEditRequest = async (req, res) => {
|
|
try {
|
|
|
|
const { id } = req.params;
|
|
edit_request = req.body.edit_request;
|
|
|
|
// 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({ edit_request });
|
|
|
|
res.status(200).json({
|
|
status: "success",
|
|
message: "Submission edit request updated",
|
|
data: "",
|
|
});
|
|
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ status: "failed", message: err.message });
|
|
}
|
|
};
|
|
|
|
exports.enableOrDisableSubmissionEditAccess = async (req, res) => {
|
|
try {
|
|
|
|
const { id } = req.params;
|
|
edit_access = req.body.edit_access;
|
|
|
|
// 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({ edit_request : 0 , edit_access : edit_access});
|
|
|
|
res.status(200).json({
|
|
status: "success",
|
|
message: "Submission edit access updated",
|
|
data: "",
|
|
});
|
|
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ status: "failed", message: err.message });
|
|
}
|
|
};
|
|
|
|
|
|
exports.approveOrRejectSubmission = async (req, res) => {
|
|
try {
|
|
|
|
const { id } = req.params;
|
|
approve_reject_status = req.body.approve_reject_status;
|
|
if(approve_reject_status == 1)
|
|
{
|
|
statusString = 'Approved';
|
|
}else{
|
|
statusString = 'Rejected';
|
|
}
|
|
|
|
// 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({ approve_reject_status : approve_reject_status , status : statusString });
|
|
|
|
res.status(200).json({
|
|
status: "success",
|
|
message: "Submission edit access updated",
|
|
data: "",
|
|
});
|
|
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ status: "failed", message: err.message });
|
|
}
|
|
};
|
|
|
|
|
|
|
|
exports.getQuarterPeriods = async (req, res) => {
|
|
try {
|
|
const { current_year, current_quarter } = req.body;
|
|
|
|
if (!current_year || !current_quarter) {
|
|
return res
|
|
.status(400)
|
|
.json({ status: "failed", message: "current_year and current_quarter are required" });
|
|
}
|
|
|
|
const quarter_periods = getQuarterPeriods(Number(current_year), current_quarter);
|
|
|
|
return res.status(200).json({ status: "success", data: quarter_periods });
|
|
} catch (err) {
|
|
return res.status(500).json({ status: "failed", message: err.message });
|
|
}
|
|
};
|