principal distributor multipal added successfully
This commit is contained in:
parent
5d4058f170
commit
8d88e4ec0a
@ -69,19 +69,10 @@ export const AddshippingAddressByAdmin = async (req, res) => {
|
|||||||
tradeName,
|
tradeName,
|
||||||
gstNumber,
|
gstNumber,
|
||||||
} = req.body;
|
} = req.body;
|
||||||
// console.log(req.body);
|
|
||||||
// console.log(req.params._id);
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
if (!street || !city || !state || !postalCode || !panNumber) {
|
if (!street || !city || !state || !postalCode || !panNumber) {
|
||||||
return res
|
return res.status(400).json({ msg: "Please provide all required fields" });
|
||||||
.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" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create shipping address object
|
// Create shipping address object
|
||||||
@ -96,17 +87,28 @@ export const AddshippingAddressByAdmin = async (req, res) => {
|
|||||||
gstNumber,
|
gstNumber,
|
||||||
user: req.params._id, // Assuming req.params._id contains the correct user ID
|
user: req.params._id, // Assuming req.params._id contains the correct user ID
|
||||||
});
|
});
|
||||||
// console.log(newAddress);
|
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
success: true,
|
success: true,
|
||||||
address: newAddress,
|
address: newAddress,
|
||||||
message: "Shipping address added successfully",
|
message: "Shipping address added successfully",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} 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({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: error.message ? error.message : "Something went wrong",
|
message: error.message || "Something went wrong",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -28,7 +28,12 @@ const shippingAddressSchema = new mongoose.Schema(
|
|||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
trim: 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: {
|
country: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -37,22 +42,27 @@ const shippingAddressSchema = new mongoose.Schema(
|
|||||||
panNumber: {
|
panNumber: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
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: {
|
tradeName: {
|
||||||
type: String,
|
type: String,
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
gstNumber: {
|
gstNumber: {
|
||||||
type: String,
|
type: String,
|
||||||
|
required: true,
|
||||||
|
set: v => v.toUpperCase(),
|
||||||
validate: {
|
validate: {
|
||||||
validator: function (v) {
|
validator: function (v) {
|
||||||
// Check if gstNumber is provided before applying validation
|
return /^(\d{2}[A-Z]{5}\d{4}[A-Z]{1}\d[Z]{1}[A-Z\d]{1})$/.test(v);
|
||||||
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;
|
|
||||||
},
|
},
|
||||||
message: (props) => `${props.value} is not a valid GST number!`,
|
message: props => `${props.value} is not a valid GST number!`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isDefault: {
|
isDefault: {
|
||||||
|
@ -16,7 +16,7 @@ router
|
|||||||
.route("/admin/new/:_id")
|
.route("/admin/new/:_id")
|
||||||
.post(
|
.post(
|
||||||
isAuthenticatedUser,
|
isAuthenticatedUser,
|
||||||
authorizeRoles("admin", "Employee"),
|
authorizeRoles("admin"),
|
||||||
AddshippingAddressByAdmin
|
AddshippingAddressByAdmin
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -9,6 +9,273 @@ import password from "secure-random-password";
|
|||||||
import { Order } from "../Orders/orderModel.js";
|
import { Order } from "../Orders/orderModel.js";
|
||||||
import { RegisterEmail } from "../EmailCMS/RegisterEmail/registerEmailModal.js";
|
import { RegisterEmail } from "../EmailCMS/RegisterEmail/registerEmailModal.js";
|
||||||
import { Config } from "../setting/Configration/Config_model.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.
|
||||||
|
<br/>Name: <strong>${item.name}</strong><br/>
|
||||||
|
<br/>Mobile Number: <strong>${item.phone}</strong><br/>
|
||||||
|
<br/>Password: <strong>${password}</strong><br/><br/>
|
||||||
|
<a href="${process.env.PD_APP_URL}/login">Click here to login</a><br/><br/>
|
||||||
|
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
|
// 1.Register a User
|
||||||
// export const registerUser = async (req, res) => {
|
// export const registerUser = async (req, res) => {
|
||||||
// try {
|
// try {
|
||||||
@ -85,21 +352,23 @@ import { Config } from "../setting/Configration/Config_model.js";
|
|||||||
// };
|
// };
|
||||||
export const registerUser = async (req, res) => {
|
export const registerUser = async (req, res) => {
|
||||||
try {
|
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
|
// Check if user already exists
|
||||||
let user = await User.findOne({ email });
|
let user = await User.findOne({ email });
|
||||||
if (user) {
|
if (user) {
|
||||||
// If user exists, update their details if needed
|
// If user exists, update their details if needed
|
||||||
user.name = name;
|
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.phone = phone;
|
||||||
user.role = role;
|
user.role = role;
|
||||||
user.accessTo = accessTo;
|
user.accessTo = accessTo;
|
||||||
|
|
||||||
// Save updates
|
// Save updates
|
||||||
await user.save();
|
await user.save();
|
||||||
|
// console.log("finduser", user);
|
||||||
// Respond with success and userId
|
// Respond with success and userId
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
@ -117,7 +386,7 @@ export const registerUser = async (req, res) => {
|
|||||||
role,
|
role,
|
||||||
accessTo,
|
accessTo,
|
||||||
});
|
});
|
||||||
|
// console.log(user);
|
||||||
// Generate uniqueId
|
// Generate uniqueId
|
||||||
const currentYear = new Date().getFullYear().toString().slice(-2);
|
const currentYear = new Date().getFullYear().toString().slice(-2);
|
||||||
const randomChars = crypto.randomBytes(4).toString("hex").toUpperCase();
|
const randomChars = crypto.randomBytes(4).toString("hex").toUpperCase();
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
getAllEmployee,
|
getAllEmployee,
|
||||||
deleteEmployeeById,
|
deleteEmployeeById,
|
||||||
updateEmployeeById,
|
updateEmployeeById,
|
||||||
|
uploadPrincipaldistributors,
|
||||||
} from "./userController.js";
|
} from "./userController.js";
|
||||||
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.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/logout").get(logout);
|
||||||
|
|
||||||
router.route("/user/details").get(isAuthenticatedUser, getUserDetails);
|
router.route("/user/details").get(isAuthenticatedUser, getUserDetails);
|
||||||
|
router
|
||||||
|
.route('/principaldistributor/upload').post(
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles('admin'),
|
||||||
|
uploadPrincipaldistributors
|
||||||
|
);
|
||||||
router
|
router
|
||||||
.route("/admin/users")
|
.route("/admin/users")
|
||||||
.get(isAuthenticatedUser, authorizeRoles("admin", "Employee"), getAllUser);
|
.get(isAuthenticatedUser, authorizeRoles("admin", "Employee"), getAllUser);
|
||||||
|
Loading…
Reference in New Issue
Block a user