GWM : product upload and get previous quarter data

This commit is contained in:
Gowtham M 2025-11-04 12:22:13 +05:30
parent ec77398eff
commit 6724b13765
5 changed files with 209 additions and 0 deletions

View File

@ -1,5 +1,9 @@
const db = require("../models");
const Product = db.Product;
const fs = require("fs");
const csv = require("csv-parser");
const path = require("path");
exports.createProduct = async (req, res) => {
try {
@ -66,3 +70,50 @@ exports.deleteProduct = async (req, res) => {
res.status(500).send({'status':"failed",'message':err.message });
}
};
exports.uploadProductsFromCSV = async (req, res) => {
try {
if (!req.file) {
return res.status(400).send({ status: "failed", message: "No file uploaded" });
}
const results = [];
const filePath = req.file.path;
// Read CSV and store rows
fs.createReadStream(filePath)
.pipe(csv())
.on("data", (row) => {
results.push(row);
})
.on("end", async () => {
try {
// Insert all rows into Product table
const inserted = await Product.bulkCreate(results, { validate: true });
fs.unlinkSync(filePath); // delete file after processing
res.status(201).send({
status: "success",
message: `${inserted.length} products inserted successfully`,
data: inserted,
});
} catch (dbErr) {
res.status(500).send({
status: "failed",
message: dbErr.message,
});
}
});
} catch (error) {
res.status(500).send({ status: "failed", message: error.message });
}
};
exports.downloadProductSample = async (req, res) => {
try {
const filePath = path.join(__dirname, "../writable/uploads/sample_files/products_upload_sample.csv");
return res.download(filePath, "products_upload_sample.csv");
} catch (err) {
return res.status(500).send({ status: "failed", message: err.message });
}
};

View File

@ -526,3 +526,48 @@ exports.getQuarterPeriods = async (req, res) => {
return res.status(500).json({ status: "failed", message: err.message });
}
};
exports.getPreviousForecastData = async (req, res) => {
try {
const { establishment_id, quarter, year, product_id } = req.query;
if(!establishment_id || !quarter || !year || !product_id){
return res.status(400).json({ status:"failed", message:"Missing required query params" });
}
// find submission id
const submission = await Submission.findOne({
where : { establishment_id, quarter, year },
});
if(!submission){
return res.status(404).json({ status:"failed", message:"No previous submission found" });
}
// find submission product row
const submissionProduct = await SubmissionProduct.findOne({
where : {
submission_id : submission.id,
product_id
},
include:[
{
model: Product,
as: "product",
attributes:["product_name","hs_code"]
}
]
});
if(!submissionProduct){
return res.status(404).json({ status:"failed", message:"No previous product row found" });
}
return res.status(200).json({ status:"success", data: submissionProduct });
} catch (err) {
return res.status(500).json({ status:"failed", message: err.message });
}
};

View File

@ -18,8 +18,15 @@ const dashboardController = require("../controllers/dashboard.controller");
const notificationTemplateController = require("../controllers/notificationTemplate.controller");
const quarterlyWindowsController = require("../controllers/quarterlyWindowsConfiguration.controller");
const path = require("path");
const multer = require("multer");
const upload = multer({ dest: "../writable/uploads/products_bulk_uploads_files" });
/**
* @swagger
* tags:
@ -1015,6 +1022,62 @@ router.put("/products/:id",[verifySignature, verifyToken], productController.upd
*/
router.delete("/products/:id",[verifySignature, verifyToken], productController.deleteProduct);
/**
* @swagger
* /api/products/uploadCSV:
* post:
* summary: Upload products in bulk using CSV file
* description: This API accepts CSV file and inserts multiple products in bulk. CSV header columns must match Product table columns.
* tags: [Products]
* security:
* - appSignature: []
* - bearerAuth: []
* requestBody:
* required: true
* content:
* multipart/form-data:
* schema:
* type: object
* properties:
* file:
* type: string
* format: binary
* description: CSV file to upload
* responses:
* 201:
* description: Products uploaded successfully
* 400:
* description: No file uploaded
* 500:
* description: Server error
*/
router.post("/products/uploadCSV",[ verifySignature, verifyToken, upload.single("file")], productController.uploadProductsFromCSV);
/**
* @swagger
* /api/products/download-sample:
* get:
* summary: Download sample CSV template for bulk product upload
* tags: [Products]
* responses:
* 200:
* description: Sample CSV file downloaded successfully
* content:
* text/csv:
* schema:
* type: string
* format: binary
* 404:
* description: File not found
* 500:
* description: Server error
*/
router.get("/download-sample-product-upload-file",[verifySignature, verifyToken], productController.downloadProductSample);
@ -1964,6 +2027,43 @@ router.put("/approveOrRejectSubmission/:id",[verifySignature, verifyToken], subm
*/
router.post("/getQuarterPeriods",[verifySignature, verifyToken], submissionController.getQuarterPeriods);
/**
* @swagger
* /api/submissions/getPreviousForecastData:
* get:
* summary: Get Previous and Forecast Data based on Establishment + Quarter + Year + Product
* tags: [Submissions]
* security:
* - appSignature: []
* - bearerAuth: []
* parameters:
* - in: query
* name: establishment_id
* required: true
* schema: { type: integer }
* - in: query
* name: quarter
* required: true
* schema: { type: string, enum: [Q1, Q2, Q3, Q4] }
* - in: query
* name: year
* required: true
* schema: { type: integer }
* - in: query
* name: product_id
* required: true
* schema: { type: integer }
* responses:
* 200:
* description: Previous forecast data fetched successfully
* 404:
* description: Not found
* 500:
* description: Server error
*/
router.get("/submissions/getPreviousForecastData", submissionController.getPreviousForecastData);

12
package-lock.json generated
View File

@ -11,6 +11,7 @@
"dependencies": {
"bcryptjs": "^3.0.2",
"cors": "^2.8.5",
"csv-parser": "^3.2.0",
"dotenv": "^17.2.3",
"exceljs": "^4.4.0",
"express": "^5.1.0",
@ -724,6 +725,17 @@
"node": ">= 10"
}
},
"node_modules/csv-parser": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/csv-parser/-/csv-parser-3.2.0.tgz",
"integrity": "sha512-fgKbp+AJbn1h2dcAHKIdKNSSjfp43BZZykXsCjzALjKy80VXQNHPFJ6T9Afwdzoj24aMkq8GwDS7KGcDPpejrA==",
"bin": {
"csv-parser": "bin/csv-parser"
},
"engines": {
"node": ">= 10"
}
},
"node_modules/dayjs": {
"version": "1.11.18",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",

View File

@ -13,6 +13,7 @@
"dependencies": {
"bcryptjs": "^3.0.2",
"cors": "^2.8.5",
"csv-parser": "^3.2.0",
"dotenv": "^17.2.3",
"exceljs": "^4.4.0",
"express": "^5.1.0",