diff --git a/resources/ShippingAddresses/ShippingAddressController.js b/resources/ShippingAddresses/ShippingAddressController.js
index cdd374f..7a83833 100644
--- a/resources/ShippingAddresses/ShippingAddressController.js
+++ b/resources/ShippingAddresses/ShippingAddressController.js
@@ -69,19 +69,10 @@ export const AddshippingAddressByAdmin = async (req, res) => {
tradeName,
gstNumber,
} = req.body;
- // console.log(req.body);
- // console.log(req.params._id);
+
// Validate required fields
if (!street || !city || !state || !postalCode || !panNumber) {
- return res
- .status(400)
- .json({ msg: "Please provide all required fields" });
- }
-
- // Validate PAN number format
- const panNumberRegex = /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/;
- if (!panNumberRegex.test(panNumber)) {
- return res.status(400).json({ message: "Invalid PAN number format" });
+ return res.status(400).json({ msg: "Please provide all required fields" });
}
// Create shipping address object
@@ -96,17 +87,28 @@ export const AddshippingAddressByAdmin = async (req, res) => {
gstNumber,
user: req.params._id, // Assuming req.params._id contains the correct user ID
});
- // console.log(newAddress);
+
res.status(201).json({
success: true,
address: newAddress,
message: "Shipping address added successfully",
});
} catch (error) {
- console.error("Error creating shipping address:", error.message);
+ // console.error("Error creating shipping address:", error.message);
+
+ // Check for validation errors
+ if (error.name === 'ValidationError') {
+ const errorMessages = Object.values(error.errors).map(err => err.message);
+ return res.status(400).json({
+ success: false,
+ message: errorMessages.join(", "),
+ });
+ }
+
+ // General error
res.status(500).json({
success: false,
- message: error.message ? error.message : "Something went wrong",
+ message: error.message || "Something went wrong",
});
}
};
diff --git a/resources/ShippingAddresses/ShippingAddressModel.js b/resources/ShippingAddresses/ShippingAddressModel.js
index 5983f00..57502ed 100644
--- a/resources/ShippingAddresses/ShippingAddressModel.js
+++ b/resources/ShippingAddresses/ShippingAddressModel.js
@@ -28,7 +28,12 @@ const shippingAddressSchema = new mongoose.Schema(
type: String,
required: true,
trim: true,
- match: /^\d{6}$/,
+ validate: {
+ validator: function (v) {
+ return /^\d{6}$/.test(v);
+ },
+ message: "Postal code must be a 6-digit number",
+ },
},
country: {
type: String,
@@ -37,22 +42,27 @@ const shippingAddressSchema = new mongoose.Schema(
panNumber: {
type: String,
required: true,
+ set: v => v.toUpperCase(), // Convert to uppercase before saving
+ validate: {
+ validator: function (v) {
+ return /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(v);
+ },
+ message: props => `${props.value} is not a valid PAN number!`,
+ },
},
tradeName: {
type: String,
+ required: true,
},
gstNumber: {
type: String,
+ required: true,
+ set: v => v.toUpperCase(),
validate: {
validator: function (v) {
- // Check if gstNumber is provided before applying validation
- if (v && v.trim().length > 0) {
- return /^(\d{2}[A-Z]{5}\d{4}[A-Z]{1}\d[Z]{1}[A-Z\d]{1})$/.test(v);
- }
- // If gstNumber is not provided, it's considered valid
- return true;
+ return /^(\d{2}[A-Z]{5}\d{4}[A-Z]{1}\d[Z]{1}[A-Z\d]{1})$/.test(v);
},
- message: (props) => `${props.value} is not a valid GST number!`,
+ message: props => `${props.value} is not a valid GST number!`,
},
},
isDefault: {
diff --git a/resources/ShippingAddresses/ShippingAddressRoute.js b/resources/ShippingAddresses/ShippingAddressRoute.js
index 9ea8bf2..ef789c1 100644
--- a/resources/ShippingAddresses/ShippingAddressRoute.js
+++ b/resources/ShippingAddresses/ShippingAddressRoute.js
@@ -16,7 +16,7 @@ router
.route("/admin/new/:_id")
.post(
isAuthenticatedUser,
- authorizeRoles("admin", "Employee"),
+ authorizeRoles("admin"),
AddshippingAddressByAdmin
);
diff --git a/resources/user/userController.js b/resources/user/userController.js
index 6457d6d..efd94ae 100644
--- a/resources/user/userController.js
+++ b/resources/user/userController.js
@@ -9,6 +9,273 @@ import password from "secure-random-password";
import { Order } from "../Orders/orderModel.js";
import { RegisterEmail } from "../EmailCMS/RegisterEmail/registerEmailModal.js";
import { Config } from "../setting/Configration/Config_model.js";
+import XLSX from "xlsx";
+import fs from "fs";
+import path from "path";
+import validator from 'validator';
+import ShippingAddress from "../ShippingAddresses/ShippingAddressModel.js";
+
+const generatePassword = (name, email) => {
+ // Combine name and email, and convert to lowercase
+ const combinedStr = (name + email).toLowerCase();
+
+ // Define character pools
+ const specialChars = "@#*";
+ const numbers = "0123456789";
+ const alphaLower = combinedStr.match(/[a-z]/g) || [];
+ const alphaUpper = combinedStr.match(/[A-Z]/g) || [];
+
+ // Ensure at least one character from each category
+ const specialChar = specialChars.charAt(
+ Math.floor(Math.random() * specialChars.length)
+ );
+ const numberChar = numbers.charAt(Math.floor(Math.random() * numbers.length));
+ const lowerChar =
+ alphaLower.length > 0
+ ? alphaLower[Math.floor(Math.random() * alphaLower.length)]
+ : String.fromCharCode(Math.floor(Math.random() * 26) + 97);
+ const upperChar =
+ alphaUpper.length > 0
+ ? alphaUpper[Math.floor(Math.random() * alphaUpper.length)]
+ : String.fromCharCode(Math.floor(Math.random() * 26) + 65);
+
+ // Combine required characters
+ let passwordChars = [specialChar, numberChar, lowerChar, upperChar];
+
+ // Fill remaining positions with random characters from the combined string
+ const allChars = combinedStr + specialChars + numbers;
+ while (passwordChars.length < 8) {
+ passwordChars.push(
+ allChars.charAt(Math.floor(Math.random() * allChars.length))
+ );
+ }
+
+ // Shuffle characters to ensure randomness
+ passwordChars = passwordChars.sort(() => Math.random() - 0.5);
+
+ // Generate password of length 8
+ const password = passwordChars.slice(0, 8).join("");
+
+ return password;
+};
+
+export const uploadPrincipaldistributors = async (req, res) => {
+ try {
+ if (!req.files || !req.files.file) {
+ return res.status(400).json({ message: "No file uploaded" });
+ }
+
+ const file = req.files.file;
+ const filePath = path.join("public", "uploads", file.name);
+
+ // Ensure 'uploads' directory exists
+ if (!fs.existsSync(path.dirname(filePath))) {
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
+ }
+
+ // Move the file from temp to the uploads directory
+ await file.mv(filePath);
+
+ // Process the file
+ const fileBuffer = fs.readFileSync(filePath);
+ const workbook = XLSX.read(fileBuffer, { type: "buffer" });
+ const sheetName = workbook.SheetNames[0];
+ const worksheet = workbook.Sheets[sheetName];
+ const data = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
+
+ if (data.length <= 1) {
+ return res.status(400).json({ message: "Empty spreadsheet or no data found" });
+ }
+
+ const headers = data[0];
+
+ // Map headers from the Excel file to your schema
+ const headerMapping = {
+ "Principal Distributor Name": "name",
+ "Email": "email",
+ "Phone Number": "phone",
+ "PAN Number": "panNumber",
+ "Trade Name": "tradeName",
+ "GST Number": "gstNumber",
+ "State": "state",
+ "City": "city",
+ "Street": "street",
+ "Pincode": "postalCode",
+ };
+
+ const requiredHeaders = Object.keys(headerMapping);
+
+ if (!requiredHeaders.every((header) => headers.includes(header))) {
+ return res.status(400).json({ message: "Missing required columns in spreadsheet" });
+ }
+
+ const errors = [];
+ const processedUsers = [];
+
+ for (let i = 1; i < data.length; i++) {
+ const row = data[i];
+ const item = {};
+
+ headers.forEach((header, index) => {
+ if (headerMapping[header]) {
+ item[headerMapping[header]] = row[index] !== undefined ? row[index] : "";
+ }
+ });
+
+ // Initialize error tracking for each item
+ const missingFields = new Set();
+ const validationErrors = new Set();
+
+ // Validate required fields
+ if (!item.name) missingFields.add("name");
+ if (!item.email) missingFields.add("email");
+ if (!item.phone) missingFields.add("phone");
+ if (!item.panNumber) missingFields.add("panNumber");
+ if (!item.tradeName) missingFields.add("tradeName");
+ if (!item.gstNumber) missingFields.add("gstNumber");
+ if (!item.state) missingFields.add("state");
+ if (!item.city) missingFields.add("city");
+ if (!item.street) missingFields.add("street");
+ if (!item.postalCode) missingFields.add("postalCode");
+
+ // Check email validity
+ if (item.email && !validator.isEmail(item.email)) {
+ validationErrors.add("incorrect mail");
+ }
+
+ // Validate mobile number
+ if (item.phone && !/^\d{10}$/.test(item.phone)) {
+ validationErrors.add("Invalid Mobile Number (should be 10 digits)");
+ }
+
+ // Check GST, PAN, and postal code validation
+ item.panNumber = item.panNumber ? item.panNumber.toUpperCase() : "";
+ item.gstNumber = item.gstNumber ? item.gstNumber.toUpperCase() : "";
+
+ // Validate PAN Number
+ if (item.panNumber && !/^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(item.panNumber)) {
+ validationErrors.add("Invalid PAN Number");
+ }
+
+ // Validate GST Number
+ if (item.gstNumber && !/^(\d{2}[A-Z]{5}\d{4}[A-Z]{1}\d[Z]{1}[A-Z\d]{1})$/.test(item.gstNumber)) {
+ validationErrors.add("Invalid GST Number");
+ }
+
+ // Validate Postal Code
+ if (item.postalCode && !/^\d{6}$/.test(item.postalCode)) {
+ validationErrors.add("Invalid Postal Code");
+ }
+
+ // Combine all errors into a single message
+ let errorMessage = "";
+ if (missingFields.size > 0) {
+ errorMessage += `Missing fields: ${Array.from(missingFields).join(", ")}. `;
+ }
+ if (validationErrors.size > 0) {
+ errorMessage += `Validation errors: ${Array.from(validationErrors).join(", ")}.`;
+ }
+
+ // If there are errors, push them to the errors array
+ if (errorMessage.trim()) {
+ errors.push({
+ name: item.name || "N/A",
+ email: item.email || "N/A",
+ phone: item.phone || "N/A",
+ panNumber: item.panNumber || "N/A",
+ gstNumber: item.gstNumber || "N/A",
+ message: errorMessage.trim(),
+ });
+ continue;
+ }
+
+ // Generate a password
+ const password = generatePassword(item.name, item.email);
+ item.role = "principal-Distributor";
+ const currentYear = new Date().getFullYear().toString().slice(-2);
+ const randomChars = crypto.randomBytes(4).toString("hex").toUpperCase();
+ item.uniqueId = `${currentYear}-${randomChars}`;
+ // Check for existing user
+ let user = await User.findOne({ email: item.email });
+
+ if (user) {
+ // Update existing user details
+ user.name = item.name;
+ user.phone = item.phone;
+ await user.save();
+ } else {
+ // Create a new user
+ user = new User({
+ name: item.name,
+ email: item.email,
+ phone: item.phone,
+ password,
+ role: item.role,
+ uniqueId: item.uniqueId,
+ });
+ await user.save();
+
+ // Send email with the new user details
+ await sendEmail({
+ to: item.email,
+ from: process.env.SEND_EMAIL_FROM,
+ subject: `Cheminova Account Created`,
+ html: `
+ Your Principal Distributor Account is created successfully.
+
Name: ${item.name}
+
Mobile Number: ${item.phone}
+
Password: ${password}
+ Click here to login
+ If you have not requested this email, please ignore it.
+ `,
+ });
+ }
+
+ // Create or update shipping address
+ const addressData = {
+ street: item.street,
+ city: item.city,
+ state: item.state,
+ postalCode: item.postalCode,
+ country: "India", // Default country
+ panNumber: item.panNumber,
+ tradeName: item.tradeName,
+ gstNumber: item.gstNumber,
+ user: user._id,
+ };
+
+ let existingAddress = await ShippingAddress.findOne({ user: user._id });
+
+ if (existingAddress) {
+ // Update existing address
+ await ShippingAddress.updateOne({ user: user._id }, addressData);
+ } else {
+ // Create new address
+ await ShippingAddress.create(addressData);
+ }
+
+ processedUsers.push({
+ ...user._doc,
+ ...addressData,
+ });
+ }
+
+ fs.unlinkSync(filePath); // Clean up uploaded file
+
+ res.status(201).json({
+ message:
+ errors.length > 0
+ ? "File processed with errors!"
+ : "File processed successfully!",
+ processedUsers: processedUsers.length, // Total processed users
+ errors,
+ });
+ } catch (error) {
+ console.error("Error:", error);
+ res.status(500).json({ message: error.message || "Something went wrong!" });
+ }
+};
+
// 1.Register a User
// export const registerUser = async (req, res) => {
// try {
@@ -85,21 +352,23 @@ import { Config } from "../setting/Configration/Config_model.js";
// };
export const registerUser = async (req, res) => {
try {
- const { name, email, password, phone, accessTo, role } = req.body;
-
+ const { name, email, phone, accessTo, role } = req.body;
+ // console.log(req.body);
+ const password = generatePassword(name, email);
+ // console.log(password);
// Check if user already exists
let user = await User.findOne({ email });
if (user) {
// If user exists, update their details if needed
user.name = name;
- user.password = password; // In a real application, you should hash this
+ // user.password = password; // In a real application, you should hash this
user.phone = phone;
user.role = role;
user.accessTo = accessTo;
// Save updates
await user.save();
-
+ // console.log("finduser", user);
// Respond with success and userId
return res.status(200).json({
success: true,
@@ -117,7 +386,7 @@ export const registerUser = async (req, res) => {
role,
accessTo,
});
-
+ // console.log(user);
// Generate uniqueId
const currentYear = new Date().getFullYear().toString().slice(-2);
const randomChars = crypto.randomBytes(4).toString("hex").toUpperCase();
diff --git a/resources/user/userRoute.js b/resources/user/userRoute.js
index 62aac03..9541235 100644
--- a/resources/user/userRoute.js
+++ b/resources/user/userRoute.js
@@ -14,6 +14,7 @@ import {
getAllEmployee,
deleteEmployeeById,
updateEmployeeById,
+ uploadPrincipaldistributors,
} from "./userController.js";
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
@@ -30,7 +31,12 @@ router.route("/user/password/reset/:token").put(resetPassword);
router.route("/user/logout").get(logout);
router.route("/user/details").get(isAuthenticatedUser, getUserDetails);
-
+router
+ .route('/principaldistributor/upload').post(
+ isAuthenticatedUser,
+ authorizeRoles('admin'),
+ uploadPrincipaldistributors
+);
router
.route("/admin/users")
.get(isAuthenticatedUser, authorizeRoles("admin", "Employee"), getAllUser);