fcsc_ipi_backend/app/controllers/submission.controller.js

400 lines
12 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 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 });
}
};