GWM : submission data updated
This commit is contained in:
parent
55787d3cbd
commit
0df0d647dd
@ -10,6 +10,7 @@ const Product = db.Product;
|
||||
const { Op } = require("sequelize");
|
||||
const { Sequelize } = require("sequelize");
|
||||
const { sendEmail } = require("../services/email.service");
|
||||
const { getQuarterPeriods } = require("../services/quarterService");
|
||||
|
||||
|
||||
|
||||
@ -23,8 +24,59 @@ exports.createSubmission = async (req, res) => {
|
||||
|
||||
const submission = await Submission.create(submissionData);
|
||||
if (products.length) {
|
||||
products.forEach((p) => (p.submission_id = submission.id));
|
||||
await SubmissionProduct.bulkCreate(products);
|
||||
// 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, {
|
||||
@ -38,58 +90,150 @@ exports.createSubmission = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateSubmission = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { products = [], ...submissionData } = req.body;
|
||||
// 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" });
|
||||
// // 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);
|
||||
// // 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 },
|
||||
});
|
||||
// // 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);
|
||||
}
|
||||
}
|
||||
// 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" }],
|
||||
});
|
||||
// // 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,
|
||||
});
|
||||
// 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 });
|
||||
}
|
||||
};
|
||||
// } 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) => {
|
||||
@ -185,10 +329,12 @@ exports.viewSubmissionDetails = async (req, res) => {
|
||||
],
|
||||
});
|
||||
|
||||
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 });
|
||||
res.status(200).json({ status: "success", data , quarter_periods });
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).json({ status: "failed", message: err.message });
|
||||
@ -281,3 +427,23 @@ exports.approveOrRejectSubmission = async (req, res) => {
|
||||
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 });
|
||||
}
|
||||
};
|
||||
|
||||
@ -12,6 +12,34 @@ module.exports = (sequelize, DataTypes) => {
|
||||
product_id: DataTypes.INTEGER,
|
||||
unit_id: DataTypes.INTEGER,
|
||||
annual_installed_capacity: DataTypes.STRING(100),
|
||||
|
||||
// --- Previous Periods ---
|
||||
previous_quantity_period_one: { type: DataTypes.STRING(100), allowNull: true },
|
||||
previous_quantity_period_two: { type: DataTypes.STRING(100), allowNull: true },
|
||||
previous_quantity_period_three: { type: DataTypes.STRING(100), allowNull: true },
|
||||
|
||||
previous_cost_period_one: { type: DataTypes.STRING(100), allowNull: true },
|
||||
previous_cost_period_two: { type: DataTypes.STRING(100), allowNull: true },
|
||||
previous_cost_period_three: { type: DataTypes.STRING(100), allowNull: true },
|
||||
|
||||
// --- Current Periods ---
|
||||
current_quantity_period_one: { type: DataTypes.STRING(100), allowNull: true },
|
||||
current_quantity_period_two: { type: DataTypes.STRING(100), allowNull: true },
|
||||
current_quantity_period_three: { type: DataTypes.STRING(100), allowNull: true },
|
||||
|
||||
current_cost_period_one: { type: DataTypes.STRING(100), allowNull: true },
|
||||
current_cost_period_two: { type: DataTypes.STRING(100), allowNull: true },
|
||||
current_cost_period_three: { type: DataTypes.STRING(100), allowNull: true },
|
||||
|
||||
// --- Forecast Periods ---
|
||||
forecast_quantity_period_one: { type: DataTypes.STRING(100), allowNull: true },
|
||||
forecast_quantity_period_two: { type: DataTypes.STRING(100), allowNull: true },
|
||||
forecast_quantity_period_three: { type: DataTypes.STRING(100), allowNull: true },
|
||||
|
||||
forecast_cost_period_one: { type: DataTypes.STRING(100), allowNull: true },
|
||||
forecast_cost_period_two: { type: DataTypes.STRING(100), allowNull: true },
|
||||
forecast_cost_period_three: { type: DataTypes.STRING(100), allowNull: true },
|
||||
|
||||
previous_quantity: DataTypes.STRING(100),
|
||||
previous_cost: DataTypes.STRING(100),
|
||||
current_quantity: DataTypes.STRING(100),
|
||||
|
||||
@ -1545,6 +1545,24 @@ router.delete("/unit_master/:id",[verifySignature, verifyToken], unitMasterContr
|
||||
* product_id: { type: integer }
|
||||
* unit_id: { type: integer }
|
||||
* annual_installed_capacity: { type: string }
|
||||
* previous_quantity_period_one: { type: string }
|
||||
* previous_quantity_period_two: { type: string }
|
||||
* previous_quantity_period_three: { type: string }
|
||||
* previous_cost_period_one: { type: string }
|
||||
* previous_cost_period_two: { type: string }
|
||||
* previous_cost_period_three: { type: string }
|
||||
* current_quantity_period_one: { type: string }
|
||||
* current_quantity_period_two: { type: string }
|
||||
* current_quantity_period_three: { type: string }
|
||||
* current_cost_period_one: { type: string }
|
||||
* current_cost_period_two: { type: string }
|
||||
* current_cost_period_three: { type: string }
|
||||
* forecast_quantity_period_one: { type: string }
|
||||
* forecast_quantity_period_two: { type: string }
|
||||
* forecast_quantity_period_three: { type: string }
|
||||
* forecast_cost_period_one: { type: string }
|
||||
* forecast_cost_period_two: { type: string }
|
||||
* forecast_cost_period_three: { type: string }
|
||||
* previous_quantity: { type: string }
|
||||
* previous_cost: { type: string }
|
||||
* current_quantity: { type: string }
|
||||
@ -1600,6 +1618,24 @@ router.post("/submissions",[verifySignature, verifyToken], submissionController.
|
||||
* product_id: { type: integer }
|
||||
* unit_id: { type: integer }
|
||||
* annual_installed_capacity: { type: string }
|
||||
* previous_quantity_period_one: { type: string }
|
||||
* previous_quantity_period_two: { type: string }
|
||||
* previous_quantity_period_three: { type: string }
|
||||
* previous_cost_period_one: { type: string }
|
||||
* previous_cost_period_two: { type: string }
|
||||
* previous_cost_period_three: { type: string }
|
||||
* current_quantity_period_one: { type: string }
|
||||
* current_quantity_period_two: { type: string }
|
||||
* current_quantity_period_three: { type: string }
|
||||
* current_cost_period_one: { type: string }
|
||||
* current_cost_period_two: { type: string }
|
||||
* current_cost_period_three: { type: string }
|
||||
* forecast_quantity_period_one: { type: string }
|
||||
* forecast_quantity_period_two: { type: string }
|
||||
* forecast_quantity_period_three: { type: string }
|
||||
* forecast_cost_period_one: { type: string }
|
||||
* forecast_cost_period_two: { type: string }
|
||||
* forecast_cost_period_three: { type: string }
|
||||
* previous_quantity: { type: string }
|
||||
* previous_cost: { type: string }
|
||||
* current_quantity: { type: string }
|
||||
@ -1760,7 +1796,29 @@ router.put("/enableOrDisableSubmissionEditAccess/:id",[verifySignature, verifyTo
|
||||
router.put("/approveOrRejectSubmission/:id",[verifySignature, verifyToken], submissionController.approveOrRejectSubmission);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/getQuarterPeriods:
|
||||
* post:
|
||||
* summary: get Quarter Periods based on current quarter and year
|
||||
* tags: [Submissions]
|
||||
* security:
|
||||
* - appSignature: []
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* current_year: { type: integer }
|
||||
* current_quarter: { type: string }
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Updated successfully
|
||||
*/
|
||||
router.post("/getQuarterPeriods",[verifySignature, verifyToken], submissionController.getQuarterPeriods);
|
||||
|
||||
|
||||
|
||||
|
||||
73
app/services/quarterService.js
Normal file
73
app/services/quarterService.js
Normal file
@ -0,0 +1,73 @@
|
||||
// services/quarterService.js
|
||||
|
||||
/**
|
||||
* Get Quarter and Month details based on current quarter and financial year
|
||||
* @param {number} currentYear - e.g. 2025
|
||||
* @param {string} currentQuarter - e.g. 'Q4'
|
||||
* @returns {object} - structured period data
|
||||
*/
|
||||
exports.getQuarterPeriods = (currentYear, currentQuarter) => {
|
||||
// Define quarters based on financial year (Apr–Mar)
|
||||
const quarters = {
|
||||
Q1: ["Apr", "May", "Jun"],
|
||||
Q2: ["Jul", "Aug", "Sep"],
|
||||
Q3: ["Oct", "Nov", "Dec"],
|
||||
Q4: ["Jan", "Feb", "Mar"],
|
||||
};
|
||||
|
||||
const allQuarters = ["Q1", "Q2", "Q3", "Q4"];
|
||||
const currentIndex = allQuarters.indexOf(currentQuarter);
|
||||
|
||||
if (currentIndex === -1) {
|
||||
throw new Error("Invalid quarter. Use one of: Q1, Q2, Q3, Q4");
|
||||
}
|
||||
|
||||
// --- Previous Quarter ---
|
||||
let previousQuarter = allQuarters[(currentIndex - 1 + 4) % 4];
|
||||
let previousYear = currentYear;
|
||||
// If current quarter is Q1, previous year is same financial year → currentYear
|
||||
// But Q1 (Apr-Jun) comes after Mar, so same financial year
|
||||
if (currentQuarter === "Q1") {
|
||||
previousYear = currentYear - 1;
|
||||
} else if (currentQuarter === "Q4") {
|
||||
previousYear = currentYear; // Q4 (Jan–Mar) belongs to same financial year end
|
||||
}
|
||||
|
||||
// --- Forecast Quarter ---
|
||||
let forecastQuarter = allQuarters[(currentIndex + 1) % 4];
|
||||
let forecastYear = currentYear;
|
||||
// If next quarter is Q1, then financial year increments
|
||||
if (forecastQuarter === "Q1") {
|
||||
forecastYear = currentYear + 1;
|
||||
}
|
||||
|
||||
// Construct Output Object
|
||||
const output = {
|
||||
previous_month: {
|
||||
previous_period_one: quarters[previousQuarter][0],
|
||||
previous_period_two: quarters[previousQuarter][1],
|
||||
previous_period_three: quarters[previousQuarter][2],
|
||||
},
|
||||
previous_year: previousYear,
|
||||
previous_quarter: previousQuarter,
|
||||
|
||||
current_month: {
|
||||
current_period_one: quarters[currentQuarter][0],
|
||||
current_period_two: quarters[currentQuarter][1],
|
||||
current_period_three: quarters[currentQuarter][2],
|
||||
},
|
||||
current_year: currentYear,
|
||||
current_quarter: currentQuarter,
|
||||
|
||||
forecast_month: {
|
||||
forecast_period_one: quarters[forecastQuarter][0],
|
||||
forecast_period_two: quarters[forecastQuarter][1],
|
||||
forecast_period_three: quarters[forecastQuarter][2],
|
||||
},
|
||||
forecast_year: forecastYear,
|
||||
forecast_quarter: forecastQuarter,
|
||||
};
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user