GWM : iip Calculation fix commit
This commit is contained in:
parent
21d1d17bde
commit
0a2b20213c
@ -61,6 +61,7 @@ exports.createEstablishment = async (req, res) => {
|
||||
"industry_code",
|
||||
"license_number",
|
||||
"isic_code",
|
||||
"zone",
|
||||
].forEach(key => {
|
||||
if (req.body[key] === "") req.body[key] = null;
|
||||
});
|
||||
@ -109,7 +110,8 @@ exports.createEstablishment = async (req, res) => {
|
||||
created_by,
|
||||
establishment_user,
|
||||
establishment_products,
|
||||
ERN
|
||||
ERN,
|
||||
zone,
|
||||
} = req.body;
|
||||
|
||||
// Basic Validation
|
||||
@ -243,6 +245,10 @@ exports.createEstablishment = async (req, res) => {
|
||||
total_emirati,
|
||||
total_employees,
|
||||
ERN: sanitizeStringValue(ERN),
|
||||
zone:
|
||||
zone === undefined || zone === null || zone === ""
|
||||
? null
|
||||
: sanitizeStringValue(zone),
|
||||
created_by: req.body.created_by || req.user.id,
|
||||
created_at: new Date(),
|
||||
});
|
||||
@ -421,6 +427,7 @@ exports.getAllEstablishments = async (req, res) => {
|
||||
worksheet.columns = [
|
||||
{ header: "ID", key: "id", width: 10 },
|
||||
{ header: "Establishment Name", key: "factory_name", width: 30 },
|
||||
{ header: "Zone", key: "zone", width: 16 },
|
||||
{ header: "Contact Name", key: "establishment_contact_person_name", width: 30 },
|
||||
{ header: "Emirate", key: "emirate_name", width: 20 },
|
||||
{ header: "ISIC Code", key: "isic_code", width: 20 },
|
||||
@ -438,6 +445,7 @@ exports.getAllEstablishments = async (req, res) => {
|
||||
worksheet.addRow({
|
||||
id: item.id,
|
||||
factory_name: item.factory_name,
|
||||
zone: item.zone ?? "-",
|
||||
establishment_contact_person_name: item.establishment_contact_person_name,
|
||||
emirate_name: item.establishment_emirate?.name || "-",
|
||||
isic_code: item.isic_code || "-",
|
||||
@ -600,7 +608,8 @@ exports.updateEstablishment = async (req, res) => {
|
||||
"permanent_factory_code",
|
||||
"industry_code",
|
||||
"license_number",
|
||||
"isic_code"
|
||||
"isic_code",
|
||||
"zone",
|
||||
].forEach(key => {
|
||||
if (req.body[key] === "") req.body[key] = null;
|
||||
});
|
||||
@ -723,6 +732,10 @@ exports.updateEstablishment = async (req, res) => {
|
||||
if (isic_code !== undefined) {
|
||||
estData.isic_code = isic_code;
|
||||
}
|
||||
|
||||
if (estData.zone !== undefined && estData.zone !== null && estData.zone !== "") {
|
||||
estData.zone = sanitizeStringValue(estData.zone);
|
||||
}
|
||||
|
||||
estData.updated_by = estData.updated_by || req.user.id;
|
||||
estData.updated_at = estData.updated_at || new Date();
|
||||
@ -1913,6 +1926,10 @@ exports.establishmentBulkUpload = async (req, res) => {
|
||||
Number(r.number_of_non_emirati_male || 0) +
|
||||
Number(r.number_of_non_emirati_female || 0),
|
||||
|
||||
zone:
|
||||
r.zone && String(r.zone).trim() !== ""
|
||||
? sanitizeStringValue(String(r.zone).trim())
|
||||
: null,
|
||||
created_by: req.user.id
|
||||
}, { transaction: transaction });
|
||||
|
||||
|
||||
@ -14,6 +14,21 @@ const cleanString = (value) =>
|
||||
? sanitize(value, { allowedTags: [], allowedAttributes: {} })
|
||||
: value;
|
||||
|
||||
/** Parses optional products.weight_in_ib (nullable integer, non-negative). */
|
||||
function parseWeightInIb(value) {
|
||||
if (value === undefined || value === null || value === "") {
|
||||
return { ok: true, value: null };
|
||||
}
|
||||
const n = parseInt(String(value).trim(), 10);
|
||||
if (Number.isNaN(n)) {
|
||||
return { ok: false, message: "weight_in_ib must be a valid integer." };
|
||||
}
|
||||
if (n < 0) {
|
||||
return { ok: false, message: "weight_in_ib must be non-negative." };
|
||||
}
|
||||
return { ok: true, value: n };
|
||||
}
|
||||
|
||||
exports.createProduct = async (req, res) => {
|
||||
try {
|
||||
const product_name = cleanString(req.body.product_name);
|
||||
@ -21,6 +36,11 @@ exports.createProduct = async (req, res) => {
|
||||
const hs_code = req.body.hs_code;
|
||||
const unit_id = req.body.unit_id;
|
||||
|
||||
const weightParsed = parseWeightInIb(req.body.weight_in_ib);
|
||||
if (!weightParsed.ok) {
|
||||
return res.status(400).json({ status: "failed", message: weightParsed.message });
|
||||
}
|
||||
|
||||
if (hs_description && hs_description.length > 1000) {
|
||||
return res.status(400).json({
|
||||
status: "failed",
|
||||
@ -67,6 +87,7 @@ exports.createProduct = async (req, res) => {
|
||||
hs_code,
|
||||
hs_description,
|
||||
unit_id,
|
||||
weight_in_ib: weightParsed.value,
|
||||
created_by: req.user.id
|
||||
});
|
||||
|
||||
@ -150,6 +171,14 @@ exports.updateProduct = async (req, res) => {
|
||||
updated_at: new Date()
|
||||
};
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(req.body, "weight_in_ib")) {
|
||||
const weightParsed = parseWeightInIb(req.body.weight_in_ib);
|
||||
if (!weightParsed.ok) {
|
||||
return res.status(400).json({ status: "failed", message: weightParsed.message });
|
||||
}
|
||||
object.weight_in_ib = weightParsed.value;
|
||||
}
|
||||
|
||||
const [updated] = await Product.update(object, { where: { id: req.params.id } });
|
||||
|
||||
if (!updated) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||
@ -348,6 +377,12 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
||||
mappedKey = "unit";
|
||||
} else if (/desc(ription)?/i.test(normalizedKey)) {
|
||||
mappedKey = "description";
|
||||
} else if (
|
||||
normalizedKey === "weight_in_ib" ||
|
||||
/^weight.*(ib|lb)/i.test(normalizedKey) ||
|
||||
/^weight$/i.test(normalizedKey)
|
||||
) {
|
||||
mappedKey = "weight_in_ib";
|
||||
}
|
||||
|
||||
cleanRow[mappedKey] = row[key] ? row[key].trim() : null;
|
||||
@ -368,10 +403,12 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
||||
|
||||
// Validate required columns
|
||||
const requiredCols = ["hs_code", "product_name", "unit", "description"];
|
||||
const optionalCols = ["weight_in_ib"];
|
||||
const allowedCols = requiredCols.concat(optionalCols);
|
||||
const headers = Object.keys(csvResults[0]);
|
||||
|
||||
const missingCols = requiredCols.filter(col => !headers.includes(col));
|
||||
const extraCols = headers.filter(col => !requiredCols.includes(col));
|
||||
const extraCols = headers.filter(col => !allowedCols.includes(col));
|
||||
|
||||
if (missingCols.length > 0 || extraCols.length > 0) {
|
||||
deleteFileSecure(sanitizedPath);
|
||||
@ -398,6 +435,30 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
||||
const unit = row.unit ? row.unit.trim().toLowerCase() : "";
|
||||
const description = row.description ? row.description.trim().toLowerCase() : "";
|
||||
|
||||
let weightInIb = null;
|
||||
if (
|
||||
row.weight_in_ib !== undefined &&
|
||||
row.weight_in_ib !== null &&
|
||||
String(row.weight_in_ib).trim() !== ""
|
||||
) {
|
||||
const w = parseInt(String(row.weight_in_ib).trim(), 10);
|
||||
if (Number.isNaN(w)) {
|
||||
validationErrors.push({
|
||||
row: rowNumber,
|
||||
error: "weight_in_ib must be numeric",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (w < 0) {
|
||||
validationErrors.push({
|
||||
row: rowNumber,
|
||||
error: "weight_in_ib must be non-negative",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
weightInIb = w;
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if (!hsCode || !productName) {
|
||||
validationErrors.push({
|
||||
@ -455,7 +516,8 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
||||
hsCode: hsCode,
|
||||
productName: productName,
|
||||
unit: unit,
|
||||
description: description
|
||||
description: description,
|
||||
weightInIb,
|
||||
});
|
||||
}
|
||||
|
||||
@ -560,7 +622,8 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
||||
hs_code: row.hsCode,
|
||||
product_name: row.productName,
|
||||
unit_id: unitId,
|
||||
hs_description: row.description,
|
||||
hs_description: row.description,
|
||||
weight_in_ib: row.weightInIb,
|
||||
created_by: userId,
|
||||
created_at: new Date(),
|
||||
});
|
||||
|
||||
@ -1 +1 @@
|
||||
Establishment Id * (Mandatory),Factory Name * (Mandatory),User Name * (Mandatory),Email * (Mandatory),Emirate * (Mandatory),City/Town * (Mandatory),Principal activity Code (ISIC Rev 4 - 4 digits) * (Mandatory),HS Code 1 * (Mandatory),HS Code 2,HS Code 3,HS Code 4,HS Code 5,Permanent Factory Code,Industry Code Business Register,Description,Industry Code Mismatch Remarks,Establishment Address,Postal Code,PO Box,Makani Number,Contact Person Name,Contact Person Designation,Mobile Number,Website,Number of Emirati Male,Number of Emirati Female,Number of Non-Emirati Male,Number of Non-Emirati Female
|
||||
Establishment Id * (Mandatory),Factory Name * (Mandatory),User Name * (Mandatory),Email * (Mandatory),Emirate * (Mandatory),City/Town * (Mandatory),Principal activity Code (ISIC Rev 4 - 4 digits) * (Mandatory),HS Code 1 * (Mandatory),HS Code 2,HS Code 3,HS Code 4,HS Code 5,Permanent Factory Code,Industry Code Business Register,Description,Industry Code Mismatch Remarks,Establishment Address,Postal Code,PO Box,Makani Number,Contact Person Name,Contact Person Designation,Mobile Number,Website,Number of Emirati Male,Number of Emirati Female,Number of Non-Emirati Male,Number of Non-Emirati Female,Zone (Optional)
|
||||
|
||||
|
@ -1 +1 @@
|
||||
HS Code * (Mandatory),Product Name * (Mandatory),Unit * (Mandatory),Description
|
||||
HS Code * (Mandatory),Product Name * (Mandatory),Unit * (Mandatory),Description,Weight in lb (Optional)
|
||||
|
||||
|
@ -74,6 +74,7 @@ module.exports = (sequelize, DataTypes) => {
|
||||
allowNull: true,
|
||||
},
|
||||
ERN: { type: DataTypes.STRING },
|
||||
zone: { type: DataTypes.STRING },
|
||||
},
|
||||
{
|
||||
timestamps: false,
|
||||
|
||||
@ -42,10 +42,6 @@ module.exports = (sequelize, DataTypes) => {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
isic_code: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
is_active: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
|
||||
@ -688,6 +688,7 @@ router.post("/test/submissions-with-products",[verifySignature], testController.
|
||||
* total_emirati: { type: integer }
|
||||
* total_employees: { type: integer }
|
||||
* ERN: { type: string }
|
||||
* zone: { type: string, description: "Establishment zone (optional)" }
|
||||
* created_by: { type: integer }
|
||||
* establishment_user:
|
||||
* type: object
|
||||
@ -865,6 +866,7 @@ router.get("/establishments/:id",[verifySignature, verifyToken], establishmentCo
|
||||
* total_emirati: { type: integer }
|
||||
* total_employees: { type: integer }
|
||||
* ERN: { type: string }
|
||||
* zone: { type: string, description: "Establishment zone (optional)" }
|
||||
* updated_by: { type: integer }
|
||||
* establishment_products:
|
||||
* type: array
|
||||
@ -1278,6 +1280,10 @@ router.post("/trigger-establishment-users-welcome-email",[verifySignature, verif
|
||||
* unit_id:
|
||||
* type: integer
|
||||
* example: "select data from unit master"
|
||||
* weight_in_ib:
|
||||
* type: integer
|
||||
* description: Optional weight used in IPI weighting (integer).
|
||||
* example: 100
|
||||
* is_active:
|
||||
* type: boolean
|
||||
* example: true
|
||||
@ -1361,6 +1367,10 @@ router.get("/products/:id", [verifySignature, verifyToken],productController.get
|
||||
* unit_id:
|
||||
* type: integer
|
||||
* example: "select data from unit master"
|
||||
* weight_in_ib:
|
||||
* type: integer
|
||||
* description: Optional weight used in IPI weighting (integer). Omit to leave unchanged; send null to clear.
|
||||
* example: 100
|
||||
* is_active:
|
||||
* type: boolean
|
||||
* example: true
|
||||
|
||||
Loading…
Reference in New Issue
Block a user