import mongoose from "mongoose"; import RetailDistributor from "./RetailDistributorModel.js"; import validator from "validator"; import password from "secure-random-password"; import crypto from "crypto"; import { RdOrder } from "../RD_Ordes/rdOrderModal.js"; import sendEmail, { sendOtp } from "../../Utils/sendEmail.js"; import { KYC } from "../KYC/KycModel.js"; import { generatePassword } from "../../Utils/generatepassword.js"; import XLSX from "xlsx"; import fs from "fs"; import path from "path"; import ShippingAddressRD from "../ShippingAddressesRD/RDShippingAddressModel.js"; export const uploadRetaildistributors = async (req, res) => { try { if (!mongoose.Types.ObjectId.isValid(req.user._id)) { return res.status(400).json({ message: "Please login again" }); } 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 = { "Retail Distributor Name": "name", Email: "email", "Phone Number": "mobile_number", "PAN Number": "pan_number", "Trade Name": "trade_name", "GST Number": "gst_number", "Aadhar Number": "aadhar_number", State: "state", City: "city", District: "district", Address: "address", Pincode: "pincode", }; 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]; // Skip the row if it's completely empty if (row.every((cell) => cell === undefined || cell === "")) { continue; } 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.mobile_number) missingFields.add("mobile_number"); if (!item.pan_number) missingFields.add("pan_number"); if (!item.gst_number) missingFields.add("gst_number"); if (!item.trade_name) missingFields.add("trade_name"); if (!item.aadhar_number) missingFields.add("aadhar_number"); if (!item.state) missingFields.add("state"); if (!item.city) missingFields.add("city"); if (!item.pincode) missingFields.add("pincode"); if (!item.district) missingFields.add("district"); if (!item.address) missingFields.add("address"); // Check email validity if (item.email && !validator.isEmail(item.email)) { validationErrors.add("incorrect mail"); } // Validate mobile number if (item.mobile_number && !/^\d{10}$/.test(item.mobile_number)) { validationErrors.add("Invalid Mobile Number (should be 10 digits)"); } // Check GST, PAN, and postal code validation item.pan_number = item.pan_number ? item.pan_number.toUpperCase() : ""; item.gst_number = item.gst_number ? item.gst_number.toUpperCase() : ""; // Validate PAN Number if ( item.pan_number && !/^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(item.pan_number) ) { validationErrors.add("Invalid PAN Number"); } // Validate GST Number if ( item.gst_number && !/^(\d{2}[A-Z]{5}\d{4}[A-Z]{1}\d[Z]{1}[A-Z\d]{1})$/.test( item.gst_number ) ) { validationErrors.add("Invalid GST Number"); } // Validate Aadhar number if (item.aadhar_number && !/^\d{12}$/.test(item.aadhar_number)) { validationErrors.add("Invalid Aadhar Number (should be 12 digits)"); } // Validate Postal Code if (item.pincode && !/^\d{6}$/.test(item.pincode)) { 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", TradeName: item.trade_name || "N/A", phone: item.mobile_number || "N/A", panNumber: item.pan_number || "N/A", gstNumber: item.gst_number || "N/A", AadharNumber: item.aadhar_number || "N/A", message: errorMessage.trim(), }); continue; } // Generate a password const password = generatePassword(item.name, item.email); // Check for existing user by uniqueId let Kyc = await KYC.findOne({ email: item.email }); let Retaildistributor = await RetailDistributor.findOne({ email: item.email, }); let existingAddress = await ShippingAddressRD.findOne({ user: Retaildistributor?._id, isDefault: true, }).exec(); if (!existingAddress) { existingAddress = await ShippingAddressRD.findOne({ user: Retaildistributor?._id, }) .sort({ createdAt: 1 }) .exec(); } if (Kyc) { // Track updated fields const updatedFields = []; const addressFields = [ "Name", "phoneNumber", "state", "city", "street", "tradeName", "postalCode", "district", ]; // Check for changes in user details let kycUpdated = false; for (let field in item) { const currentValue = Kyc[field]?.toString(); const newValue = item[field]?.toString(); if (currentValue !== newValue) { updatedFields.push(field); Kyc[field] = item[field]; // Update Kyc with the new value if (Retaildistributor && field !== "email") { Retaildistributor[field] = item[field]; } kycUpdated = true; } } // Update Kyc and Retaildistributor if there are any changes if (kycUpdated) { await Kyc.save(); await Retaildistributor.save(); // Check for changes in address details const addressData = { Name: item.name, phoneNumber: item.mobile_number.toString(), street: item.address, city: item.city, state: item.state, postalCode: item.pincode, district: item.district, country: "India", // Default country tradeName: item.trade_name, user: Retaildistributor._id, }; console.log(addressData); let addressUpdated = false; if (existingAddress) { const addressUpdates = []; addressFields.forEach((field) => { if (existingAddress[field] !== addressData[field]) { addressUpdates.push(field); addressUpdated = true; } }); if (addressUpdated) { await ShippingAddressRD.updateOne( { user: Retaildistributor._id }, addressData ); } } else { // Create new address await ShippingAddressRD.create(addressData); } updatedDistributors.push({ ...Kyc._doc, updatedFields: updatedFields.join(", "), }); } } else { // Create a new Kyc Kyc = new KYC({ ...item, status: "approved", }); const newkyc = await Kyc.save(); const retailDistributorData = { name: item.name, email: item.email, mobile_number: item.mobile_number, kyc: newkyc._id, password, }; Retaildistributor = new RetailDistributor(retailDistributorData); const newRd = await Retaildistributor.save(); // Now create the address for the new user const addressData = { Name: item.name, phoneNumber: item.mobile_number.toString(), street: item.address, city: item.city, state: item.state, postalCode: item.pincode, district: item.district, country: "India", // Default country tradeName: item.trade_name, user: newRd._id, // Use the saved user's ID isDefault: true, }; await ShippingAddressRD.create(addressData); // Send email with the new password await sendEmail({ to: `${item.email}`, // Change to your recipient from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender subject: `Cheminova Account Created`, html: `Your Retail Distributor Account is created successfully.
name is: ${item.name}

MobileNumber is: ${item.mobile_number}

Email is: ${item.email}

password is: ${password}

If you have not requested this email, please ignore it.`, }); newlyCreated.push({ Kyc }); } } // Clean up uploaded file if any error occurs if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } res.status(200).json({ message: "File processed successfully", newlyCreated, updatedDistributors, errors, }); } catch (error) { console.error(error); // Clean up uploaded file if any error occurs if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } res.status(500).json({ message: "Internal Server Error" }); } }; export const loginRD = async (req, res) => { const { email, password } = req.body; try { if (!email || !password) { return res.status(400).json({ message: "Please Enter Email & Password" }); } const retailDistributor = await RetailDistributor.findOne({ email }).select( "+password" ); if (!retailDistributor) { return res.status(400).json({ message: "Invalid Email or Password" }); } const isPasswordMatched = await retailDistributor.comparePassword(password); if (!isPasswordMatched) { return res.status(400).json({ message: "Invalid Email or Password" }); } const token = retailDistributor.getJWTToken(); return res.status(200).json({ success: true, token, message: "Login Successfully", }); } catch (error) { return res.status(500).json({ message: error.message ? error.message : "Something went wrong!", }); } }; export const ChangePasswordRD = async (req, res) => { // Retrieve id from req.params const { oldPassword, newPassword, confirmPassword } = req.body; const userId = req.user._id; // Use the ID from the URL or from the authenticated user // console.log(userId); if (!oldPassword) { return res.status(400).json({ message: "Please Enter Old password" }); } if (!newPassword) { return res.status(400).json({ message: "Please Enter New Password " }); } if (!confirmPassword) { return res.status(400).json({ message: "Please Enter Confirm Password" }); } try { const retailDistributor = await RetailDistributor.findById(userId).select( "+password" ); if (!retailDistributor) { return res.status(404).json({ message: "Retail Distributer not found" }); } const isPasswordMatched = await retailDistributor.comparePassword( oldPassword ); if (!isPasswordMatched) { return res.status(400).json({ message: "Old password is incorrect" }); } if (newPassword !== confirmPassword) { return res .status(400) .json({ message: "New password and confirm Password do not match" }); } retailDistributor.password = newPassword; await retailDistributor.save(); return res .status(200) .json({ success: true, message: "Password updated successfully" }); } catch (error) { console.error("Error updating password:", error); return res.status(500).json({ message: error.message ? error.message : "Server error!", }); } }; export const forgotPasswordRD = async (req, res) => { try { // Check if email is provided const { email } = req.body; if (!email) { return res.status(400).json({ message: "Please Enter Email!" }); } // Find the Retail Distributor by email const retailDistributor = await RetailDistributor.findOne({ email }); if (!retailDistributor) { return res.status(404).json({ message: "Retail Distributor not found" }); } // Generate a random password const newPassword = password.randomPassword({ length: 12, characters: [ { characters: password.upper, exactly: 1 }, // At least 1 uppercase letter { characters: password.symbols, exactly: 1 }, // At least 1 symbol password.lower, // Lowercase letters password.digits, // Digits ], }); // Update the retail distributor's password retailDistributor.password = newPassword; await retailDistributor.save(); // The pre-save hook in your schema will handle password hashing // Send an email to the retail distributor with the new password await sendEmail({ to: retailDistributor.email, from: process.env.SEND_EMAIL_FROM, subject: `Cheminova Password Recovery`, html: `Your new password is: ${newPassword}

If you did not request this, please ignore this email.`, }); // Respond with success message return res.status(200).json({ success: true, message: `Email sent to ${retailDistributor.email} successfully`, }); } catch (error) { console.error("Error during password reset:", error); return res.status(500).json({ message: error.message || "Something went wrong!", }); } }; export const UpdateProfileRD = async (req, res) => { const { name, mobile_number } = req.body; // Only expecting name from the request body const userId = req.user._id; // User ID from authenticated user try { // Find the RetailDistributor by user ID const retailDistributor = await RetailDistributor.findById(userId); if (!retailDistributor) { return res.status(404).json({ message: "Retail Distributor not found" }); } // Assuming you have an 'isVerified' field in your RetailDistributor schema // Update name if provided if (name) { retailDistributor.name = name; retailDistributor.mobile_number = mobile_number ? mobile_number : retailDistributor.mobile_number; } else { return res.status(400).json({ message: "Name is required" }); } // Save the updated RetailDistributor await retailDistributor.save(); return res.status(200).json({ retailDistributor, message: "Profile updated successfully", }); } catch (error) { return res.status(500).json({ message: error.message || "Server error!", }); } }; export const getmyProfileRD = async (req, res) => { try { // Fetch the profile data using the authenticated user's ID const myData = await RetailDistributor.findById(req.user?._id); if (myData) { return res.status(200).json({ success: true, message: "Profile fetched successfully!", myData, }); } else { return res.status(404).json({ success: false, message: "Retail Distributor not found", }); } } catch (error) { return res.status(500).json({ success: false, message: error.message || "Something went wrong!", }); } }; //reatil distributor mapping export const getAllRetailDistributorApproved = async (req, res) => { try { // Extract query parameters const { page = 1, show = 10, tradename, name, mobile_number, principaldistributor, } = req.query; const skip = (page - 1) * show; // Build the aggregation pipeline let pipeline = [ { $lookup: { from: "kycs", // Assuming your KYC collection is named "kycs" localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, // Unwind kycDetails and allow null/empty arrays { $lookup: { from: "users", // Assuming your User collection is named "users" localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, // Unwind principalDetails and allow null/empty arrays // Lookup for mappedTM (Territory Manager) { $lookup: { from: "territorymanagers", // Assuming your Territory Manager collection localField: "mappedTM", foreignField: "_id", as: "mappedTMDetails", }, }, { $unwind: { path: "$mappedTMDetails", preserveNullAndEmptyArrays: true }, }, // Unwind mappedTMDetails and allow null/empty arrays // Lookup for mappedSC (Sales Coordinator) { $lookup: { from: "salescoordinators", // Assuming your Sales Coordinator collection localField: "mappedSC", foreignField: "_id", as: "mappedSCDetails", }, }, { $unwind: { path: "$mappedSCDetails", preserveNullAndEmptyArrays: true }, }, // Unwind mappedSCDetails and allow null/empty arrays // Filter to ensure data exists in kyc or principalDetails { $match: { $or: [ { "kycDetails.trade_name": { $exists: true } }, // Ensure KYC exists { "principalDetails.name": { $exists: true } }, // Ensure Principal Distributor exists ], }, }, ]; // Add filters based on query parameters // Filter by KYC trade_name (case-insensitive) if (tradename) { pipeline.push({ $match: { "kycDetails.trade_name": new RegExp(tradename, "i") }, }); } // Filter by principal_distributer name (case-insensitive) if (principaldistributor) { pipeline.push({ $match: { "principalDetails.name": new RegExp(principaldistributor, "i"), }, }); } // Filter by name (RetailDistributor model's name) if (name) { pipeline.push({ $match: { name: new RegExp(name, "i") }, // Case-insensitive search for name }); } // Filter by mobile_number (RetailDistributor model's mobile number) if (mobile_number) { pipeline.push({ $match: { mobile_number: new RegExp(mobile_number, "i") }, // Case-insensitive search for mobile_number }); } // Project only the required fields pipeline.push({ $project: { _id: 1, // RetailDistributor ID uniqueId: 1, // RetailDistributor uniqueId name: 1, // RetailDistributor name mobile_number: 1, // RetailDistributor mobile_number email: 1, // RetailDistributor email "kycDetails.trade_name": 1, // Only trade_name from kyc "principalDetails.name": 1, // Only name from principal_distributer "mappedTMDetails.name": 1, // Only name from mappedTM (Territory Manager) "mappedSCDetails.name": 1, // Only name from mappedSC (Sales Coordinator) createdAt: 1, // For sorting }, }); // Pagination and sorting pipeline.push({ $sort: { createdAt: -1 } }); pipeline.push({ $skip: skip }); pipeline.push({ $limit: parseInt(show) }); // Execute the aggregation pipeline const Retaildistributor = await RetailDistributor.aggregate(pipeline); // Get total count of documents matching the query const countPipeline = [ { $lookup: { from: "kycs", localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "users", localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, { $match: { $or: [ { "kycDetails.trade_name": { $exists: true } }, { "principalDetails.name": { $exists: true } }, ], }, }, ]; // Apply search filters to count query // Filter by KYC trade_name if (tradename) { countPipeline.push({ $match: { "kycDetails.trade_name": new RegExp(tradename, "i") }, }); } // Filter by principal_distributer name if (principaldistributor) { countPipeline.push({ $match: { "principalDetails.name": new RegExp(principaldistributor, "i"), }, }); } // Filter by name if (name) { countPipeline.push({ $match: { name: new RegExp(name, "i") }, }); } // Filter by mobile_number if (mobile_number) { countPipeline.push({ $match: { mobile_number: new RegExp(mobile_number, "i") }, }); } // Get the total count of filtered documents const total_data = await RetailDistributor.aggregate([ ...countPipeline, { $count: "total" }, ]); const totalCount = total_data[0]?.total || 0; // Ensure count is zero if no data found // Send the response with pagination data res.status(200).json({ success: true, total_data: totalCount, total_pages: Math.ceil(totalCount / show), Retaildistributor, }); } catch (error) { console.error(error); res.status(500).json({ message: "Server Error", error }); } }; export const getAllRetailDistributorwithTotalorder = async (req, res) => { try { const { page = 1, show = 10, tradename, name, mobile_number, principaldistributor, } = req.query; const skip = (page - 1) * show; // Build the aggregation pipeline let pipeline = [ { $lookup: { from: "kycs", // KYC collection localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "users", // Principal Distributor collection localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, { $lookup: { from: "territorymanagers", // Territory Manager collection localField: "mappedTM", foreignField: "_id", as: "mappedTMDetails", }, }, { $unwind: { path: "$mappedTMDetails", preserveNullAndEmptyArrays: true }, }, { $lookup: { from: "salescoordinators", // Sales Coordinator collection localField: "mappedSC", foreignField: "_id", as: "mappedSCDetails", }, }, { $unwind: { path: "$mappedSCDetails", preserveNullAndEmptyArrays: true }, }, ]; // Add filters based on query parameters const matchConditions = {}; if (tradename) matchConditions["kycDetails.trade_name"] = new RegExp(tradename, "i"); if (name) matchConditions["name"] = new RegExp(name, "i"); if (mobile_number) matchConditions["mobile_number"] = new RegExp(mobile_number, "i"); if (principaldistributor) matchConditions["principalDetails.name"] = new RegExp( principaldistributor, "i" ); if (Object.keys(matchConditions).length) { pipeline.push({ $match: matchConditions }); } // Project required fields early pipeline.push({ $project: { _id: 1, uniqueId: 1, name: 1, mobile_number: 1, email: 1, "kycDetails.trade_name": 1, "principalDetails.name": 1, "mappedTMDetails.name": 1, "mappedSCDetails.name": 1, createdAt: 1, }, }); // Pagination and sorting pipeline.push({ $sort: { createdAt: -1 } }); pipeline.push({ $skip: skip }); pipeline.push({ $limit: parseInt(show) }); // Execute the main aggregation pipeline const Retaildistributor = await RetailDistributor.aggregate(pipeline); // Aggregate orders data for each distributor const orderStats = await RdOrder.aggregate([ { $match: { addedBy: { $in: Retaildistributor.map((user) => user._id) } }, }, { $group: { _id: "$addedBy", // Group by distributor ID totalOrders: { $sum: 1 }, // Count total orders lastOrderDate: { $max: "$createdAt" }, // Get last order date }, }, ]); // Combine order stats with Retaildistributor data const usersWithOrderStats = Retaildistributor.map((user) => { const orderData = orderStats.find( (order) => order._id.toString() === user._id.toString() ); return { ...user, totalOrders: orderData ? orderData.totalOrders : 0, lastOrderDate: orderData ? orderData.lastOrderDate : null, }; }); // Get total count of documents matching the query const countPipeline = [{ $match: matchConditions }, { $count: "total" }]; const total_data = await RetailDistributor.aggregate(countPipeline); const totalCount = total_data[0]?.total || 0; // Send the response res.status(200).json({ success: true, total_data: totalCount, total_pages: Math.ceil(totalCount / show), Retaildistributor: usersWithOrderStats, }); } catch (error) { console.error(error); res.status(500).json({ message: "Server Error", error }); } }; //get RD by Id export const getRDId = async (req, res) => { try { const { id } = req.params; // console.log(id); // Fetch the KYC document from the database by ID const RD = await RetailDistributor.findById(id) .populate("principal_distributer", "name email phone") .populate("addedBy") .populate("kyc") .populate("mappedTM") .populate("mappedSC"); // Check if the KYC document exists if (!RD) { return res.status(404).json({ message: "No RetailDistributor found" }); } // console.log(RD); // Send the fetched KYC document as a response res.status(200).json(RD); } catch (error) { // Handle any errors that occur during the fetch operation res.status(500).json({ message: "Server Error", error }); } }; //mapping export const getAllRDbytmid = async (req, res) => { try { // Extract query parameters const { page = 1, show = 10, tradename, name, mobile_number, principaldistributor, } = req.query; const { mappedTMId } = req.params; // Extract mappedTM ID from request params // Convert mappedTMId to ObjectId if it's a valid ObjectId string let mappedTMObjectId; try { mappedTMObjectId = mongoose.Types.ObjectId(mappedTMId); } catch (error) { return res.status(400).json({ message: "Invalid mappedTM ID format" }); } const skip = (page - 1) * show; // Build the aggregation pipeline let pipeline = [ { $match: { mappedTM: mappedTMObjectId, // Filter by mappedTM ObjectId }, }, { $lookup: { from: "kycs", // Assuming your KYC collection is named "kycs" localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, // Unwind kycDetails and allow null/empty arrays { $lookup: { from: "users", // Assuming your User collection is named "users" localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, // Unwind principalDetails and allow null/empty arrays // Lookup for mappedTM (Territory Manager) { $lookup: { from: "territorymanagers", // Assuming your Territory Manager collection localField: "mappedTM", foreignField: "_id", as: "mappedTMDetails", }, }, { $unwind: { path: "$mappedTMDetails", preserveNullAndEmptyArrays: true }, }, // Unwind mappedTMDetails and allow null/empty arrays // Lookup for mappedSC (Sales Coordinator) { $lookup: { from: "salescoordinators", // Assuming your Sales Coordinator collection localField: "mappedSC", foreignField: "_id", as: "mappedSCDetails", }, }, { $unwind: { path: "$mappedSCDetails", preserveNullAndEmptyArrays: true }, }, // Unwind mappedSCDetails and allow null/empty arrays // Filter to ensure data exists in kyc or principalDetails { $match: { $or: [ { "kycDetails.trade_name": { $exists: true } }, // Ensure KYC exists { "principalDetails.name": { $exists: true } }, // Ensure Principal Distributor exists ], }, }, ]; // Add filters based on query parameters // Filter by KYC trade_name (case-insensitive) if (tradename) { pipeline.push({ $match: { "kycDetails.trade_name": new RegExp(tradename, "i") }, }); } // Filter by principal_distributer name (case-insensitive) if (principaldistributor) { pipeline.push({ $match: { "principalDetails.name": new RegExp(principaldistributor, "i"), }, }); } // Filter by name (RetailDistributor model's name) if (name) { pipeline.push({ $match: { name: new RegExp(name, "i") }, // Case-insensitive search for name }); } // Filter by mobile_number (RetailDistributor model's mobile number) if (mobile_number) { pipeline.push({ $match: { mobile_number: new RegExp(mobile_number, "i") }, // Case-insensitive search for mobile_number }); } // Project only the required fields pipeline.push({ $project: { _id: 1, // RetailDistributor ID uniqueId: 1, // RetailDistributor uniqueId name: 1, // RetailDistributor name mobile_number: 1, // RetailDistributor mobile_number email: 1, // RetailDistributor email "kycDetails.trade_name": 1, // Only trade_name from kyc "principalDetails.name": 1, // Only name from principal_distributer "mappedTMDetails.name": 1, // Only name from mappedTM (Territory Manager) "mappedSCDetails.name": 1, // Only name from mappedSC (Sales Coordinator) createdAt: 1, // For sorting }, }); // Pagination and sorting pipeline.push({ $sort: { createdAt: -1 } }); pipeline.push({ $skip: skip }); pipeline.push({ $limit: parseInt(show) }); // Execute the aggregation pipeline const Retaildistributor = await RetailDistributor.aggregate(pipeline); // Get total count of documents matching the query const countPipeline = [ { $match: { mappedTM: mappedTMObjectId, // Filter by mappedTM ObjectId }, }, { $lookup: { from: "kycs", localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "users", localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, { $match: { $or: [ { "kycDetails.trade_name": { $exists: true } }, { "principalDetails.name": { $exists: true } }, ], }, }, ]; // Apply search filters to count query // Filter by KYC trade_name if (tradename) { countPipeline.push({ $match: { "kycDetails.trade_name": new RegExp(tradename, "i") }, }); } // Filter by principal_distributer name if (principaldistributor) { countPipeline.push({ $match: { "principalDetails.name": new RegExp(principaldistributor, "i"), }, }); } // Filter by name if (name) { countPipeline.push({ $match: { name: new RegExp(name, "i") }, }); } // Filter by mobile_number if (mobile_number) { countPipeline.push({ $match: { mobile_number: new RegExp(mobile_number, "i") }, }); } // Get the total count of filtered documents const total_data = await RetailDistributor.aggregate([ ...countPipeline, { $count: "total" }, ]); const totalCount = total_data[0]?.total || 0; // Ensure count is zero if no data found // Send the response with pagination data res.status(200).json({ success: true, total_data: totalCount, total_pages: Math.ceil(totalCount / show), Retaildistributor, }); } catch (error) { console.error(error); res.status(500).json({ message: "Server Error", error }); } }; export const getAllRDbyscid = async (req, res) => { try { // Extract query parameters const { page = 1, show = 10, tradename, name, mobile_number, principaldistributor, } = req.query; const { mappedSCId } = req.params; // Extract mappedTM ID from request params // Convert mappedSCId to ObjectId if it's a valid ObjectId string let mappedSCObjectId; try { mappedSCObjectId = mongoose.Types.ObjectId(mappedSCId); } catch (error) { return res.status(400).json({ message: "Invalid mappedSC ID format" }); } const skip = (page - 1) * show; // Build the aggregation pipeline let pipeline = [ { $match: { mappedSC: mappedSCObjectId, // Filter by mappedSC ObjectId }, }, { $lookup: { from: "kycs", // Assuming your KYC collection is named "kycs" localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, // Unwind kycDetails and allow null/empty arrays { $lookup: { from: "users", // Assuming your User collection is named "users" localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, // Unwind principalDetails and allow null/empty arrays // Lookup for mappedTM (Territory Manager) { $lookup: { from: "territorymanagers", // Assuming your Territory Manager collection localField: "mappedTM", foreignField: "_id", as: "mappedTMDetails", }, }, { $unwind: { path: "$mappedTMDetails", preserveNullAndEmptyArrays: true }, }, // Unwind mappedTMDetails and allow null/empty arrays // Lookup for mappedSC (Sales Coordinator) { $lookup: { from: "salescoordinators", // Assuming your Sales Coordinator collection localField: "mappedSC", foreignField: "_id", as: "mappedSCDetails", }, }, { $unwind: { path: "$mappedSCDetails", preserveNullAndEmptyArrays: true }, }, // Unwind mappedSCDetails and allow null/empty arrays // Filter to ensure data exists in kyc or principalDetails { $match: { $or: [ { "kycDetails.trade_name": { $exists: true } }, // Ensure KYC exists { "principalDetails.name": { $exists: true } }, // Ensure Principal Distributor exists ], }, }, ]; // Add filters based on query parameters // Filter by KYC trade_name (case-insensitive) if (tradename) { pipeline.push({ $match: { "kycDetails.trade_name": new RegExp(tradename, "i") }, }); } // Filter by principal_distributer name (case-insensitive) if (principaldistributor) { pipeline.push({ $match: { "principalDetails.name": new RegExp(principaldistributor, "i"), }, }); } // Filter by name (RetailDistributor model's name) if (name) { pipeline.push({ $match: { name: new RegExp(name, "i") }, // Case-insensitive search for name }); } // Filter by mobile_number (RetailDistributor model's mobile number) if (mobile_number) { pipeline.push({ $match: { mobile_number: new RegExp(mobile_number, "i") }, // Case-insensitive search for mobile_number }); } // Project only the required fields pipeline.push({ $project: { _id: 1, // RetailDistributor ID uniqueId: 1, // RetailDistributor uniqueId name: 1, // RetailDistributor name mobile_number: 1, // RetailDistributor mobile_number email: 1, // RetailDistributor email "kycDetails.trade_name": 1, // Only trade_name from kyc "principalDetails.name": 1, // Only name from principal_distributer "mappedTMDetails.name": 1, // Only name from mappedTM (Territory Manager) "mappedSCDetails.name": 1, // Only name from mappedSC (Sales Coordinator) createdAt: 1, // For sorting }, }); // Pagination and sorting pipeline.push({ $sort: { createdAt: -1 } }); pipeline.push({ $skip: skip }); pipeline.push({ $limit: parseInt(show) }); // Execute the aggregation pipeline const Retaildistributor = await RetailDistributor.aggregate(pipeline); // Get total count of documents matching the query const countPipeline = [ { $match: { mappedSC: mappedSCObjectId, // Filter by mappedTM ObjectId }, }, { $lookup: { from: "kycs", localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "users", localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, { $match: { $or: [ { "kycDetails.trade_name": { $exists: true } }, { "principalDetails.name": { $exists: true } }, ], }, }, ]; // Apply search filters to count query // Filter by KYC trade_name if (tradename) { countPipeline.push({ $match: { "kycDetails.trade_name": new RegExp(tradename, "i") }, }); } // Filter by principal_distributer name if (principaldistributor) { countPipeline.push({ $match: { "principalDetails.name": new RegExp(principaldistributor, "i"), }, }); } // Filter by name if (name) { countPipeline.push({ $match: { name: new RegExp(name, "i") }, }); } // Filter by mobile_number if (mobile_number) { countPipeline.push({ $match: { mobile_number: new RegExp(mobile_number, "i") }, }); } // Get the total count of filtered documents const total_data = await RetailDistributor.aggregate([ ...countPipeline, { $count: "total" }, ]); const totalCount = total_data[0]?.total || 0; // Ensure count is zero if no data found // Send the response with pagination data res.status(200).json({ success: true, total_data: totalCount, total_pages: Math.ceil(totalCount / show), Retaildistributor, }); } catch (error) { console.error(error); res.status(500).json({ message: "Server Error", error }); } }; export const getAllRDbypdid = async (req, res) => { try { // Extract query parameters const { page = 1, show = 10, tradename, name, mobile_number } = req.query; const { mappedPDId } = req.params; // Extract mappedTM ID from request params // Convert mappedPDId to ObjectId if it's a valid ObjectId string let mappedPDObjectId; try { mappedPDObjectId = mongoose.Types.ObjectId(mappedPDId); } catch (error) { return res.status(400).json({ message: "Invalid mappedPD ID format" }); } const skip = (page - 1) * show; // Build the aggregation pipeline let pipeline = [ { $match: { principal_distributer: mappedPDObjectId, // Filter by principal_distributer ObjectId }, }, { $lookup: { from: "kycs", // Assuming your KYC collection is named "kycs" localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, // Unwind kycDetails and allow null/empty arrays { $lookup: { from: "users", // Assuming your User collection is named "users" localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, // Unwind principalDetails and allow null/empty arrays // Lookup for mappedTM (Territory Manager) { $lookup: { from: "territorymanagers", // Assuming your Territory Manager collection localField: "mappedTM", foreignField: "_id", as: "mappedTMDetails", }, }, { $unwind: { path: "$mappedTMDetails", preserveNullAndEmptyArrays: true }, }, // Unwind mappedTMDetails and allow null/empty arrays // Lookup for mappedSC (Sales Coordinator) { $lookup: { from: "salescoordinators", // Assuming your Sales Coordinator collection localField: "mappedSC", foreignField: "_id", as: "mappedSCDetails", }, }, { $unwind: { path: "$mappedSCDetails", preserveNullAndEmptyArrays: true }, }, // Unwind mappedSCDetails and allow null/empty arrays // Filter to ensure data exists in kyc or principalDetails { $match: { $or: [ { "kycDetails.trade_name": { $exists: true } }, // Ensure KYC exists { "principalDetails.name": { $exists: true } }, // Ensure Principal Distributor exists ], }, }, ]; // Add filters based on query parameters // Filter by KYC trade_name (case-insensitive) if (tradename) { pipeline.push({ $match: { "kycDetails.trade_name": new RegExp(tradename, "i") }, }); } // Filter by name (RetailDistributor model's name) if (name) { pipeline.push({ $match: { name: new RegExp(name, "i") }, // Case-insensitive search for name }); } // Filter by mobile_number (RetailDistributor model's mobile number) if (mobile_number) { pipeline.push({ $match: { mobile_number: new RegExp(mobile_number, "i") }, // Case-insensitive search for mobile_number }); } // Project only the required fields pipeline.push({ $project: { _id: 1, // RetailDistributor ID uniqueId: 1, // RetailDistributor uniqueId name: 1, // RetailDistributor name mobile_number: 1, // RetailDistributor mobile_number email: 1, // RetailDistributor email "kycDetails.trade_name": 1, // Only trade_name from kyc "mappedTMDetails.name": 1, // Only name from mappedTM (Territory Manager) "mappedSCDetails.name": 1, // Only name from mappedSC (Sales Coordinator) "principalDetails.name": 1, // Only name from principal_distributer createdAt: 1, // For sorting }, }); // Pagination and sorting pipeline.push({ $sort: { createdAt: -1 } }); pipeline.push({ $skip: skip }); pipeline.push({ $limit: parseInt(show) }); // Execute the aggregation pipeline const Retaildistributor = await RetailDistributor.aggregate(pipeline); // Get total count of documents matching the query const countPipeline = [ { $match: { principal_distributer: mappedPDObjectId, // Filter by mappedTM ObjectId }, }, { $lookup: { from: "kycs", localField: "kyc", foreignField: "_id", as: "kycDetails", }, }, { $unwind: { path: "$kycDetails", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "users", localField: "principal_distributer", foreignField: "_id", as: "principalDetails", }, }, { $unwind: { path: "$principalDetails", preserveNullAndEmptyArrays: true, }, }, { $match: { $or: [ { "kycDetails.trade_name": { $exists: true } }, { "principalDetails.name": { $exists: true } }, ], }, }, ]; // Apply search filters to count query // Filter by KYC trade_name if (tradename) { countPipeline.push({ $match: { "kycDetails.trade_name": new RegExp(tradename, "i") }, }); } // Filter by name if (name) { countPipeline.push({ $match: { name: new RegExp(name, "i") }, }); } // Filter by mobile_number if (mobile_number) { countPipeline.push({ $match: { mobile_number: new RegExp(mobile_number, "i") }, }); } // Get the total count of filtered documents const total_data = await RetailDistributor.aggregate([ ...countPipeline, { $count: "total" }, ]); const totalCount = total_data[0]?.total || 0; // Ensure count is zero if no data found // Send the response with pagination data res.status(200).json({ success: true, total_data: totalCount, total_pages: Math.ceil(totalCount / show), Retaildistributor, }); } catch (error) { console.error(error); res.status(500).json({ message: "Server Error", error }); } }; export const updateRDMapped = async (req, res) => { try { const { id } = req.params; const { principal_distributor, mappedTM, mappedSC } = req.body; // console.log(req.body); // console.log(req.params); // Find the RetailDistributor document by ID const RD = await RetailDistributor.findById(id); if (!RD) { return res.status(404).json({ message: "RetailDistributor not found" }); } // Update the fields if provided in the request body if (principal_distributor) { RD.principal_distributer = principal_distributor; } if (mappedTM) { RD.mappedTM = mappedTM; } if (mappedSC) { RD.mappedSC = mappedSC; } // Save the updated document await RD.save(); res.status(200).json({ message: "RetailDistributor record updated successfully", data: RD, }); } catch (error) { // Handle any errors during the update res.status(500).json({ message: "Error updating RD record", error: error.message, }); } }; export const updateunmapRD = async (req, res) => { try { const { id } = req.params; const { principal_distributor, mappedTM, mappedSC } = req.body; // Find the RetailDistributor document by ID const RD = await RetailDistributor.findById(id); if (!RD) { return res.status(404).json({ message: "RetailDistributor not found" }); } // Update the fields if provided in the request body if (principal_distributor) { RD.principal_distributer = null; } if (mappedTM) { RD.mappedTM = null; } if (mappedSC) { RD.mappedSC = null; } // Save the updated document await RD.save(); res.status(200).json({ message: "RetailDistributor record updated successfully", data: RD, }); } catch (error) { // Handle any errors during the update res.status(500).json({ message: "Error updating RD record", error: error.message, }); } }; export const saveFCMTokenForRD = async (req, res) => { const { fcmToken } = req.body; const userId = req.user._id; try { // Fetch the current FCM token for the user const user = await RetailDistributor.findById(userId); if (!user) { return res.status(404).send("User not found"); } // Check if the new FCM token is different from the current one if (user.fcm_token && user.fcm_token === fcmToken) { return res.status(200).send("FCM Token is already up to date"); } // Update the FCM token user.fcm_token = fcmToken; await user.save(); res.status(200).send("FCM Token saved successfully"); } catch (error) { console.error("Error saving FCM Token:", error); res.status(500).send("Internal Server Error"); } };