From 8d88e4ec0a461d908e0997ffc284f6dcfd02fc30 Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Thu, 8 Aug 2024 16:05:35 +0530 Subject: [PATCH] principal distributor multipal added successfully --- .../ShippingAddressController.js | 30 +- .../ShippingAddresses/ShippingAddressModel.js | 26 +- .../ShippingAddresses/ShippingAddressRoute.js | 2 +- resources/user/userController.js | 279 +++++++++++++++++- resources/user/userRoute.js | 8 +- 5 files changed, 316 insertions(+), 29 deletions(-) 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);