import ErrorHander from "../../Utils/errorhander.js";
import catchAsyncErrors from "../../middlewares/catchAsyncErrors.js";
import User from "./userModel.js";
import sendToken from "../../Utils/jwtToken.js";
import sendEmail from "../../Utils/sendEmail.js";
import crypto from "crypto";
import cloudinary from "cloudinary";
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 = {
"PD ID (From SAP)": "uniqueId",
"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 newlyCreated = [];
const updatedDistributors = [];
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.uniqueId) missingFields.add("uniqueId");
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({
uniqueId: item.uniqueId || "N/A",
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";
// Check for existing user by uniqueId
let distributor = await User.findOne({ uniqueId: item.uniqueId });
if (distributor) {
// Track updated fields
const updatedFields = [];
const addressFields = ['panNumber', 'gstNumber', 'state', 'city', 'street', 'tradeName', 'postalCode'];
const existingAddress = await ShippingAddress.findOne({ user: distributor._id });
// Check for changes in user details
let userUpdated = false;
if (distributor.name !== item.name) {
updatedFields.push("name");
distributor.name = item.name;
userUpdated = true;
}
if (distributor.phone !== item.phone.toString()) {
updatedFields.push("phone");
distributor.phone = item.phone;
userUpdated = true;
}
// Update user
if (userUpdated) {
await distributor.save();
}
// Check for changes in address details
const addressData = {
street: item.street,
city: item.city,
state: item.state,
postalCode: item.postalCode.toString(),
country: "India", // Default country
panNumber: item.panNumber,
tradeName: item.tradeName,
gstNumber: item.gstNumber,
user: distributor._id,
};
let addressUpdated = false;
if (existingAddress) {
const addressUpdates = [];
addressFields.forEach(field => {
if (existingAddress[field] !== addressData[field]) {
addressUpdates.push(field);
addressUpdated = true;
}
});
if (addressUpdated) {
await ShippingAddress.updateOne({ user: distributor._id }, addressData);
if (addressUpdates.length > 0) {
updatedFields.push(`Address fields: ${addressUpdates.join(", ")}`);
}
}
} else {
// Create new address
await ShippingAddress.create(addressData);
updatedFields.push("New address created");
}
// Add to updatedDistributors only if there are updated fields
if (updatedFields.length > 0) {
updatedDistributors.push({
...distributor._doc,
updatedFields: updatedFields.join(", ")
});
}
} else {
// Create a new user
distributor = new User({
name: item.name,
email: item.email,
phone: item.phone,
password,
role: item.role,
uniqueId: item.uniqueId,
});
await distributor.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.
`,
});
newlyCreated.push(distributor._doc);
}
}
fs.unlinkSync(filePath); // Clean up uploaded file
res.status(201).json({
message:
errors.length > 0
? "File processed with errors!"
: "File processed successfully!",
processedUsers: {
newlyCreated: newlyCreated.length,
updatedDistributors: updatedDistributors.length
},
errors,
newlyCreated,
updatedDistributors
});
} catch (error) {
console.error("Error processing file:", error);
res.status(500).json({ message: "Error processing file", error: error.message });
}
};
// 1.Register a User
// export const registerUser = async (req, res) => {
// try {
// const { name, email, password, phone, accessTo, role } = req.body;
// // console.log("this is the password ", password, name, req.body);
// let findUser = await User.findOne({ email });
// if (findUser) {
// return res
// .status(400)
// .json({ success: false, message: "User already exists" });
// }
// if (req.files) {
// const files = req.files.avatar;
// const myCloud = await cloudinary.uploader.upload(
// files.tempFilePath,
// {
// folder: "Cheminova/user-image",
// },
// function (error, result) {
// result, error;
// }
// );
// }
// const user = await User.create({
// name,
// email,
// password,
// phone,
// role,
// accessTo,
// // avatar: {
// // public_id: myCloud.public_id,
// // url: myCloud.secure_url,
// // },
// });
// // const emailData = await RegisterEmail.find();
// // let emailSubject = emailData[0]?.subject;
// // let emailDescription = emailData[0]?.description;
// const config = await Config.find();
// let appName = config[0]?.appName;
// // await sendEmail({
// // to: `${email}`, // Change to your recipient
// // from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender
// // subject: `Welcome to Cheminova - Let the Shopping Begin!`,
// // html: `
// // Welcome to Cheminova - Let the Shopping Begin! // //
// //You can login into :${role === "Employee" || role === "admin" // // ? `https://admin.smellika.com/` // // : `https://smellika.com` // // }
// //Below are your login credentials:
// //Email: ${email}
// //Password: ${password}
// // Happy shopping,