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",
|
"industry_code",
|
||||||
"license_number",
|
"license_number",
|
||||||
"isic_code",
|
"isic_code",
|
||||||
|
"zone",
|
||||||
].forEach(key => {
|
].forEach(key => {
|
||||||
if (req.body[key] === "") req.body[key] = null;
|
if (req.body[key] === "") req.body[key] = null;
|
||||||
});
|
});
|
||||||
@ -109,7 +110,8 @@ exports.createEstablishment = async (req, res) => {
|
|||||||
created_by,
|
created_by,
|
||||||
establishment_user,
|
establishment_user,
|
||||||
establishment_products,
|
establishment_products,
|
||||||
ERN
|
ERN,
|
||||||
|
zone,
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
// Basic Validation
|
// Basic Validation
|
||||||
@ -243,6 +245,10 @@ exports.createEstablishment = async (req, res) => {
|
|||||||
total_emirati,
|
total_emirati,
|
||||||
total_employees,
|
total_employees,
|
||||||
ERN: sanitizeStringValue(ERN),
|
ERN: sanitizeStringValue(ERN),
|
||||||
|
zone:
|
||||||
|
zone === undefined || zone === null || zone === ""
|
||||||
|
? null
|
||||||
|
: sanitizeStringValue(zone),
|
||||||
created_by: req.body.created_by || req.user.id,
|
created_by: req.body.created_by || req.user.id,
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
});
|
});
|
||||||
@ -421,6 +427,7 @@ exports.getAllEstablishments = async (req, res) => {
|
|||||||
worksheet.columns = [
|
worksheet.columns = [
|
||||||
{ header: "ID", key: "id", width: 10 },
|
{ header: "ID", key: "id", width: 10 },
|
||||||
{ header: "Establishment Name", key: "factory_name", width: 30 },
|
{ 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: "Contact Name", key: "establishment_contact_person_name", width: 30 },
|
||||||
{ header: "Emirate", key: "emirate_name", width: 20 },
|
{ header: "Emirate", key: "emirate_name", width: 20 },
|
||||||
{ header: "ISIC Code", key: "isic_code", width: 20 },
|
{ header: "ISIC Code", key: "isic_code", width: 20 },
|
||||||
@ -438,6 +445,7 @@ exports.getAllEstablishments = async (req, res) => {
|
|||||||
worksheet.addRow({
|
worksheet.addRow({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
factory_name: item.factory_name,
|
factory_name: item.factory_name,
|
||||||
|
zone: item.zone ?? "-",
|
||||||
establishment_contact_person_name: item.establishment_contact_person_name,
|
establishment_contact_person_name: item.establishment_contact_person_name,
|
||||||
emirate_name: item.establishment_emirate?.name || "-",
|
emirate_name: item.establishment_emirate?.name || "-",
|
||||||
isic_code: item.isic_code || "-",
|
isic_code: item.isic_code || "-",
|
||||||
@ -600,7 +608,8 @@ exports.updateEstablishment = async (req, res) => {
|
|||||||
"permanent_factory_code",
|
"permanent_factory_code",
|
||||||
"industry_code",
|
"industry_code",
|
||||||
"license_number",
|
"license_number",
|
||||||
"isic_code"
|
"isic_code",
|
||||||
|
"zone",
|
||||||
].forEach(key => {
|
].forEach(key => {
|
||||||
if (req.body[key] === "") req.body[key] = null;
|
if (req.body[key] === "") req.body[key] = null;
|
||||||
});
|
});
|
||||||
@ -724,6 +733,10 @@ exports.updateEstablishment = async (req, res) => {
|
|||||||
estData.isic_code = isic_code;
|
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_by = estData.updated_by || req.user.id;
|
||||||
estData.updated_at = estData.updated_at || new Date();
|
estData.updated_at = estData.updated_at || new Date();
|
||||||
// update establishment
|
// update establishment
|
||||||
@ -1913,6 +1926,10 @@ exports.establishmentBulkUpload = async (req, res) => {
|
|||||||
Number(r.number_of_non_emirati_male || 0) +
|
Number(r.number_of_non_emirati_male || 0) +
|
||||||
Number(r.number_of_non_emirati_female || 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
|
created_by: req.user.id
|
||||||
}, { transaction: transaction });
|
}, { transaction: transaction });
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,21 @@ const cleanString = (value) =>
|
|||||||
? sanitize(value, { allowedTags: [], allowedAttributes: {} })
|
? sanitize(value, { allowedTags: [], allowedAttributes: {} })
|
||||||
: value;
|
: 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) => {
|
exports.createProduct = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const product_name = cleanString(req.body.product_name);
|
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 hs_code = req.body.hs_code;
|
||||||
const unit_id = req.body.unit_id;
|
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) {
|
if (hs_description && hs_description.length > 1000) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
status: "failed",
|
status: "failed",
|
||||||
@ -67,6 +87,7 @@ exports.createProduct = async (req, res) => {
|
|||||||
hs_code,
|
hs_code,
|
||||||
hs_description,
|
hs_description,
|
||||||
unit_id,
|
unit_id,
|
||||||
|
weight_in_ib: weightParsed.value,
|
||||||
created_by: req.user.id
|
created_by: req.user.id
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,6 +171,14 @@ exports.updateProduct = async (req, res) => {
|
|||||||
updated_at: new Date()
|
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 } });
|
const [updated] = await Product.update(object, { where: { id: req.params.id } });
|
||||||
|
|
||||||
if (!updated) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
if (!updated) res.status(404).send({'status':"failed",'message':"Record Not found",'data': "" });
|
||||||
@ -348,6 +377,12 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
|||||||
mappedKey = "unit";
|
mappedKey = "unit";
|
||||||
} else if (/desc(ription)?/i.test(normalizedKey)) {
|
} else if (/desc(ription)?/i.test(normalizedKey)) {
|
||||||
mappedKey = "description";
|
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;
|
cleanRow[mappedKey] = row[key] ? row[key].trim() : null;
|
||||||
@ -368,10 +403,12 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
|||||||
|
|
||||||
// Validate required columns
|
// Validate required columns
|
||||||
const requiredCols = ["hs_code", "product_name", "unit", "description"];
|
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 headers = Object.keys(csvResults[0]);
|
||||||
|
|
||||||
const missingCols = requiredCols.filter(col => !headers.includes(col));
|
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) {
|
if (missingCols.length > 0 || extraCols.length > 0) {
|
||||||
deleteFileSecure(sanitizedPath);
|
deleteFileSecure(sanitizedPath);
|
||||||
@ -398,6 +435,30 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
|||||||
const unit = row.unit ? row.unit.trim().toLowerCase() : "";
|
const unit = row.unit ? row.unit.trim().toLowerCase() : "";
|
||||||
const description = row.description ? row.description.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
|
// Validate required fields
|
||||||
if (!hsCode || !productName) {
|
if (!hsCode || !productName) {
|
||||||
validationErrors.push({
|
validationErrors.push({
|
||||||
@ -455,7 +516,8 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
|||||||
hsCode: hsCode,
|
hsCode: hsCode,
|
||||||
productName: productName,
|
productName: productName,
|
||||||
unit: unit,
|
unit: unit,
|
||||||
description: description
|
description: description,
|
||||||
|
weightInIb,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,6 +623,7 @@ exports.uploadProductsFromCSV = async (req, res) => {
|
|||||||
product_name: row.productName,
|
product_name: row.productName,
|
||||||
unit_id: unitId,
|
unit_id: unitId,
|
||||||
hs_description: row.description,
|
hs_description: row.description,
|
||||||
|
weight_in_ib: row.weightInIb,
|
||||||
created_by: userId,
|
created_by: userId,
|
||||||
created_at: new Date(),
|
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,
|
allowNull: true,
|
||||||
},
|
},
|
||||||
ERN: { type: DataTypes.STRING },
|
ERN: { type: DataTypes.STRING },
|
||||||
|
zone: { type: DataTypes.STRING },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
timestamps: false,
|
timestamps: false,
|
||||||
|
|||||||
@ -42,10 +42,6 @@ module.exports = (sequelize, DataTypes) => {
|
|||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
},
|
},
|
||||||
isic_code: {
|
|
||||||
type: DataTypes.INTEGER,
|
|
||||||
allowNull: true,
|
|
||||||
},
|
|
||||||
is_active: {
|
is_active: {
|
||||||
type: DataTypes.BOOLEAN,
|
type: DataTypes.BOOLEAN,
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
|
|||||||
@ -688,6 +688,7 @@ router.post("/test/submissions-with-products",[verifySignature], testController.
|
|||||||
* total_emirati: { type: integer }
|
* total_emirati: { type: integer }
|
||||||
* total_employees: { type: integer }
|
* total_employees: { type: integer }
|
||||||
* ERN: { type: string }
|
* ERN: { type: string }
|
||||||
|
* zone: { type: string, description: "Establishment zone (optional)" }
|
||||||
* created_by: { type: integer }
|
* created_by: { type: integer }
|
||||||
* establishment_user:
|
* establishment_user:
|
||||||
* type: object
|
* type: object
|
||||||
@ -865,6 +866,7 @@ router.get("/establishments/:id",[verifySignature, verifyToken], establishmentCo
|
|||||||
* total_emirati: { type: integer }
|
* total_emirati: { type: integer }
|
||||||
* total_employees: { type: integer }
|
* total_employees: { type: integer }
|
||||||
* ERN: { type: string }
|
* ERN: { type: string }
|
||||||
|
* zone: { type: string, description: "Establishment zone (optional)" }
|
||||||
* updated_by: { type: integer }
|
* updated_by: { type: integer }
|
||||||
* establishment_products:
|
* establishment_products:
|
||||||
* type: array
|
* type: array
|
||||||
@ -1278,6 +1280,10 @@ router.post("/trigger-establishment-users-welcome-email",[verifySignature, verif
|
|||||||
* unit_id:
|
* unit_id:
|
||||||
* type: integer
|
* type: integer
|
||||||
* example: "select data from unit master"
|
* example: "select data from unit master"
|
||||||
|
* weight_in_ib:
|
||||||
|
* type: integer
|
||||||
|
* description: Optional weight used in IPI weighting (integer).
|
||||||
|
* example: 100
|
||||||
* is_active:
|
* is_active:
|
||||||
* type: boolean
|
* type: boolean
|
||||||
* example: true
|
* example: true
|
||||||
@ -1361,6 +1367,10 @@ router.get("/products/:id", [verifySignature, verifyToken],productController.get
|
|||||||
* unit_id:
|
* unit_id:
|
||||||
* type: integer
|
* type: integer
|
||||||
* example: "select data from unit master"
|
* 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:
|
* is_active:
|
||||||
* type: boolean
|
* type: boolean
|
||||||
* example: true
|
* example: true
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user