const boom = require("boom"); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const customJwtAuth = require("../customAuthJwt"); const mongoose = require("mongoose"); const fastify = require("fastify")({ logger: true, genReqId(req) { return uuidv4(); }, }); const { Counter} = require('../models/User') const {Department, Desgination, City, Deparments, Branch, Zone,IndianLocations} = require('../models/Department') const generateCityId = async () => { var result = await Counter.findOneAndUpdate( { _id: 'customer_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return result.seq; }; const generateBranchId = async () => { var result = await Counter.findOneAndUpdate( { _id: 'customer_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return result.seq; }; const generateDepartmentId = async (city, departmentName) => { const cityPrefix = city.substring(0, 2).toUpperCase(); // Extract first two letters of city const departmentPrefix = departmentName.substring(0, 2).toUpperCase(); // Extract first two letters of departmentName const result = await Counter.findOneAndUpdate( { _id: 'desgination_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return `AW${cityPrefix}${departmentPrefix}${result.seq}`; // Generate ID }; exports.addCity = async (request, reply) => { try { const { phone, officeName, location, city, state, country, zone, office_address1, address2, pincode, createdBy, updatedBy, email, gstNo, googleLocation, latitude, longitude, // nameoftheContactPerson, } = request.body; // Generate unique cityId const c_id = await generateCityId(); const cityId = `AWCI${c_id}`; // Check for existing records with specific fields const existingPhone = await City.findOne({ phone }); if (existingPhone) { return reply.status(400).send({ message: 'Phone number already exists' }); } const existingOfficeName = await City.findOne({ officeName }); if (existingOfficeName) { return reply.status(400).send({ message: 'Office name already exists' }); } const existingCityId = await City.findOne({ cityId }); if (existingCityId) { return reply.status(400).send({ message: 'City ID already exists' }); } // Create new city record const citys = new City({ cityId, phone, officeName, location, city, office_address1, address2, state, zone, country, pincode, email, gstNo, googleLocation, latitude, longitude, // nameoftheContactPerson, createdBy, updatedBy, }); await citys.save(); reply.send({ citys, message: 'City Created Successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.addBranch = async (request, reply) => { try { const { phone, land_line_number, officeName, location, city, state, country, zone, office_address1, address2, pincode, createdBy, updatedBy, email, //nameoftheContactPerson, googleLocation, latitude, longitude } = request.body; // Generate departmentId based on departmentName // const prefix = departmentName.substring(0, 2).toUpperCase(); // Extract first two letters and convert to uppercase const b_id = await generateBranchId(); const branchId = `AWBR${b_id}`; // Check for existing department const existingStore = await Branch.findOne({ branchId }); if (existingStore) { return reply.status(400).send({ message: 'Branch is already registered' }); } // Create new department const branch = new Branch({ branchId, phone, land_line_number, officeName, location, city, office_address1, address2, state, zone, country, pincode, email, // nameoftheContactPerson, googleLocation, latitude, longitude, // departmentName, createdBy, updatedBy, }); await branch.save(); reply.send({ branch, message: 'Account Created Successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.addZone = async (request, reply) => { try { const { officeName, location, city, zone, area, createdBy, updatedBy, } = request.body; // Generate departmentId based on departmentName // const prefix = departmentName.substring(0, 2).toUpperCase(); // Extract first two letters and convert to uppercase const b_id = await generateBranchId(); const zoneId = `AWZN${b_id}`; // Check for existing department const existingStore = await Zone.findOne({ zoneId }); if (existingStore) { return reply.status(400).send({ message: 'Branch is already registered' }); } const zones = new Zone({ zoneId, officeName, location, city, zone, area, createdBy, updatedBy, }); await zones.save(); reply.send({ zones, message: 'Account Created Successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.getallCompanyNames = async (req, reply) => { try { await City.find() .select("officeName -_id") // Select only officeName and exclude _id .exec() .then((docs) => { const officeNames = ["ALL", ...docs.map((doc) => doc.officeName)]; // Prepend "ALL" reply.send({ status_code: 200, data: officeNames, count: officeNames.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; exports.deletecityInfo = async (req, reply) => { try { const cityId = req.params.cityId; const department = await City.findOneAndDelete({ cityId:cityId }); reply.send({ status_code: 200, message: 'Delete Sucessfully', department}); } catch (err) { throw boom.boomify(err); } }; exports.deleteBranchInfo = async (req, reply) => { try { const branchId = req.params.branchId; const branch = await Branch.findOneAndDelete({ branchId:branchId }); reply.send({ status_code: 200, message: 'Delete Sucessfully', branch}); } catch (err) { throw boom.boomify(err); } }; exports.editcity = async (request, reply) => { try { const { cityId } = request.params; const { phone, city, state, country, zone, address1, address2, pincode, email, officeName } = request.body; const existing = await City.findOne({ cityId }); if (!existing) { return reply.status(404).send({ message: 'City not found' }); } // const phoneExists = await Department.findOne({ phone, departmentId: { $ne: departmentId } }); // if (phoneExists) { // return reply.status(400).send({ message: 'Phone is already registered to another user' }); // } existing.phone = phone || existing.phone; existing.city = city || existing.city; existing.state = state || existing.state; existing.country = country || existing.country; existing.zone = zone || existing.zone; existing.officeName = officeName || existing.officeName; existing.pincode = pincode || existing.pincode; existing.address1 = address1 || existing.address1; existing.address2 = address2 || existing.address2; existing.email = email || existing.email; await existing.save(); reply.send({ message: 'City user updated successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.editBranch = async (request, reply) => { try { const { branchId } = request.params; const { phone, land_line_number, officeName, city, state, country, zone, address1, address2, pincode, email // departmentName } = request.body; const existing = await Branch.findOne({ branchId }); if (!existing) { return reply.status(404).send({ message: 'Branch not found' }); } // const phoneExists = await Department.findOne({ phone, departmentId: { $ne: departmentId } }); // if (phoneExists) { // return reply.status(400).send({ message: 'Phone is already registered to another user' }); // } existing.phone = phone || existing.phone; existing.land_line_number = land_line_number || existing.land_line_number; existing.city = city || existing.city; existing.state = state || existing.state; existing.country = country || existing.country; existing.zone = zone || existing.zone; existing.officeName = officeName || existing.officeName; existing.pincode = pincode || existing.pincode; existing.address1 = address1 || existing.address1; existing.address2 = address2 || existing.address2; existing.email = email || existing.email; await existing.save(); reply.send({ message: 'Branch user updated successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.addDepartment = async (request, reply) => { try { const { phone, officeName, alternativeContactNumber, gender, personalEmail, city, personal_city, reportingManager_mobile_number, reportingManager_email, firstName, lastName, departmentName, reportingManager, email, state, password, country, zone, address1, address2, pincode, desginationName, location, picture, dateOfJoin, employeeType, createdBy, updatedBy, } = request.body; // Generate departmentId const departmentId = await generateDepartmentId(city, departmentName); // Check if the phone is already registered const existingStore = await Deparments.findOne({ phone }); if (existingStore) { return reply.status(400).send({ message: "Phone is already registered" }); } // Hash the password const hashedPassword = await bcrypt.hash(password, 10); // 🟢 Handle reportingManager "Self" let finalReportingManager = reportingManager; let finalReportingManagerMobile = reportingManager_mobile_number; let finalReportingManagerEmail = reportingManager_email; if (reportingManager?.toLowerCase() === "self") { // Default format let managerString = `${firstName || ""} ${lastName || ""} - (${phone}) - ${city}`; // If departmentName is "Head Office" or "Branch Office" → add departmentName if ( ["head office", "branch office"].includes( (departmentName || "").toLowerCase().trim() ) ) { managerString += ` - ${departmentName}`; } finalReportingManager = managerString; finalReportingManagerMobile = phone; finalReportingManagerEmail = email; } // Create new department const department = new Deparments({ departmentId, alternativeContactNumber, officeName, reportingManager_mobile_number: finalReportingManagerMobile, reportingManager_email: finalReportingManagerEmail, personal_city, gender, city, firstName, lastName, email, personalEmail, reportingManager: finalReportingManager, departmentName, phone, address1, address2, services: { password: { bcrypt: hashedPassword } }, state, zone, country, pincode, desginationName, location, picture, dateOfJoin, employeeType, createdBy, updatedBy, }); await department.save(); reply.send({ department, message: "Account Created Successfully" }); } catch (err) { console.error("❌ Error in addDepartment:", err); reply.status(500).send({ message: err.message }); } }; exports.getDetails = async (request, reply) => { try { const { id } = request.params; let data; if (id.startsWith('AWBR')) { data = await Branch.findOne({ branchId: id }); } else { data = await City.findOne({ cityId: id }); } if (!data) { return reply.status(404).send({ message: 'Not found' }); } reply.send({ data }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.getCityDetails = async (request, reply) => { try { const cityId = request.params.cityId; const data = await City.findOne({ cityId }); if (!data) { return reply.status(404).send({ message: 'City not found' }); } reply.send({ data }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.getBranchDetails = async (request, reply) => { try { const branchId = request.params.branchId; const data = await Branch.findOne({ branchId }); if (!data) { return reply.status(404).send({ message: 'Branch not found' }); } reply.send({ data }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.getSinledepartmentData = async (req, reply) => { try { const { departmentId } = req.params; const department = await Deparments.findOne({ departmentId: departmentId }); if (!department) { return reply.code(404).send({ success: false, message: 'Department not found.' }); } reply.code(200).send({ success: true, message: 'Designation data retrieved successfully.', data: department }); } catch (error) { console.error('Error fetching department data:', error); reply.code(500).send({ success: false, message: 'Failed to retrieve department data.', error: error.message, }); } }; exports.getalldepartments = async (req, reply) => { try { await Deparments.find() .exec() .then((docs) => { reply.send({ status_code: 200, data: docs, count: docs.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; exports.getallCitiesData = async (req, reply) => { try { console.log("Fetching all cities..."); // Debug log const cities = await City.distinct('city'); // Fetch distinct city names from the database // Normalize the city names to avoid duplicates const normalizedCities = [...new Set(cities.map(city => city.trim().toUpperCase()))]; console.log("Cities fetched:", normalizedCities); // Log the cleaned cities reply.send({ status_code: 200, data: normalizedCities, count: normalizedCities.length }); } catch (err) { console.error("Error fetching cities:", err); // Log the error for debugging throw boom.boomify(err); } }; exports.getallZonesData = async (req, reply) => { try { console.log("Fetching all zones..."); // Debug log const zones = await City.distinct('zone'); // Fetch distinct zone names from the database // Normalize the zone names to avoid duplicates const normalizedZones = [...new Set(zones.map(zone => zone.trim().toUpperCase()))]; console.log("Zones fetched:", normalizedZones); // Log the cleaned zones reply.send({ status_code: 200, data: normalizedZones, count: normalizedZones.length }); } catch (err) { console.error("Error fetching zones:", err); // Log the error for debugging throw boom.boomify(err); } }; exports.getallLocationData = async (req, reply) => { try { console.log("Fetching all locations..."); // Debug log const locations = await City.distinct('location'); // Fetch distinct locations from the database // Normalize the location names to uppercase and remove duplicates const normalizedLocations = [...new Set(locations.map(location => location.trim().toUpperCase()))]; console.log("Locations fetched:", normalizedLocations); // Log the cleaned locations reply.send({ status_code: 200, data: normalizedLocations, count: normalizedLocations.length }); } catch (err) { console.error("Error fetching locations:", err); // Log the error for debugging throw boom.boomify(err); } }; exports.deletedepartmentInfo = async (req, reply) => { try { const departmentId = req.params.departmentId; const department = await Deparments.findOneAndDelete({ departmentId:departmentId }); reply.send({ status_code: 200, message: 'Delete Sucessfully', department}); } catch (err) { throw boom.boomify(err); } }; exports.editdepartment = async (request, reply) => { try { const { departmentId } = request.params; const { phone, alternativeContactNumber, gender, personalEmail, city, firstName, lastName, email, reportingManager, departmentName, state, country, zone, address1, address2, pincode, desginationName, personal_city, reportingManager_mobile_number, reportingManager_email, officeName, picture, employeeType } = request.body; const existing = await Deparments.findOne({ departmentId }); if (!existing) { return reply.status(404).send({ message: "Department not found" }); } const phoneExists = await Deparments.findOne({ phone, departmentId: { $ne: departmentId }, }); if (phoneExists) { return reply .status(400) .send({ message: "Phone is already registered to another user" }); } // 🟢 Handle reportingManager "Self" let finalReportingManager = reportingManager || existing.reportingManager; let finalReportingManagerMobile = reportingManager_mobile_number || existing.reportingManager_mobile_number; let finalReportingManagerEmail = reportingManager_email || existing.reportingManager_email; if (reportingManager?.toLowerCase() === "self") { finalReportingManager = `${firstName || existing.firstName || ""} ${ lastName || existing.lastName || "" } - (${phone || existing.phone}) - ${city || existing.city}`; finalReportingManagerMobile = phone || existing.phone; finalReportingManagerEmail = email || existing.email; } // 🔹 Update fields existing.phone = phone || existing.phone; existing.alternativeContactNumber = alternativeContactNumber || existing.alternativeContactNumber; existing.personalEmail = personalEmail || existing.personalEmail; existing.gender = gender || existing.gender; existing.city = city || existing.city; existing.state = state || existing.state; existing.country = country || existing.country; existing.zone = zone || existing.zone; existing.desginationName = desginationName || existing.desginationName; existing.pincode = pincode || existing.pincode; existing.address1 = address1 || existing.address1; existing.address2 = address2 || existing.address2; existing.email = email || existing.email; existing.firstName = firstName || existing.firstName; existing.lastName = lastName || existing.lastName; existing.departmentName = departmentName || existing.departmentName; existing.personal_city = personal_city || existing.personal_city; existing.officeName = officeName || existing.officeName; existing.picture = picture || existing.picture; existing.employeeType = employeeType || existing.employeeType; // 🔹 Assign formatted reportingManager existing.reportingManager = finalReportingManager; existing.reportingManager_mobile_number = finalReportingManagerMobile; existing.reportingManager_email = finalReportingManagerEmail; await existing.save(); reply.send({ message: "Department user updated successfully" }); } catch (err) { console.error("❌ Error in editdepartment:", err); reply.status(500).send({ message: err.message }); } }; const getLocationsByCityZoneOffice = async (city, zone, officeName) => { try { // Build matchCondition dynamically const matchCondition = {}; // City filter if (city.trim().toUpperCase() !== "ALL") { matchCondition.city = { $regex: `^${city.trim().toLowerCase()}$`, $options: "i" }; } // Zone filter if (zone.trim().toUpperCase() !== "ALL") { matchCondition.zone = zone.trim(); } // Office name filter if (officeName && officeName.trim().toUpperCase() !== "ALL") { matchCondition.officeName = { $regex: `^${officeName.trim()}$`, $options: "i" }; } const result = await Zone.aggregate([ { $project: { city: { $toLower: { $trim: { input: "$city" } } }, zone: { $trim: { input: "$zone" } }, officeName: { $trim: { input: "$officeName" } }, location: 1 } }, { $match: matchCondition }, { $group: { _id: { city: "$city", officeName: "$officeName" }, locations: { $push: "$location" } } }, { $project: { _id: 0, city: "$_id.city", officeName: "$_id.officeName", locations: { $reduce: { input: "$locations", initialValue: [], in: { $concatArrays: ["$$value", "$$this"] } } } } } ]); if (result.length) { // Flatten all locations from all offices if city/zone are ALL let allLocations = [...new Set(result.flatMap(r => r.locations))]; // Ensure "ALL" at the top if (!allLocations.includes("ALL")) { allLocations.unshift("ALL"); } return { city: city.trim().toUpperCase(), officeName: officeName ? officeName.trim().toUpperCase() : "ALL", locations: allLocations }; } else { return { city: city.trim().toUpperCase(), officeName: officeName ? officeName.trim().toUpperCase() : "ALL", locations: ["ALL"] }; } } catch (err) { console.error(err); throw new Error("Error fetching locations."); } }; exports.getZonebasedLocations = async (req, reply) => { try { const { city, zone, officeName } = req.query; console.log("Received City:", `"${city}"`, "Zone:", `"${zone}"`, "Office:", `"${officeName}"`); if (!city || !zone) { return reply.status(400).send({ message: "City and zone are required." }); } const locations = await getLocationsByCityZoneOffice( city.trim(), zone.trim(), officeName ? officeName.trim() : "ALL" ); if (!locations) { return reply.send({ status_code: 404, message: "No data found." }); } reply.send({ status_code: 200, data: locations }); } catch (err) { reply.status(500).send({ message: err.message }); } }; const getLocationsByZone = async (zone) => { try { const result = await City.aggregate([ { $match: { zone: { $regex: `^${zone}$`, $options: "i" }, // Case-insensitive match for the zone }, }, { $unwind: "$location" // Unwind the location field if it is an array }, { $group: { _id: "$zone", // Group by zone locations: { $addToSet: { $toUpper: { $trim: { input: "$location" } } // Convert to uppercase and trim whitespace } }, }, }, { $project: { _id: 0, // Exclude the _id field zone: "$_id", // Include zone locations: 1 // Return locations }, }, ]); return result; } catch (err) { console.error(err); throw new Error("Error fetching locations."); } }; exports.getLocationsByZone = async (req, reply) => { try { const { zone } = req.params; // Get zone from path params if (!zone) { return reply.status(400).send({ message: "Zone is required." }); } const locations = await getLocationsByZone(zone); reply.send({ status_code: 200, data: locations }); } catch (err) { reply.status(500).send({ message: err.message }); } }; const getZonesByCityAndOffice = async (city, officeName) => { try { const result = await Zone.aggregate([ { $project: { city: { $trim: { input: "$city" } }, // Trim city officeName: { $trim: { input: "$officeName" } }, // Trim officeName zone: 1 } }, { $match: { ...(city && city !== "ALL" ? { city: { $regex: `^${city.trim()}$`, $options: "i" } } : {}), ...(officeName && officeName !== "ALL" ? { officeName: { $regex: `^${officeName.trim()}$`, $options: "i" } } : {}) } }, { $group: { _id: { city: { $toUpper: "$city" }, officeName: { $toUpper: "$officeName" } }, zones: { $addToSet: "$zone" } } }, { $project: { _id: 0, city: "$_id.city", officeName: "$_id.officeName", zones: 1 } } ]); // Add "ALL" to zones and sort result.forEach(item => { item.zones = ["ALL", ...new Set(item.zones)].sort((a, b) => a === "ALL" ? -1 : b.localeCompare(a) ); }); return result; } catch (err) { console.error("Error fetching zones:", err); throw new Error("Error fetching zones."); } }; exports.getZonesByCityAndOffice = async (req, reply) => { try { const { city, officeName } = req.params; if (!city || city.trim() === "" || !officeName || officeName.trim() === "") { return reply.status(400).send({ message: "City and Office Name are required." }); } const zones = await getZonesByCityAndOffice(city.trim(), officeName.trim()); if (zones.length === 0) { return reply.status(404).send({ message: "No zones found for the specified city and office." }); } reply.send({ status_code: 200, data: zones }); } catch (err) { reply.status(500).send({ message: err.message }); } }; const getAreasByCitys = async (city) => { try { const result = await Zone.aggregate([ { $project: { city: { $trim: { input: "$city" } }, // Trim city field in DB area: 1 // Keep zone field } }, { $match: { city: { $regex: `^${city.trim()}$`, $options: "i" }, // Trim & case-insensitive } }, { $group: { _id: { $toUpper: "$city" }, // Normalize city name areas: { $addToSet: "$area" } // Collect unique zones } }, { $project: { _id: 0, // Exclude _id city: "$_id", // Return city name areas: 1 // Return collected zones } } ]); // Add "ALL" to the zones array and sort it result.forEach(item => { item.areas = ["ALL", ...new Set(item.areas)].sort((a, b) => (a === "ALL" ? -1 : a - b)); }); return result; } catch (err) { console.error("Error fetching areas:", err); throw new Error("Error fetching areas."); } }; exports.getAreasByCity = async (req, reply) => { try { const { city } = req.params; if (!city || city.trim() === "") { return reply.status(400).send({ message: "City is required." }); } const zones = await getAreasByCitys(city.trim()); // Trim input if (zones.length === 0) { return reply.status(404).send({ message: "No zones found for the specified city." }); } reply.send({ status_code: 200, data: zones }); } catch (err) { reply.status(500).send({ message: err.message }); } }; const getZonesByArea = async (area) => { try { const result = await Zone.aggregate([ { $project: { area: { $trim: { input: "$area" } }, // Trim area field in DB zone: 1 // Keep zone field } }, { $match: { area: { $regex: `^${area.trim()}$`, $options: "i" } // Case-insensitive match on area } }, { $group: { _id: { $toUpper: "$area" }, // Normalize area name zones: { $addToSet: "$zone" } // Collect unique zones } }, { $project: { _id: 0, // Exclude _id area: "$_id", zones: 1 // Return collected zones } } ]); // ✅ Correct sorting: "ALL" first, then other zones in ascending order result.forEach(item => { item.zones = ["ALL", ...item.zones.filter(z => z !== "ALL").sort((a, b) => a.localeCompare(b))]; }); return result; } catch (err) { console.error("Error fetching zones:", err); throw new Error("Error fetching zones."); } }; // Fastify route handler to get zones based on area only exports.getZonesByArea = async (req, reply) => { try { const { area } = req.params; if (!area || area.trim() === "") { return reply.status(400).send({ message: "Area is required." }); } const zones = await getZonesByArea(area.trim()); if (zones.length === 0) { return reply.status(404).send({ message: "No zones found for the specified area." }); } reply.send({ status_code: 200, data: zones }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.getDepartments = async (req, reply) => { try { console.log("Request Params:", req.params); let { departmentName, city, officeName, employeeType } = req.params; if (!departmentName || !city || !officeName || !employeeType) { return reply.status(400).send({ message: "Department Name, City, Office Name, and Employee Type are required.", }); } const departments = await getDepartmentsByName(officeName, city, departmentName, employeeType); if (departments.length === 0) { return reply.status(404).send({ message: "No departments found for the specified parameters.", }); } reply.send({ status_code: 200, data: departments }); } catch (err) { console.error("API Error:", err); reply.status(500).send({ message: err.message }); } }; const getDepartmentsByName = async (officeName, city, departmentName, employeeType) => { try { const query = {}; if (officeName && officeName.trim().toUpperCase() !== "ALL") { query.officeName = { $regex: officeName.trim(), $options: "i" }; } if (city && city.trim().toUpperCase() !== "ALL") { query.city = { $regex: city.trim(), $options: "i" }; } if (departmentName && departmentName.trim().toUpperCase() !== "ALL") { query.departmentName = { $regex: departmentName.trim(), $options: "i" }; } if (employeeType && employeeType.trim().toUpperCase() !== "ALL") { query.employeeType = { $regex: `^${employeeType.trim()}$`, $options: "i" }; } console.log("MongoDB Query:", JSON.stringify(query, null, 2)); const result = await Deparments.find(query).lean(); console.log("Query Result:", result); return result; } catch (err) { console.error("Error fetching department data:", err); throw new Error("Error fetching department data."); } }; const getDepartmentNames = async () => { try { const result = await Deparments.aggregate([ { $group: { _id: { $toUpper: { $trim: { input: "$departmentName" } }, // Convert to uppercase & trim spaces }, }, }, { $sort: { _id: 1 } // Sort alphabetically }, { $group: { _id: null, departmentNames: { $addToSet: "$_id" } // Collect unique values in an array } }, { $project: { _id: 0, departmentNames: 1 // Return only the array }, } ]); return result.length > 0 ? result[0].departmentNames : []; // Return an empty array if no data } catch (err) { console.error(err); throw new Error("Error fetching department names."); } }; // API Route exports.getAllDepartmentNames = async (req, reply) => { try { const departments = await getDepartmentNames(); reply.send({ status_code: 200, data: departments }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.getCitiesByOfficeName = async (req, reply) => { try { let { officeName } = req.params; if (!officeName) { return reply.code(400).send({ error: "officeName is required" }); } // Split by comma and normalize names let officeNames = officeName.split(',').map(name => name.trim().replace(/\s+/g, ' ') ); // Handle "All" — fetch all cities from both collections if (officeNames.includes('All')) { const allCityDocs = await City.find().select("city -_id").lean(); const allBranchDocs = await Branch.find().select("city -_id").lean(); const allCities = [...new Set([ ...allCityDocs.map(doc => doc.city), ...allBranchDocs.map(doc => doc.city), ])]; allCities.unshift("ALL"); // ✅ Add "ALL" at the beginning return reply.send({ status_code: 200, data: allCities }); } // Build regex conditions for each office name const regexConditions = officeNames.map(name => ({ officeName: { $regex: new RegExp(name.replace(/\s+/g, '\\s*'), 'i') } })); // Query both collections const cityResults = await City.find({ $or: regexConditions }).select("city -_id").lean(); const branchResults = await Branch.find({ $or: regexConditions }).select("city -_id").lean(); // Extract and merge unique city names const cityNames = [...new Set([ ...cityResults.map(c => c.city), ...branchResults.map(b => b.city) ])]; cityNames.unshift("ALL"); // ✅ Add "ALL" at the beginning reply.send({ status_code: 200, data: cityNames }); } catch (err) { console.error("Error fetching cities:", err); reply.send({ error: err.message }); } }; // Helper function to fetch department names by city const getDepartmentNamesByCity = async (city) => { try { const trimmedCity = city.trim(); const query = { $or: [ { city: { $regex: `^\\s*${trimmedCity}\\s*$`, $options: "i" } }, // { officeName: { $regex: `^\\s*${trimmedCity}\\s*$`, $options: "i" } } ] }; console.log("MongoDB Query:", JSON.stringify(query, null, 2)); const result = await Deparments.find(query) .select("departmentName -_id") .lean(); // Remove duplicate department names return [...new Set(result.map(doc => doc.departmentName))]; } catch (error) { console.error("Error fetching departments by city or officeName:", error); throw new Error("Error fetching departments by city or officeName."); } }; exports.getOffices = async (req, reply) => { try { let { officeName, city } = req.params; const filter = {}; // Apply officeName filter only if not ALL if (officeName && officeName.toUpperCase() !== 'ALL') { const officeNames = officeName.split(',').map(name => new RegExp(name.trim().replace(/\s+/g, '\\s*'), 'i') // fuzzy match ); filter.officeName = { $in: officeNames }; } // Apply city filter only if not ALL if (city && city.toUpperCase() !== 'ALL') { const cities = city.split(',').map(name => new RegExp(name.trim().replace(/\s+/g, '\\s*'), 'i') ); filter.city = { $in: cities }; } console.log("Filter being applied:", filter); // Fetch offices from DB const offices = await Deparments.find(filter).lean(); // Extract unique department names let departmentNames = [...new Set(offices.map(o => o.departmentName))]; // Always include "ALL" at the start of the list departmentNames = ['ALL', ...departmentNames]; reply.send({ status_code: 200, message: "Fetched successfully", data: departmentNames, }); } catch (error) { console.error("Error in getOffices:", error); reply.code(500).send({ status_code: 500, message: "Internal server error", error: error.message, }); } }; exports.getDepartmentsByCity = async (req, reply) => { try { const { city } = req.params; if (!city || city.trim() === "") { return reply.status(400).send({ message: "City is required." }); } const departmentNames = await getDepartmentNamesByCity(city); if (departmentNames.length === 0) { return reply.status(404).send({ message: "No departments found for the specified city." }); } reply.send({ status_code: 200, data: departmentNames }); } catch (error) { console.error("API Error:", error); reply.status(500).send({ message: error.message }); } }; exports.getAllStates = async (req, reply) => { try { const states = await IndianLocations.find({}, "state").sort({ state: 1 }); // Sorting A to Z reply.send(states); } catch (err) { reply.status(500).send({ error: "Failed to fetch states" }); } }; exports.getAllCities = async (req, reply) => { try { // Fetch only the majorCities field from all documents const docs = await IndianLocations.find({}, "majorCities").lean(); // Flatten the array of arrays and remove duplicates const cities = [...new Set(docs.flatMap(doc => doc.majorCities))]; // Sort alphabetically (case-insensitive) cities.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" })); reply.send(cities); } catch (err) { console.error("Error fetching cities:", err); reply.status(500).send({ error: "Failed to fetch cities" }); } }; exports.getStaeBasedCites = async (request, reply) => { try { const { stateName } = request.params; const state = await IndianLocations.findOne({ state: stateName }, "majorCities"); if (!state) { return reply.status(404).send({ error: "State not found" }); } reply.send(state.majorCities); } catch (err) { reply.status(500).send({ error: "Failed to fetch cities" }); } }; exports.getCitiesBasedState = async (request, reply) => { try { // Match the param name from the route exactly const { majorcities } = request.params; if (!majorcities) { return reply.status(400).send({ error: "majorcities param is required" }); } // Case-insensitive regex match against elements in the array const stateDoc = await IndianLocations.findOne( { majorCities: { $regex: new RegExp(`^${majorcities.trim()}$`, "i") } }, "state" ).lean(); if (!stateDoc) { return reply.status(404).send({ error: "City not found" }); } reply.send({ state: stateDoc.state }); } catch (err) { console.error("Error fetching state:", err); reply.status(500).send({ error: "Failed to fetch state" }); } }; exports.getStaffDepartmentDetails = async (request, reply) => { try { const { officeName, city } = request.params; const department = await Deparments.find({ officeName: { $regex: officeName.trim(), $options: "i" }, // no ^$ anchors city: { $regex: city.trim(), $options: "i" } }); if (!department.length) { return reply.status(404).send({ message: "Department not found" }); } reply.send({ department }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.updateBranchOrCompanyDetails = async (request, reply) => { try { const { id } = request.params; const updateData = request.body; let updatedDoc; if (id.startsWith("AWBR")) { // Find existing Branch before update const existing = await Branch.findOne({ branchId: id }); updatedDoc = await Branch.findOneAndUpdate( { branchId: id }, { ...updateData, updatedAt: new Date() }, { new: true } ); // 🔄 Cascade update to Department employees if city/officeName changed if (updatedDoc && existing) { if ( (updateData.city && updateData.city !== existing.city) || (updateData.officeName && updateData.officeName !== existing.officeName) ) { await Deparments.updateMany( { officeName: existing.officeName, city: existing.city }, { $set: { city: updateData.city || existing.city, officeName: updateData.officeName || existing.officeName, }, } ); } } } else if (id.startsWith("AWCI")) { // Find existing City before update const existing = await City.findOne({ cityId: id }); updatedDoc = await City.findOneAndUpdate( { cityId: id }, { ...updateData, updatedAt: new Date() }, { new: true } ); // 🔄 Cascade update to Department employees if city/officeName changed if (updatedDoc && existing) { if ( (updateData.city && updateData.city !== existing.city) || (updateData.officeName && updateData.officeName !== existing.officeName) ) { await Deparments.updateMany( { officeName: existing.officeName, city: existing.city }, { $set: { city: updateData.city || existing.city, officeName: updateData.officeName || existing.officeName, }, } ); } } } else { return reply.code(400).send({ error: "Invalid ID format" }); } if (!updatedDoc) { return reply.code(404).send({ message: "Record not found" }); } return reply.send({ message: "Details updated successfully", data: updatedDoc, }); } catch (err) { request.log.error(err); return reply .code(500) .send({ error: "Failed to update details", details: err.message }); } };