Added API: getManufacturingMonthlyOverview

This commit is contained in:
unknown 2025-12-24 16:46:10 +05:30
parent 454f97e84c
commit 8ce1d8b8e4
7 changed files with 369 additions and 5 deletions

View File

@ -1,5 +1,8 @@
const db = require("../models");
const ManufacturingIpi = db.ManufacturingIpi;
const Isic2DigitIndices = db.Isic2DigitIndices;
const Isic3DigitIndices = db.Isic3DigitIndices;
const Isic4DigitIndices = db.Isic4DigitIndices;
const logger = require("../services/logger");
const formatDecimal = (value) => {
@ -38,6 +41,153 @@ exports.getAllManufacturingIndexDetails = async (req, res) => {
} catch (error) {
logger.error(`getAllManufacturingIndexDetails API: ${error.message}`);
logger.error(`Stack trace: ${error.stack}`);
res.status(500).send({ status: "failed", message: "Internal server error" });
}
};
exports.getManufacturingMonthlyOverviewByYearMonth = async (req, res) => {
try {
const { year, month } = req.query;
// Validate parameters exist
if (!year || !month) {
logger.warn('getManufacturingMonthlyOverview API: Missing required parameters');
return res.status(400).send({
status: "failed",
message: "Year and month are required"
});
}
// Sanitize and validate input - prevent SQL injection
const yearInt = parseInt(year, 10);
const monthInt = parseInt(month, 10);
// Validate that parsing was successful
if (isNaN(yearInt) || isNaN(monthInt)) {
logger.warn(`getManufacturingMonthlyOverview API: Invalid input - year: ${year}, month: ${month}`);
return res.status(400).send({
status: "failed",
message: "Year and month must be valid numbers"
});
}
// Validate year range (reasonable bounds)
if (yearInt < 2000 || yearInt > 2100) {
return res.status(400).send({
status: "failed",
message: "Year must be between 2000 and 2100"
});
}
// Validate month range
if (monthInt < 1 || monthInt > 12) {
return res.status(400).send({
status: "failed",
message: "Month must be between 1 and 12"
});
}
// Common where clause
const whereClause = {
year: yearInt,
month: monthInt
};
// Fetch data from all tables in parallel
const [manufacturingData, isic2DigitData, isic3DigitData, isic4DigitData] = await Promise.all([
ManufacturingIpi.findOne({
attributes: ['manufacturing_index', 'mom_change', 'yoy_change'],
where: whereClause
}),
Isic2DigitIndices.findAll({
attributes: ['isic_2digit_code', 'isic_description', 'total_weight', 'weighted_index_sum', 'isic_2digit_index'],
where: whereClause,
order: [['isic_2digit_code', 'ASC']]
}),
Isic3DigitIndices.findAll({
attributes: ['isic_3digit_code', 'isic_description', 'total_weight', 'weighted_index_sum', 'isic_3digit_index'],
where: whereClause,
order: [['isic_3digit_code', 'ASC']]
}),
Isic4DigitIndices.findAll({
attributes: ['isic_4digit_code', 'isic_description', 'total_weight', 'weighted_index_sum', 'isic_4digit_index'],
where: whereClause,
order: [['isic_4digit_code', 'ASC']]
})
]);
// Check if manufacturing data exists (main data)
if (!manufacturingData) {
logger.info(`getManufacturingMonthlyOverview API: No data found for year ${yearInt}, month ${monthInt}`);
return res.status(404).send({
status: "failed",
message: "No data found for the specified period"
});
}
// Format Manufacturing IPI data
const plainManufacturing = manufacturingData.get({ plain: true });
const formattedManufacturing = {
manufacturing_index: formatDecimal(plainManufacturing.manufacturing_index),
mom_change: formatDecimal(plainManufacturing.mom_change),
yoy_change: formatDecimal(plainManufacturing.yoy_change),
};
// Format ISIC 2-digit data
const formattedIsic2Digit = isic2DigitData.map(item => {
const plainItem = item.get({ plain: true });
return {
isic_2digit_code: plainItem.isic_2digit_code,
isic_description: plainItem.isic_description,
total_weight: formatDecimal(plainItem.total_weight),
weighted_index_sum: formatDecimal(plainItem.weighted_index_sum),
isic_2digit_index: formatDecimal(plainItem.isic_2digit_index),
};
});
// Format ISIC 3-digit data
const formattedIsic3Digit = isic3DigitData.map(item => {
const plainItem = item.get({ plain: true });
return {
isic_3digit_code: plainItem.isic_3digit_code,
isic_description: plainItem.isic_description,
total_weight: formatDecimal(plainItem.total_weight),
weighted_index_sum: formatDecimal(plainItem.weighted_index_sum),
isic_3digit_index: formatDecimal(plainItem.isic_3digit_index),
};
});
// Format ISIC 4-digit data
const formattedIsic4Digit = isic4DigitData.map(item => {
const plainItem = item.get({ plain: true });
return {
isic_4digit_code: plainItem.isic_4digit_code,
isic_description: plainItem.isic_description,
total_weight: formatDecimal(plainItem.total_weight),
weighted_index_sum: formatDecimal(plainItem.weighted_index_sum),
isic_4digit_index: formatDecimal(plainItem.isic_4digit_index),
};
});
logger.info(`getManufacturingMonthlyOverview API: Successfully fetched data for year ${yearInt}, month ${monthInt}`);
res.status(200).send({
status: "success",
message: "Fetched successfully",
manufacturing_total: formattedManufacturing,
isic_2digit: formattedIsic2Digit,
isic_3digit: formattedIsic3Digit,
isic_4digit: formattedIsic4Digit
});
} catch (error) {
logger.error(`getManufacturingMonthlyOverview API Error: ${error.message}`);
logger.error(`Stack trace: ${error.stack}`);
res.status(500).send({
status: "failed",
message: "Internal server error"
});
}
};

View File

@ -118,7 +118,7 @@ exports.getAllProducts = async (req, res) => {
});
} catch (error) {
logger.error(err.message);
logger.error(error.message);
res.status(500).send({ status: "failed", message: "Internal server error" });
}
};
@ -133,7 +133,7 @@ exports.getProductById = async (req, res) => {
res.status(200).send({'status':"success",'message':"Fetched successfully",'data': data });
} catch (error) {
logger.error(err.message);
logger.error(error.message);
res.status(500).send({'status':"failed",'message': "Internal server error" });
}
};
@ -170,7 +170,7 @@ exports.deleteProduct = async (req, res) => {
res.status(200).send({'status':"success",'message':"Deleted successfully",'data': "" });
} catch (error) {
logger.error(err.message);
logger.error(error.message);
res.status(500).send({'status':"failed",'message': "Internal server error" });
}
};
@ -181,7 +181,7 @@ exports.downloadProductSample = async (req, res) => {
const filePath = path.join(__dirname, "../downloads_csv/products_upload_sample.csv");
return res.download(filePath, "products_upload_sample.csv");
} catch (error) {
logger.error(err.message);
logger.error(error.message);
res.status(500).send({'status':"failed",'message': "Internal server error" });
}
};

View File

@ -30,7 +30,9 @@ db.Emirate = require("./emirate.model")(sequelize, DataTypes);
db.CityTown = require("./cityTown.model")(sequelize, DataTypes);
db.SubmissionHistory = require("./submissionHistory.model")(sequelize, DataTypes);
db.ManufacturingIpi = require("./manufacturingIPI.model.js")(sequelize, DataTypes);
db.Isic2DigitIndices = require("./isic2DigitIndices.model.js")(sequelize, DataTypes);
db.Isic3DigitIndices = require("./isic3DigitIndices.model.js")(sequelize, DataTypes);
db.Isic4DigitIndices = require("./isic4DigitIndices.model.js")(sequelize, DataTypes);
// Associations
db.Establishment.hasMany(db.EstablishmentUser, {
foreignKey: "establishment_id",

View File

@ -0,0 +1,59 @@
module.exports = (sequelize, DataTypes) => {
const Isic2DigitIndices = sequelize.define("isic_2digit_indices", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
isic_2digit_code: {
type: DataTypes.STRING,
allowNull: false,
},
isic_description: {
type: DataTypes.STRING,
allowNull: true,
validate: {
len: {
args: [0, 1000],
msg: "Description is too long. Maximum allowed length is 1000 characters."
}}
},
year: {
type: DataTypes.INTEGER,
allowNull: false,
},
month: {
type: DataTypes.INTEGER,
allowNull: false,
},
month_name: {
type: DataTypes.STRING,
allowNull: false,
},
total_weight: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
},
weighted_index_sum: {
type: DataTypes.DECIMAL(10, 4),
allowNull: false,
},
isic_2digit_index: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
updated_at: {
type: DataTypes.DATE,
allowNull: true,
},
}, {
tableName: "isic_2digit_indices",
timestamps: false,
});
return Isic2DigitIndices;
};

View File

@ -0,0 +1,59 @@
module.exports = (sequelize, DataTypes) => {
const Isic3DigitIndices = sequelize.define("isic_3digit_indices", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
isic_3digit_code: {
type: DataTypes.STRING,
allowNull: false,
},
isic_description: {
type: DataTypes.STRING,
allowNull: true,
validate: {
len: {
args: [0, 1000],
msg: "Description is too long. Maximum allowed length is 1000 characters."
}}
},
year: {
type: DataTypes.INTEGER,
allowNull: false,
},
month: {
type: DataTypes.INTEGER,
allowNull: false,
},
month_name: {
type: DataTypes.STRING,
allowNull: false,
},
total_weight: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
},
weighted_index_sum: {
type: DataTypes.DECIMAL(10, 4),
allowNull: false,
},
isic_3digit_index: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
updated_at: {
type: DataTypes.DATE,
allowNull: true,
},
}, {
tableName: "isic_3digit_indices",
timestamps: false,
});
return Isic3DigitIndices;
};

View File

@ -0,0 +1,59 @@
module.exports = (sequelize, DataTypes) => {
const Isic4DigitIndices = sequelize.define("isic_4digit_indices", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
isic_4digit_code: {
type: DataTypes.STRING,
allowNull: false,
},
isic_description: {
type: DataTypes.STRING,
allowNull: true,
validate: {
len: {
args: [0, 1000],
msg: "Description is too long. Maximum allowed length is 1000 characters."
}}
},
year: {
type: DataTypes.INTEGER,
allowNull: false,
},
month: {
type: DataTypes.INTEGER,
allowNull: false,
},
month_name: {
type: DataTypes.STRING,
allowNull: false,
},
total_weight: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
},
weighted_index_sum: {
type: DataTypes.DECIMAL(10, 4),
allowNull: false,
},
isic_4digit_index: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
updated_at: {
type: DataTypes.DATE,
allowNull: true,
},
}, {
tableName: "isic_4digit_indices",
timestamps: false,
});
return Isic4DigitIndices;
};

View File

@ -3013,6 +3013,41 @@ router.get("/unit_master_download_sample_file",[verifySignature, verifyToken], u
*/
router.get("/manufacturing/getManufacturingIndex",[verifySignature, verifyToken], ManufacturingIpiController.getAllManufacturingIndexDetails);
/**
* @swagger
* /api/manufacturing/getManufacturingMonthlyOverview
* get:
* summary: Get Manufacturing IPI Monthly Overview by year and month
* tags: [ManufacturingIPI]
* security:
* - appSignature: []
* - CSRF: []
* cookieAuth: []
* parameters:
* - name: year
* in: query
* required: true
* schema:
* type: integer
* description: Year (e.g., 2025)
* - name: month
* in: query
* required: true
* schema:
* type: integer
* description: Month (1-12)
* responses:
* 200:
* description: Manufacturing IPI Monthly Overview fetched successfully
* 400:
* description: Invalid parameters
* 404:
* description: Data not found
* 500:
* description: Server error
*/
router.get("/manufacturing/getManufacturingMonthlyOverview", [verifySignature, verifyToken], ManufacturingIpiController.getManufacturingMonthlyOverviewByYearMonth);