diff --git a/src/controllers/admincontroller.js b/src/controllers/admincontroller.js index 5775accc..d0125289 100644 --- a/src/controllers/admincontroller.js +++ b/src/controllers/admincontroller.js @@ -59,16 +59,6 @@ exports.adminSignUp = async (request, reply) => { - // Check if an admin with the same phone number or username already exists - // const existingAdminUsername = await Admin.findOne({ username }); - // const existingAdmin = await Admin.findOne({ phone }); - - // if (existingAdmin) { - // return reply.status(400).send({ message: 'Phone already registered' }); - // } - // if (existingAdminUsername) { - // return reply.status(400).send({ message: 'Username already registered' }); - // } // Hash the password using bcrypt const hashedPassword = await bcrypt.hash(password, 10); @@ -122,34 +112,6 @@ exports.editAdmin = async (request, reply) => { }; -// Admin Login Function (With Phone Number) -// exports.adminLogin = async (request, reply) => { -// try { -// const { phone, password } = request.body; - -// // Check if an admin with the phone number exists -// const admin = await Admin.findOne({ phone }); - -// if (!admin) { -// return reply.status(401).send({ message: 'Invalid phone number or password' }); -// } - -// // Compare the password entered by the user with the hashed password stored in the database -// const isPasswordValid = await bcrypt.compare(password, admin.password); - -// if (!isPasswordValid) { -// return reply.status(401).send({ message: 'Invalid phone number or password' }); -// } - - -// // Generate a JWT token for the authenticated admin -// const token = jwt.sign({ phone: admin.phone, role: 'admin' }, JWT_SECRET, { expiresIn: '1h' }); - -// return reply.send({ token, admin }); -// } catch (err) { -// reply.status(500).send({ message: err.message }); -// } -// }; exports.adminLogin = async (request, reply) => { try { @@ -440,276 +402,10 @@ exports.getAllCompanys = async (req, reply) => { } }; -// exports.getBranchDetails = async (req, reply) => { -// try { -// const { officeName } = req.params; - -// const branchDetails = await Branch.find({ -// officeName: { $regex: new RegExp(`^${officeName}$`, 'i') } -// }); - -// return reply.send({ -// status_code: 200, -// message: "Fetched successfully", -// data: branchDetails, -// }); -// } catch (err) { -// console.error("Error fetching branch details:", err); -// return reply.status(500).send({ error: "Internal server error" }); -// } -// }; - - -// exports.getAllOffices = async (req, reply) => { -// try { -// const { officeName } = req.query; - -// let filter = {}; - -// if (officeName && officeName.toUpperCase() !== "ALL") { -// // Partial and case-insensitive match -// filter.officeName = { $regex: new RegExp(officeName, "i") }; -// } - -// const offices = await Branch.find(filter).lean(); - -// return reply.code(200).send({ -// status_code: 200, -// message: "Fetched successfully", -// data: offices -// }); -// } catch (error) { -// console.error("Error fetching offices:", error); -// return reply.code(500).send({ -// status_code: 500, -// message: "Internal server error" -// }); -// } -// }; - -// exports.getAllOffices = async (req, reply) => { -// try { -// const { officeName } = req.query; - -// if (!officeName) { -// return reply.code(400).send({ -// status_code: 400, -// message: "officeName query param is required" -// }); -// } - -// const nameRegex = new RegExp(officeName.trim(), "i"); - -// // Fetch head offices, branches, and departments -// const [headOffices, branches, departments] = await Promise.all([ -// City.find({ officeName: nameRegex }).lean(), -// Branch.find({ officeName: nameRegex }).lean(), -// Deparments.find({ officeName: nameRegex }).lean() -// ]); - -// if (headOffices.length === 0 && branches.length === 0) { -// return reply.code(404).send({ -// status_code: 404, -// message: "No offices found for the given officeName" -// }); -// } - -// const allOffices = []; - -// // Process head offices (with employee count) -// headOffices.forEach(ho => { -// const officeNameTrimmed = ho.officeName.trim().toLowerCase(); - -// // Get all department docs for this office -// const matchingDepartments = departments.filter( -// d => d.officeName?.trim().toLowerCase() === officeNameTrimmed -// ); - -// // Count employees: 1 main person per doc + sub-team members -// const employeeCount = matchingDepartments.reduce((count, dep) => { -// const mainPerson = 1; -// const subTeamCount = Array.isArray(dep?.team_member?.team_member) -// ? dep.team_member.team_member.length -// : 0; -// return count + mainPerson + subTeamCount; -// }, 0); - -// allOffices.push({ -// officeType: "headOffice", -// officeName: ho.officeName.trim(), -// city: ho.city?.trim() || "", -// cityId: ho.cityId || "", -// employeeCount, -// phone: ho.phone || "", -// address: ho.office_address1 || "", -// state: ho.state || "", -// country: ho.country || "", -// pincode: ho.pincode || "", -// email: ho.email || "", -// latitude:ho.latitude || "", -// longitude: ho.longitude || "", -// googleLocation: ho.googleLocation || "", -// createdAt: ho.createdAt || "", -// updatedAt: ho.updatedAt || "" -// }); -// }); - -// // Process branches (no employee count here) -// branches.forEach(br => { -// allOffices.push({ -// officeType: "branch", -// branchId: br.branchId || "", -// officeName: br.officeName?.trim() || "", -// city: br.city?.trim() || "", -// zone: br.zone || "", -// location: br.location || [], -// phone: br.phone || "", -// address: br.office_address1 || "", -// address2: br.address2 || "", -// state: br.state || "", -// country: br.country || "", -// pincode: br.pincode || "", -// email: br.email || "", -// contactPerson: br.nameoftheContactPerson || "", -// latitude:br.latitude || "", -// longitude: br.longitude || "", -// googleLocation: br.googleLocation || "", -// createdAt: br.createdAt || "", -// updatedAt: br.updatedAt || "" -// }); -// }); - -// return reply.code(200).send({ -// status_code: 200, -// message: "Fetched successfully", -// data: allOffices -// }); - -// } catch (error) { -// console.error("Error fetching city offices:", error); -// return reply.code(500).send({ -// status_code: 500, -// message: "Internal server error" -// }); -// } -// }; - - -// exports.getAllOffices = async (req, reply) => { -// try { -// const { officeName } = req.query; - -// if (!officeName) { -// return reply.code(400).send({ -// status_code: 400, -// message: "officeName query param is required" -// }); -// } - -// let headOffices, branches, departments; - -// if (officeName.trim().toUpperCase() === "ALL") { -// // ✅ Fetch all without filtering -// [headOffices, branches, departments] = await Promise.all([ -// City.find().lean(), -// Branch.find().lean(), -// Deparments.find().lean() -// ]); -// } else { -// const nameRegex = new RegExp(officeName.trim(), "i"); -// [headOffices, branches, departments] = await Promise.all([ -// City.find({ officeName: nameRegex }).lean(), -// Branch.find({ officeName: nameRegex }).lean(), -// Deparments.find({ officeName: nameRegex }).lean() -// ]); -// } - -// if (headOffices.length === 0 && branches.length === 0) { -// return reply.code(404).send({ -// status_code: 404, -// message: "No offices found" -// }); -// } - -// const allOffices = []; - -// // Process head offices (with employee count) -// headOffices.forEach(ho => { -// const officeNameTrimmed = ho.officeName.trim().toLowerCase(); - -// // Get all department docs for this office -// const matchingDepartments = departments.filter( -// d => d.officeName?.trim().toLowerCase() === officeNameTrimmed -// ); - -// // Count employees: 1 main person per doc + sub-team members -// const employeeCount = matchingDepartments.reduce((count, dep) => { -// const mainPerson = 1; -// const subTeamCount = Array.isArray(dep?.team_member?.team_member) -// ? dep.team_member.team_member.length -// : 0; -// return count + mainPerson + subTeamCount; -// }, 0); - -// allOffices.push({ -// officeType: "headOffice", -// officeName: ho.officeName.trim(), -// city: ho.city?.trim() || "", -// cityId: ho.cityId || "", -// employeeCount, -// phone: ho.phone || "", -// address: ho.office_address1 || "", -// state: ho.state || "", -// country: ho.country || "", -// pincode: ho.pincode || "", -// email: ho.email || "", -// latitude: ho.latitude || "", -// longitude: ho.longitude || "", -// googleLocation: ho.googleLocation || "", -// createdAt: ho.createdAt || "", -// updatedAt: ho.updatedAt || "" -// }); -// }); - -// // Process branches (no employee count here) -// branches.forEach(br => { -// allOffices.push({ -// officeType: "branch", -// branchId: br.branchId || "", -// officeName: br.officeName?.trim() || "", -// city: br.city?.trim() || "", -// zone: br.zone || "", -// location: br.location || [], -// phone: br.phone || "", -// address: br.office_address1 || "", -// address2: br.address2 || "", -// state: br.state || "", -// country: br.country || "", -// pincode: br.pincode || "", -// email: br.email || "", -// contactPerson: br.nameoftheContactPerson || "", -// latitude: br.latitude || "", -// longitude: br.longitude || "", -// googleLocation: br.googleLocation || "", -// createdAt: br.createdAt || "", -// updatedAt: br.updatedAt || "" -// }); -// }); - -// return reply.code(200).send({ -// status_code: 200, -// message: "Fetched successfully", -// data: allOffices -// }); - -// } catch (error) { -// console.error("Error fetching city offices:", error); -// return reply.code(500).send({ -// status_code: 500, -// message: "Internal server error" -// }); -// } -// }; + + + + exports.getAllOffices = async (req, reply) => { try { @@ -981,555 +677,6 @@ exports.getAllOfficesByCity = async (req, reply) => { -// exports.getAllOfficesByCity = async (req, reply) => { -// try { -// const { city } = req.query; - -// if (!city) { -// return reply.code(400).send({ -// status_code: 400, -// message: "city query param is required" -// }); -// } - -// const cityRegex = new RegExp(city.trim(), "i"); - -// // 1) Find head offices (city schema) -// const headOffices = await City.find({ city: cityRegex }).lean(); - -// if (!headOffices.length) { -// return reply.code(404).send({ -// status_code: 404, -// message: `No head office found for city ${city}` -// }); -// } - -// // 2) Build response for each headOffice -// const finalResponse = []; - -// for (const ho of headOffices) { -// // (optional) Employee count logic -// const departments = await Deparments.find({ city: ho.city }).lean(); -// const employeeCount = departments.reduce((count, dep) => { -// const mainPerson = 1; -// const subTeamCount = Array.isArray(dep?.team_member?.team_member) -// ? dep.team_member.team_member.length -// : 0; -// return count + mainPerson + subTeamCount; -// }, 0); - -// // 3) Find branches with same officeName -// const branches = await Branch.find({ -// officeName: new RegExp(ho.officeName.trim(), "i") -// }).lean(); - -// // 4) Construct office data -// const offices = []; - -// // Head Office (from citySchema) -// offices.push({ -// officeType: "headOffice", -// officeName: ho.officeName?.trim() || "", -// city: ho.city?.trim() || "", -// cityId: ho.cityId || "", -// employeeCount, -// phone: ho.phone || "", -// address: ho.office_address1 || "", -// address2: ho.address2 || "", -// state: ho.state || "", -// country: ho.country || "", -// pincode: ho.pincode || "", -// email: ho.email || "", -// latitude: ho.latitude || 0, -// longitude: ho.longitude || 0, -// googleLocation: ho.googleLocation || "", -// createdAt: ho.createdAt || "", -// updatedAt: ho.updatedAt || "" -// }); - -// // Branches (from branchSchema) -// branches.forEach(br => { -// offices.push({ -// officeType: "branchOffice", -// branchId: br.branchId || "", -// officeName: br.officeName?.trim() || "", -// city: br.city?.trim() || "", -// employeeCount, // optional: same count or separate -// phone: br.phone || "", -// address: br.office_address1 || "", -// address2: br.address2 || "", -// state: br.state || "", -// country: br.country || "", -// pincode: br.pincode || "", -// email: br.email || "", -// contactPerson: br.nameoftheContactPerson || "", -// latitude: br.latitude || 0, -// longitude: br.longitude || 0, -// googleLocation: br.googleLocation || "", -// createdAt: br.createdAt || "", -// updatedAt: br.updatedAt || "" -// }); -// }); - -// // 5) Push into final response -// finalResponse.push({ -// officeName: ho.officeName?.trim() || "", -// city: ho.city?.trim() || "", -// offices -// }); -// } - -// return reply.code(200).send({ -// status_code: 200, -// message: "Fetched successfully", -// data: finalResponse -// }); - -// } catch (error) { -// console.error("❌ Error in getAllOfficesByCity:", error); -// return reply.code(500).send({ -// status_code: 500, -// message: "Internal server error", -// error: error.message -// }); -// } -// }; - - -// exports.getAllOfficesByCity = async (req, reply) => { -// try { -// const { city } = req.query; - -// if (!city) { -// return reply.code(400).send({ -// status_code: 400, -// message: "city query param is required" -// }); -// } - -// const cityRegex = new RegExp(city.trim(), "i"); - -// // Fetch head offices, branches, and departments -// const [headOffices, branches, departments] = await Promise.all([ -// City.find({ city: cityRegex }).lean(), -// Branch.find({ city: cityRegex }).lean(), -// Deparments.find({ city: cityRegex }).lean() -// ]); - -// if (!headOffices.length && !branches.length) { -// return reply.code(404).send({ -// status_code: 404, -// message: `No offices found in city ${city}` -// }); -// } - -// const officeMap = new Map(); - -// // 🔹 Process Head Offices -// headOffices.forEach(ho => { -// const cityTrimmed = ho.city?.trim().toLowerCase(); -// const matchingDepartments = departments.filter( -// d => d.city?.trim().toLowerCase() === cityTrimmed -// ); - -// // Count employees -// const employeeCount = matchingDepartments.reduce((count, dep) => { -// const mainPerson = 1; -// const subTeamCount = Array.isArray(dep?.team_member?.team_member) -// ? dep.team_member.team_member.length -// : 0; -// return count + mainPerson + subTeamCount; -// }, 0); - -// const officeNameKey = ho.officeName?.trim().toLowerCase(); - -// if (!officeMap.has(officeNameKey)) { -// officeMap.set(officeNameKey, { -// officeName: ho.officeName?.trim() || "", -// city: ho.city?.trim() || "", -// offices: [] -// }); -// } - -// officeMap.get(officeNameKey).offices.push({ -// officeType: "headOffice", -// officeName: ho.officeName?.trim() || "", -// city: ho.city?.trim() || "", -// cityId: ho.cityId || "", -// employeeCount, -// phone: ho.phone || "", -// address: ho.office_address1 || "", -// state: ho.state || "", -// country: ho.country || "", -// pincode: ho.pincode || "", -// email: ho.email || "", -// latitude: ho.latitude || "", -// longitude: ho.longitude || "", -// googleLocation: ho.googleLocation || "", -// createdAt: ho.createdAt || "", -// updatedAt: ho.updatedAt || "" -// }); -// }); - -// // 🔹 Process Branches -// branches.forEach(br => { -// const officeNameKey = br.officeName?.trim().toLowerCase(); - -// if (!officeMap.has(officeNameKey)) { -// officeMap.set(officeNameKey, { -// officeName: br.officeName?.trim() || "", -// city: br.city?.trim() || "", -// offices: [] -// }); -// } - -// officeMap.get(officeNameKey).offices.push({ -// officeType: "branch", -// branchId: br.branchId || "", -// officeName: br.officeName?.trim() || "", -// city: br.city?.trim() || "", -// zone: br.zone || "", -// location: Array.isArray(br.location) ? br.location : [], -// phone: br.phone || "", -// address: br.office_address1 || "", -// address2: br.address2 || "", -// state: br.state || "", -// country: br.country || "", -// pincode: br.pincode || "", -// email: br.email || "", -// contactPerson: br.nameoftheContactPerson || "", -// latitude: br.latitude || "", -// longitude: br.longitude || "", -// googleLocation: br.googleLocation || "", -// createdAt: br.createdAt || "", -// updatedAt: br.updatedAt || "" -// }); -// }); - -// // 🔹 Final grouped response -// const finalResponse = Array.from(officeMap.values()); - -// return reply.code(200).send({ -// status_code: 200, -// message: "Fetched successfully", -// data: finalResponse -// }); - -// } catch (error) { -// console.error("❌ Error in getAllOfficesByCity:", error); -// return reply.code(500).send({ -// status_code: 500, -// message: "Internal server error", -// error: error.message -// }); -// } -// }; - - - - -// exports.getAllOfficesByCity = async (req, reply) => { -// try { -// const { city } = req.query; - -// if (!city) { -// return reply.code(400).send({ -// status_code: 400, -// message: "city query param is required" -// }); -// } - -// const cityRegex = new RegExp(city.trim(), "i"); - -// // Fetch head offices and branches in this city -// const headOffices = await City.find({ city: cityRegex }).lean(); -// const branches = await Branch.find({ city: cityRegex }).lean(); - -// if (!headOffices.length && !branches.length) { -// return reply.code(404).send({ -// status_code: 404, -// message: `No offices found in city ${city}` -// }); -// } - -// // Group by officeName -// const officeMap = new Map(); - -// // Process head offices -// headOffices.forEach(ho => { -// const key = ho.officeName?.trim().toLowerCase(); -// if (!officeMap.has(key)) { -// officeMap.set(key, { -// officeName: ho.officeName?.trim() || "", -// city: ho.city?.trim() || "", -// headOffices: [] -// }); -// } -// officeMap.get(key).headOffices.push({ -// officeType: "headOffice", -// city: ho.city?.trim() || "", -// employeeCount: ho.employeeCount || 0, -// phone: ho.phone || "", -// address: ho.address || "", -// state: ho.state || "", -// country: ho.country || "", -// pincode: ho.pincode || "", -// email: ho.email || "" -// }); -// }); - -// // Process branches -// branches.forEach(br => { -// const key = br.officeName?.trim().toLowerCase(); -// if (!officeMap.has(key)) { -// officeMap.set(key, { -// officeName: br.officeName?.trim() || "", -// city: br.city?.trim() || "", -// headOffices: [] -// }); -// } -// officeMap.get(key).headOffices.push({ -// officeType: "branch", -// branchId: br.branchId || "", -// city: br.city?.trim() || "", -// zone: br.zone || "", -// phone: br.phone || "", -// address: br.address || "", -// state: br.state || "" -// }); -// }); - -// // Final response array -// const finalResponse = Array.from(officeMap.values()); - -// return reply.code(200).send({ -// status_code: 200, -// message: "Fetched successfully", -// data: finalResponse -// }); - -// } catch (err) { -// console.error("❌ Error in getAllOfficesByCity:", err); -// return reply.code(500).send({ -// status_code: 500, -// message: "Internal server error", -// error: err.message -// }); -// } -// }; - - - - - -// exports.getCityOffices = async (req, reply) => { -// try { -// const { officeName } = req.query; - -// if (!officeName) { -// return reply.code(400).send({ -// status_code: 400, -// message: "officeName query param is required" -// }); -// } - -// // Regex filter for partial & case-insensitive match -// const nameRegex = new RegExp(officeName.trim(), "i"); - -// // Step 1: Fetch head offices matching the officeName -// const headOffices = await City.find({ officeName: nameRegex }).lean(); - -// // Step 2: Fetch branches matching the officeName -// const branches = await Branch.find({ officeName: nameRegex }).lean(); - -// // Step 3: Fetch departments matching the officeName -// const departments = await Deparments.find({ officeName: nameRegex }).lean(); - -// if (headOffices.length === 0 && branches.length === 0) { -// return reply.code(404).send({ -// status_code: 404, -// message: "No offices found for the given officeName" -// }); -// } - -// // Step 4: Build city-wise result -// const cityMap = {}; - -// headOffices.forEach(ho => { -// const officeNameTrimmed = ho.officeName.trim(); - -// // Find department for this office to get employee count -// const departmentDoc = departments.find( -// d => -// d.officeName && -// d.officeName.trim().toLowerCase() === officeNameTrimmed.toLowerCase() -// ); -// const employeeCount = -// departmentDoc?.team_member?.team_member?.length || 0; - -// cityMap[ho.city.trim().toLowerCase()] = { -// city: ho.city.trim(), -// headOffice: { -// officeName: ho.officeName.trim(), -// employeeCount, -// phone: ho.phone || "", -// address: ho.office_address1 || "", -// state: ho.state || "", -// country: ho.country || "", -// pincode: ho.pincode || "", -// email: ho.email || "" -// }, -// branches: [] -// }; -// }); - -// // Step 5: Attach branches -// branches.forEach(br => { -// const cityKey = br.city.trim().toLowerCase(); -// if (!cityMap[cityKey]) { -// cityMap[cityKey] = { -// city: br.city.trim(), -// headOffice: null, -// branches: [] -// }; -// } -// cityMap[cityKey].branches.push({ -// officeName: br.officeName?.trim() || "", -// location: br.location || [], -// phone: br.phone || "", -// address: br.address1 || "" -// }); -// }); - -// // Step 6: Convert to array -// const result = Object.values(cityMap); - -// return reply.code(200).send({ -// status_code: 200, -// message: "Fetched successfully", -// data: result -// }); -// } catch (error) { -// console.error("Error fetching city offices:", error); -// return reply.code(500).send({ -// status_code: 500, -// message: "Internal server error" -// }); -// } -// }; - -// exports.getCityOffices = async (req, reply) => { -// try { -// const { officeName } = req.query; - -// if (!officeName) { -// return reply.code(400).send({ -// status_code: 400, -// message: "officeName query param is required" -// }); -// } - -// const nameRegex = new RegExp(officeName.trim(), "i"); - -// // Step 1: Fetch head offices -// const headOffices = await City.find({ officeName: nameRegex }).lean(); - -// // Step 2: Fetch branches -// const branches = await Branch.find({ officeName: nameRegex }).lean(); - -// // Step 3: Fetch departments -// const departments = await Deparments.find({ officeName: nameRegex }).lean(); - -// if (headOffices.length === 0 && branches.length === 0) { -// return reply.code(404).send({ -// status_code: 404, -// message: "No offices found for the given officeName" -// }); -// } - -// const cityMap = {}; - -// headOffices.forEach(ho => { -// const officeNameTrimmed = ho.officeName.trim(); - -// // Find department for this office to get employee count -// const departmentDoc = departments.find( -// d => d.officeName?.trim().toLowerCase() === officeNameTrimmed.toLowerCase() -// ); -// console.log("departmentDoc",departmentDoc) -// const mainPersonCount = departmentDoc?.team_member?.main_person ? 1 : 0; -// const subTeamCount = Array.isArray(departmentDoc?.team_member?.team_member) -// ? departmentDoc.team_member.team_member.length -// : 0; - -// const employeeCount = mainPersonCount + subTeamCount; - -// cityMap[ho.city.trim().toLowerCase()] = { -// // cityId: ho.cityId || "", // added cityId -// city: ho.city.trim(), -// headOffice: { -// officeName: ho.officeName.trim(), -// cityId: ho.cityId || "", // added cityId -// employeeCount, -// phone: ho.phone || "", -// address: ho.office_address1 || "", -// state: ho.state || "", -// country: ho.country || "", -// pincode: ho.pincode || "", -// email: ho.email || "" -// }, -// // branches: [] -// }; -// }); - -// // Step 5: Attach branches -// branches.forEach(br => { -// const cityKey = br.city.trim().toLowerCase(); - -// if (!cityMap[cityKey]) { -// cityMap[cityKey] = { -// //cityId: br.cityId || "", -// city: br.city.trim(), -// // headOffice: null, -// branches: [] -// }; -// } - -// cityMap[cityKey].branches.push({ -// branchId: br.branchId || "", -// officeName: br.officeName?.trim() || "", -// zone: br.zone || "", -// location: br.location || [], -// phone: br.phone || "", -// address: br.office_address1 || "", -// address2: br.address2 || "", -// state: br.state || "", -// country: br.country || "", -// pincode: br.pincode || "", -// email: br.email || "", -// contactPerson: br.nameoftheContactPerson || "", -// createdAt: br.createdAt || "", -// updatedAt: br.updatedAt || "" -// }); -// }); - -// const result = Object.values(cityMap); - -// return reply.code(200).send({ -// status_code: 200, -// message: "Fetched successfully", -// data: result -// }); - -// } catch (error) { -// console.error("Error fetching city offices:", error); -// return reply.code(500).send({ -// status_code: 500, -// message: "Internal server error" -// }); -// } -// }; - exports.getCityOffices = async (req, reply) => { try { const { officeName } = req.query; diff --git a/src/controllers/departmentController.js b/src/controllers/departmentController.js index aaa00515..49c825f8 100644 --- a/src/controllers/departmentController.js +++ b/src/controllers/departmentController.js @@ -13,14 +13,6 @@ const fastify = require("fastify")({ const { Counter} = require('../models/User') const {Department, Desgination, City, Deparments, Branch, Zone,IndianLocations} = require('../models/Department') -// const generateDepartmentId = async (prefix) => { -// const result = await Counter.findOneAndUpdate( -// { _id: 'department_id' }, -// { $inc: { seq: 1 } }, -// { upsert: true, new: true } -// ); -// return `AW${prefix}${result.seq}`; -// }; const generateCityId = async () => { var result = await Counter.findOneAndUpdate( @@ -40,14 +32,6 @@ const generateCityId = async () => { return result.seq; }; -// const generateDesginationId = async (prefix) => { -// const result = await Counter.findOneAndUpdate( -// { _id: 'desgination_id' }, -// { $inc: { seq: 1 } }, -// { upsert: true, new: true } -// ); -// return `AW${prefix}${result.seq}`; -// }; const generateDepartmentId = async (city, departmentName) => { const cityPrefix = city.substring(0, 2).toUpperCase(); // Extract first two letters of city @@ -245,34 +229,7 @@ const generateDepartmentId = async (city, departmentName) => { reply.status(500).send({ message: err.message }); } }; -// exports.getSinledepartmentData = async (req, reply) => { -// try { -// const { departmentId } = req.params; - -// const department = await Department.findOne({ departmentId: departmentId }); - -// if (!department) { -// return reply.code(404).send({ -// success: false, -// message: 'Department not found.' -// }); -// } - -// reply.code(200).send({ -// success: true, -// message: 'Department 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.getallCompanyNames = async (req, reply) => { try { await City.find() @@ -293,32 +250,6 @@ exports.getallCompanyNames = async (req, reply) => { -// exports.getAllDepartmentsParticularFields = async (req, reply) => { -// try { -// const departments = await Department.find().exec(); - -// // Grouping the data -// const result = { -// cities: [...new Set(departments.map((doc) => doc.city))], -// zones: [...new Set(departments.map((doc) => doc.zone))], -// pincodes: [...new Set(departments.map((doc) => doc.pincode))], -// departments: [...new Set(departments.map((doc) => doc.departmentName))], -// states: [...new Set(departments.map((doc) => doc.state))], -// countries: [...new Set(departments.map((doc) => doc.country))], -// }; - -// // Sending the response -// reply.send({ -// status_code: 200, -// data: result, -// count: departments.length, -// }); -// } catch (err) { -// console.error(err); -// reply.send({ error: err.message }); -// } -// }; - exports.deletecityInfo = async (req, reply) => { try { @@ -451,73 +382,6 @@ exports.getallCompanyNames = async (req, reply) => { }; -// exports.addDesgination = async (request, reply) => { -// try { -// const { -// phone, -// city, -// firstName, -// lastName, -// departmentName, -// reportingManager, -// email, -// state, -// password, -// country, -// zone, -// address1, -// address2, -// pincode, -// desginationName, -// location, -// createdBy, -// updatedBy, -// } = request.body; - -// // Generate desginationId based on desginationName -// const prefix = departmentName.substring(0, 2).toUpperCase(); -// const desginationId = await generateDesginationId(prefix); - -// // Check if the phone is already registered -// const existingStore = await Desgination.findOne({ phone }); -// if (existingStore) { -// return reply.status(400).send({ message: 'Phone is already registered' }); -// } - -// // Hash the password -// const hashedPassword = await bcrypt.hash(password, 10); - -// // Create a new designation -// const desgination = new Desgination({ -// desginationId, -// city, -// firstName, -// lastName, -// email, -// reportingManager, -// departmentName, -// phone, -// address1, -// address2, -// services: { password: { bcrypt: hashedPassword } }, -// state, -// zone, -// country, -// pincode, -// desginationName, -// location, -// createdBy, -// updatedBy, -// }); - -// await desgination.save(); - -// reply.send({ desgination, message: 'Account Created Successfully' }); -// } catch (err) { -// reply.status(500).send({ message: err.message }); -// } -// }; - exports.addDepartment = async (request, reply) => { try { @@ -570,7 +434,19 @@ exports.addDepartment = async (request, reply) => { let finalReportingManagerEmail = reportingManager_email; if (reportingManager?.toLowerCase() === "self") { - finalReportingManager = `${firstName || ""} ${lastName || ""} - (${phone}) - ${city}`; + // 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; } @@ -617,6 +493,7 @@ exports.addDepartment = async (request, reply) => { } }; + exports.getDetails = async (request, reply) => { try { @@ -866,119 +743,6 @@ exports.editdepartment = async (request, reply) => { } }; -// exports.getAllDesignationsParticularFields = async (req, reply) => { -// try { -// const departments = await Desgination.find().exec(); - -// // Grouping the data -// const result = { -// cities: [...new Set(departments.map((doc) => doc.city))], -// zones: [...new Set(departments.map((doc) => doc.zone))], -// pincodes: [...new Set(departments.map((doc) => doc.pincode))], -// departments: [...new Set(departments.map((doc) => doc.departmentName))], -// states: [...new Set(departments.map((doc) => doc.state))], -// countries: [...new Set(departments.map((doc) => doc.country))], -// designations: [...new Set(departments.map((doc) => doc.desginationName))], -// reportingMangers: [...new Set(departments.map((doc) => doc.reportingManager))], - -// }; - -// // Sending the response -// reply.send({ -// status_code: 200, -// data: result, -// count: departments.length, -// }); -// } catch (err) { -// console.error(err); -// reply.send({ error: err.message }); -// } -// }; - -// const getLocationsByCityAndZone = async (city, zone) => { -// try { -// const matchCondition = { -// city: { $regex: `^${city.trim().toLowerCase()}$`, $options: "i" }, -// }; - -// // If a specific zone (not "ALL") is provided, filter by that zone -// if (zone.trim().toUpperCase() !== "ALL") { -// matchCondition.zone = zone.trim(); -// } - -// const result = await Zone.aggregate([ -// { -// $project: { -// city: { $toLower: { $trim: { input: "$city" } } }, -// zone: { $trim: { input: "$zone" } }, -// location: 1, -// }, -// }, -// { -// $match: matchCondition, -// }, -// { -// $group: { -// _id: "$city", -// locations: { $push: "$location" }, -// }, -// }, -// { -// $project: { -// _id: 0, -// city: "$_id", -// locations: { -// $reduce: { -// input: "$locations", -// initialValue: [], -// in: { $concatArrays: ["$$value", "$$this"] }, -// }, -// }, -// }, -// }, -// ]); - -// console.log("Query Result:", result); - -// if (result.length) { -// let locations = [...new Set(result[0].locations)]; // Remove duplicates - -// // Ensure "ALL" is always the first element -// if (!locations.includes("ALL")) { -// locations.unshift("ALL"); -// } - -// return { city, locations }; -// } else { -// return { city, locations: ["ALL"] }; // If no data, return only "ALL" -// } -// } catch (err) { -// console.error(err); -// throw new Error("Error fetching locations."); -// } -// }; - -// exports.getZonebasedLocations = async (req, reply) => { -// try { -// const { city, zone } = req.query; -// console.log("Received City:", `"${city}"`, "Received Zone:", `"${zone}"`); - -// if (!city || !zone) { -// return reply.status(400).send({ message: "City and zone are required." }); -// } - -// const locations = await getLocationsByCityAndZone(city.trim(), zone.trim()); - -// 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 getLocationsByCityZoneOffice = async (city, zone, officeName) => { try { @@ -1142,68 +906,6 @@ exports.getZonebasedLocations = async (req, reply) => { } }; - // const getZonesByCitys = async (city) => { - // try { - // const result = await Zone.aggregate([ - // { - // $project: { - // city: { $trim: { input: "$city" } }, // Trim city field in DB - // zone: 1 // Keep zone field - // } - // }, - // { - // $match: { - // city: { $regex: `^${city.trim()}$`, $options: "i" }, // Trim & case-insensitive - // } - // }, - // { - // $group: { - // _id: { $toUpper: "$city" }, // Normalize city name - // zones: { $addToSet: "$zone" } // Collect unique zones - // } - // }, - // { - // $project: { - // _id: 0, // Exclude _id - // city: "$_id", // Return city name - // zones: 1 // Return collected zones - // } - // } - // ]); - - // // Add "ALL" to the zones array and sort it - // result.forEach(item => { - // item.zones = ["ALL", ...new Set(item.zones)].sort((a, b) => (a === "ALL" ? -1 : a - b)); - // }); - - // return result; - // } catch (err) { - // console.error("Error fetching zones:", err); - // throw new Error("Error fetching zones."); - // } - // }; - - - // exports.getZonesByCity = async (req, reply) => { - // try { - // const { city } = req.params; - - // if (!city || city.trim() === "") { - // return reply.status(400).send({ message: "City is required." }); - // } - - // const zones = await getZonesByCitys(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 getZonesByCityAndOffice = async (city, officeName) => { @@ -1399,131 +1101,6 @@ exports.getZonesByCityAndOffice = async (req, reply) => { } }; - // const getDepartmentsByName = async (departmentName, city) => { - // try { - // const result = await Deparments.find({ - // departmentName: { $regex: `^${departmentName.trim()}$`, $options: "i" }, // Case-insensitive search - // city: { $regex: `^${city.trim()}$`, $options: "i" }, // Case-insensitive search - // }).lean(); // Convert to plain JSON - - // return result; - // } catch (err) { - // console.error("Error fetching department data:", err); - // throw new Error("Error fetching department data."); - // } - // }; - -// Updated helper function that accepts all three parameters -// const getDepartmentsByName = async (officeName, city, departmentName) => { -// try { -// // Trim all parameters -// const trimmedOfficeName = officeName.trim(); -// const trimmedCity = city.trim(); -// const trimmedDepartment = departmentName.trim(); - -// const query = { -// officeName: { $regex: trimmedOfficeName, $options: "i" }, -// departmentName: { $regex: trimmedDepartment, $options: "i" }, -// city: { $regex: trimmedCity, $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."); -// } -// }; - - - // API Route - // exports.getDepartments = async (req, reply) => { - // try { - // console.log("Request Params:", req.params); // Debugging log - - // let { departmentName, city, officeName } = req.params; - - // if (!departmentName || !city || !officeName) { - // return reply.status(400).send({ message: "Department Name, City, and Office Name are required." }); - // } - - // departmentName = departmentName.trim(); - // city = city.trim(); - // officeName = officeName.trim(); - - // // Note the order: officeName, city, departmentName - // const departments = await getDepartmentsByName(officeName, city, departmentName); - - // 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) => { -// 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" }; -// } - -// 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."); -// } -// }; - -// exports.getDepartments = async (req, reply) => { -// try { -// console.log("Request Params:", req.params); - -// let { departmentName, city, officeName } = req.params; - -// if (!departmentName || !city || !officeName) { -// return reply.status(400).send({ -// message: "Department Name, City, and Office Name are required.", -// }); -// } - -// const departments = await getDepartmentsByName(officeName, city, departmentName); - -// 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 }); -// } -// }; - exports.getDepartments = async (req, reply) => { @@ -1631,54 +1208,6 @@ const getDepartmentsByName = async (officeName, city, departmentName, employeeTy }; -// 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), -// ])]; - -// 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) -// ])]; - -// reply.send({ status_code: 200, data: cityNames }); -// } catch (err) { -// console.error("Error fetching cities:", err); -// reply.send({ error: err.message }); -// } -// }; - exports.getCitiesByOfficeName = async (req, reply) => { try { let { officeName } = req.params; @@ -1806,55 +1335,6 @@ exports.getOffices = async (req, reply) => { } }; - -// exports.getOffices = async (req, reply) => { -// try { -// const { officeName, city } = req.params; - -// const filter = {}; - -// if (officeName && officeName !== 'ALL') { -// const officeNames = officeName.split(',').map(name => -// new RegExp(`^${name.trim()}$`, 'i') -// ); -// filter.officeName = { $in: officeNames }; -// } -// console.log("officeName",officeName) -// if (city && city !== 'ALL') { -// const cities = city.split(',').map(c => -// new RegExp(`^${c.trim()}$`, 'i') -// ); -// filter.city = { $in: cities }; -// } -// console.log("officeName",officeName) - -// const offices = await Deparments.find(filter).lean(); -// console.log(offices, "offices"); - -// const departmentNames = [...new Set(offices.map(o => o.departmentName))]; -// console.log(departmentNames, "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, -// }); -// } -// }; - - - - - - // API route handler exports.getDepartmentsByCity = async (req, reply) => { try { const { city } = req.params; @@ -1970,107 +1450,6 @@ exports.getStaffDepartmentDetails = async (request, reply) => { }; - - - -// exports.updateBranchOrCompanyDetails = async (request, reply) => { -// try { -// const { id } = request.params; -// const updateData = request.body; -// let updatedDoc; - -// if (id.startsWith("AWBR")) { -// // Update Branch -// updatedDoc = await Branch.findOneAndUpdate( -// { branchId: id }, -// { ...updateData, updatedAt: new Date() }, -// { new: true } -// ); -// } else if (id.startsWith("AWCI")) { -// // Update City -// updatedDoc = await City.findOneAndUpdate( -// { cityId: id }, -// { ...updateData, updatedAt: new Date() }, -// { new: true } -// ); -// } 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 }); -// } -// }; - - -// exports.updateBranchOrCompanyDetails = async (request, reply) => { -// try { -// const { id } = request.params; -// const updateData = request.body; -// let updatedDoc; - -// if (id.startsWith("AWBR")) { -// // Update Branch -// updatedDoc = await Branch.findOneAndUpdate( -// { branchId: id }, -// { ...updateData, updatedAt: new Date() }, -// { new: true } -// ); - -// // Update department schema if office name matches -// if (updateData.city) { -// await Deparments.updateMany( -// { officeName: updatedDoc.officeName }, -// { $set: { city: updateData.city } } -// ); -// } -// } else if (id.startsWith("AWCI")) { -// // Update City -// updatedDoc = await City.findOneAndUpdate( -// { cityId: id }, -// { ...updateData, updatedAt: new Date() }, -// { new: true } -// ); - -// // Update department schema if office name matches -// if (updateData.city) { -// await Department.updateMany( -// { officeName: updatedDoc.officeName }, -// { $set: { city: updateData.city } } -// ); -// } -// } 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 }); -// } -// }; - - exports.updateBranchOrCompanyDetails = async (request, reply) => { try { const { id } = request.params; diff --git a/src/controllers/installationController.js b/src/controllers/installationController.js index 9d923667..ba3f1d40 100644 --- a/src/controllers/installationController.js +++ b/src/controllers/installationController.js @@ -102,361 +102,7 @@ exports.createTeamMember = async (req, reply) => { - // exports.getTeamMembers = async (request, reply) => { - // try { - // const { departmentId,officeName,city } = request.params; // ✅ Get departmentId from request params - - // // ✅ Find the department using departmentId - // const department = await Deparments.findOne({ departmentId }); - - // if (!department) { - // return reply.status(404).send({ - // simplydata: { - // error: true, - // message: "Department not found", - // }, - // }); - // } - - // // ✅ Extract team members from department schema - // const teamMembers = department.team_member.team_member; - - // return reply.send({ - // simplydata: { - // error: false, - // message: "Team members retrieved successfully", - // teamMembers, // ✅ Return the list of team members - // }, - // }); - - // } catch (err) { - // console.error("Error fetching team members:", err); - // reply.status(500).send({ - // simplydata: { - // error: true, - // message: "Internal server error", - // }, - // }); - // } - // }; - -// exports.getAllDepartments = async (request, reply) => { -// try { -// const { departmentName } = request.params; - -// if (!departmentName) { -// return reply.status(400).send({ -// simplydata: { -// error: true, -// message: "departmentName is required in path params", -// }, -// }); -// } - -// // ✅ Find all departments matching departmentName -// const departments = await Deparments.find({ departmentName }).lean(); - -// if (!departments.length) { -// return reply.status(404).send({ -// simplydata: { -// error: true, -// message: "No departments found with the given departmentName", -// }, -// }); -// } - -// return reply.send({ -// simplydata: { -// error: false, -// message: "Departments retrieved successfully", -// data: departments, -// }, -// }); - -// } catch (err) { -// console.error("Error fetching departments:", err); -// return reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; - -// exports.assignTeamMemberToQuotation = async (request, reply) => { -// try { -// const { installationId } = request.params; // Get installationId from URL params -// const { teamMemberId } = request.body; // Get teamMemberId from request body - -// if (!teamMemberId) { -// return reply.status(400).send({ -// simplydata: { -// error: true, -// message: "teamMemberId is required", -// }, -// }); -// } - -// // Find installation by installationId -// const installation = await Install.findOne({ installationId }); - -// if (!installation) { -// return reply.status(404).send({ -// simplydata: { -// error: true, -// message: "Installation not found", -// }, -// }); -// } - -// // Extract team members list -// const teamMembers = installation.team_member.team_member; - -// // Check if provided teamMemberId exists in the installation's team -// const assignedTeamMember = teamMembers.find(member => member.teamMemberId === teamMemberId); - -// if (!assignedTeamMember) { -// return reply.status(404).send({ -// simplydata: { -// error: true, -// message: "Team member not found in this installation", -// }, -// }); -// } - -// // Here, you would save the assigned team member to the quotation (modify as needed) -// const quotation = { -// installationId, -// assignedTeamMember -// }; - -// return reply.send({ -// simplydata: { -// error: false, -// message: "Team member assigned to quotation successfully", -// quotation -// }, -// }); - -// } catch (err) { -// console.error("Error assigning team member to quotation:", err); -// reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; - - -// exports.getAllDepartments = async (request, reply) => { -// try { -// const { departmentName } = request.params; - -// if (!departmentName) { -// return reply.status(400).send({ -// simplydata: { -// error: true, -// message: "departmentName is required in path params", -// }, -// }); -// } - -// // Find all departments matching departmentName -// const departments = await Deparments.find({ departmentName }).lean(); - -// if (!departments.length) { -// return reply.status(404).send({ -// simplydata: { -// error: true, -// message: "No departments found with the given departmentName", -// }, -// }); -// } - -// // Add extra object { firstName: "Self" } at start -// const extraObject = { firstName: "Self" }; -// const responseData = [extraObject, ...departments]; - -// return reply.send({ -// simplydata: { -// error: false, -// message: "Departments retrieved successfully", -// data: responseData, -// }, -// }); - -// } catch (err) { -// console.error("Error fetching departments:", err); -// return reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; - -// exports.getAllDepartments = async (request, reply) => { -// try { -// const { departmentName } = request.params; - -// if (!departmentName) { -// return reply.status(400).send({ -// simplydata: { -// error: true, -// message: "departmentName is required in path params", -// }, -// }); -// } - -// // Find all departments matching departmentName -// const departments = await Deparments.find({ departmentName }).lean(); - -// // Always start with Self -// const responseData = [{ firstName: "Self" }, ...(departments || [])]; - -// return reply.send({ -// simplydata: { -// error: false, -// message: departments.length -// ? "Departments retrieved successfully" -// : "No departments found with the given departmentName", -// data: responseData, - -// }, -// }); - -// } catch (err) { -// console.error("Error fetching departments:", err); -// return reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; - -// exports.getAllDepartments = async (request, reply) => { -// try { -// const { officeName, city } = request.params; - -// if (!officeName || !city) { -// return reply.status(400).send({ -// simplydata: { -// error: true, -// message: "officeName and city are required in path params", -// }, -// }); -// } - -// // Case-insensitive regex without start/end anchors to avoid trailing space issues -// const nameRegex = new RegExp(officeName.trim().replace(/\s+/g, "\\s*"), "i"); -// const cityRegex = new RegExp(city.trim().replace(/\s+/g, "\\s*"), "i"); - -// // 1️⃣ Branch match -// const branchMatch = await Branch.findOne({ -// officeName: nameRegex, -// city: cityRegex, -// }).lean(); - -// // 2️⃣ City match -// const cityMatch = await City.findOne({ -// officeName: nameRegex, -// city: cityRegex, -// }).lean(); - -// // 3️⃣ Departments -// const departments = await Deparments.find({ -// officeName: nameRegex, -// city: cityRegex, -// }).lean(); - -// const responseData = [{ firstName: "Self" }]; - -// if (branchMatch) { -// responseData.push({ -// officeType: "branch", -// ...branchMatch -// }); -// } -// if (cityMatch) { -// responseData.push({ -// officeType: "headOffice", -// ...cityMatch -// }); -// } - -// responseData.push(...departments); - -// return reply.send({ -// simplydata: { -// error: false, -// message: -// departments.length || branchMatch || cityMatch -// ? "Data retrieved successfully" -// : "No data found for the given officeName and city", -// data: responseData, -// }, -// }); - -// } catch (err) { -// console.error("Error fetching departments:", err); -// return reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; - -// Controller -// exports.getTeamMembers = async (request, reply) => { -// try { -// const { departmentId, officeName, city } = request.params; - -// // Make regex tolerate spaces -// const department = await Deparments.findOne({ -// departmentId, -// officeName: { $regex: new RegExp(`^\\s*${officeName.trim()}\\s*$`, "i") }, -// city: { $regex: new RegExp(`^\\s*${city.trim()}\\s*$`, "i") } -// }).lean(); - -// console.log("department", department); - -// if (!department) { -// return reply.status(404).send({ -// simplydata: { -// error: true, -// message: "Department not found for given office and city", -// }, -// }); -// } - -// const teamMembers = department.team_member?.team_member || []; - -// return reply.send({ -// simplydata: { -// error: false, -// message: "Team members retrieved successfully", -// teamMembers, -// }, -// }); -// } catch (err) { -// console.error("Error fetching team members:", err); -// reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; exports.getTeamMembers = async (request, reply) => { try { @@ -975,325 +621,38 @@ exports.getInstallationTeamMembers = async (request, reply) => { } }; - // exports.getQuotationsByInstallationAndTeamMember = async (request, reply) => { - // try { - // const { installationId, teamMemberId } = request.params; - - // if (!installationId || !teamMemberId) { - // return reply.status(400).send({ - // simplydata: { - // error: true, - // message: "Both installationId and teamMemberId are required", - // }, - // }); - // } - - // // 🔹 Fetch quotations where installationId matches and teamMemberId is assigned - // const quotations = await Order.find({ - // installationId, - // assignedTeamMembers: teamMemberId, - // }); - - // if (!quotations || quotations.length === 0) { - // return reply.status(404).send({ - // simplydata: { - // error: true, - // message: "No quotations found for this installation and team member", - // }, - // }); - // } - - // return reply.send({ - // simplydata: { - // error: false, - // message: "Quotations fetched successfully", - // quotations, - // }, - // }); - // } catch (err) { - // console.error("Error fetching quotations:", err); - // reply.status(500).send({ - // simplydata: { - // error: true, - // message: "Internal server error", - // }, - // }); - // } - // }; - -// exports.getQuotationsByInstallationAndTeamMember = async (request, reply) => { -// try { -// const { installationId, teamMemberId } = request.params; -// if (!installationId || !teamMemberId) { -// return reply.status(400).send({ -// simplydata: { -// error: true, -// message: "Both installationId and teamMemberId are required", -// }, -// }); -// } +exports.getQuotationsByInstallationAndTeamMember = async (request, reply) => { + try { + const { installationId, teamMemberId } = request.params; -// // 🔹 Find quotations matching installationId and assignedTeamMembers -// const quotations = await Order.find({ -// installationId, -// assignedTeamMembers: teamMemberId, -// }).lean(); // use lean() for performance, since we'll enrich manually + if (!installationId || !teamMemberId) { + return reply.status(400).send({ + simplydata: { + error: true, + message: "Both installationId and teamMemberId are required", + }, + }); + } -// if (!quotations || quotations.length === 0) { -// return reply.status(404).send({ -// simplydata: { -// error: true, -// message: "No quotations found for this installation and team member", -// }, -// }); -// } + // 🔹 Find quotations matching installationId and assignedTeamMembers + let quotations = await Order.find({ + installationId, + assignedTeamMembers: teamMemberId, + }); -// // 🔹 Enrich each quotation with customer details -// const enrichedQuotations = await Promise.all( -// quotations.map(async (quotation) => { -// const customer = await User.findOne({ customerId: quotation.customerId }).lean(); + if (!quotations || quotations.length === 0) { + return reply.status(404).send({ + simplydata: { + error: true, + message: "No quotations found for this installation and team member", + }, + }); + } -// return { -// ...quotation, -// customer: customer || null, // attach under 'customer' -// }; -// }) -// ); - -// return reply.send({ -// simplydata: { -// error: false, -// message: "Quotations fetched successfully", -// quotations: enrichedQuotations, -// }, -// }); -// } catch (err) { -// console.error("Error fetching quotations:", err); -// return reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; - - -// exports.getQuotationsByInstallationAndTeamMember = async (request, reply) => { -// try { -// const { installationId, teamMemberId } = request.params; - -// if (!installationId || !teamMemberId) { -// return reply.status(400).send({ -// simplydata: { -// error: true, -// message: "Both installationId and teamMemberId are required", -// }, -// }); -// } - -// // 🔹 Find quotations matching installationId and assignedTeamMembers -// let quotations = await Order.find({ -// installationId, -// assignedTeamMembers: teamMemberId, -// }).lean(); - -// if (!quotations || quotations.length === 0) { -// return reply.status(404).send({ -// simplydata: { -// error: true, -// message: "No quotations found for this installation and team member", -// }, -// }); -// } - -// // ✅ Filter: keep only quotations where at least one master_connections.work_status === 'active' -// quotations = quotations.filter(q => -// Array.isArray(q.master_connections) && -// q.master_connections.some(mc => mc.work_status === 'active') -// ); - -// // If no quotations left after filtering, return empty list -// if (!quotations.length) { -// return reply.send({ -// simplydata: { -// error: false, -// message: "No active quotations found for this installation and team member", -// quotations: [], -// }, -// }); -// } - -// // 🔹 Enrich each quotation with customer details -// const enrichedQuotations = await Promise.all( -// quotations.map(async (quotation) => { -// const customer = await User.findOne({ customerId: quotation.customerId }).lean(); -// // 🔹 Keep only active master_connections -// const activeMasters = quotation.master_connections?.filter(mc => mc.work_status === 'active') || []; - -// return { -// ...quotation, -// master_connections: activeMasters, -// customer: customer || null, -// }; -// }) -// ); - - -// return reply.send({ -// simplydata: { -// error: false, -// message: "Active quotations fetched successfully", -// quotations: enrichedQuotations, -// }, -// }); -// } catch (err) { -// console.error("Error fetching quotations:", err); -// return reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; - -// exports.getQuotationsByInstallationAndTeamMember = async (request, reply) => { -// try { -// const { installationId, teamMemberId } = request.params; - -// if (!installationId || !teamMemberId) { -// return reply.status(400).send({ -// simplydata: { -// error: true, -// message: "Both installationId and teamMemberId are required", -// }, -// }); -// } - -// // 🔹 Find quotations matching installationId and assignedTeamMembers -// let quotations = await Order.find({ -// installationId, -// assignedTeamMembers: teamMemberId, -// }); - -// if (!quotations || quotations.length === 0) { -// return reply.status(404).send({ -// simplydata: { -// error: true, -// message: "No quotations found for this installation and team member", -// }, -// }); -// } - -// // ✅ Step 1: update master_connections where work_status is missing to 'active' -// for (const order of quotations) { -// let updated = false; - -// if (Array.isArray(order.master_connections)) { -// for (const mc of order.master_connections) { -// if (!mc.work_status) { -// mc.work_status = 'active'; -// updated = true; -// } -// } -// } - -// if (updated) { -// await order.save(); -// } -// } - -// // Re-fetch quotations as lean after update -// quotations = await Order.find({ -// installationId, -// assignedTeamMembers: teamMemberId, -// }).lean(); - -// // ✅ Filter: keep only quotations where at least one master_connections.work_status === 'active' -// quotations = quotations.filter(q => -// Array.isArray(q.master_connections) && -// q.master_connections.some(mc => mc.work_status === 'active') -// ); - -// // If no quotations left after filtering, return empty list -// if (!quotations.length) { -// return reply.send({ -// simplydata: { -// error: false, -// message: "No active quotations found for this installation and team member", -// quotations: [], -// }, -// }); -// } - -// // 🔹 Enrich each quotation with customer details & keep only active master_connections -// const enrichedQuotations = await Promise.all( -// quotations.map(async (quotation) => { -// const customer = await User.findOne({ customerId: quotation.customerId }).lean(); - -// const activeMasters = quotation.master_connections?.filter(mc => -// mc.work_status === 'active' -// ) || []; - -// return { -// ...quotation, -// master_connections: activeMasters, -// customer: customer || null, -// }; -// }) -// ); - -// return reply.send({ -// simplydata: { -// error: false, -// message: "Active quotations fetched successfully", -// quotations: enrichedQuotations, -// }, -// }); -// } catch (err) { -// console.error("Error fetching quotations:", err); -// return reply.status(500).send({ -// simplydata: { -// error: true, -// message: "Internal server error", -// }, -// }); -// } -// }; - -exports.getQuotationsByInstallationAndTeamMember = async (request, reply) => { - try { - const { installationId, teamMemberId } = request.params; - - if (!installationId || !teamMemberId) { - return reply.status(400).send({ - simplydata: { - error: true, - message: "Both installationId and teamMemberId are required", - }, - }); - } - - // 🔹 Find quotations matching installationId and assignedTeamMembers - let quotations = await Order.find({ - installationId, - assignedTeamMembers: teamMemberId, - }); - - if (!quotations || quotations.length === 0) { - return reply.status(404).send({ - simplydata: { - error: true, - message: "No quotations found for this installation and team member", - }, - }); - } - - // ✅ Step 1: update master_connections where work_status is missing to 'active' - for (const order of quotations) { - let updated = false; + // ✅ Step 1: update master_connections where work_status is missing to 'active' + for (const order of quotations) { + let updated = false; if (Array.isArray(order.master_connections)) { for (const mc of order.master_connections) { @@ -2077,229 +1436,6 @@ exports.createMasterSlaveData = async (req, reply) => { } }; -// exports.masterConnectedSlaveList = async (req, reply) => { -// try { -// const { connectedTo } = req.params; - -// // Step 1: Get master device details -// const master = await Insensors.findOne({ hardwareId: connectedTo, type: 'master' }).lean(); -// if (!master) { -// return reply.status(404).send({ -// success: false, -// message: "Master device not found" -// }); -// } - -// // Step 2: Get tank metadata for master -// const tankDetails = await Tank.findOne({ hardwareId: connectedTo }, { tankLocation: 1, typeOfWater: 1 }).lean(); - -// const masterTypeOfWater = tankDetails?.typeOfWater || null; - -// // Step 3: Get slave tanks connected to master -// const slaveTanks = await Insensors.find({ connected_to: connectedTo, type: 'slave' }).lean(); -// const slaveCount = slaveTanks.length; - -// // Step 4: Get latest IotData for master -// const latestIotData = await IotData.findOne({ hardwareId: connectedTo }).sort({ date: -1 }).lean(); - -// // Step 5: Fetch order to get masterName and location -// const order = await Order.findOne({ "master_connections.hardwareId": connectedTo }).lean(); -// let masterOrderInfo = {}; -// if (order) { -// const match = order.master_connections.find(mc => mc.hardwareId === connectedTo); -// if (match) { -// masterOrderInfo = { -// masterName: match.master_name || "", -// location: match.location || "" -// }; -// } -// } - -// // Step 6: Prepare master object for response -// const masterResponse = { -// ...master, -// isMaster: true, -// tankLocation: tankDetails?.tankLocation || null, -// typeOfWater: masterTypeOfWater, -// tankHeight: null, -// masterName: masterOrderInfo.masterName, -// location: masterOrderInfo.location -// }; - -// // Step 7: Process each slave -// const processedSlaves = slaveTanks.map(slave => { -// const originalHardwareId = slave.hardwareId; -// const tankHardwareId = slave.tankhardwareId; - -// // Determine final hardwareId: prefer tankhardwareId if exists -// const finalHardwareId = tankHardwareId || originalHardwareId; - -// const matchingTankData = latestIotData?.tanks?.find(t => -// t.tankhardwareId === finalHardwareId || t.hardwareId === finalHardwareId -// ); - -// return { -// ...slave, -// isMaster: false, -// hardwareId: finalHardwareId, // Replace hardwareId with tankhardwareId if present -// tankHeight: matchingTankData?.tankHeight ?? null, -// typeOfWater: masterTypeOfWater === 'bore' ? 'bore' : (slave.typeOfWater || null) -// }; -// }); - -// // Step 8: Combine master and slaves into one array -// const combinedData = [masterResponse, ...processedSlaves]; - -// return reply.send({ -// success: true, -// tankLocation: tankDetails?.tankLocation || null, -// typeOfWater: masterTypeOfWater, -// connectedSlaveCount: slaveCount, -// data: combinedData -// }); - -// } catch (error) { -// console.error("Error fetching master connected slave data:", error); -// return reply.status(500).send({ -// success: false, -// message: "Internal Server Error" -// }); -// } -// }; - - - - -// exports.masterConnectedSlaveList = async (req, reply) => { -// try { -// const { connectedTo } = req.params; - -// // Step 1: Find all slave tanks where connected_to matches -// const slaveTanks = await Insensors.find({ connected_to: connectedTo }).lean(); -// console.log(slaveTanks, "slaveTanks"); - -// if (!slaveTanks || slaveTanks.length === 0) { -// return reply.status(404).send({ -// success: false, -// message: "No tanks found for the given connected_to value" -// }); -// } - -// // Step 2: Fetch `tankLocation` and `typeOfWater` from the Tank schema (for master device display) -// const tankDetails = await Tank.findOne( -// { hardwareId: connectedTo }, -// { tankLocation: 1, typeOfWater: 1 } -// ); - -// if (!tankDetails) { -// return reply.status(404).send({ -// success: false, -// message: "Tank details not found for the given connectedTo" -// }); -// } - -// // Step 3: Count the number of connected slaves -// const slaveCount = slaveTanks.length; - -// // Step 4: Fetch latest IotData for the master to extract tankHeight for each slave -// const latestIotData = await IotData.findOne({ hardwareId: connectedTo }).sort({ date: -1 }).lean(); - -// // Step 5: Prepare processed response for each tank -// const processedSlaves = slaveTanks.map(slave => { -// if (slave.type === 'slave') { -// // Find matching tank data for this slave in IotData -// const matchingTankData = latestIotData?.tanks?.find(tank => tank.tankhardwareId === slave.hardwareId); - -// return { -// ...slave, -// tankHeight: matchingTankData?.tankHeight ?? null // Add tankHeight if found -// }; -// } else { -// // Remove unnecessary fields for master type -// const { -// tankName, -// tankLocation, -// typeOfWater, -// ...rest -// } = slave; -// return rest; -// } -// }); - -// return reply.send({ -// success: true, -// tankLocation: tankDetails.tankLocation, -// typeOfWater: tankDetails.typeOfWater, -// connectedSlaveCount: slaveCount, -// data: processedSlaves -// }); - -// } catch (error) { -// console.error("Error fetching master connected slave data:", error); -// return reply.status(500).send({ -// success: false, -// message: "Internal Server Error" -// }); -// } -// }; - - - -// exports.masterConnectedSlaveList = async (req, reply) => { -// try { -// const { connectedTo } = req.params; - -// // Step 1: Get master details -// const master = await Insensors.findOne({ hardwareId: connectedTo, type: 'master' }).lean(); -// if (!master) { -// return reply.status(404).send({ -// success: false, -// message: "Master device not found" -// }); -// } - -// // Step 2: Get slave tanks connected to master -// const slaveTanks = await Insensors.find({ connected_to: connectedTo, type: 'slave' }).lean(); -// const slaveCount = slaveTanks.length; - -// // Step 3: Get Tank metadata for master -// const tankDetails = await Tank.findOne({ hardwareId: connectedTo }, { tankLocation: 1, typeOfWater: 1 }).lean(); - -// // Step 4: Get latest IotData for master -// const latestIotData = await IotData.findOne({ hardwareId: connectedTo }).sort({ date: -1 }).lean(); - -// // Step 5: Process slaves -// const processedSlaves = slaveTanks.map(slave => { -// const matchingTankData = latestIotData?.tanks?.find(tank => tank.tankhardwareId === slave.hardwareId); -// return { -// ...slave, -// tankHeight: matchingTankData?.tankHeight ?? null -// }; -// }); - -// // Step 6: Prepare full master object -// const masterResponse = { -// ...master, -// tankLocation: tankDetails?.tankLocation || null, -// typeOfWater: tankDetails?.typeOfWater || null -// }; - -// return reply.send({ -// success: true, -// master: masterResponse, -// connectedSlaveCount: slaveCount, -// slaves: processedSlaves -// }); - -// } catch (error) { -// console.error("Error fetching master connected slave data:", error); -// return reply.status(500).send({ -// success: false, -// message: "Internal Server Error" -// }); -// } -// }; - function feetToCm(value) { const v = parseFloat(value); return !isNaN(v) ? parseFloat((v * 30.48).toFixed(2)) : null; @@ -2827,48 +1963,6 @@ exports.updateWorkStatusAndProductStatus = async (req, reply) => { }; -// exports.addMediaToInsensor = async (req, reply) => { -// try { -// const { hardwareId, customerId, type } = req.params; -// const { urls, mediaType } = req.body; - -// if (!hardwareId || !customerId || !type || !urls || !mediaType) { -// return reply.status(400).send({ success: false, message: "Missing required fields" }); -// } - -// const insensor = await Insensors.findOne({ hardwareId, customerId, type }); -// if (!insensor) { -// return reply.status(404).send({ success: false, message: "Insensor not found" }); -// } - -// const mediaItems = urls.map(url => ({ url, createdAt: new Date() })); - -// if (mediaType === 'video') { -// insensor.manualTestVideos.push(...mediaItems); -// } else if (mediaType === 'material') { -// insensor.materialReceivedPictures.push(...mediaItems); -// } else if (mediaType === 'workStatus') { -// insensor.workStatusPictures.push(...mediaItems); -// } else { -// return reply.status(400).send({ success: false, message: "Invalid mediaType" }); -// } - -// await insensor.save(); - -// // ✅ fetch the updated document as plain object -// const updatedInsensor = await Insensors.findOne({ hardwareId, customerId, type }).lean(); -// console.log("updatedInsensor",updatedInsensor) -// return reply.send({ -// success: true, -// message: "Media saved successfully", -// data: updatedInsensor -// }); -// } catch (error) { -// console.error("Error adding media to insensor:", error); -// return reply.status(500).send({ success: false, message: "Internal server error" }); -// } -// }; - exports.addMediaToInsensor = async (req, reply) => { try { @@ -2971,627 +2065,53 @@ exports.mastrerList = async (req, reply) => { -//const Insensor = mongoose.model('insensors', insensorsSchema); // if not already defined +exports.getMasterSlaveSummary = async (req, reply) => { + try { + const { customerId } = req.params; -// exports.getMasterSlaveSummary = async (req, reply) => { -// const { customerId } = req.params; + if (!customerId) { + return reply.status(400).send({ error: "customerId is required" }); + } -// try { -// const masters = await Insensors.aggregate([ -// { -// $match: { -// customerId, -// type: "master" -// } -// }, -// { -// $lookup: { -// from: 'Insensors', // collection name should match MongoDB collection -// let: { masterId: '$hardwareId' }, -// pipeline: [ -// { -// $match: { -// $expr: { -// $and: [ -// { $eq: ['$type', 'slave'] }, -// { $eq: ['$customerId', customerId] }, -// { $eq: ['$connected_to', '$$masterId'] } -// ] -// } -// } -// }, -// { -// $project: { -// _id: 1, -// hardwareId: 1, -// tankName: 1, -// tankLocation: 1, -// model: 1, -// status: 1, -// indate: 1 -// } -// } -// ], -// as: 'connected_slaves' -// } -// }, -// { -// $addFields: { -// connected_slave_count: { $size: '$connected_slaves' } -// } -// }, -// { -// $project: { -// _id: 1, -// hardwareId: 1, -// tankName: 1, -// tankLocation: 1, -// model: 1, -// status: 1, -// indate: 1, -// connected_slave_count: 1, -// connected_slaves: 1 -// } -// } -// ]); - -// const totalMasters = await Insensors.countDocuments({ customerId, type: 'master' }); -// const totalSlaves = await Insensors.countDocuments({ customerId, type: 'slave' }); - -// reply.code(200).send({ -// totalMasters, -// totalSlaves, -// masters -// }); -// } catch (err) { -// console.error(err); -// reply.code(500).send({ error: 'Server error', details: err.message }); -// } -// } + // Fetch all master devices from Insensors + const masters = await Insensors.find({ customerId, type: "master" }).lean(); + // Fetch orders to build orderMap: hardwareId → { masterName, location, work_status } + const orders = await Order.find({ customerId }).lean(); + const orderMap = {}; // key: hardwareId + orders.forEach(order => { + if (Array.isArray(order.master_connections)) { + order.master_connections.forEach(connection => { + if (connection.hardwareId) { + orderMap[connection.hardwareId] = { + masterName: connection.master_name || null, + location: connection.location || null, + work_status: connection.work_status || null + }; + } + }); + } + }); + const result = []; -// exports.getMasterSlaveSummary = async (req, reply) => { -// try { -// const { customerId } = req.params; + for (const master of masters) { + const orderInfo = orderMap[master.hardwareId] || {}; -// if (!customerId) { -// return reply.status(400).send({ message: "Missing customerId" }); -// } + // ✅ Only keep masters where work_status === 'active' + if (orderInfo.work_status !== 'active') { + continue; // skip this master + } -// const allDevices = await Insensors.find({ customerId }); - -// const masters = allDevices.filter(device => device.type === 'master'); -// const slaves = allDevices.filter(device => device.type === 'slave'); - -// const enrichDeviceWithTimestamp = async (device) => { -// const hardwareId = device.hardwareId?.trim(); -// if (!hardwareId) return device.toObject(); - -// const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); -// const enriched = device.toObject(); - -// if (latestData?.date) { -// const indiaTime = moment.tz(latestData.date, "Asia/Kolkata"); -// const date = indiaTime.format("DD-MM-YYYY"); -// const time = indiaTime.format("HH:mm:ss"); -// const now = moment.tz("Asia/Kolkata"); -// const diffInMinutes = now.diff(indiaTime, "minutes"); -// const isGSMConnected = diffInMinutes <= 1; -// const gsmStatus = isGSMConnected ? "connected" : "disconnected"; - -// if (device.type === 'master') { -// enriched.connected_gsm_date = date; -// enriched.connected_gsm_time = time; -// enriched.gsm_connected_status = gsmStatus; -// enriched.gsm_last_check_time = indiaTime.format("YYYY-MM-DD HH:mm:ss"); -// } -// } - -// if (latestData?.tanks && Array.isArray(latestData.tanks)) { -// const enrichedTanks = latestData.tanks.map(tank => { -// const tankMoment = moment.tz(tank.date, "Asia/Kolkata"); -// const tankDiff = moment.tz("Asia/Kolkata").diff(tankMoment, "minutes"); -// const loraStatus = tankDiff <= 1 ? "connected" : "disconnected"; -// return { -// ...tank, -// connected_status: loraStatus -// }; -// }); - -// enriched.tanks = enrichedTanks; - -// if (device.type === 'slave') { -// const connectedTank = enrichedTanks.find(tank => tank.tankhardwareId === device.hardwareId); -// enriched.lora_connected_status = connectedTank ? connectedTank.connected_status : "disconnected"; -// enriched.connected_lora_date = connectedTank ? moment(connectedTank.date).tz("Asia/Kolkata").format("DD-MM-YYYY") : null; -// enriched.connected_lora_time = connectedTank ? connectedTank.time : null; -// enriched.lora_last_check_time = connectedTank ? moment(connectedTank.date).tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss") : null; -// } -// } - -// if (device.type === 'slave') { -// delete enriched.connected_gsm_date; -// delete enriched.connected_gsm_time; -// delete enriched.gsm_connected_status; -// delete enriched.gsm_last_check_time; -// } - -// if (device.type === 'master') { -// delete enriched.connected_lora_date; -// delete enriched.connected_lora_time; -// delete enriched.lora_connected_status; -// delete enriched.lora_last_check_time; -// delete enriched.tanks; // ✅ Remove tanks for master -// } - -// return enriched; -// }; - -// const enrichedMasters = await Promise.all(masters.map(enrichDeviceWithTimestamp)); -// const enrichedSlaves = await Promise.all(slaves.map(enrichDeviceWithTimestamp)); - -// const masterSummary = enrichedMasters.map(master => { -// const connectedSlaves = enrichedSlaves.filter(slave => slave.connected_to === master.connected_to); -// return { -// ...master, -// connected_slave_count: connectedSlaves.length, -// connected_slaves: connectedSlaves -// }; -// }); + // Prefer Insensors name/location, fallback to order info + const masterName = master.masterName || orderInfo.masterName || null; + const location = master.location || orderInfo.location || null; -// return reply.send({ -// status_code: 200, -// message: "Success", -// master_count: enrichedMasters.length, -// slave_count: enrichedSlaves.length, -// data: masterSummary -// }); - -// } catch (err) { -// console.error("Error in getMasterSlaveSummary:", err); -// return reply.status(500).send({ -// status_code: 500, -// message: "Internal Server Error" -// }); -// } -// }; - - - - -// exports.getMasterSlaveSummary = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.status(400).send({ message: "Missing customerId" }); -// } - -// const allDevices = await Insensors.find({ customerId }); -// const masters = allDevices.filter(d => d.type === 'master'); -// const slaves = allDevices.filter(d => d.type === 'slave'); - -// const enrichDevice = async (device) => { -// const enriched = device.toObject(); -// const hardwareId = device.hardwareId?.trim(); - -// if (!hardwareId) return enriched; - -// // Fetch latest IotData blindly for this device -// const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); - -// if (latestData?.date) { -// const indiaTime = moment.tz(latestData.date, "Asia/Kolkata"); -// const now = moment.tz("Asia/Kolkata"); -// const diffMins = now.diff(indiaTime, "minutes"); -// const isConnected = diffMins <= 1; - -// enriched.connected_gsm_date = indiaTime.format("DD-MM-YYYY"); -// enriched.connected_gsm_time = indiaTime.format("HH:mm:ss"); -// enriched.gsm_connected_status = isConnected ? "connected" : "disconnected"; -// enriched.gsm_last_check_time = indiaTime.format("YYYY-MM-DD HH:mm:ss"); -// } - -// // Only apply LoRa logic for slaves -// if (device.type === 'slave' && latestData?.tanks?.length) { -// const matchingTank = latestData.tanks.find( -// tank => tank.tankhardwareId?.trim() === hardwareId -// ); - -// if (matchingTank) { -// const loraTime = moment.tz(matchingTank.date, "Asia/Kolkata"); -// const loraDiff = moment.tz("Asia/Kolkata").diff(loraTime, "minutes"); -// const isLoraConnected = loraDiff <= 1; - -// enriched.connected_lora_date = loraTime.format("DD-MM-YYYY"); -// enriched.connected_lora_time = matchingTank.time; -// enriched.lora_connected_status = isLoraConnected ? "connected" : "disconnected"; -// enriched.lora_last_check_time = loraTime.format("YYYY-MM-DD HH:mm:ss"); -// } else { -// enriched.connected_lora_date = null; -// enriched.connected_lora_time = null; -// enriched.lora_connected_status = "disconnected"; -// enriched.lora_last_check_time = null; -// } -// } - -// // Remove irrelevant fields -// if (device.type === 'slave') { -// delete enriched.tanks; -// } -// if (device.type === 'master') { -// delete enriched.connected_lora_date; -// delete enriched.connected_lora_time; -// delete enriched.lora_connected_status; -// delete enriched.lora_last_check_time; -// delete enriched.tanks; -// } - -// return enriched; -// }; - -// const enrichedMasters = await Promise.all(masters.map(enrichDevice)); -// const enrichedSlaves = await Promise.all(slaves.map(enrichDevice)); - -// const masterSummary = enrichedMasters.map(master => { -// const connectedSlaves = enrichedSlaves.filter( -// slave => slave.connected_to === master.connected_to -// ); -// return { -// ...master, -// connected_slave_count: connectedSlaves.length, -// connected_slaves: connectedSlaves -// }; -// }); - -// return reply.send({ -// status_code: 200, -// message: "Success", -// master_count: enrichedMasters.length, -// slave_count: enrichedSlaves.length, -// data: masterSummary -// }); - -// } catch (err) { -// console.error("Error in getMasterSlaveSummary:", err); -// return reply.status(500).send({ -// status_code: 500, -// message: "Internal Server Error" -// }); -// } -// }; - -// exports.getMasterSlaveSummary = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.status(400).send({ error: 'customerId is required' }); -// } - -// // Fetch all devices for the customer -// const allDevices = await Insensors.find({ customerId }).lean(); - -// // Group devices -// const masters = allDevices.filter(dev => dev.type === 'master'); -// const slaves = allDevices.filter(dev => dev.type === 'slave'); - -// // Create a map of slaves by connected_to hardwareId -// const slaveMap = {}; -// for (const slave of slaves) { -// const masterId = slave.connected_to; -// if (!slaveMap[masterId]) { -// slaveMap[masterId] = []; -// } - -// const loraTime = slave.connected_lora_time || null; -// const loraDate = slave.connected_lora_date || null; - -// slaveMap[masterId].push({ -// hardwareId: slave.hardwareId, -// tankName: slave.tankName || null, -// location: slave.tankLocation || null, -// connected_status: slave.connected_status || 'disconnected', -// connected_lora_time: loraTime, -// connected_lora_date: loraDate -// }); -// } - -// const response = []; - -// for (const master of masters) { -// // Fetch latest IoT data for this master -// const latestData = await IotData.findOne({ hardwareId: master.hardwareId }) -// .sort({ date: -1 }) -// .lean(); - -// const enriched = { -// ...master, -// connected_status: master.connected_status || 'disconnected', -// connected_slave_count: slaveMap[master.hardwareId]?.length || 0, -// connected_slaves: slaveMap[master.hardwareId] || [] -// }; - -// // Use saved GSM fields from Insensors -// if (master.gsm_last_check_time) { -// enriched.gsm_last_check_time = master.gsm_last_check_time; - -// const indiaTime = moment.tz(master.gsm_last_check_time, 'Asia/Kolkata'); -// enriched.connected_gsm_date = indiaTime.format('DD-MM-YYYY'); -// enriched.connected_gsm_time = indiaTime.format('HH:mm:ss'); -// } - -// // If LoRa timestamps are available from master (some masters act like slaves too) -// if (master.connected_lora_date && master.connected_lora_time) { -// enriched.connected_lora_date = master.connected_lora_date; -// enriched.connected_lora_time = master.connected_lora_time; -// } - -// response.push(enriched); -// } - -// return reply.send({ -// status_code: 200, -// message: 'Master-slave summary retrieved successfully', -// data: response -// }); -// } catch (err) { -// console.error('Error in getMasterSlaveSummary:', err); -// return reply.status(500).send({ error: 'Internal Server Error' }); -// } -// }; - - -// exports.getMasterSlaveSummary = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.status(400).send({ error: 'customerId is required' }); -// } - -// // Fetch all devices for the customer -// const allDevices = await Insensors.find({ customerId }).lean(); - -// // Group devices -// const masters = allDevices.filter(dev => dev.type === 'master'); -// const slaves = allDevices.filter(dev => dev.type === 'slave'); - -// // Create a map of slaves by connected_to hardwareId -// const slaveMap = {}; -// for (const slave of slaves) { -// const masterId = slave.connected_to; -// if (!slaveMap[masterId]) { -// slaveMap[masterId] = []; -// } - -// const loraTime = slave.connected_lora_time || null; -// const loraDate = slave.connected_lora_date || null; - -// // Fetch masterName using the connected_to masterId -// const master = masters.find(m => m.hardwareId === masterId); -// const masterName = master ? master.masterName : 'Unknown'; - -// slaveMap[masterId].push({ -// hardwareId: slave.hardwareId, -// tankName: slave.tankName || null, -// location: slave.tankLocation || null, -// connected_status: slave.connected_status || 'disconnected', -// connected_lora_time: loraTime, -// connected_lora_date: loraDate, -// type: slave.type || 'N/A', // Add 'type' field -// typeOfWater: slave.typeOfWater || 'N/A', // Add 'typeOfWater' field -// lora_last_check_time: slave.lora_last_check_time && slave.lora_last_check_time -// ? `${slave.lora_last_check_time}` -// : null, // Add 'lora_last_check_time' field -// connected_to: slave.connected_to, // Add 'connected_to' field -// masterName: masterName // Add 'masterName' field -// }); -// } - -// const response = []; - -// for (const master of masters) { -// // Fetch latest IoT data for this master -// const latestData = await IotData.findOne({ hardwareId: master.hardwareId }) -// .sort({ date: -1 }) -// .lean(); - -// const enriched = { -// ...master, -// connected_status: master.connected_status || 'disconnected', -// connected_slave_count: slaveMap[master.hardwareId]?.length || 0, -// connected_slaves: slaveMap[master.hardwareId] || [] -// }; - -// // Use saved GSM fields from Insensors -// if (master.gsm_last_check_time) { -// enriched.gsm_last_check_time = master.gsm_last_check_time; - -// const indiaTime = moment.tz(master.gsm_last_check_time, 'Asia/Kolkata'); -// enriched.connected_gsm_date = indiaTime.format('DD-MM-YYYY'); -// enriched.connected_gsm_time = indiaTime.format('HH:mm:ss'); -// } - -// // If LoRa timestamps are available from master (some masters act like slaves too) -// if (master.connected_lora_date && master.connected_lora_time) { -// enriched.connected_lora_date = master.connected_lora_date; -// enriched.connected_lora_time = master.connected_lora_time; -// } - -// response.push(enriched); -// } - -// return reply.send({ -// status_code: 200, -// message: 'Master-slave summary retrieved successfully', -// data: response -// }); -// } catch (err) { -// console.error('Error in getMasterSlaveSummary:', err); -// return reply.status(500).send({ error: 'Internal Server Error' }); -// } -// }; -// exports.getMasterSlaveSummary = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.status(400).send({ error: 'customerId is required' }); -// } - -// // Fetch all masters for the customer from the Insensors schema -// const masters = await Insensors.find({ customerId, type: 'master' }).lean(); - -// // Fetch orders for the customer to map master connections -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// // Mapping master hardwareId from the orders schema to masterName and location -// orders.forEach(order => { -// order.master_connections.forEach(connection => { -// orderMap[connection.hardwareId] = { -// masterName: connection.master_name || 'Unknown', -// location: connection.location || 'Unknown' -// }; -// }); -// }); - -// const result = []; - -// // Loop through each master and enrich it with data -// for (const master of masters) { -// const orderInfo = orderMap[master.hardwareId] || {}; // Get order info based on hardwareId -// const masterName = orderInfo.masterName || 'Unknown'; -// const location = orderInfo.location || 'Unknown'; - -// const latestGsmData = await IotData.findOne({ hardwareId: master.hardwareId }) -// .sort({ date: -1, time: -1 }) -// .lean(); - -// let connectedGsmDate = null; -// let connectedGsmTime = null; -// if (latestGsmData?.date && latestGsmData?.time) { -// const indiaTime = moment.tz(latestGsmData.date, 'Asia/Kolkata'); -// connectedGsmDate = indiaTime.format('DD-MM-YYYY'); -// connectedGsmTime = latestGsmData.time; -// } - -// let gsmLastDisconnect = master.gsm_last_disconnect_time; -// if (master.connected_status === 'disconnected' && connectedGsmDate && connectedGsmTime) { -// const disconnectTime = `${connectedGsmDate} ${connectedGsmTime}`; -// await Insensors.updateOne({ hardwareId: master.hardwareId }, { $set: { gsm_last_disconnect_time: disconnectTime } }); -// gsmLastDisconnect = disconnectTime; -// } - -// const connectedSlaves = []; -// const slaves = await Insensors.find({ connected_to: master.hardwareId, type: 'slave' }).lean(); - -// for (const slave of slaves) { -// const slaveIot = await IotData.findOne({ hardwareId: slave.hardwareId }).sort({ date: -1, time: -1 }).lean(); - -// const loraDate = slave.connected_lora_date || (slaveIot?.date ? moment.tz(slaveIot.date, 'Asia/Kolkata').format('DD-MM-YYYY') : null); -// const loraTime = slave.connected_lora_time || slaveIot?.time || null; - -// let loraLastDisconnect = slave.lora_last_disconnect_time; -// if (slave.connected_status === 'disconnected' && loraDate && loraTime) { -// const disconnectTime = `${loraDate} ${loraTime}`; -// await Insensors.updateOne({ hardwareId: slave.hardwareId }, { $set: { lora_last_disconnect_time: disconnectTime } }); -// loraLastDisconnect = disconnectTime; -// } - -// connectedSlaves.push({ -// hardwareId: slave.hardwareId, -// tankName: slave.tankName, -// location: slave.tankLocation, -// connected_status: slave.connected_status, -// connected_lora_date: loraDate, -// connected_lora_time: loraTime, -// lora_last_disconnect_time: loraLastDisconnect, -// type: slave.type || 'slave' -// }); -// } - -// result.push({ -// hardwareId: master.hardwareId, -// masterName, -// location, -// type: master.type || 'master', -// connected_status: master.connected_status, -// connected_slave_count: connectedSlaves.length, -// connected_slaves: connectedSlaves, -// connected_gsm_date: connectedGsmDate, -// connected_gsm_time: connectedGsmTime, -// gsm_last_check_time: master.gsm_last_check_time || null, -// gsm_last_disconnect_time: gsmLastDisconnect, -// connected_lora_date: master.connected_lora_date || null, -// connected_lora_time: master.connected_lora_time || null -// }); -// } - -// return reply.send({ -// status_code: 200, -// message: 'Master-slave summary retrieved successfully', -// data: result -// }); - -// } catch (error) { -// console.error('Error in getMasterSlaveSummary:', error); -// return reply.status(500).send({ error: 'Internal Server Error' }); -// } -// }; - - - -exports.getMasterSlaveSummary = async (req, reply) => { - try { - const { customerId } = req.params; - - if (!customerId) { - return reply.status(400).send({ error: "customerId is required" }); - } - - // Fetch all master devices from Insensors - const masters = await Insensors.find({ customerId, type: "master" }).lean(); - - // Fetch orders to build orderMap: hardwareId → { masterName, location, work_status } - const orders = await Order.find({ customerId }).lean(); - const orderMap = {}; // key: hardwareId - - orders.forEach(order => { - if (Array.isArray(order.master_connections)) { - order.master_connections.forEach(connection => { - if (connection.hardwareId) { - orderMap[connection.hardwareId] = { - masterName: connection.master_name || null, - location: connection.location || null, - work_status: connection.work_status || null - }; - } - }); - } - }); - - const result = []; - - for (const master of masters) { - const orderInfo = orderMap[master.hardwareId] || {}; - - // ✅ Only keep masters where work_status === 'active' - if (orderInfo.work_status !== 'active') { - continue; // skip this master - } - - // Prefer Insensors name/location, fallback to order info - const masterName = master.masterName || orderInfo.masterName || null; - const location = master.location || orderInfo.location || null; - - // Fetch latest GSM data - const latestGsmData = await IotData.findOne({ hardwareId: master.hardwareId }) - .sort({ date: -1, time: -1 }) - .lean(); + // Fetch latest GSM data + const latestGsmData = await IotData.findOne({ hardwareId: master.hardwareId }) + .sort({ date: -1, time: -1 }) + .lean(); let connectedGsmDate = null; let connectedGsmTime = null; @@ -4141,351 +2661,6 @@ exports.getCompleteMasterSlaveSummary = async (req, reply) => { return reply.status(500).send({ error: "Internal Server Error" }); } }; -// exports.getMasterWithSlaves = async (req, reply) => { -// try { -// const { installationId, customerId, hardwareId } = req.params; - -// if (!installationId || !customerId || !hardwareId) { -// return reply.code(400).send({ success: false, message: "installationId, customerId, and hardwareId are required" }); -// } - -// // Find order -// const order = await Order.findOne({ installationId, customerId }).lean(); -// if (!order) { -// return reply.code(404).send({ success: false, message: "Order not found" }); -// } - -// // Find master device in Insensors -// const master = await Insensors.findOne({ -// hardwareId, -// customerId, -// }).lean(); - -// if (!master) { -// return reply.code(404).send({ success: false, message: "Master device not found in Insensors" }); -// } - -// // // Find slaves connected to this master -// // const slaves = await Insensors.find({ -// // connected_to: hardwareId, -// // customerId, -// // type: 'slave' -// // }).lean(); - -// return reply.send({ -// success: true, -// master, -// }); - -// } catch (error) { -// console.error("Error fetching master and slaves:", error); -// return reply.code(500).send({ success: false, message: "Internal server error" }); -// } -// }; - -// exports.editTankDimensions = async (req, reply) => { -// try { -// const { customerId, teamMemberId, hardwareId, tankHardwareId } = req.params; -// const { height, width, length } = req.body; - -// if (!customerId || !teamMemberId || !hardwareId || !tankHardwareId) { -// return reply.code(400).send({ -// success: false, -// message: 'customerId, teamMemberId, hardwareId and tankHardwareId are required' -// }); -// } - -// // if (height === undefined || width === undefined || length === undefined) { -// // return reply.code(400).send({ -// // success: false, -// // message: 'height, width and length are required in body (in cm)' -// // }); -// // } - -// if ( -// isNaN(parseFloat(height)) || -// isNaN(parseFloat(width)) || -// isNaN(parseFloat(length)) -// ) { -// return reply.code(400).send({ -// success: false, -// message: 'height, width and length must be numeric values (in cm)' -// }); -// } - -// // ✅ Helper: cm to feet -// const cmToFeet = (cm) => { -// const v = parseFloat(cm); -// return !isNaN(v) ? parseFloat((v / 30.48).toFixed(2)) : null; -// }; - -// // Step 1: Find install record with teamMemberId -// const installRecord = await Install.findOne({ -// 'team_member.team_member.teamMemberId': teamMemberId -// }).lean(); - -// if (!installRecord) { -// return reply.code(404).send({ -// success: false, -// message: 'Team member not found or not assigned' -// }); -// } - -// const teamMemberDetails = installRecord.team_member?.team_member?.find( -// member => member.teamMemberId === teamMemberId -// ) || null; - -// if (!teamMemberDetails) { -// return reply.code(404).send({ -// success: false, -// message: 'Team member details not found under install record' -// }); -// } - -// // Step 2: Find the matching order using installationId and customerId -// const orderRecord = await Order.findOne({ -// installationId: installRecord.installationId, -// customerId -// }).lean(); - -// if (!orderRecord) { -// return reply.code(404).send({ -// success: false, -// message: 'Order not found for this installation and customer' -// }); -// } - -// // Step 3: Convert cm to feet before saving -// const heightInFeet = cmToFeet(height); -// const widthInFeet = cmToFeet(width); -// const lengthInFeet = cmToFeet(length); - -// // Step 4: Update the tank -// const updatedTank = await Tank.findOneAndUpdate( -// { -// customerId, -// hardwareId, -// tankhardwareId: tankHardwareId -// }, -// { -// $set: { -// height: heightInFeet, -// width: widthInFeet, -// length: lengthInFeet -// } -// }, -// { new: true } -// ).lean(); - -// if (!updatedTank) { -// return reply.code(404).send({ -// success: false, -// message: 'Tank not found with given customerId, hardwareId and tankHardwareId' -// }); -// } - -// // Step 5: Return success response with both feet & original cm -// return reply.send({ -// success: true, -// message: 'Tank dimensions updated successfully', -// updatedTank: { -// ...updatedTank, -// heightIncm: parseFloat(height), -// widthIncm: parseFloat(width), -// lengthIncm: parseFloat(length) -// }, -// teamMember: { -// teamMemberId: teamMemberDetails.teamMemberId, -// firstName: teamMemberDetails.firstName, -// phone: teamMemberDetails.phone, -// email: teamMemberDetails.email, -// alternativePhone: teamMemberDetails.alternativePhone, -// installationTeamMemId: teamMemberDetails.installationTeamMemId, -// status: teamMemberDetails.status -// } -// }); - -// } catch (error) { -// console.error('Error updating tank dimensions:', error); -// return reply.code(500).send({ -// success: false, -// message: 'Internal server error' -// }); -// } -// }; - -// exports.getMasterWithSlaves = async (req, reply) => { -// try { -// const { installationId, customerId, hardwareId } = req.params; - -// if (!installationId || !customerId || !hardwareId) { -// return reply.code(400).send({ success: false, message: "installationId, customerId, and hardwareId are required" }); -// } - -// // Find order -// const order = await Order.findOne({ installationId, customerId }).lean(); -// if (!order) { -// return reply.code(404).send({ success: false, message: "Order not found" }); -// } - -// // Find master device in Insensors -// const master = await Insensors.findOne({ -// hardwareId, -// customerId, -// }).lean(); - -// if (!master) { -// return reply.code(404).send({ success: false, message: "Master device not found in Insensors" }); -// } - -// // Find matching master in order.master_connections -// const matchingMaster = order.master_connections?.find(m => m.hardwareId === hardwareId); - -// let masterName = null; -// let location = null; -// if (matchingMaster) { -// masterName = matchingMaster.master_name ?? null; -// location = matchingMaster.location ?? null; -// } - -// // Build enriched master object -// const enrichedMaster = { -// ...master, -// masterName, -// location, -// hardwareId: master.hardwareId -// }; - -// // 👉 Find slaves connected to this master -// const slaves = await Insensors.find({ -// customerId, -// connected_to: hardwareId, -// type: 'slave' -// }).lean(); - -// // Add masterName & location to each slave -// const enrichedSlaves = slaves.map(slave => ({ -// ...slave, -// masterName, -// location -// })); - -// return reply.send({ -// success: true, -// master: enrichedMaster, -// slaves: enrichedSlaves -// }); - -// } catch (error) { -// console.error("Error fetching master and slaves:", error); -// return reply.code(500).send({ success: false, message: "Internal server error" }); -// } -// }; - -// exports.getMasterWithSlaves = async (req, reply) => { -// try { -// const { installationId, customerId, hardwareId } = req.params; - -// if (!installationId || !customerId || !hardwareId) { -// return reply.code(400).send({ success: false, message: "installationId, customerId, and hardwareId are required" }); -// } - -// // Find order -// const order = await Order.findOne({ installationId, customerId }).lean(); -// if (!order) { -// return reply.code(404).send({ success: false, message: "Order not found" }); -// } - -// // Find device in Insensors (could be master or slave) -// const device = await Insensors.findOne({ -// hardwareId, -// customerId, -// }).lean(); - -// if (!device) { -// return reply.code(404).send({ success: false, message: "Device not found in Insensors" }); -// } - -// let master; -// let masterName = null; -// let location = null; -// let slaves = []; - -// if (device.type === 'master') { -// // Case: passed hardwareId is master -// master = device; - -// // Find matching master in order.master_connections -// const matchingMaster = order.master_connections?.find(m => m.hardwareId === hardwareId); -// if (matchingMaster) { -// masterName = matchingMaster.master_name ?? null; -// location = matchingMaster.location ?? null; -// } - -// // Find slaves connected to this master -// slaves = await Insensors.find({ -// customerId, -// connected_to: hardwareId, -// type: 'slave' -// }).lean(); - -// } else if (device.type === 'slave' && device.connected_to) { -// // Case: passed hardwareId is slave → need to find master -// master = await Insensors.findOne({ -// hardwareId: device.connected_to, -// customerId, -// type: 'master' -// }).lean(); - -// if (!master) { -// return reply.code(404).send({ success: false, message: "Master device linked to this slave not found" }); -// } - -// // Find matching master in order.master_connections -// const matchingMaster = order.master_connections?.find(m => m.hardwareId === device.connected_to); -// if (matchingMaster) { -// masterName = matchingMaster.master_name ?? null; -// location = matchingMaster.location ?? null; -// } - -// // Find other slaves connected to the same master (including this slave) -// slaves = await Insensors.find({ -// customerId, -// connected_to: device.connected_to, -// type: 'slave' -// }).lean(); - -// } else { -// return reply.code(400).send({ success: false, message: "Device type unknown or missing connected_to" }); -// } - -// // Enrich master object -// const enrichedMaster = { -// ...master, -// masterName, -// location, -// hardwareId: master.hardwareId -// }; - -// // Enrich each slave with masterName & location -// const enrichedSlaves = slaves.map(slave => ({ -// ...slave, -// masterName, -// location -// })); - -// return reply.send({ -// success: true, -// master: enrichedMaster, -// slaves: enrichedSlaves -// }); - -// } catch (error) { -// console.error("Error fetching master and slaves:", error); -// return reply.code(500).send({ success: false, message: "Internal server error" }); -// } -// }; - exports.getMasterWithSlaves = async (req, reply) => { try { const { installationId, customerId, hardwareId } = req.params; @@ -4757,548 +2932,35 @@ async function getTankHeight(tankhardwareId) { return matchedTank?.tankHeight || null; } -// exports.getIotDataByCustomer = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.code(400).send({ error: "customerId is required" }); -// } - -// // 1. Fetch all tanks by customerId -// const tanks = await Tank.find({ customerId }); -// console.log("Tanks found:", tanks.length); - -// if (!tanks || tanks.length === 0) { -// return reply.code(404).send({ message: "No tanks found for this customer." }); -// } - -// // 2. Collect all motor_ids from input & output connections -// const motorIdSet = new Set(); - -// for (const tank of tanks) { -// const { inputConnections = [], outputConnections = [] } = tank.connections || {}; -// inputConnections.forEach(conn => { -// if (conn.motor_id) motorIdSet.add(conn.motor_id.trim()); -// }); +exports.getIotDataByCustomer = async (req, reply) => { + try { + const { customerId } = req.params; -// outputConnections.forEach(conn => { -// if (conn.motor_id) motorIdSet.add(conn.motor_id.trim()); -// }); -// } + if (!customerId) { + return reply.code(400).send({ error: "customerId is required" }); + } -// const motorIds = Array.from(motorIdSet); -// console.log("Unique motorIds collected:", motorIds); + // ✅ Get all sensors for the customer + const sensors = await Insensors.find({ customerId }); -// if (motorIds.length === 0) { -// return reply.send({ status_code: 200, message: "No motors connected", data: [] }); -// } + if (!sensors.length) { + return reply.code(404).send({ message: "No sensors found for this customer." }); + } -// // 3. Fetch the latest IotData for each unique hardwareId -// const latestIotDataPromises = motorIds.map(hardwareId => -// IotData.findOne({ hardwareId }).sort({ date: -1 }).lean() -// ); + // ✅ Filter master sensors + let masterSensors = sensors.filter(s => s.type === 'master'); -// const iotDataResults = await Promise.all(latestIotDataPromises); -// const filteredData = iotDataResults.filter(doc => doc); // remove nulls + // ✅ If hardwareId is provided, filter to that master only + // if (hardwareId) { + // masterSensors = masterSensors.filter(m => m.hardwareId?.trim() === hardwareId.trim()); + // } -// console.log("Latest IotData entries found:", filteredData.length); + if (!masterSensors.length) { + return reply.code(404).send({ message: "No master found for the given hardwareId or customer." }); + } -// return reply.send({ -// status_code: 200, -// message: "Success", -// data: filteredData -// }); - -// } catch (err) { -// console.error("Error fetching IoT data by customerId:", err); -// return reply.code(500).send({ error: "Internal Server Error" }); -// } -// }; - -// exports.getIotDataByCustomer = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.code(400).send({ error: "customerId is required" }); -// } - -// // Fetch all sensors of the customer -// const sensors = await Insensors.find({ customerId }); - -// if (!sensors || sensors.length === 0) { -// return reply.code(404).send({ message: "No sensors found for this customer." }); -// } - -// // Extract unique hardwareIds -// const hardwareIds = [ -// ...new Set( -// sensors.map(sensor => sensor.connected_to?.trim()).filter(Boolean) -// ) -// ]; - -// if (hardwareIds.length === 0) { -// return reply.send({ status_code: 200, message: "No connected hardwareIds found", data: [] }); -// } - -// // Fetch latest IoT data and enrich it -// const latestDataPromises = hardwareIds.map(async hardwareId => { -// const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); - -// const relatedSensors = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId); - -// let message = "GSM is not connected"; -// if (latestRecord?.tanks?.some(tank => parseFloat(tank.tankHeight || 0) > 0)) { -// message = "GSM is connected"; -// } - -// // Prepare individual tank connection status -// const tanksStatus = relatedSensors.map(sensor => { -// const tankhardwareId = sensor.hardwareId?.trim(); - -// const matchedTank = latestRecord?.tanks?.find( -// tank => tank.tankhardwareId === tankhardwareId -// ); - -// const loraMessage = -// matchedTank && parseFloat(matchedTank.tankHeight || 0) > 0 -// ? "LORA is connected" -// : "LORA is not connected"; - -// return { -// tankhardwareId, -// tankName: sensor.tankName ?? null, -// tankLocation: sensor.tankLocation ?? null, -// masterName: sensor.masterName ?? null, -// location: sensor.location ?? null, -// loraMessage, -// latestTankData: matchedTank || null -// }; -// }); - -// return { -// hardwareId, -// message, -// masterName: relatedSensors[0]?.masterName ?? null, -// location: relatedSensors[0]?.location ?? null, -// tanks: tanksStatus.slice(1) // 👈 Skip the first tank -// }; -// }); - -// const iotDataGrouped = await Promise.all(latestDataPromises); - -// return reply.send({ -// status_code: 200, -// message: "Success", -// data: iotDataGrouped -// }); - -// } catch (err) { -// console.error("Error fetching IoT data by customerId:", err); -// return reply.code(500).send({ error: "Internal Server Error" }); -// } -// }; - - -// exports.getIotDataByCustomer = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.code(400).send({ error: "customerId is required" }); -// } - -// // Fetch all sensors for the customer -// const sensors = await Insensors.find({ customerId }); - -// if (!sensors || sensors.length === 0) { -// return reply.code(404).send({ message: "No sensors found for this customer." }); -// } - -// // Extract unique hardwareIds that are connected to sensors -// const hardwareIds = [ -// ...new Set( -// sensors.map(sensor => sensor.connected_to?.trim()).filter(Boolean) -// ) -// ]; - -// if (hardwareIds.length === 0) { -// return reply.send({ status_code: 200, message: "No connected hardwareIds found", data: [] }); -// } - -// // Fetch the latest IoT data and enrich it with sensor details -// const latestDataPromises = hardwareIds.map(async hardwareId => { -// // Fetch the latest IoT data for this hardwareId -// const latestRecord = await IotData.findOne({ hardwareId }) -// .sort({ date: -1 }) // Sorting to get the latest record based on the date -// .lean(); - -// // If no IoT data is found for this hardwareId, return a placeholder -// if (!latestRecord) { -// return { -// hardwareId, -// message: "No IoT data found", -// tanks: [] -// }; -// } - -// // Find sensors related to this hardwareId -// const relatedSensors = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId); - -// // Check if this hardwareId is "disconnected" in Insensors (based on your logic, e.g., isConnected=false) -// const isDisconnected = relatedSensors.some(sensor => sensor.isConnected === false); // You can adjust this check based on your schema. - -// // Default message for GSM connection status -// let message = isDisconnected ? "GSM is disconnected" : "GSM is not connected"; - -// // If any tank data has height > 0, assume GSM is connected, overriding the disconnected state -// if (latestRecord?.tanks?.some(tank => parseFloat(tank.tankHeight || 0) > 0)) { -// message = "GSM is connected"; -// } - -// // Enrich each tank with the IoT data -// const tanksStatus = relatedSensors.map(sensor => { -// const tankhardwareId = sensor.hardwareId?.trim(); -// const matchedTank = latestRecord?.tanks?.find( -// tank => tank.tankhardwareId === tankhardwareId -// ); - -// // Check if LoRa is connected based on the tankHeight -// const loraMessage = -// matchedTank && parseFloat(matchedTank.tankHeight || 0) > 0 -// ? "LORA is connected" -// : "LORA is not connected"; - -// return { -// tankhardwareId, -// tankName: sensor.tankName ?? null, -// tankLocation: sensor.tankLocation ?? null, -// masterName: sensor.masterName ?? null, -// location: sensor.location ?? null, -// loraMessage, -// latestTankData: matchedTank || null -// }; -// }); - -// return { -// hardwareId, -// message, -// masterName: relatedSensors[0]?.masterName ?? null, -// location: relatedSensors[0]?.location ?? null, -// tanks: tanksStatus -// }; -// }); - -// // Wait for all promises to resolve to gather all the enriched data -// const iotDataGrouped = await Promise.all(latestDataPromises); - -// // Return the final response -// return reply.send({ -// status_code: 200, -// message: "Success", -// data: iotDataGrouped -// }); - -// } catch (err) { -// console.error("Error fetching IoT data by customerId:", err); -// return reply.code(500).send({ error: "Internal Server Error" }); -// } -// }; - -//important -// exports.getIotDataByCustomer = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.status(400).send({ error: "customerId is required" }); -// } - -// console.log("Fetching data for customerId:", customerId); - -// // Step 1: Fetch all sensors for the customer -// const sensors = await Insensors.find({ customerId }); - -// if (!sensors || sensors.length === 0) { -// return reply.send({ status_code: 404, message: "No sensors found for this customer", data: [] }); -// } - -// // Step 2: Fetch latest IoT data for each sensor's hardwareId -// const enrichedSensors = await Promise.all(sensors.map(async (sensor) => { -// const { connected_to: hardwareId, masterName, location } = sensor; - -// // Fetch the latest IoT data for this hardwareId -// const iotData = await IotData.findOne({ hardwareId }) -// .sort({ date: -1 }) // Sort to get the latest data -// .lean(); - -// if (!iotData) { -// return { -// hardwareId, -// message: "No IoT data found", -// masterName, -// location, -// tanks: [] -// }; -// } - -// // Step 3: Get GSM status based on the latest IoT data -// const latestRecord = iotData; -// const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata"); -// const connected_gsm_date = indiaTime.format("YYYY-MM-DD"); -// const connected_gsm_time = indiaTime.format("HH:mm:ss"); - -// const now = moment.tz("Asia/Kolkata"); -// const diffInMinutes = now.diff(indiaTime, "minutes"); -// const isGSMConnected = diffInMinutes <= 1; -// const gsmStatus = isGSMConnected ? "GSM Connected" : "GSM Not Connected"; - -// // Step 4: Annotate each tank with LoRa connection status -// const tanksWithConnectionStatus = latestRecord.tanks.map(tank => { -// const tankMoment = moment.tz(tank.date, "Asia/Kolkata"); -// const tankDiff = now.diff(tankMoment, "minutes"); - -// const loraStatus = tankDiff <= 1 ? "LORA is connected" : "LORA is not connected"; -// return { -// tankhardwareId: tank.tankhardwareId, -// tankName: sensor.tankName ?? null, -// tankLocation: sensor.tankLocation ?? null, -// masterName: sensor.masterName ?? null, -// location: sensor.location ?? null, -// loraMessage: loraStatus, -// latestTankData: tank -// }; -// }); - -// // Step 5: Return enriched sensor data in the desired format -// return { -// hardwareId, -// message: gsmStatus, -// masterName, -// location, -// tanks: tanksWithConnectionStatus -// }; -// })); - -// // Step 6: Return the enriched data for the customer -// return reply.send({ -// status_code: 200, -// message: "Success", -// data: enrichedSensors -// }); - -// } catch (err) { -// console.error("Error in getAllDataForCustomer:", err); -// return reply.status(500).send({ error: "Internal Server Error" }); -// } -// }; - - -// exports.getIotDataByCustomer = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.status(400).send({ error: "customerId is required" }); -// } - -// console.log("Fetching data for customerId:", customerId); - -// // Step 1: Fetch all sensors for the customer -// const sensors = await Insensors.find({ customerId }); - -// if (!sensors || sensors.length === 0) { -// return reply.send({ status_code: 404, message: "No sensors found for this customer", data: [] }); -// } - -// // Step 2: Fetch latest IoT data for each sensor's hardwareId -// const enrichedSensors = await Promise.all(sensors.map(async (sensor) => { -// const { connected_to: hardwareId, masterName, location } = sensor; - -// // Fetch the latest IoT data for this hardwareId -// const iotData = await IotData.findOne({ hardwareId }) -// .sort({ date: -1 }) // Sort to get the latest data -// .lean(); - -// if (!iotData) { -// return { -// hardwareId, -// message: "No IoT data found", -// masterName, -// location, -// tanks: [] -// }; -// } - -// // Step 3: Get GSM status based on the latest IoT data -// const latestRecord = iotData; -// const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata"); -// const connected_gsm_date = indiaTime.format("YYYY-MM-DD"); -// const connected_gsm_time = indiaTime.format("HH:mm:ss"); - -// const now = moment.tz("Asia/Kolkata"); -// const diffInMinutes = now.diff(indiaTime, "minutes"); -// const isGSMConnected = diffInMinutes <= 1; -// const gsmStatus = isGSMConnected ? "GSM Connected" : "GSM Not Connected"; - -// // Step 4: Annotate each tank with LoRa connection status -// const tanksWithConnectionStatus = latestRecord.tanks.slice(0, 2).map(tank => { // Limit to 2 tanks -// const tankMoment = moment.tz(tank.date, "Asia/Kolkata"); -// const tankDiff = now.diff(tankMoment, "minutes"); - -// const loraStatus = tankDiff <= 1 ? "LORA is connected" : "LORA is not connected"; -// return { -// tankhardwareId: tank.tankhardwareId, -// tankName: sensor.tankName ?? null, -// tankLocation: sensor.tankLocation ?? null, -// masterName: sensor.masterName ?? null, -// location: sensor.location ?? null, -// loraMessage: loraStatus, -// latestTankData: tank -// }; -// }); - -// // Step 5: Return enriched sensor data in the desired format -// return { -// hardwareId, -// message: gsmStatus, -// masterName, -// location, -// tanks: tanksWithConnectionStatus -// }; -// })); - -// // Step 6: Return the enriched data for the customer -// return reply.send({ -// status_code: 200, -// message: "Success", -// data: enrichedSensors -// }); - -// } catch (err) { -// console.error("Error in getAllDataForCustomer:", err); -// return reply.status(500).send({ error: "Internal Server Error" }); -// } -// }; - - -// exports.getIotDataByCustomer = async (req, reply) => { -// try { -// const { customerId } = req.params; - -// if (!customerId) { -// return reply.code(400).send({ error: "customerId is required" }); -// } - -// // Step 1: Get all devices for this customer -// const sensors = await Insensors.find({ customerId }); - -// if (!sensors.length) { -// return reply.code(404).send({ message: "No sensors found for this customer." }); -// } - -// // Step 2: Get all unique master hardwareIds from connected_to -// const masterHardwareIds = [ -// ...new Set( -// sensors.map(s => s.connected_to?.trim()).filter(Boolean) -// ) -// ]; - -// // Step 3: Loop over each master (connected_to) and build enriched data -// const enrichedMasters = await Promise.all(masterHardwareIds.map(async (hardwareId) => { -// const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); - -// if (!latestRecord) { -// return { -// hardwareId, -// message: "No IoT data found", -// tanks: [] -// }; -// } - -// // Get all slaves connected to this master -// const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId); - -// const message = latestRecord.tanks.some(t => parseFloat(t.tankHeight || 0) > 0) -// ? "GSM is connected" -// : "GSM is not connected"; - -// // Map connected slaves to tank details -// let tanks = connectedSlaves.map(slave => { -// const slaveId = slave.hardwareId?.trim(); -// const matchedTank = latestRecord.tanks.find(tank => tank.tankhardwareId === slaveId); - -// const loraMessage = matchedTank && parseFloat(matchedTank.tankHeight || 0) > 0 -// ? "LORA is connected" -// : "LORA is not connected"; - -// return { -// tankhardwareId: slaveId, -// tankName: slave.tankName ?? null, -// tankLocation: slave.tankLocation ?? null, -// masterName: slave.masterName ?? null, -// location: slave.location ?? null, -// loraMessage, -// latestTankData: matchedTank ?? null -// }; -// }); - -// // ❗ Remove the first tank entry -// tanks = tanks.slice(1); - -// return { -// hardwareId, -// message, -// masterName: connectedSlaves[0]?.masterName ?? null, -// location: connectedSlaves[0]?.location ?? null, -// tanks -// }; -// })); - -// return reply.send({ -// status_code: 200, -// message: "Success", -// data: enrichedMasters -// }); - -// } catch (err) { -// console.error("Error fetching IoT data by customerId:", err); -// return reply.code(500).send({ error: "Internal Server Error" }); -// } -// }; - - - -exports.getIotDataByCustomer = async (req, reply) => { - try { - const { customerId } = req.params; - - if (!customerId) { - return reply.code(400).send({ error: "customerId is required" }); - } - - // ✅ Get all sensors for the customer - const sensors = await Insensors.find({ customerId }); - - if (!sensors.length) { - return reply.code(404).send({ message: "No sensors found for this customer." }); - } - - // ✅ Filter master sensors - let masterSensors = sensors.filter(s => s.type === 'master'); - - // ✅ If hardwareId is provided, filter to that master only - // if (hardwareId) { - // masterSensors = masterSensors.filter(m => m.hardwareId?.trim() === hardwareId.trim()); - // } - - if (!masterSensors.length) { - return reply.code(404).send({ message: "No master found for the given hardwareId or customer." }); - } - - const masterHardwareIds = masterSensors.map(m => m.hardwareId?.trim()); + const masterHardwareIds = masterSensors.map(m => m.hardwareId?.trim()); // ✅ Build map of masterName/location from Order const orders = await Order.find({ customerId }).lean(); @@ -5484,3530 +3146,323 @@ exports.getIotDataByCustomerAndHardwareId = async (req, reply) => { }; +const cron = require("node-cron"); +const Admin = require("../models/admin"); -//const moment = require("moment-timezone"); +// ⬇️ Include the function here or import it if it's in another file +const updateConnectedStatusOnly = async (customerId, hardwareId) => { + try { + const sensors = await Insensors.find({ customerId }); + if (!sensors.length) return; -// exports.raiseATicket = async (req, reply) => { -// try { -// const { customerId, connected_to } = req.params; + const now = moment.tz("Asia/Kolkata"); + const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); + if (!latestRecord) return; -// if (!customerId || !connected_to) { -// return reply.code(400).send({ error: "customerId and connected_to are required" }); -// } + const gsmTime = moment.tz(latestRecord.date, "Asia/Kolkata"); + const gsmDiff = now.diff(gsmTime, "minutes"); + const gsmConnected = gsmDiff <= 1; -// const sensors = await Insensors.find({ customerId }).lean(); -// const orders = await Order.find({ customerId }).lean(); + const connectedSlaves = sensors.filter(s => s.connected_to?.trim() === hardwareId); + const tankMap = {}; + (latestRecord.tanks || []).forEach(t => { + if (t.tankhardwareId) { + tankMap[t.tankhardwareId.trim()] = t; + } + }); -// if (!sensors.length) { -// return reply.code(404).send({ message: "No sensors found for this customer." }); -// } + const allSlavesConnected = connectedSlaves.every(slave => { + const slaveId = slave.tankhardwareId?.trim(); + const tank = tankMap[slaveId]; + if (!tank || !tank.date || tank.tankHeight === "0") return false; + const loraTime = moment.tz(tank.date, "Asia/Kolkata"); + return now.diff(loraTime, "minutes") <= 1; + }); -// const masterSensor = sensors.find(s => s.hardwareId?.trim() === connected_to.trim() && s.type === "master"); -// if (!masterSensor) { -// return reply.code(404).send({ message: "Master hardwareId not found." }); -// } + const masterStatus = gsmConnected && allSlavesConnected ? "connected" : "disconnected"; + await Insensors.updateOne({ hardwareId, customerId }, { $set: { connected_status: masterStatus } }); -// const orderMap = {}; -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); + for (const slave of connectedSlaves) { + const slaveId = slave.tankhardwareId?.trim(); + const tank = tankMap[slaveId]; -// const now = moment.tz("Asia/Kolkata"); + let status = "disconnected"; + if (tank && tank.date && tank.tankHeight !== "0") { + const loraTime = moment.tz(tank.date, "Asia/Kolkata"); + if (now.diff(loraTime, "minutes") <= 1) status = "connected"; + } -// function getDisconnectDuration(timeStr) { -// if (!timeStr) return null; -// const time = moment.tz(timeStr, "DD-MM-YYYY HH:mm:ss", "Asia/Kolkata"); -// return time.isValid() ? now.diff(time, "minutes") : null; -// } + await Insensors.updateOne({ hardwareId: slave.hardwareId }, { $set: { connected_status: status } }); + } + } catch (error) { + console.error("❌ updateConnectedStatusOnly error:", error); + } +}; -// const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean(); -// let masterConnectedStatus = "disconnected"; -// let lastDataTime = "No data"; -// let diffInMinutes = null; -// if (latestMasterRecord?.date) { -// const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); -// diffInMinutes = now.diff(indiaTime, "minutes"); -// lastDataTime = indiaTime.format("DD-MM-YYYY HH:mm:ss"); -// if (diffInMinutes <= 1) masterConnectedStatus = "connected"; -// } +const generateTicketId = () => { + return "AWTKT" + Date.now(); // Or use UUID or nanoid +}; -// const connectedSlaves = sensors.filter( -// s => s.connected_to?.trim() === connected_to.trim() && s.type === "slave" -// ); - -// const formattedSlaves = []; -// const disconnectedSlaves = []; - -// for (const slave of connectedSlaves) { -// const slaveData = latestMasterRecord?.tanks.find(t => t.tankhardwareId === slave.tankhardwareId); -// let slaveStatus = "disconnected"; -// let lastSlaveDataTime = "No data"; -// let slaveDiff = null; - -// if (slaveData?.date) { -// const slaveTime = moment.tz(slaveData.date, "Asia/Kolkata"); -// slaveDiff = now.diff(slaveTime, "minutes"); -// lastSlaveDataTime = slaveTime.format("DD-MM-YYYY HH:mm:ss"); -// if (slaveDiff <= 1) slaveStatus = "connected"; -// } - -// if (slaveStatus === "disconnected") { -// disconnectedSlaves.push({ -// slaveHardwareId: slave.tankhardwareId, -// slaveName: slave.tankName || "Unknown Slave" -// }); -// } - -// formattedSlaves.push({ -// hardwareId: slave.hardwareId, -// slaveName: slave.tankName || null, -// location: slave.tankLocation || null, -// type: "slave", -// connected_status: slaveStatus, -// last_data_time: lastSlaveDataTime, -// diff_in_minutes: slaveDiff -// }); -// } -// const issuesToAdd = []; - -// // ✅ Only raise a ticket if master is disconnected -// // if (masterConnectedStatus === "disconnected") { -// // const existingMasterTicket = await Support.findOne({ -// // "issues.hardwareId": connected_to, -// // "issues.type": "GSM or LoRa Disconnected" -// // }); - -// // if (!existingMasterTicket) { -// // const slaveHardwareIds = disconnectedSlaves.map(s => s.slaveHardwareId); -// // const slaveNames = disconnectedSlaves.map(s => s.slaveName); - -// // issuesToAdd.push({ -// // type: "GSM or LoRa Disconnected", -// // masterHardwareId: connected_to, -// // hardwareId: connected_to, // Master hardwareId -// // hardwareIds: slaveHardwareIds, // Slave tankHardwareIds -// // slaveNames, -// // message: `Master ${connected_to} is disconnected along with ${slaveHardwareIds.length} slave(s)` -// // }); -// // } -// // } - -// if (masterConnectedStatus === "disconnected") { -// const existingMasterTicket = await Support.findOne({ -// "issues.hardwareId": connected_to, -// "issues.type": "GSM or LoRa Disconnected" -// }); - -// if (!existingMasterTicket) { -// const slaveHardwareIds = disconnectedSlaves.map(s => s.slaveHardwareId); -// const slaveNames = disconnectedSlaves.map(s => s.slaveName); - -// // Check if disconnection is at least 15 minutes old -// if (diffInMinutes >= 1) { -// issuesToAdd.push({ -// type: "GSM or LoRa Disconnected", -// masterHardwareId: connected_to, -// hardwareId: connected_to, -// hardwareIds: slaveHardwareIds, -// slaveNames, -// message: `Master ${connected_to} is disconnected along with ${slaveHardwareIds.length} slave(s)`, -// disconnectedAt: lastDataTime // optional: for future tracking -// }); -// } -// } -// } - +const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => { + const now = new Date(); + const formattedNow = new Date(now.getTime() + 19800000) // +05:30 IST offset + .toISOString() + .replace("T", " ") + .substring(0, 19); -// if (issuesToAdd.length > 0) { -// const supportRecord = await Support.findOne({ supportId: "AWHYSU64" }); - -// if (supportRecord) { -// await Support.findOneAndUpdate( -// { supportId: "AWHYSU64" }, -// { -// $push: { issues: { $each: issuesToAdd } }, -// $set: { updatedAt: new Date(), lastTicketRaisedAt: moment().tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss") } -// } -// ); -// } -// } - + // ✅ If issue already exists anywhere for this hardwareId, SKIP + const issueAlreadyExists = [ + ...supportRecord.issues, + ...supportRecord.categorizedIssues, + //...supportRecord.resolvedIssues + ].some((issue) => issue.hardwareId === masterHardwareId); -// const masterDetails = { -// hardwareId: connected_to, -// masterName: masterSensor.masterName || orderMap[connected_to]?.masterName || null, -// location: masterSensor.location || orderMap[connected_to]?.location || null, -// type: "master", -// connected_status: masterConnectedStatus, -// last_data_time: lastDataTime, -// diff_in_minutes: diffInMinutes -// }; + if (issueAlreadyExists) { + console.log(`⛔ Issue already exists for ${masterHardwareId}. Not raising again.`); + return; + } -// return reply.send({ -// status_code: 200, -// message: "Checked connection and raised ticket if needed.", -// master: masterDetails, -// connected_slaves: formattedSlaves -// }); + // ✅ Prepare slave hardwareIds and names + const slaveHardwareIds = slaveData.map((s) => s.tankhardwareId).sort(); + const slaveNames = slaveData.map((s) => s.sensorName || s.tankName || "").sort(); -// } catch (error) { -// console.error("Error raising ticket:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; + // ✅ Create new issue + const newIssue = { + type: "GSM or LoRa Disconnected", + masterHardwareId, + hardwareId: masterHardwareId, + hardwareIds: slaveHardwareIds, + slaveNames: slaveNames, + resolved: false, + movedToCategory: false, + lastTicketRaisedAt: formattedNow, + createdAt: formattedNow, + }; + supportRecord.issues.push(newIssue); + supportRecord.lastTicketRaisedAt = formattedNow; + await supportRecord.save(); + console.log(`✅ New ticket raised for ${masterHardwareId}`); +}; -// exports.raiseATicket = async (req, reply) => { -// try { -// const { customerId, connected_to } = req.params; -// if (!customerId || !connected_to) { -// return reply.code(400).send({ error: "customerId and connected_to are required" }); -// } +cron.schedule("*/1 * * * *", async () => { + try { + console.log("🔁 Running auto-disconnect ticket check..."); -// // Fetch all sensors and orders for the customer -// const sensors = await Insensors.find({ customerId }).lean(); -// const orders = await Order.find({ customerId }).lean(); + // Step 1: Get all support profiles + const allSupportProfiles = await Support.find({}); -// if (!sensors.length) { -// return reply.code(404).send({ message: "No sensors found for this customer." }); -// } + for (const supportRecord of allSupportProfiles) { + const supportId = supportRecord.supportId; + if (!supportId) continue; -// // Find master sensor matching connected_to -// const masterSensor = sensors.find(s => s.hardwareId?.trim() === connected_to.trim() && s.type === "master"); -// if (!masterSensor) { -// return reply.code(404).send({ message: "Master hardwareId not found." }); -// } + // Step 2: Find all master sensors + const allMasters = await Insensors.find({ type: "master" }).lean(); -// // Map orders for quick lookup of masterName and location -// const orderMap = {}; -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); - -// const now = moment.tz("Asia/Kolkata"); - -// // Helper to get the latest record from multiple IoT data docs -// function getLatestDataRecord(records) { -// if (!records || records.length === 0) return null; -// return records.reduce((latest, record) => { -// if (!latest) return record; -// return new Date(record.date) > new Date(latest.date) ? record : latest; -// }, null); -// } - -// // Fetch all IoT data for the master (no date limit here, adjust if needed) -// const allMasterIotData = await IotData.find({ hardwareId: connected_to }).lean(); -// const latestMasterRecord = getLatestDataRecord(allMasterIotData); - -// let masterConnectedStatus = "disconnected"; -// let lastDataTime = "No data"; -// let diffInMinutes = null; - -// if (latestMasterRecord?.date) { -// const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); -// diffInMinutes = now.diff(indiaTime, "minutes"); -// lastDataTime = indiaTime.format("DD-MM-YYYY HH:mm:ss"); -// if (diffInMinutes <= 1) masterConnectedStatus = "connected"; // within 1 minute considered connected -// } - -// // Find slaves connected to this master -// const connectedSlaves = sensors.filter( -// s => s.connected_to?.trim() === connected_to.trim() && s.type === "slave" -// ); - -// const slaveHardwareIds = connectedSlaves.map(s => s.tankhardwareId); - -// // Fetch all IoT data for slaves -// const allSlaveIotData = await IotData.find({ hardwareId: { $in: slaveHardwareIds } }).lean(); - -// const formattedSlaves = []; -// const disconnectedSlaves = []; - -// for (const slave of connectedSlaves) { -// const slaveRecords = allSlaveIotData.filter(d => d.hardwareId === slave.tankhardwareId); -// const latestSlaveRecord = getLatestDataRecord(slaveRecords); - -// let slaveStatus = "disconnected"; -// let lastSlaveDataTime = "No data"; -// let slaveDiff = null; - -// if (latestSlaveRecord?.date) { -// const slaveTime = moment.tz(latestSlaveRecord.date, "Asia/Kolkata"); -// slaveDiff = now.diff(slaveTime, "minutes"); -// lastSlaveDataTime = slaveTime.format("DD-MM-YYYY HH:mm:ss"); -// if (slaveDiff <= 1) slaveStatus = "connected"; -// } - -// if (slaveStatus === "disconnected") { -// disconnectedSlaves.push({ -// slaveHardwareId: slave.tankhardwareId, -// slaveName: slave.tankName || "Unknown Slave" -// }); -// } - -// formattedSlaves.push({ -// hardwareId: slave.hardwareId, -// slaveName: slave.tankName || null, -// location: slave.tankLocation || null, -// type: "slave", -// connected_status: slaveStatus, -// last_data_time: lastSlaveDataTime, -// diff_in_minutes: slaveDiff -// }); -// } - -// const issuesToAdd = []; - -// // Raise ticket only if master is disconnected and disconnection is at least 1 minute old -// if (masterConnectedStatus === "disconnected") { -// const existingMasterTicket = await Support.findOne({ -// "issues.hardwareId": connected_to, -// "issues.type": "GSM or LoRa Disconnected" -// }); - -// if (!existingMasterTicket && diffInMinutes >= 1) { -// const slaveHardwareIds = disconnectedSlaves.map(s => s.slaveHardwareId); -// const slaveNames = disconnectedSlaves.map(s => s.slaveName); - -// issuesToAdd.push({ -// type: "GSM or LoRa Disconnected", -// masterHardwareId: connected_to, -// hardwareId: connected_to, -// hardwareIds: slaveHardwareIds, -// slaveNames, -// message: `Master ${connected_to} is disconnected along with ${slaveHardwareIds.length} slave(s)`, -// disconnectedAt: lastDataTime // optional -// }); -// } -// } - -// if (issuesToAdd.length > 0) { -// const supportRecord = await Support.findOne({ supportId: "AWHYSU64" }); - -// if (supportRecord) { -// await Support.findOneAndUpdate( -// { supportId: "AWHYSU64" }, -// { -// $push: { issues: { $each: issuesToAdd } }, -// $set: { -// updatedAt: new Date(), -// lastTicketRaisedAt: moment().tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss") -// } -// } -// ); -// } -// } - -// const masterDetails = { -// hardwareId: connected_to, -// masterName: masterSensor.masterName || orderMap[connected_to]?.masterName || null, -// location: masterSensor.location || orderMap[connected_to]?.location || null, -// type: "master", -// connected_status: masterConnectedStatus, -// last_data_time: lastDataTime, -// diff_in_minutes: diffInMinutes -// }; - -// return reply.send({ -// status_code: 200, -// message: "Checked connection and raised ticket if needed.", -// master: masterDetails, -// connected_slaves: formattedSlaves -// }); - -// } catch (error) { -// console.error("Error raising ticket:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - - - -// exports.raiseATicket = async (req, reply) => { -// try { -// const { customerId, connected_to } = req.params; - -// if (!customerId || !connected_to) { -// return reply.code(400).send({ error: "customerId and connected_to are required" }); -// } - -// const sensors = await Insensors.find({ customerId }); - -// if (!sensors.length) { -// return reply.code(404).send({ message: "No sensors found for this customer." }); -// } - -// const masterSensor = sensors.find(s => s.hardwareId?.trim() === connected_to.trim() && s.type === "master"); - -// if (!masterSensor) { -// return reply.code(404).send({ message: "Master hardwareId not found." }); -// } - -// const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean(); - -// if (!latestMasterRecord) { -// return reply.code(404).send({ message: "No IoT data found for this hardwareId." }); -// } - -// const now = moment.tz("Asia/Kolkata"); -// const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); -// const diffInMinutesMaster = now.diff(indiaTime, "minutes"); - -// const masterDisconnected = diffInMinutesMaster > 1 ? [{ -// hardwareId: connected_to, -// masterName: masterSensor.tankName || "Unknown Master", -// connected_status: "disconnected", -// last_seen_minutes_ago: diffInMinutesMaster -// }] : []; - -// const connectedSlaves = sensors.filter(sensor => -// sensor.connected_to?.trim() === connected_to.trim() && -// sensor.type === "slave" -// ); - -// const disconnectedSlaves = []; -// const slaveStatusList = []; - -// for (const slave of connectedSlaves) { -// const slaveId = slave.tankhardwareId?.trim(); -// const matchedTank = latestMasterRecord.tanks.find(tank => tank.tankhardwareId === slaveId); - -// let isDisconnected = true; -// let loraDiffInMinutes = null; - -// if (matchedTank && matchedTank.date) { -// const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata"); -// loraDiffInMinutes = now.diff(tankTime, "minutes"); - -// if (loraDiffInMinutes <= 1) { -// isDisconnected = false; -// } -// } - -// const slaveInfo = { -// hardwareId: connected_to, -// slaveHardwareId: slaveId, -// slaveName: slave.tankName || "Unknown Slave", -// connected_status: isDisconnected ? "disconnected" : "connected", -// last_seen_minutes_ago: loraDiffInMinutes -// }; - -// slaveStatusList.push(slaveInfo); - -// if (isDisconnected) { -// disconnectedSlaves.push(slaveInfo); -// } -// } - -// const issuesToAdd = []; - -// if (masterDisconnected.length > 0) { -// const existingGsmIssue = await Support.findOne({ -// "issues.hardwareId": connected_to, -// "issues.type": "GSM Disconnected" -// }); - -// if (!existingGsmIssue) { -// issuesToAdd.push({ -// type: "GSM Disconnected", -// hardwareId: connected_to, -// message: `Master GSM disconnected - ${connected_to}` -// }); -// } -// } - -// const newHardwareIds = []; -// const newSlaveNames = []; - -// for (const slave of disconnectedSlaves) { -// const existingSlaveIssue = await Support.findOne({ -// "issues.hardwareIds": slave.slaveHardwareId, -// "issues.masterHardwareId": connected_to, -// "issues.type": "LoRa Disconnected" -// }); - -// if (!existingSlaveIssue) { -// newHardwareIds.push(slave.slaveHardwareId); -// newSlaveNames.push(slave.slaveName); -// } -// } - -// if (newHardwareIds.length > 0) { -// issuesToAdd.push({ -// type: "LoRa Disconnected", -// masterHardwareId: connected_to, -// hardwareIds: newHardwareIds, -// slaveNames: newSlaveNames, -// message: `Slaves LoRa disconnected under master ${connected_to}` -// }); -// } - -// if (issuesToAdd.length > 0) { -// const supportRecord = await Support.findOne({ supportId: "AWHYSU64" }); - -// if (supportRecord) { -// await Support.findOneAndUpdate( -// { _id: supportRecord._id }, -// { -// $push: { -// issues: { $each: issuesToAdd } -// }, -// updatedAt: new Date() -// }, -// { new: true } -// ); -// } else { -// console.error("Support record not found for supportId AWHYSU64"); -// } -// } - -// return reply.send({ -// status_code: 200, -// message: "Checked connection and updated support if needed.", -// masterDisconnected, -// disconnectedSlaves, -// connectedSlaves: slaveStatusList -// }); - -// } catch (error) { -// console.error("Error raising ticket:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - - -// const raiseATicketLikeLogic = async (customerId, connected_to) => { -// try { -// if (!customerId || !connected_to) return; - -// const sensors = await Insensors.find({ customerId }).lean(); -// const orders = await Order.find({ customerId }).lean(); - -// if (!sensors.length) return; - -// const masterSensor = sensors.find( -// s => s.hardwareId?.trim() === connected_to.trim() && s.type === "master" -// ); -// if (!masterSensor) return; - -// const orderMap = {}; -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); - -// const now = moment.tz("Asia/Kolkata"); - -// function getLatestDataRecord(records) { -// if (!records || records.length === 0) return null; -// return records.reduce((latest, record) => { -// if (!latest) return record; -// return new Date(record.date) > new Date(latest.date) ? record : latest; -// }, null); -// } - -// const allMasterIotData = await IotData.find({ hardwareId: connected_to }).lean(); -// const latestMasterRecord = getLatestDataRecord(allMasterIotData); - -// let masterConnectedStatus = "disconnected"; -// let lastDataTime = "No data"; -// let diffInMinutes = null; - -// if (latestMasterRecord?.date) { -// const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); -// diffInMinutes = now.diff(indiaTime, "minutes"); -// lastDataTime = indiaTime.format("DD-MM-YYYY HH:mm:ss"); -// if (diffInMinutes <= 1) masterConnectedStatus = "connected"; -// } - -// const connectedSlaves = sensors.filter( -// s => s.connected_to?.trim() === connected_to.trim() && s.type === "slave" -// ); - -// const slaveHardwareIds = connectedSlaves.map(s => s.tankhardwareId); -// const allSlaveIotData = await IotData.find({ hardwareId: { $in: slaveHardwareIds } }).lean(); - -// const disconnectedSlaves = []; - -// for (const slave of connectedSlaves) { -// const slaveRecords = allSlaveIotData.filter(d => d.hardwareId === slave.tankhardwareId); -// const latestSlaveRecord = getLatestDataRecord(slaveRecords); - -// let slaveStatus = "disconnected"; -// let slaveDiff = null; - -// if (latestSlaveRecord?.date) { -// const slaveTime = moment.tz(latestSlaveRecord.date, "Asia/Kolkata"); -// slaveDiff = now.diff(slaveTime, "minutes"); -// if (slaveDiff <= 1) slaveStatus = "connected"; -// } - -// if (slaveStatus === "disconnected") { -// disconnectedSlaves.push({ -// slaveHardwareId: slave.tankhardwareId, -// slaveName: slave.tankName || "Unknown Slave" -// }); -// } -// } - -// const supportRecord = await Support.findOne({ supportId: "AWHYSU64" }); -// if (!supportRecord) return; - -// const existingIssues = supportRecord.issues || []; - -// const existingMasterIssue = existingIssues.find( -// issue => -// issue.hardwareId === connected_to && -// issue.type === "GSM or LoRa Disconnected" -// ); - -// const alreadyReportedSlaves = new Set( -// existingMasterIssue?.hardwareIds || [] -// ); - -// const newSlaveHardwareIds = []; -// const newSlaveNames = []; - -// for (const slave of disconnectedSlaves) { -// if (!alreadyReportedSlaves.has(slave.slaveHardwareId)) { -// newSlaveHardwareIds.push(slave.slaveHardwareId); -// newSlaveNames.push(slave.slaveName); -// } -// } - -// if (masterConnectedStatus === "disconnected" && diffInMinutes >= 1 && (newSlaveHardwareIds.length > 0 || !existingMasterIssue)) { -// const newIssue = { -// type: "GSM or LoRa Disconnected", -// masterHardwareId: connected_to, -// hardwareId: connected_to, -// hardwareIds: newSlaveHardwareIds, -// slaveNames: newSlaveNames, -// message: `Master ${connected_to} is disconnected along with ${newSlaveHardwareIds.length} new slave(s)`, -// disconnectedAt: lastDataTime -// }; - -// await Support.findOneAndUpdate( -// { supportId: "AWHYSU64" }, -// { -// $push: existingMasterIssue ? { -// "issues.$[elem].hardwareIds": { $each: newSlaveHardwareIds }, -// "issues.$[elem].slaveNames": { $each: newSlaveNames } -// } : { -// issues: newIssue -// }, -// $set: { -// updatedAt: new Date(), -// lastTicketRaisedAt: now.format("YYYY-MM-DD HH:mm:ss") -// } -// }, -// existingMasterIssue -// ? { arrayFilters: [{ "elem.hardwareId": connected_to, "elem.type": "GSM or LoRa Disconnected" }] } -// : {} -// ); -// } - -// } catch (error) { -// console.error("Error in raiseATicketLikeLogic:", error); -// } -// }; - -// const raiseATicketLikeLogic = async (customerId, connected_to) => { -// try { -// if (!customerId || !connected_to) return; - -// const sensors = await Insensors.find({ customerId }).lean(); -// const orders = await Order.find({ customerId }).lean(); - -// if (!sensors.length) return; - -// const masterSensor = sensors.find( -// s => s.hardwareId?.trim() === connected_to.trim() && s.type === "master" -// ); -// if (!masterSensor) return; - -// const orderMap = {}; -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); - -// const now = moment.tz("Asia/Kolkata"); - -// function getLatestDataRecord(records) { -// if (!records || records.length === 0) return null; -// return records.reduce((latest, record) => { -// if (!latest) return record; -// return new Date(record.date) > new Date(latest.date) ? record : latest; -// }, null); -// } - -// const allMasterIotData = await IotData.find({ hardwareId: connected_to }).lean(); -// const latestMasterRecord = getLatestDataRecord(allMasterIotData); - -// let masterConnectedStatus = "disconnected"; -// let lastDataTime = "No data"; -// let diffInMinutes = null; - -// if (latestMasterRecord?.date) { -// const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); -// diffInMinutes = now.diff(indiaTime, "minutes"); -// lastDataTime = indiaTime.format("DD-MM-YYYY HH:mm:ss"); -// if (diffInMinutes <= 2) masterConnectedStatus = "connected"; -// } - -// const connectedSlaves = sensors.filter( -// s => s.connected_to?.trim() === connected_to.trim() && s.type === "slave" -// ); - -// const slaveHardwareIds = connectedSlaves.map(s => s.tankhardwareId); -// const allSlaveIotData = await IotData.find({ hardwareId: { $in: slaveHardwareIds } }).lean(); - -// const disconnectedSlaves = []; - -// for (const slave of connectedSlaves) { -// const slaveRecords = allSlaveIotData.filter(d => d.hardwareId === slave.tankhardwareId); -// const latestSlaveRecord = getLatestDataRecord(slaveRecords); - -// let slaveStatus = "disconnected"; -// let slaveDiff = null; - -// if (latestSlaveRecord?.date) { -// const slaveTime = moment.tz(latestSlaveRecord.date, "Asia/Kolkata"); -// slaveDiff = now.diff(slaveTime, "minutes"); -// if (slaveDiff <= 2) slaveStatus = "connected"; -// } - -// if (slaveStatus === "disconnected") { -// disconnectedSlaves.push({ -// slaveHardwareId: slave.tankhardwareId, -// slaveName: slave.tankName || "Unknown Slave" -// }); -// } -// } - -// const supportRecord = await Support.findOne({ supportId: "AWHYSU64" }); -// if (!supportRecord) return; - -// const existingIssues = supportRecord.issues || []; - -// // Find existing unresolved issue -// const existingMasterIssue = existingIssues.find( -// issue => -// issue.hardwareId === connected_to && -// issue.type === "GSM or LoRa Disconnected" && -// issue.resolved !== true // <-- only unresolved -// ); - -// const alreadyReportedSlaves = new Set( -// existingMasterIssue?.hardwareIds || [] -// ); - -// const newSlaveHardwareIds = []; -// const newSlaveNames = []; - -// for (const slave of disconnectedSlaves) { -// if (!alreadyReportedSlaves.has(slave.slaveHardwareId)) { -// newSlaveHardwareIds.push(slave.slaveHardwareId); -// newSlaveNames.push(slave.slaveName); -// } -// } - -// const formattedNow = now.format("YYYY-MM-DD HH:mm:ss"); - -// if ( -// masterConnectedStatus === "disconnected" && -// diffInMinutes >= 2 && -// (newSlaveHardwareIds.length > 0 || !existingMasterIssue) -// ) { -// if (!existingMasterIssue) { -// // Create new issue with resolved: false -// const newIssue = { -// type: "GSM or LoRa Disconnected", -// masterHardwareId: connected_to, -// hardwareId: connected_to, -// hardwareIds: newSlaveHardwareIds, -// slaveNames: newSlaveNames, -// message: `Master ${connected_to} is disconnected along with ${newSlaveHardwareIds.length} new slave(s)`, -// disconnectedAt: lastDataTime, -// lastTicketRaisedAt: formattedNow, -// resolved: false // <--- add resolved flag here -// }; - -// await Support.findOneAndUpdate( -// { supportId: "AWHYSU64" }, -// { -// $push: { issues: newIssue }, -// $set: { updatedAt: new Date() } -// } -// ); -// } else { -// // Update existing unresolved issue only -// await Support.findOneAndUpdate( -// { supportId: "AWHYSU64" }, -// { -// $push: { -// "issues.$[elem].hardwareIds": { $each: newSlaveHardwareIds }, -// "issues.$[elem].slaveNames": { $each: newSlaveNames } -// }, -// $set: { -// "issues.$[elem].lastTicketRaisedAt": formattedNow, -// updatedAt: new Date() -// } -// }, -// { -// arrayFilters: [ -// { "elem.hardwareId": connected_to, "elem.type": "GSM or LoRa Disconnected", "elem.resolved": false } -// ] -// } -// ); -// } -// } -// } catch (error) { -// console.error("Error in raiseATicketLikeLogic:", error); -// } -// }; - - -// const cron = require("node-cron"); - -// cron.schedule("* * * * *", async () => { -// console.log("Running auto ticket check..."); - -// const allMasters = await Insensors.find({ type: "master" }).lean(); -// for (const master of allMasters) { -// await raiseATicketLikeLogic(master.customerId, master.hardwareId); -// } -// }); - -const cron = require("node-cron"); -const Admin = require("../models/admin"); - -// const raiseATicketLikeLogic = async (customerId, connected_to) => { -// try { -// if (!customerId || !connected_to) return; - -// const sensors = await Insensors.find({ customerId }).lean(); -// const orders = await Order.find({ customerId }).lean(); -// if (!sensors.length) return; - -// const masterSensor = sensors.find( -// s => s.hardwareId?.trim() === connected_to.trim() && s.type === "master" -// ); -// if (!masterSensor) return; - -// const orderMap = {}; -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); - -// const now = moment.tz("Asia/Kolkata"); - -// function getLatestDataRecord(records) { -// if (!records || records.length === 0) return null; -// return records.reduce((latest, record) => { -// if (!latest) return record; -// return new Date(record.date) > new Date(latest.date) ? record : latest; -// }, null); -// } - -// // 🔸 Master status check -// const allMasterIotData = await IotData.find({ hardwareId: connected_to }).lean(); -// const latestMasterRecord = getLatestDataRecord(allMasterIotData); - -// let masterConnectedStatus = "disconnected"; -// let lastDataTime = "No data"; -// let diffInMinutes = null; - -// if (latestMasterRecord?.date) { -// const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); -// diffInMinutes = now.diff(indiaTime, "minutes"); -// lastDataTime = indiaTime.format("DD-MM-YYYY HH:mm:ss"); -// if (diffInMinutes <= 2) masterConnectedStatus = "connected"; -// } - -// // 🔸 Slave status check -// const connectedSlaves = sensors.filter( -// s => s.connected_to?.trim() === connected_to.trim() && s.type === "slave" -// ); -// console.log("connectedSlaves",connectedSlaves) -// const slaveHardwareIds = connectedSlaves.map(s => s.tankhardwareId); -// // const allSlaveIotData = await IotData.find({ "tanks.tankhardwareId": { $in: slaveHardwareIds } }).lean(); -// const allSlaveIotData = await IotData.aggregate([ -// { $match: { "tanks.tankhardwareId": { $in: slaveHardwareIds } } }, -// { $project: { -// hardwareId: 1, -// date: 1, -// "tanks": { -// $filter: { -// input: "$tanks", -// as: "tank", -// cond: { $in: ["$$tank.tankhardwareId", slaveHardwareIds] } -// } -// } -// } -// } -// ]); -// console.log("allSlaveIotData",allSlaveIotData) -// // 🔹 Create map of latest tank data -// const latestTankDataMap = {}; -// for (const record of allSlaveIotData) { -// const baseDate = record.date; -// for (const tank of record.tanks || []) { -// const tankId = tank.tankhardwareId; -// const tankDate = tank.date || baseDate; - -// if (!tankId || !tankDate) continue; - -// if ( -// !latestTankDataMap[tankId] || -// new Date(tankDate) > new Date(latestTankDataMap[tankId].date) -// ) { -// latestTankDataMap[tankId] = { -// date: tankDate, -// time: tank.time, -// hardwareId: tankId -// }; -// } -// } -// } - -// const disconnectedSlaves = []; -// for (const slave of connectedSlaves) { -// const latestSlaveRecord = latestTankDataMap[slave.tankhardwareId]; - -// let slaveStatus = "disconnected"; -// if (latestSlaveRecord?.date) { -// const slaveTime = moment.tz(latestSlaveRecord.date, "Asia/Kolkata"); -// const slaveDiff = now.diff(slaveTime, "minutes"); -// if (slaveDiff <= 2) slaveStatus = "connected"; -// } - -// if (slaveStatus === "disconnected") { -// disconnectedSlaves.push({ -// slaveHardwareId: slave.tankhardwareId, -// slaveName: slave.tankName || "Unknown Slave" -// }); -// } -// } -// console.log(",disconnectedSlaves",disconnectedSlaves) - -// if (disconnectedSlaves.length === 0 && masterConnectedStatus === "connected") { -// return; // ✅ No ticket needed -// } - -// const supportRecord = await Support.findOne({ supportId: "AWHYSU64" }); -// if (!supportRecord) return; - -// const existingIssues = supportRecord.issues || []; -// const existingMasterIssue = existingIssues.find( -// issue => -// issue.hardwareId === connected_to && -// issue.type === "GSM or LoRa Disconnected" && -// issue.resolved !== true -// ); - -// const alreadyReportedSlaves = new Set(existingMasterIssue?.hardwareIds || []); -// const newSlaveHardwareIds = []; -// const newSlaveNames = []; - -// for (const slave of disconnectedSlaves) { -// if (!alreadyReportedSlaves.has(slave.slaveHardwareId)) { -// newSlaveHardwareIds.push(slave.slaveHardwareId); -// newSlaveNames.push(slave.slaveName); -// } -// } - -// const formattedNow = now.format("YYYY-MM-DD HH:mm:ss"); - -// // 🔸 Raise new issue -// if (!existingMasterIssue && (masterConnectedStatus === "disconnected" || disconnectedSlaves.length > 0)) { -// const newIssue = { -// type: "GSM or LoRa Disconnected", -// masterHardwareId: connected_to, -// hardwareId: connected_to, -// hardwareIds: newSlaveHardwareIds, -// slaveNames: newSlaveNames, -// message: `Master ${connected_to} is ${masterConnectedStatus} with ${disconnectedSlaves.length} disconnected slave(s)`, -// disconnectedAt: lastDataTime, -// lastTicketRaisedAt: formattedNow, -// resolved: false -// }; -// await Support.findOneAndUpdate( -// { supportId: "AWHYSU64" }, -// { $push: { issues: newIssue }, $set: { updatedAt: new Date() } } -// ); -// } - -// // 🔸 Update existing issue with new disconnected slaves -// if (existingMasterIssue && newSlaveHardwareIds.length > 0) { -// await Support.findOneAndUpdate( -// { supportId: "AWHYSU64" }, -// { -// $push: { -// "issues.$[elem].hardwareIds": { $each: newSlaveHardwareIds }, -// "issues.$[elem].slaveNames": { $each: newSlaveNames } -// }, -// $set: { -// "issues.$[elem].lastTicketRaisedAt": formattedNow, -// updatedAt: new Date() -// } -// }, -// { -// arrayFilters: [ -// { -// "elem.hardwareId": connected_to, -// "elem.type": "GSM or LoRa Disconnected", -// "elem.resolved": false -// } -// ] -// } -// ); -// } -// } catch (error) { -// console.error("Error in raiseATicketLikeLogic:", error); -// } -// }; - -// const raiseATicketLikeLogic = async (customerId, connected_to) => { -// try { -// if (!customerId || !connected_to) return; - -// const normalizedConnectedTo = connected_to.trim().toLowerCase(); - -// const sensors = await Insensors.find({ customerId }).lean(); -// if (!sensors.length) return; - -// const masterSensor = sensors.find( -// (s) => s.hardwareId?.trim().toLowerCase() === normalizedConnectedTo && s.type === "master" -// ); -// if (!masterSensor) return; - -// const orders = await Order.find({ customerId }).lean(); - -// const connectedSlaves = sensors.filter( -// (s) => s.connected_to?.trim().toLowerCase() === normalizedConnectedTo && s.type === "slave" -// ); - -// const disconnectedSlaves = connectedSlaves -// .filter((s) => s.connected_status === "disconnected") -// .map((s) => ({ -// slaveHardwareId: s.tankhardwareId?.trim().toLowerCase(), -// slaveName: s.tankName || "Unknown Slave", -// })); - -// const supportRecord = await Support.findOne({ supportId: "AWHYSU64" }); -// if (!supportRecord) return; - -// const now = moment.tz("Asia/Kolkata"); -// const formattedNow = now.format("YYYY-MM-DD HH:mm:ss"); - -// const existingMasterIssue = supportRecord.issues.find( -// (issue) => -// issue.hardwareId?.trim().toLowerCase() === normalizedConnectedTo && -// issue.type === "GSM or LoRa Disconnected" && -// !issue.resolved && -// !issue.movedToCategory -// ); - -// if (existingMasterIssue) { -// if (masterSensor.connected_status === "connected") { -// return; -// } -// return; -// } - -// const existingSlaveHardwareIds = new Set(); -// supportRecord.issues -// .filter( -// (issue) => -// issue.hardwareId?.trim().toLowerCase() === normalizedConnectedTo && -// !issue.movedToCategory -// ) -// .forEach((issue) => { -// (issue.hardwareIds || []).forEach((id) => { -// if (typeof id === "string") { -// existingSlaveHardwareIds.add(id.trim().toLowerCase()); -// } -// }); -// }); - -// const newSlaveHardwareIds = []; -// const newSlaveNames = []; - -// for (const slave of disconnectedSlaves) { -// const sensorCurrent = sensors.find( -// (s) => s.tankhardwareId?.trim().toLowerCase() === slave.slaveHardwareId -// ); -// console.log("sensorCurrent",sensorCurrent) -// if ( -// sensorCurrent && -// sensorCurrent.connected_status === "disconnected" && -// !existingSlaveHardwareIds.has(slave.slaveHardwareId) -// ) { -// newSlaveHardwareIds.push(slave.slaveHardwareId); -// newSlaveNames.push(slave.slaveName); -// } -// } - -// // 👇 Even if no new slaves found, if master is disconnected, still raise a ticket -// const masterDisconnected = masterSensor.connected_status !== "connected"; - -// if (!masterDisconnected && newSlaveHardwareIds.length === 0) { -// return; -// } - -// const lastDataTime = -// masterSensor.connected_gsm_date && masterSensor.connected_gsm_time -// ? `${masterSensor.connected_gsm_date} ${masterSensor.connected_gsm_time}` -// : "No data"; - -// const message = `Master ${connected_to} is ${masterSensor.connected_status || "disconnected"}${newSlaveHardwareIds.length > 0 -// ? ` with ${newSlaveHardwareIds.length} disconnected slave(s)` -// : ""}`; - -// const newIssue = { -// type: "GSM or LoRa Disconnected", -// masterHardwareId: normalizedConnectedTo, -// hardwareId: normalizedConnectedTo, -// hardwareIds: newSlaveHardwareIds, -// slaveNames: newSlaveNames, -// message, -// disconnectedAt: lastDataTime, -// lastTicketRaisedAt: formattedNow, -// resolved: false, -// movedToCategory: false, -// createdAt: formattedNow, -// }; - -// await Support.findOneAndUpdate( -// { supportId: "AWHYSU64" }, -// { -// $push: { issues: newIssue }, -// $set: { updatedAt: new Date() }, -// } -// ); -// } catch (error) { -// console.error("Error in raiseATicketLikeLogic:", error); -// } -// }; - - - -// Your existing raiseATicketLikeLogic function must be accessible - -// ⬇️ Include the function here or import it if it's in another file -const updateConnectedStatusOnly = async (customerId, hardwareId) => { - try { - const sensors = await Insensors.find({ customerId }); - if (!sensors.length) return; - - const now = moment.tz("Asia/Kolkata"); - const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); - if (!latestRecord) return; - - const gsmTime = moment.tz(latestRecord.date, "Asia/Kolkata"); - const gsmDiff = now.diff(gsmTime, "minutes"); - const gsmConnected = gsmDiff <= 1; - - const connectedSlaves = sensors.filter(s => s.connected_to?.trim() === hardwareId); - const tankMap = {}; - (latestRecord.tanks || []).forEach(t => { - if (t.tankhardwareId) { - tankMap[t.tankhardwareId.trim()] = t; - } - }); - - const allSlavesConnected = connectedSlaves.every(slave => { - const slaveId = slave.tankhardwareId?.trim(); - const tank = tankMap[slaveId]; - if (!tank || !tank.date || tank.tankHeight === "0") return false; - const loraTime = moment.tz(tank.date, "Asia/Kolkata"); - return now.diff(loraTime, "minutes") <= 1; - }); - - const masterStatus = gsmConnected && allSlavesConnected ? "connected" : "disconnected"; - await Insensors.updateOne({ hardwareId, customerId }, { $set: { connected_status: masterStatus } }); - - for (const slave of connectedSlaves) { - const slaveId = slave.tankhardwareId?.trim(); - const tank = tankMap[slaveId]; - - let status = "disconnected"; - if (tank && tank.date && tank.tankHeight !== "0") { - const loraTime = moment.tz(tank.date, "Asia/Kolkata"); - if (now.diff(loraTime, "minutes") <= 1) status = "connected"; - } - - await Insensors.updateOne({ hardwareId: slave.hardwareId }, { $set: { connected_status: status } }); - } - } catch (error) { - console.error("❌ updateConnectedStatusOnly error:", error); - } -}; - - - -// const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => { -// const now = new Date(); -// const formattedNow = new Date(now.getTime() + 19800000) // +05:30 offset in ms -// .toISOString() -// .replace("T", " ") -// .substring(0, 19); - -// // Check if already categorized -// const alreadyCategorized = supportRecord.categorizedIssues.some( -// (catIssue) => catIssue.hardwareId === masterHardwareId -// ); - -// // Check if already raised and unresolved & not categorized -// const alreadyRaisedUnresolved = supportRecord.issues.some( -// (issue) => -// issue.hardwareId === masterHardwareId && -// issue.resolved === false && -// issue.movedToCategory === false -// ); - -// if (alreadyCategorized) { -// console.log(`⛔ Ticket for ${masterHardwareId} already categorized. Skipping.`); -// return; -// } - -// if (alreadyRaisedUnresolved) { -// console.log(`⛔ Unresolved ticket already exists for ${masterHardwareId}. Skipping.`); -// return; -// } - -// const slaveHardwareIds = slaveData.map((slave) => slave.tankhardwareId); -// const slaveNames = slaveData.map((slave) => slave.sensorName || slave.tankName || ""); - -// const newIssue = { -// type: "GSM or LoRa Disconnected", -// masterHardwareId, -// hardwareId: masterHardwareId, -// hardwareIds: slaveHardwareIds, -// slaveNames: slaveNames, -// resolved: false, -// movedToCategory: false, -// lastTicketRaisedAt: formattedNow, -// createdAt: formattedNow, -// }; - -// supportRecord.issues.push(newIssue); -// supportRecord.lastTicketRaisedAt = formattedNow; - -// await supportRecord.save(); -// console.log(`✅ New ticket raised for ${masterHardwareId}`); -// }; - - - -// exports.raiseATicket = async (req, reply) => { -// try { -// const { customerId, connected_to } = req.params; - -// if (!customerId || !connected_to) { -// return reply.code(400).send({ error: "customerId and connected_to are required" }); -// } - -// const masterDevice = await Insensors.findOne({ -// customerId, -// hardwareId: connected_to, -// type: "master" -// }).lean(); - -// if (!masterDevice) { -// return reply.code(404).send({ message: "Master device not found" }); -// } - -// const allSlaves = await Insensors.find({ -// connected_to, -// customerId, -// type: "slave" -// }).lean(); - -// const disconnectedSlaves = allSlaves.filter( -// slave => slave.connected_status === "disconnected" -// ); - -// const hasDisconnectedSlaves = disconnectedSlaves.length > 0; -// const isMasterDisconnected = masterDevice.connected_status === "disconnected"; - -// // If nothing is disconnected, no ticket should be raised -// if (!isMasterDisconnected && !hasDisconnectedSlaves) { -// return reply.code(200).send({ message: "All devices are connected. No ticket needed." }); -// } - -// const supportId = `${customerId}_${connected_to}`; -// const existingSupport = await Support.findOne({ supportId }); - -// // Helper to check if hardwareId is already in unresolved & not moved -// const isIssueAlreadyTracked = (supportDoc, hardwareId) => { -// return supportDoc.issues?.some(issue => { -// const allHwIds = [ -// issue.hardwareId?.toLowerCase(), -// ...(issue.hardwareIds?.map(id => id?.toLowerCase()) || []) -// ]; -// return ( -// allHwIds.includes(hardwareId.toLowerCase()) && -// !issue.resolved && -// issue.movedToCategory !== true -// ); -// }); -// }; - -// const nowTime = moment().tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss"); - -// if (existingSupport) { -// let updated = false; - -// // Add master if disconnected and not already tracked -// if (isMasterDisconnected && !isIssueAlreadyTracked(existingSupport, masterDevice.hardwareId)) { -// existingSupport.issues.push({ -// type: "master", -// hardwareId: masterDevice.hardwareId, -// masterName: masterDevice.deviceName || "", -// resolved: false, -// movedToCategory: false, -// createdAt: nowTime, -// lastTicketRaisedAt: nowTime -// }); -// updated = true; -// } - -// // Add each disconnected slave if not already tracked -// for (const slave of disconnectedSlaves) { -// if (isIssueAlreadyTracked(existingSupport, slave.hardwareId)) continue; - -// // If issue for this master already exists, append slave -// let masterIssue = existingSupport.issues.find(issue => -// issue.type === "master" && -// issue.hardwareId === masterDevice.hardwareId && -// !issue.resolved -// ); - -// if (!masterIssue) { -// // create new slave-type issue -// existingSupport.issues.push({ -// type: "slave", -// hardwareId: slave.hardwareId, -// masterHardwareId: masterDevice.hardwareId, -// slaveName: slave.deviceName || "", -// resolved: false, -// movedToCategory: false, -// createdAt: nowTime, -// lastTicketRaisedAt: nowTime -// }); -// } else { -// if (!masterIssue.hardwareIds) masterIssue.hardwareIds = []; -// if (!masterIssue.slaveNames) masterIssue.slaveNames = []; -// masterIssue.hardwareIds.push(slave.hardwareId); -// masterIssue.slaveNames.push(slave.deviceName || ""); -// masterIssue.lastTicketRaisedAt = nowTime; -// } - -// updated = true; -// } - -// if (updated) { -// await existingSupport.save(); -// return reply.code(201).send({ message: "Support ticket updated with new disconnected issues." }); -// } else { -// return reply.code(200).send({ message: "No new disconnected issues to add." }); -// } - -// } else { -// // Create new ticket -// const issues = []; - -// if (isMasterDisconnected) { -// issues.push({ -// type: "master", -// hardwareId: masterDevice.hardwareId, -// masterName: masterDevice.deviceName || "", -// resolved: false, -// movedToCategory: false, -// createdAt: nowTime, -// lastTicketRaisedAt: nowTime -// }); -// } - -// for (const slave of disconnectedSlaves) { -// issues.push({ -// type: "slave", -// hardwareId: slave.hardwareId, -// masterHardwareId: masterDevice.hardwareId, -// slaveName: slave.deviceName || "", -// resolved: false, -// movedToCategory: false, -// createdAt: nowTime, -// lastTicketRaisedAt: nowTime -// }); -// } - -// const newSupport = new Support({ -// supportId, -// customerId, -// connected_to, -// createdAt: nowTime, -// updatedAt: nowTime, -// status: "open", -// issues -// }); - -// await newSupport.save(); -// return reply.code(201).send({ message: "Support ticket created successfully." }); -// } - -// } catch (error) { -// console.error("Error in raiseATicket:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - - - - -// cron.schedule("* * * * *", async () => { -// console.log("Running auto ticket check..."); -// const allMasters = await Insensors.find({ }).lean(); -// for (const master of allMasters) { -// await raiseATicketLikeLogic(master.customerId, master.hardwareId); -// } -// }); - -// cron.schedule("*/1 * * * *", async () => { -// try { -// console.log("🔁 Running auto-disconnect ticket check..."); - -// // Find all master sensors -// const allMasters = await Insensors.find({ type: "master" }).lean(); - -// for (const master of allMasters) { -// const customerId = master.customerId; -// const hardwareId = master.hardwareId; - -// if (!customerId || !hardwareId) continue; - -// // Find slaves connected to this master -// const connectedSlaves = await Insensors.find({ -// connected_to: hardwareId, -// type: "slave" -// }).lean(); - -// // Filter disconnected slaves -// const disconnectedSlaves = connectedSlaves.filter( -// (s) => s.connected_status === "disconnected" -// ); - -// const masterIsDisconnected = master.connected_status === "disconnected"; - -// // Only raise ticket if master is disconnected or has disconnected slaves -// if (masterIsDisconnected || disconnectedSlaves.length > 0) { -// await raiseATicketLikeLogic(customerId, hardwareId); -// } -// } - -// console.log("✅ Auto ticket check completed."); -// } catch (err) { -// console.error("Cron error:", err); -// } -// }); - -const generateTicketId = () => { - return "AWTKT" + Date.now(); // Or use UUID or nanoid -}; - - -// const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => { -// const now = new Date(); -// const formattedNow = new Date(now.getTime() + 19800000) // +05:30 offset in ms -// .toISOString() -// .replace("T", " ") -// .substring(0, 19); - -// // Check if already categorized -// const alreadyCategorized = supportRecord.categorizedIssues.some( -// (catIssue) => catIssue.hardwareId === masterHardwareId -// ); -// if (alreadyCategorized) { -// console.log(`⛔ Ticket for ${masterHardwareId} already categorized. Skipping.`); -// return; -// } - -// // Prepare slave hardwareIds and names -// const slaveHardwareIds = slaveData.map((slave) => slave.tankhardwareId).sort(); -// const slaveNames = slaveData.map((slave) => slave.sensorName || slave.tankName || "").sort(); - -// // Check for existing unresolved and not moved-to-category issue -// const duplicateExists = supportRecord.issues.some((issue) => { -// const existingSlaveIds = (issue.hardwareIds || []).sort(); -// const existingSlaveNames = (issue.slaveNames || []).sort(); - -// return ( -// issue.hardwareId === masterHardwareId && -// issue.masterHardwareId === masterHardwareId && -// issue.resolved === false && -// issue.movedToCategory === false && -// JSON.stringify(existingSlaveIds) === JSON.stringify(slaveHardwareIds) && -// JSON.stringify(existingSlaveNames) === JSON.stringify(slaveNames) -// ); -// }); - -// if (duplicateExists) { -// console.log(`⛔ Duplicate unresolved issue already exists for ${masterHardwareId}. Skipping.`); -// return; -// } - -// // Create new issue -// const newIssue = { -// ticketId: generateTicketId(), -// type: "GSM or LoRa Disconnected", -// masterHardwareId, -// hardwareId: masterHardwareId, -// hardwareIds: slaveHardwareIds, -// slaveNames: slaveNames, -// resolved: false, -// movedToCategory: false, -// lastTicketRaisedAt: formattedNow, -// createdAt: formattedNow, -// }; -// console.log("newIssue",newIssue) -// supportRecord.issues.push(newIssue); -// supportRecord.lastTicketRaisedAt = formattedNow; -// await Support.findByIdAndUpdate( -// supportRecord._id, -// { -// $push: { issues: newIssue }, -// $set: { lastTicketRaisedAt: formattedNow } -// }, -// { new: true } -// ); - -// console.log("") -// await supportRecord.save(); -// console.log(`✅ New ticket raised for ${masterHardwareId}`); -// }; - -// const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => { -// const now = new Date(); -// const formattedNow = new Date(now.getTime() + 19800000) -// .toISOString() -// .replace("T", " ") -// .substring(0, 19); - -// // Check if already categorized -// const alreadyCategorized = supportRecord.categorizedIssues.some( -// (catIssue) => catIssue.hardwareId === masterHardwareId -// ); -// if (alreadyCategorized) { -// console.log(`⛔ Ticket for ${masterHardwareId} already categorized. Skipping.`); -// return; -// } - -// // Prepare slave hardwareIds and names -// const slaveHardwareIds = slaveData.map((slave) => slave.tankhardwareId).sort(); -// const slaveNames = slaveData.map((slave) => slave.sensorName || slave.tankName || "").sort(); - -// // Check for existing unresolved and not moved-to-category issue -// const duplicateExists = supportRecord.issues.some((issue) => { -// const existingSlaveIds = (issue.hardwareIds || []).sort(); -// const existingSlaveNames = (issue.slaveNames || []).sort(); - -// return ( -// issue.hardwareId === masterHardwareId && -// issue.masterHardwareId === masterHardwareId && -// issue.resolved === false && -// issue.movedToCategory === false && -// JSON.stringify(existingSlaveIds) === JSON.stringify(slaveHardwareIds) && -// JSON.stringify(existingSlaveNames) === JSON.stringify(slaveNames) -// ); -// }); - -// if (duplicateExists) { -// console.log(`⛔ Duplicate unresolved issue already exists for ${masterHardwareId}. Skipping.`); -// return; -// } - -// // Create new issue -// const newIssue = { -// ticketId: generateTicketId(), -// type: "GSM or LoRa Disconnected", -// masterHardwareId, -// hardwareId: masterHardwareId, -// hardwareIds: slaveHardwareIds, -// slaveNames: slaveNames, -// resolved: false, -// movedToCategory: false, -// lastTicketRaisedAt: formattedNow, -// createdAt: formattedNow, -// }; - -// console.log("newIssue", newIssue); - -// // ✅ Atomic update -// await Support.findByIdAndUpdate( -// supportRecord._id, -// { -// $push: { issues: newIssue }, -// $set: { lastTicketRaisedAt: formattedNow } -// }, -// { new: true } -// ); - -// console.log(`✅ New ticket raised for ${masterHardwareId}`); -// }; - -// cron.schedule("*/1 * * * *", async () => { -// try { -// console.log("🔁 Running auto-disconnect ticket check..."); - -// // Step 1: Get all support profiles -// const allSupportProfiles = await Support.find({}); - -// for (const supportRecord of allSupportProfiles) { -// const supportId = supportRecord.supportId; -// if (!supportId) continue; - -// // Step 2: Find all master sensors -// const allMasters = await Insensors.find({ type: "master" }).lean(); - -// for (const master of allMasters) { -// const customerId = master.customerId; -// const hardwareId = master.hardwareId; - -// if (!customerId || !hardwareId) continue; - -// // ✅ Update GSM and LoRa connection statuses -// await updateConnectedStatusOnly(customerId, hardwareId); - -// // 🔄 Re-fetch updated master and slaves -// const updatedMaster = await Insensors.findOne({ hardwareId, customerId }).lean(); -// const connectedSlaves = await Insensors.find({ -// connected_to: hardwareId, -// type: "slave" -// }).lean(); - -// // Step 3: Check disconnections -// const disconnectedSlaves = connectedSlaves.filter( -// (s) => s.connected_status === "disconnected" -// ); -// const masterIsDisconnected = updatedMaster.connected_status === "disconnected"; - -// // Step 4: Raise ticket if needed -// if (masterIsDisconnected || disconnectedSlaves.length > 0) { -// await raiseATicketLikeLogic(supportRecord, hardwareId, disconnectedSlaves); -// } -// } -// } - -// console.log("✅ Auto ticket check completed."); -// } catch (err) { -// console.error("❌ Cron error:", err); -// } -// }); - -// const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => { -// const now = new Date(); -// const formattedNow = new Date(now.getTime() + 19800000) // +05:30 offset in ms -// .toISOString() -// .replace("T", " ") -// .substring(0, 19); - -// // Check if already categorized -// const alreadyCategorized = supportRecord.categorizedIssues.some( -// (catIssue) => catIssue.hardwareId === masterHardwareId -// ); -// if (alreadyCategorized) { -// console.log(`⛔ Ticket for ${masterHardwareId} already categorized. Skipping.`); -// return; -// } - -// // Prepare slave hardwareIds and names -// const slaveHardwareIds = slaveData.map((slave) => slave.tankhardwareId).sort(); -// const slaveNames = slaveData.map((slave) => slave.sensorName || slave.tankName || "").sort(); - -// // Check for existing unresolved and not moved-to-category issue -// const duplicateExists = supportRecord.issues.some((issue) => { -// const existingSlaveIds = (issue.hardwareIds || []).sort(); -// const existingSlaveNames = (issue.slaveNames || []).sort(); - -// return ( -// issue.hardwareId === masterHardwareId && -// issue.masterHardwareId === masterHardwareId && -// issue.resolved === false && -// issue.movedToCategory === false && -// JSON.stringify(existingSlaveIds) === JSON.stringify(slaveHardwareIds) && -// JSON.stringify(existingSlaveNames) === JSON.stringify(slaveNames) -// ); -// }); - -// if (duplicateExists) { -// console.log(`⛔ Duplicate unresolved issue already exists for ${masterHardwareId}. Skipping.`); -// return; -// } - -// // Create new issue -// const newIssue = { -// type: "GSM or LoRa Disconnected", -// masterHardwareId, -// hardwareId: masterHardwareId, -// hardwareIds: slaveHardwareIds, -// slaveNames: slaveNames, -// resolved: false, -// movedToCategory: false, -// lastTicketRaisedAt: formattedNow, -// createdAt: formattedNow, -// }; - -// supportRecord.issues.push(newIssue); -// supportRecord.lastTicketRaisedAt = formattedNow; - -// await supportRecord.save(); -// console.log(`✅ New ticket raised for ${masterHardwareId}`); -// }; - -// const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => { -// const now = new Date(); -// const formattedNow = new Date(now.getTime() + 19800000) // +05:30 offset in ms -// .toISOString() -// .replace("T", " ") -// .substring(0, 19); - -// // Check if already categorized -// const alreadyCategorized = supportRecord.categorizedIssues.some( -// (catIssue) => catIssue.hardwareId === masterHardwareId -// ); -// if (alreadyCategorized) { -// console.log(`⛔ Ticket for ${masterHardwareId} already categorized. Skipping.`); -// return; -// } - -// // Check for existing unresolved, uncategorized ticket for same master -// const duplicateExists = supportRecord.issues.some((issue) => { -// return ( -// issue.hardwareId === masterHardwareId && -// issue.masterHardwareId === masterHardwareId && -// issue.resolved === false && -// issue.movedToCategory === false -// ); -// }); - -// if (duplicateExists) { -// console.log(`⛔ Duplicate unresolved issue already exists for ${masterHardwareId}. Skipping.`); -// return; -// } - -// // Prepare slave hardwareIds and names -// const slaveHardwareIds = slaveData.map((slave) => slave.tankhardwareId).sort(); -// const slaveNames = slaveData.map((slave) => slave.sensorName || slave.tankName || "").sort(); - -// // Create new issue -// const newIssue = { -// type: "GSM or LoRa Disconnected", -// masterHardwareId, -// hardwareId: masterHardwareId, -// hardwareIds: slaveHardwareIds, -// slaveNames: slaveNames, -// resolved: false, -// movedToCategory: false, -// lastTicketRaisedAt: formattedNow, -// createdAt: formattedNow, -// }; - -// supportRecord.issues.push(newIssue); -// supportRecord.lastTicketRaisedAt = formattedNow; - -// await supportRecord.save(); -// console.log(`✅ New ticket raised for ${masterHardwareId}`); -// }; - -const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => { - const now = new Date(); - const formattedNow = new Date(now.getTime() + 19800000) // +05:30 IST offset - .toISOString() - .replace("T", " ") - .substring(0, 19); - - // ✅ If issue already exists anywhere for this hardwareId, SKIP - const issueAlreadyExists = [ - ...supportRecord.issues, - ...supportRecord.categorizedIssues, - //...supportRecord.resolvedIssues - ].some((issue) => issue.hardwareId === masterHardwareId); - - if (issueAlreadyExists) { - console.log(`⛔ Issue already exists for ${masterHardwareId}. Not raising again.`); - return; - } - - // ✅ Prepare slave hardwareIds and names - const slaveHardwareIds = slaveData.map((s) => s.tankhardwareId).sort(); - const slaveNames = slaveData.map((s) => s.sensorName || s.tankName || "").sort(); - - // ✅ Create new issue - const newIssue = { - type: "GSM or LoRa Disconnected", - masterHardwareId, - hardwareId: masterHardwareId, - hardwareIds: slaveHardwareIds, - slaveNames: slaveNames, - resolved: false, - movedToCategory: false, - lastTicketRaisedAt: formattedNow, - createdAt: formattedNow, - }; - - supportRecord.issues.push(newIssue); - supportRecord.lastTicketRaisedAt = formattedNow; - - await supportRecord.save(); - console.log(`✅ New ticket raised for ${masterHardwareId}`); -}; - - -cron.schedule("*/1 * * * *", async () => { - try { - console.log("🔁 Running auto-disconnect ticket check..."); - - // Step 1: Get all support profiles - const allSupportProfiles = await Support.find({}); - - for (const supportRecord of allSupportProfiles) { - const supportId = supportRecord.supportId; - if (!supportId) continue; - - // Step 2: Find all master sensors - const allMasters = await Insensors.find({ type: "master" }).lean(); - - for (const master of allMasters) { - const customerId = master.customerId; - const hardwareId = master.hardwareId; - - if (!customerId || !hardwareId) continue; - - // ✅ Update GSM and LoRa connection statuses - await updateConnectedStatusOnly(customerId, hardwareId); - - // 🔄 Re-fetch updated master and slaves - const updatedMaster = await Insensors.findOne({ hardwareId, customerId }).lean(); - const connectedSlaves = await Insensors.find({ - connected_to: hardwareId, - type: "slave" - }).lean(); - - // Step 3: Check disconnections - const disconnectedSlaves = connectedSlaves.filter( - (s) => s.connected_status === "disconnected" - ); - const masterIsDisconnected = updatedMaster.connected_status === "disconnected"; - - // Step 4: Raise ticket if needed - if (masterIsDisconnected || disconnectedSlaves.length > 0) { - await raiseATicketLikeLogic(supportRecord, hardwareId, disconnectedSlaves); - } - } - } - - console.log("✅ Auto ticket check completed."); - } catch (err) { - console.error("❌ Cron error:", err); - } -}); - - - -exports.raiseATicketBuildingDetails = async (req, reply) => { - try { - const { customerId, connected_to, installationId } = req.params; - - if (!customerId || !connected_to || !installationId) { - return reply.code(400).send({ error: "customerId, connected_to, and installationId are required" }); - } - - const customer = await User.findOne({ customerId, installationId }).lean(); - if (!customer) { - return reply.code(404).send({ message: "Customer not found." }); - } - - const sensors = await Insensors.find({ customerId }); - if (!sensors.length) { - return reply.code(404).send({ message: "No sensors found for this customer." }); - } - - const masterSensor = sensors.find(s => (s.hardwareId?.trim() === connected_to.trim())); - if (!masterSensor) { - return reply.code(404).send({ message: "Master hardwareId not found." }); - } - - const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean(); - if (!latestMasterRecord) { - return reply.code(404).send({ message: "No IoT data found for this hardwareId." }); - } - - const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); - const now = moment.tz("Asia/Kolkata"); - const formattedNow = now.format("YYYY-MM-DD HH:mm:ss"); - - const diffInMinutesMaster = now.diff(indiaTime, "minutes"); - - if (diffInMinutesMaster > 1) { - await Insensors.updateOne( - { hardwareId: connected_to }, - { $set: { lastTicketRaisedAt: formattedNow } } - ); - } - - const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === connected_to.trim()); - - // ✅ Check if any slave is disconnected - const disconnectedSlave = connectedSlaves.find(slave => slave.connected_status === "disconnected"); - if (disconnectedSlave) { - return reply.code(400).send({ - error: `Slave device ${disconnectedSlave.hardwareId} is disconnected. Cannot raise ticket.` - }); - } - - for (const slave of connectedSlaves) { - const slaveId = slave.hardwareId?.trim(); - const matchedTank = latestMasterRecord.tanks.find(tank => tank.tankhardwareId === slaveId); - - if (matchedTank && matchedTank.date) { - const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata"); - const loraDiffInMinutes = now.diff(tankTime, "minutes"); - - if (loraDiffInMinutes > 1) { - await Insensors.updateOne( - { hardwareId: slaveId }, - { $set: { lastTicketRaisedAt: formattedNow } } - ); - } - } - } - - await Support.updateOne( - { supportId: "AWHYSU64" }, - { $set: { lastTicketRaisedAt: formattedNow } } - ); - - // Fetch updated values - const updatedMasterSensor = await Insensors.findOne({ hardwareId: connected_to }).lean(); - const updatedSupport = await Support.findOne({ supportId: "AWHYSU64" }).lean(); - - return reply.send({ - status_code: 200, - customer, - lastTicketRaisedAt: { - masterSensor: updatedMasterSensor?.lastTicketRaisedAt || null, - support: updatedSupport?.lastTicketRaisedAt || null - } - }); - - } catch (error) { - console.error("Error raising ticket:", error); - return reply.code(500).send({ error: "Internal server error" }); - } -}; - - -exports.raiseATicketSlave = async (req, reply) => { - try { - const { customerId, connected_to } = req.params; - - if (!customerId || !connected_to) { - return reply.code(400).send({ error: "customerId and connected_to are required" }); - } - - const sensors = await Insensors.find({ customerId }); - const masterSensor = sensors.find(s => s.hardwareId?.trim() === connected_to.trim()); - - if (!masterSensor) { - return reply.code(404).send({ message: "Master hardwareId not found." }); - } - - const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean(); - - if (!latestMasterRecord) { - return reply.code(404).send({ message: "No IoT data found for this hardwareId." }); - } - - const now = moment().tz("Asia/Kolkata"); - const masterTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); - const diff = now.diff(masterTime, "minutes"); - - const gsm_connected_status = diff <= 1 ? "connected" : "disconnected"; - const gsmStatus = gsm_connected_status === "connected" ? "GSM Connected" : "GSM Disconnected"; - - const formattedTime = masterTime.format("HH:mm:ss"); - const formattedDate = masterTime.format("DD-MM-YYYY"); - - const tanks = (latestMasterRecord.tanks || []).map(tank => { - const tankTime = moment.tz(tank.date, "Asia/Kolkata"); - const timeDiff = now.diff(tankTime, "minutes"); - - return { - ...tank, - time: tankTime.format("HH:mm:ss"), - connected_status: timeDiff <= 1 ? "connected" : "disconnected" - }; - }); - - const responseData = { - hardwareId: connected_to, - gsm_connected_status, - gsmStatus, - connected_gsm_date: formattedDate, - connected_gsm_time: formattedTime, - gsm_last_check_time: now.format("DD-MM-YYYY HH:mm:ss"), - tanks, - date: latestMasterRecord.date, - time: formattedTime - }; - - return reply.send({ - status_code: 200, - message: "Success", - data: responseData - }); - - } catch (error) { - console.error("Error in raiseATicketSlave:", error); - return reply.code(500).send({ error: "Internal server error" }); - } -}; - - - - - - -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const allIssues = supportRecord.issues || []; -// const hardwareSet = new Set(); - -// // Collect all hardware IDs from issues -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); // GSM -// if (Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach(id => hardwareSet.add(id)); // LoRa slaves -// } -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); // LoRa master -// } - -// const hardwareIds = [...hardwareSet]; -// const sensors = await Insensors.find({ hardwareId: { $in: hardwareIds } }).lean(); -// console.log("sensors",sensors) -// // Map sensors by hardwareId -// const sensorMap = {}; -// for (const sensor of sensors) { -// sensorMap[sensor.hardwareId] = sensor; -// } - -// const masterMap = {}; - -// for (const issue of allIssues) { -// // GSM Disconnected -// if (issue.type === "GSM or LoRa Disconnected" && issue.hardwareId) { -// const sensor = sensorMap[issue.hardwareId]; -// if (sensor && sensor.type === "master") { -// masterMap[sensor.hardwareId] = { -// hardwareId: sensor.hardwareId, -// masterName: sensor.masterName || null, -// location: sensor.location || "", -// type: "master", -// connected_status: sensor.connected_status, -// gsm_last_check_time: sensor.gsm_last_check_time, -// gsm_last_disconnect_time: sensor.gsm_last_disconnect_time, -// connected_gsm_date: sensor.connected_gsm_date, -// connected_gsm_time: sensor.connected_gsm_time, -// connected_lora_date: sensor.connected_lora_date, -// connected_lora_time: sensor.connected_lora_time, -// support_gsm_last_check_time: sensor.support_gsm_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } -// } - -// // LoRa Disconnected -// if (issue.type === "GSM or LoRa Disconnected" && issue.masterHardwareId) { -// const masterSensor = sensorMap[issue.masterHardwareId]; -// if (!masterSensor || masterSensor.type !== "master") continue; - -// if (!masterMap[masterSensor.hardwareId]) { -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: masterSensor.masterName || null, -// location: masterSensor.location || "", -// type: "master", -// connected_status: masterSensor.connected_status, -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_lora_last_check_time: masterSensor.support_lora_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; - -// // First try from issue.hardwareIds -// let slaveIds = Array.isArray(issue.hardwareIds) ? issue.hardwareIds : []; - -// // If empty, fallback to slaves connected to this master -// // If empty, fallback to slaves connected to this master's tankHardwareId -// console.log("slaveIds",slaveIds) -// if (slaveIds.length === 0) { -// // fallback: find slaves connected to this master hardwareId -// const fallbackSlaves = await Insensors.find({ -// connected_to: issue.masterHardwareId, // or masterSensor.hardwareId -// type: "slave" -// }).lean(); - -// console.log("fallbackSlaves", fallbackSlaves); -// for (const slaveSensor of fallbackSlaves) { -// master.connected_slaves.push({ -// hardwareId: slaveSensor.hardwareId, -// tankName: slaveSensor.tankName || "", -// location: slaveSensor.location || "", -// connected_status: slaveSensor.connected_status, -// connected_lora_time: slaveSensor.connected_lora_time, -// connected_lora_date: slaveSensor.connected_lora_date, -// lora_last_check_time: slaveSensor.lora_last_check_time, -// lora_last_disconnect_time: slaveSensor.lora_last_disconnect_time, -// connected_to: slaveSensor.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slaveSensor.typeOfWater, -// tankHeight: slaveSensor.tankHeight, -// support_lora_last_check_time: slaveSensor.support_lora_last_check_time, -// }); -// master.connected_slave_count++; -// } -// } - -// else { -// // Populate slaves based on provided hardwareIds -// for (const slaveId of slaveIds) { -// const slaveSensor = sensorMap[slaveId]; -// if (slaveSensor && slaveSensor.type === "slave") { -// master.connected_slaves.push({ -// hardwareId: slaveSensor.hardwareId, -// tankName: slaveSensor.tankName || "", -// location: slaveSensor.location || "", -// connected_status: slaveSensor.connected_status, -// connected_lora_time: slaveSensor.connected_lora_time, -// connected_lora_date: slaveSensor.connected_lora_date, -// lora_last_check_time: slaveSensor.lora_last_check_time, -// lora_last_disconnect_time: slaveSensor.lora_last_disconnect_time, -// connected_to: slaveSensor.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slaveSensor.typeOfWater, -// tankHeight: slaveSensor.tankHeight, -// support_lora_last_check_time: slaveSensor.support_lora_last_check_time, -// }); -// master.connected_slave_count++; -// } -// } -// } -// } -// } - -// const finalResponse = Object.values(masterMap); - -// return reply.send({ -// status_code: 200, -// supportId, -// totalMasters: finalResponse.length, -// disconnectedIssues: finalResponse -// }); - -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const allIssues = supportRecord.issues || []; -// const hardwareSet = new Set(); - -// // Collect all hardware IDs and tankHardwareIds from issues -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); // GSM -// if (Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach(id => hardwareSet.add(id)); // LoRa slaves -// } -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); // LoRa master -// } - -// const hardwareIds = [...hardwareSet]; -// const sensors = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankHardwareId: { $in: hardwareIds } } -// ] -// }).lean(); - -// const customerId = supportRecord.customerId; -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// for (const order of orders) { -// if (Array.isArray(order.master_connections)) { -// order.master_connections.forEach(conn => { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// }); -// } -// } -// // Map sensors by both hardwareId and tankHardwareId -// const sensorMap = {}; -// for (const sensor of sensors) { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankHardwareId) sensorMap[sensor.tankHardwareId] = sensor; -// } - -// const masterMap = {}; - -// for (const issue of allIssues) { -// // GSM Disconnected -// if (issue.type === "GSM or LoRa Disconnected" && issue.hardwareId) { -// const sensor = sensorMap[issue.hardwareId]; -// if (sensor && sensor.type === "master") { -// const enriched = orderMap[sensor.hardwareId] || {}; -// masterMap[sensor.hardwareId] = { -// hardwareId: sensor.hardwareId, -// masterName: enriched.masterName || sensor.masterName || null, -// location: enriched.location || sensor.location || "", -// type: "master", -// connected_status: sensor.connected_status, -// gsm_last_check_time: sensor.gsm_last_check_time, -// gsm_last_disconnect_time: sensor.gsm_last_disconnect_time, -// connected_gsm_date: sensor.connected_gsm_date, -// connected_gsm_time: sensor.connected_gsm_time, -// connected_lora_date: sensor.connected_lora_date, -// connected_lora_time: sensor.connected_lora_time, -// support_gsm_last_check_time: sensor.support_gsm_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } -// } - -// // LoRa Disconnected -// if (issue.type === "GSM or LoRa Disconnected" && issue.masterHardwareId) { -// const masterSensor = sensorMap[issue.masterHardwareId]; -// if (!masterSensor || masterSensor.type !== "master") continue; - -// if (!masterMap[masterSensor.hardwareId]) { -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: masterSensor.masterName || null, -// location: masterSensor.location || "", -// type: "master", -// connected_status: masterSensor.connected_status, -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_lora_last_check_time: masterSensor.support_lora_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; -// let slaveIds = Array.isArray(issue.hardwareIds) ? issue.hardwareIds : []; -// console.log("slaveIds",slaveIds) -// let fallbackSlaves = []; - -// if (slaveIds.length > 0) { -// // Try to fetch slaves by hardwareId or tankHardwareId -// fallbackSlaves = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: slaveIds } }, -// { tankhardwareId: { $in: slaveIds } } -// ], -// type: "slave" -// }).lean(); -// } else { -// // Fallback: find by connected_to field -// fallbackSlaves = await Insensors.find({ -// connected_to: issue.masterHardwareId, -// type: "slave" -// }).lean(); -// } - -// for (const slaveSensor of fallbackSlaves) { -// master.connected_slaves.push({ -// hardwareId: slaveSensor.hardwareId, -// tankName: slaveSensor.tankName || "", -// location: slaveSensor.location || "", -// connected_status: slaveSensor.connected_status, -// connected_lora_time: slaveSensor.connected_lora_time, -// connected_lora_date: slaveSensor.connected_lora_date, -// lora_last_check_time: slaveSensor.lora_last_check_time, -// lora_last_disconnect_time: slaveSensor.lora_last_disconnect_time, -// connected_to: slaveSensor.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slaveSensor.typeOfWater, -// tankHeight: slaveSensor.tankHeight, -// support_lora_last_check_time: slaveSensor.support_lora_last_check_time, -// }); -// master.connected_slave_count++; -// } -// } -// } - -// const finalResponse = Object.values(masterMap); - -// return reply.send({ -// status_code: 200, -// supportId, -// totalMasters: finalResponse.length, -// disconnectedIssues: finalResponse -// }); - -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const allIssues = [...(supportRecord.issues || []), ...(supportRecord.categorizedIssues || [])]; -// const hardwareSet = new Set(); - -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); -// if (Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach(id => hardwareSet.add(id)); -// } -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); -// } - -// const hardwareIds = [...hardwareSet]; - -// const sensors = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankhardwareId: { $in: hardwareIds } } -// ] -// }).lean(); - -// const sensorMap = {}; -// for (const sensor of sensors) { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; -// } - -// const customerId = sensors.length > 0 ? sensors[0].customerId : null; -// const orders = customerId ? await Order.find({ customerId }).lean() : []; - -// const orderMap = {}; -// for (const order of orders) { -// if (Array.isArray(order.master_connections)) { -// for (const conn of order.master_connections) { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// } -// } -// } - -// const masterMap = {}; -// const assignedSlaves = new Set(); - -// // ✅ Step 1: Get all unique master hardware IDs involved in the issues -// const masterHardwareIds = new Set(); - -// for (const issue of allIssues) { -// const masterId = issue.masterHardwareId || issue.hardwareId; -// const sensor = sensorMap[masterId]; -// if (sensor?.type === "master") { -// masterHardwareIds.add(sensor.hardwareId); -// } -// } - -// // ✅ Step 2: Process each unique master once -// for (const masterId of masterHardwareIds) { -// const masterSensor = sensorMap[masterId]; -// if (!masterSensor) continue; - -// const enriched = orderMap[masterSensor.hardwareId] || {}; -// if (!masterMap[masterSensor.hardwareId]) { -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: masterSensor.masterName || enriched.masterName || "", -// location: masterSensor.location || enriched.location || "", -// type: "master", -// connected_status: masterSensor.connected_status, -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; - -// const fallbackSlaves = await Insensors.find({ -// connected_to: masterSensor.hardwareId, -// type: "slave" -// }).lean(); - -// for (const slaveSensor of fallbackSlaves) { -// const slaveKey = slaveSensor.tankhardwareId || slaveSensor.hardwareId; -// if (!slaveKey || assignedSlaves.has(slaveKey)) continue; -// if (slaveSensor.connected_status !== "disconnected") continue; - -// assignedSlaves.add(slaveKey); - -// let typeOfWater = ""; -// if (customerId && slaveSensor.tankhardwareId) { -// const tank = await Tank.findOne({ -// customerId, -// tankhardwareId: slaveSensor.tankhardwareId -// }).lean(); -// if (tank?.typeOfWater) typeOfWater = tank.typeOfWater; -// } - -// master.connected_slaves.push({ -// hardwareId: slaveSensor.tankhardwareId || slaveSensor.hardwareId, -// tankName: slaveSensor.tankName || "", -// location: slaveSensor.location || "", -// connected_status: slaveSensor.connected_status, -// connected_lora_time: slaveSensor.connected_lora_time, -// connected_lora_date: slaveSensor.connected_lora_date, -// lora_last_check_time: slaveSensor.lora_last_check_time, -// lora_last_disconnect_time: slaveSensor.lora_last_disconnect_time, -// connected_to: slaveSensor.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater, -// tankHeight: slaveSensor.tankHeight, -// support_lora_last_check_time: slaveSensor.support_lora_last_check_time -// }); - -// master.connected_slave_count++; -// } -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// totalMasters: Object.keys(masterMap).length, -// disconnectedIssues: Object.values(masterMap) -// }); - -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId } = req.params; -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const allIssues = supportRecord.issues || []; -// const hardwareSet = new Set(); - -// // Collect hardwareId and masterHardwareId -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); -// } - -// const hardwareIds = [...hardwareSet]; -// const sensors = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankhardwareId: { $in: hardwareIds } } -// ] -// }).lean(); - -// const sensorMap = {}; -// for (const sensor of sensors) { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; -// } - -// const customerId = supportRecord.customerId; -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// for (const order of orders) { -// (order.master_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// }); -// } -// console.log("order",orderMap) -// const masterMap = {}; - -// for (const issue of allIssues) { -// const masterId = issue.masterHardwareId || issue.hardwareId; -// const masterSensor = sensorMap[masterId]; -// if (!masterSensor || masterSensor.type !== "master") continue; - -// // If master not already added -// if (!masterMap[masterSensor.hardwareId]) { -// const enriched = orderMap[masterSensor.hardwareId] || {}; -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: enriched.masterName || masterSensor.masterName || "", -// location: enriched.location || masterSensor.location || "", -// type: "master", -// connected_status: masterSensor.connected_status, -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time, -// support_lora_last_check_time: masterSensor.support_lora_last_check_time, -// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time, -// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; -// console.log("master",master) - -// // ✅ Always fetch slaves using connected_to -// const connectedSlaves = await Insensors.find({ -// connected_to: masterSensor.hardwareId, -// type: "slave" -// }).lean(); - -// for (const slave of connectedSlaves) { -// // Only include disconnected slaves -// if (slave.connected_status !== "disconnected") continue; - -// master.connected_slaves.push({ -// hardwareId: slave.tankhardwareId || slave.hardwareId, -// tankName: slave.tankName || "", -// location: slave.location || "", -// connected_status: slave.connected_status, -// connected_lora_time: slave.connected_lora_time, -// connected_lora_date: slave.connected_lora_date, -// lora_last_check_time: slave.lora_last_check_time, -// lora_last_disconnect_time: slave.lora_last_disconnect_time, -// connected_to: slave.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slave.typeOfWater || "", -// tankHeight: slave.tankHeight, -// support_lora_last_check_time: slave.support_lora_last_check_time, -// //team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time, -// }); - -// master.connected_slave_count++; -// } -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// totalMasters: Object.keys(masterMap).length, -// disconnectedIssues: Object.values(masterMap) -// }); - -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -//final -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId } = req.params; -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const allIssues = supportRecord.issues || []; -// const hardwareSet = new Set(); - -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); -// } - -// const hardwareIds = [...hardwareSet]; - -// const sensors = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankhardwareId: { $in: hardwareIds } } -// ] -// }).lean(); - -// const sensorMap = {}; -// for (const sensor of sensors) { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; -// } - -// let customerId = supportRecord.customerId; -// if (!customerId) { -// const firstSensor = sensors.find(sensor => sensor.customerId); -// if (firstSensor) { -// customerId = firstSensor.customerId; -// } else { -// return reply.code(404).send({ message: "Unable to determine customerId from support or sensors." }); -// } -// } - -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// for (const order of orders) { -// (order.master_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// }); -// } - -// const slaveOrderMap = {}; -// for (const order of orders) { -// (order.tank_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// slaveOrderMap[conn.hardwareId] = { -// location: conn.location || null, -// typeOfWater: conn.typeOfWater || null -// }; -// } -// }); -// } - -// const masterMap = {}; - -// for (const issue of allIssues) { -// const masterId = issue.masterHardwareId || issue.hardwareId; -// const masterSensor = sensorMap[masterId]; -// if (!masterSensor || masterSensor.type !== "master") continue; - -// if (!masterMap[masterSensor.hardwareId]) { -// const enriched = orderMap[masterSensor.hardwareId] || {}; -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: enriched.masterName || masterSensor.masterName || "", -// location: enriched.location || masterSensor.location || "", -// type: "master", -// connected_status: masterSensor.connected_status, -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time, -// support_lora_last_check_time: masterSensor.support_lora_last_check_time, -// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time, -// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; -// const connectedSlaves = await Insensors.find({ -// connected_to: masterSensor.hardwareId, -// type: "slave" -// }).lean(); - -// const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId)); - -// for (const slave of connectedSlaves) { -// const slaveHardwareId = slave.tankhardwareId || slave.hardwareId; -// if (slaveSet.has(slaveHardwareId)) continue; -// slaveSet.add(slaveHardwareId); - -// const tankInfo = await Tank.findOne({ -// $or: [ -// { hardwareId: slaveHardwareId }, -// { tankhardwareId: slaveHardwareId } -// ] -// }).lean(); - -// const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {}; -// const slaveEnriched = { -// hardwareId: slaveHardwareId, -// tankName: slave.tankName || (tankInfo?.tankName ?? ""), -// location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "", -// connected_status: slave.connected_status, -// connected_lora_time: slave.connected_lora_time, -// connected_lora_date: slave.connected_lora_date, -// lora_last_check_time: slave.lora_last_check_time, -// lora_last_disconnect_time: slave.lora_last_disconnect_time, -// connected_to: slave.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "", -// tankHeight: slave.tankHeight, -// support_lora_last_check_time: slave.support_lora_last_check_time, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time -// }; - -// master.connected_slaves.push(slaveEnriched); -// master.connected_slave_count++; -// } -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// totalMasters: Object.keys(masterMap).length, -// disconnectedIssues: Object.values(masterMap) -// }); - -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId, customerId } = req.params; - -// if (!supportId || !customerId) { -// return reply.code(400).send({ error: "supportId and customerId are required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId and customerId" }); -// } - -// const allIssues = supportRecord.issues || []; -// const hardwareSet = new Set(); - -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); -// } - -// const hardwareIds = [...hardwareSet]; - -// const sensors = await Insensors.find({ -// customerId, -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankhardwareId: { $in: hardwareIds } } -// ] -// }).lean(); - -// const sensorMap = {}; -// for (const sensor of sensors) { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; -// } - -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// for (const order of orders) { -// (order.master_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// }); -// } - -// const slaveOrderMap = {}; -// for (const order of orders) { -// (order.tank_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// slaveOrderMap[conn.hardwareId] = { -// location: conn.location || null, -// typeOfWater: conn.typeOfWater || null -// }; -// } -// }); -// } - -// const masterMap = {}; - -// for (const issue of allIssues) { -// const masterId = issue.masterHardwareId || issue.hardwareId; -// const masterSensor = sensorMap[masterId]; -// if (!masterSensor || masterSensor.type !== "master") continue; - -// if (!masterMap[masterSensor.hardwareId]) { -// const enriched = orderMap[masterSensor.hardwareId] || {}; -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: enriched.masterName || masterSensor.masterName || "", -// location: enriched.location || masterSensor.location || "", -// type: "master", -// connected_status: masterSensor.connected_status, -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time, -// support_lora_last_check_time: masterSensor.support_lora_last_check_time, -// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time, -// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; -// const connectedSlaves = await Insensors.find({ -// connected_to: masterSensor.hardwareId, -// type: "slave", -// customerId -// }).lean(); - -// const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId)); - -// for (const slave of connectedSlaves) { -// const slaveHardwareId = slave.tankhardwareId || slave.hardwareId; -// if (slaveSet.has(slaveHardwareId)) continue; -// slaveSet.add(slaveHardwareId); - -// const tankInfo = await Tank.findOne({ -// $or: [ -// { hardwareId: slaveHardwareId }, -// { tankhardwareId: slaveHardwareId } -// ] -// }).lean(); - -// const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {}; -// const slaveEnriched = { -// hardwareId: slaveHardwareId, -// tankName: slave.tankName || (tankInfo?.tankName ?? ""), -// location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "", -// connected_status: slave.connected_status, -// connected_lora_time: slave.connected_lora_time, -// connected_lora_date: slave.connected_lora_date, -// lora_last_check_time: slave.lora_last_check_time, -// lora_last_disconnect_time: slave.lora_last_disconnect_time, -// connected_to: slave.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "", -// tankHeight: slave.tankHeight, -// support_lora_last_check_time: slave.support_lora_last_check_time, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time -// }; - -// master.connected_slaves.push(slaveEnriched); -// master.connected_slave_count++; -// } -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// customerId, -// totalMasters: Object.keys(masterMap).length, -// comments: supportRecord.comments || "", -// disconnectedIssues: Object.values(masterMap) -// }); - -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; + for (const master of allMasters) { + const customerId = master.customerId; + const hardwareId = master.hardwareId; + if (!customerId || !hardwareId) continue; -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId, customerId } = req.params; + // ✅ Update GSM and LoRa connection statuses + await updateConnectedStatusOnly(customerId, hardwareId); -// if (!supportId || !customerId) { -// return reply.code(400).send({ error: "supportId and customerId are required" }); -// } + // 🔄 Re-fetch updated master and slaves + const updatedMaster = await Insensors.findOne({ hardwareId, customerId }).lean(); + const connectedSlaves = await Insensors.find({ + connected_to: hardwareId, + type: "slave" + }).lean(); -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId and customerId" }); -// } + // Step 3: Check disconnections + const disconnectedSlaves = connectedSlaves.filter( + (s) => s.connected_status === "disconnected" + ); + const masterIsDisconnected = updatedMaster.connected_status === "disconnected"; -// const allIssues = supportRecord.issues || []; -// const hardwareSet = new Set(); + // Step 4: Raise ticket if needed + if (masterIsDisconnected || disconnectedSlaves.length > 0) { + await raiseATicketLikeLogic(supportRecord, hardwareId, disconnectedSlaves); + } + } + } -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); -// } + console.log("✅ Auto ticket check completed."); + } catch (err) { + console.error("❌ Cron error:", err); + } +}); -// const hardwareIds = [...hardwareSet]; -// const sensors = await Insensors.find({ -// customerId, -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankhardwareId: { $in: hardwareIds } } -// ] -// }).lean(); -// const sensorMap = {}; -// for (const sensor of sensors) { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; -// } +exports.raiseATicketBuildingDetails = async (req, reply) => { + try { + const { customerId, connected_to, installationId } = req.params; -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// for (const order of orders) { -// (order.master_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// }); -// } + if (!customerId || !connected_to || !installationId) { + return reply.code(400).send({ error: "customerId, connected_to, and installationId are required" }); + } -// const slaveOrderMap = {}; -// for (const order of orders) { -// (order.tank_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// slaveOrderMap[conn.hardwareId] = { -// location: conn.location || null, -// typeOfWater: conn.typeOfWater || null -// }; -// } -// }); -// } + const customer = await User.findOne({ customerId, installationId }).lean(); + if (!customer) { + return reply.code(404).send({ message: "Customer not found." }); + } -// const masterMap = {}; - -// for (const issue of allIssues) { -// const masterId = issue.masterHardwareId || issue.hardwareId; -// const masterSensor = sensorMap[masterId]; -// if (!masterSensor || masterSensor.type !== "master") continue; - -// const latestMasterData = await IotData.findOne({ hardwareId: masterSensor.hardwareId }).sort({ date: -1 }).lean(); -// const now = moment.tz("Asia/Kolkata"); -// let gsmConnected = false; - -// if (latestMasterData?.date) { -// const gsmTime = moment.tz(latestMasterData.date, "Asia/Kolkata"); -// gsmConnected = now.diff(gsmTime, "minutes") <= 1; -// } - -// if (!masterMap[masterSensor.hardwareId]) { -// const enriched = orderMap[masterSensor.hardwareId] || {}; -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: enriched.masterName || masterSensor.masterName || "", -// location: enriched.location || masterSensor.location || "", -// type: "master", -// connected_status: gsmConnected ? "connected" : "disconnected", -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time, -// support_lora_last_check_time: masterSensor.support_lora_last_check_time, -// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time, -// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; -// const connectedSlaves = await Insensors.find({ -// connected_to: masterSensor.hardwareId, -// type: "slave", -// customerId -// }).lean(); - -// const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId)); - -// for (const slave of connectedSlaves) { -// const slaveHardwareId = slave.tankhardwareId || slave.hardwareId; -// if (slaveSet.has(slaveHardwareId)) continue; -// slaveSet.add(slaveHardwareId); - -// const tankInfo = await Tank.findOne({ -// $or: [ -// { hardwareId: slaveHardwareId }, -// { tankhardwareId: slaveHardwareId } -// ] -// }).lean(); - -// const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {}; - -// const matchedTank = latestMasterData?.tanks?.find(t => t.tankhardwareId === slaveHardwareId); -// let loraConnected = false; -// if (matchedTank?.date && matchedTank.tankHeight !== "0") { -// const loraTime = moment.tz(matchedTank.date, "Asia/Kolkata"); -// loraConnected = now.diff(loraTime, "minutes") <= 1; -// } - -// const slaveEnriched = { -// hardwareId: slaveHardwareId, -// tankName: slave.tankName || tankInfo?.tankName || "", -// location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "", -// connected_status: loraConnected ? "connected" : "disconnected", -// connected_lora_time: slave.connected_lora_time, -// connected_lora_date: slave.connected_lora_date, -// lora_last_check_time: slave.lora_last_check_time, -// lora_last_disconnect_time: slave.lora_last_disconnect_time, -// connected_to: slave.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "", -// tankHeight: slave.tankHeight, -// support_lora_last_check_time: slave.support_lora_last_check_time, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time -// }; - -// master.connected_slaves.push(slaveEnriched); -// master.connected_slave_count++; -// } -// } + const sensors = await Insensors.find({ customerId }); + if (!sensors.length) { + return reply.code(404).send({ message: "No sensors found for this customer." }); + } -// // const commentTexts = (supportRecord.comments || []).map(c => c.text); -// // for (const master of Object.values(masterMap)) { -// // master.comments = commentTexts; -// // } + const masterSensor = sensors.find(s => (s.hardwareId?.trim() === connected_to.trim())); + if (!masterSensor) { + return reply.code(404).send({ message: "Master hardwareId not found." }); + } -// const comments = (supportRecord.comments || []).map(c => ({ -// text: c.text, -// commentsTime: moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm") -// })); -// for (const master of Object.values(masterMap)) { -// master.comments = comments; -// } + const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean(); + if (!latestMasterRecord) { + return reply.code(404).send({ message: "No IoT data found for this hardwareId." }); + } -// return reply.send({ -// status_code: 200, -// supportId, -// customerId, -// totalMasters: Object.keys(masterMap).length, -// disconnectedIssues: Object.values(masterMap) -// }); -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; + const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); + const now = moment.tz("Asia/Kolkata"); + const formattedNow = now.format("YYYY-MM-DD HH:mm:ss"); -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId, customerId } = req.params; + const diffInMinutesMaster = now.diff(indiaTime, "minutes"); -// if (!supportId || !customerId) { -// return reply.code(400).send({ error: "supportId and customerId are required" }); -// } + if (diffInMinutesMaster > 1) { + await Insensors.updateOne( + { hardwareId: connected_to }, + { $set: { lastTicketRaisedAt: formattedNow } } + ); + } -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId and customerId" }); -// } + const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === connected_to.trim()); -// const allIssues = supportRecord.issues || []; -// const hardwareSet = new Set(); + // ✅ Check if any slave is disconnected + const disconnectedSlave = connectedSlaves.find(slave => slave.connected_status === "disconnected"); + if (disconnectedSlave) { + return reply.code(400).send({ + error: `Slave device ${disconnectedSlave.hardwareId} is disconnected. Cannot raise ticket.` + }); + } -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); -// } + for (const slave of connectedSlaves) { + const slaveId = slave.hardwareId?.trim(); + const matchedTank = latestMasterRecord.tanks.find(tank => tank.tankhardwareId === slaveId); -// const hardwareIds = [...hardwareSet]; + if (matchedTank && matchedTank.date) { + const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata"); + const loraDiffInMinutes = now.diff(tankTime, "minutes"); -// const sensors = await Insensors.find({ -// customerId, -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankhardwareId: { $in: hardwareIds } } -// ] -// }).lean(); + if (loraDiffInMinutes > 1) { + await Insensors.updateOne( + { hardwareId: slaveId }, + { $set: { lastTicketRaisedAt: formattedNow } } + ); + } + } + } -// const sensorMap = {}; -// for (const sensor of sensors) { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; -// } + await Support.updateOne( + { supportId: "AWHYSU64" }, + { $set: { lastTicketRaisedAt: formattedNow } } + ); -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// for (const order of orders) { -// (order.master_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// }); -// } + // Fetch updated values + const updatedMasterSensor = await Insensors.findOne({ hardwareId: connected_to }).lean(); + const updatedSupport = await Support.findOne({ supportId: "AWHYSU64" }).lean(); -// const slaveOrderMap = {}; -// for (const order of orders) { -// (order.tank_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// slaveOrderMap[conn.hardwareId] = { -// location: conn.location || null, -// typeOfWater: conn.typeOfWater || null -// }; -// } -// }); -// } + return reply.send({ + status_code: 200, + customer, + lastTicketRaisedAt: { + masterSensor: updatedMasterSensor?.lastTicketRaisedAt || null, + support: updatedSupport?.lastTicketRaisedAt || null + } + }); -// const masterMap = {}; -// const now = moment.tz("Asia/Kolkata"); - -// for (const issue of allIssues) { -// const masterId = issue.masterHardwareId || issue.hardwareId; -// const masterSensor = sensorMap[masterId]; -// if (!masterSensor || masterSensor.type !== "master") continue; - -// const latestMasterData = await IotData.findOne({ hardwareId: masterSensor.hardwareId }).sort({ date: -1 }).lean(); - -// let gsmConnected = false; -// if (latestMasterData?.date) { -// const gsmTime = moment.tz(latestMasterData.date, "Asia/Kolkata"); -// gsmConnected = now.diff(gsmTime, "minutes") <= 1; -// } - -// if (!masterMap[masterSensor.hardwareId]) { -// const enriched = orderMap[masterSensor.hardwareId] || {}; -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: enriched.masterName || masterSensor.masterName || "", -// location: enriched.location || masterSensor.location || "", -// type: "master", -// connected_status: gsmConnected ? "connected" : "disconnected", -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time, -// support_lora_last_check_time: masterSensor.support_lora_last_check_time, -// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time, -// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time, -// connected_slave_count: 0, -// connected_slaves: [] -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; -// const connectedSlaves = await Insensors.find({ -// connected_to: masterSensor.hardwareId, -// type: "slave", -// customerId -// }).lean(); - -// const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId)); - -// for (const slave of connectedSlaves) { -// const slaveHardwareId = slave.tankhardwareId || slave.hardwareId; -// if (slaveSet.has(slaveHardwareId)) continue; -// slaveSet.add(slaveHardwareId); - -// const tankInfo = await Tank.findOne({ -// $or: [ -// { hardwareId: slaveHardwareId }, -// { tankhardwareId: slaveHardwareId } -// ] -// }).lean(); - -// const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {}; - -// const matchedTank = latestMasterData?.tanks?.find(t => t.tankhardwareId === slaveHardwareId); -// let loraConnected = false; -// if (matchedTank?.date && matchedTank.tankHeight !== "0") { -// const loraTime = moment.tz(matchedTank.date, "Asia/Kolkata"); -// loraConnected = now.diff(loraTime, "minutes") <= 1; -// } - -// const slaveEnriched = { -// hardwareId: slaveHardwareId, -// tankName: slave.tankName || tankInfo?.tankName || "", -// location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "", -// connected_status: loraConnected ? "connected" : "disconnected", -// connected_lora_time: slave.connected_lora_time, -// connected_lora_date: slave.connected_lora_date, -// lora_last_check_time: slave.lora_last_check_time, -// lora_last_disconnect_time: slave.lora_last_disconnect_time, -// connected_to: slave.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "", -// tankHeight: slave.tankHeight, -// support_lora_last_check_time: slave.support_lora_last_check_time, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time -// }; - -// master.connected_slaves.push(slaveEnriched); -// master.connected_slave_count++; -// } -// } + } catch (error) { + console.error("Error raising ticket:", error); + return reply.code(500).send({ error: "Internal server error" }); + } +}; -// // 🔍 Filter comments by customerId -// const comments = (supportRecord.comments || []) -// .filter(c => c.customerId === customerId) -// .map(c => ({ -// text: c.text, -// commentsTime: moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm") -// })); -// for (const master of Object.values(masterMap)) { -// master.comments = comments; -// } +exports.raiseATicketSlave = async (req, reply) => { + try { + const { customerId, connected_to } = req.params; -// return reply.send({ -// status_code: 200, -// supportId, -// customerId, -// totalMasters: Object.keys(masterMap).length, -// disconnectedIssues: Object.values(masterMap) -// }); -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; + if (!customerId || !connected_to) { + return reply.code(400).send({ error: "customerId and connected_to are required" }); + } -// exports.getDisconnectedIssuesBySupportId = async (req, reply) => { -// try { -// const { supportId, customerId } = req.params; + const sensors = await Insensors.find({ customerId }); + const masterSensor = sensors.find(s => s.hardwareId?.trim() === connected_to.trim()); -// if (!supportId || !customerId) { -// return reply.code(400).send({ error: "supportId and customerId are required" }); -// } + if (!masterSensor) { + return reply.code(404).send({ message: "Master hardwareId not found." }); + } -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId and customerId" }); -// } + const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean(); -// const allIssues = supportRecord.issues || []; -// const hardwareSet = new Set(); + if (!latestMasterRecord) { + return reply.code(404).send({ message: "No IoT data found for this hardwareId." }); + } -// for (const issue of allIssues) { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); -// } + const now = moment().tz("Asia/Kolkata"); + const masterTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); + const diff = now.diff(masterTime, "minutes"); -// const hardwareIds = [...hardwareSet]; + const gsm_connected_status = diff <= 1 ? "connected" : "disconnected"; + const gsmStatus = gsm_connected_status === "connected" ? "GSM Connected" : "GSM Disconnected"; -// const sensors = await Insensors.find({ -// customerId, -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankhardwareId: { $in: hardwareIds } } -// ] -// }).lean(); + const formattedTime = masterTime.format("HH:mm:ss"); + const formattedDate = masterTime.format("DD-MM-YYYY"); -// const sensorMap = {}; -// for (const sensor of sensors) { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; -// } + const tanks = (latestMasterRecord.tanks || []).map(tank => { + const tankTime = moment.tz(tank.date, "Asia/Kolkata"); + const timeDiff = now.diff(tankTime, "minutes"); -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// for (const order of orders) { -// (order.master_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// }); -// } + return { + ...tank, + time: tankTime.format("HH:mm:ss"), + connected_status: timeDiff <= 1 ? "connected" : "disconnected" + }; + }); -// const slaveOrderMap = {}; -// for (const order of orders) { -// (order.tank_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// slaveOrderMap[conn.hardwareId] = { -// location: conn.location || null, -// typeOfWater: conn.typeOfWater || null -// }; -// } -// }); -// } + const responseData = { + hardwareId: connected_to, + gsm_connected_status, + gsmStatus, + connected_gsm_date: formattedDate, + connected_gsm_time: formattedTime, + gsm_last_check_time: now.format("DD-MM-YYYY HH:mm:ss"), + tanks, + date: latestMasterRecord.date, + time: formattedTime + }; -// const masterMap = {}; -// const now = moment.tz("Asia/Kolkata"); + return reply.send({ + status_code: 200, + message: "Success", + data: responseData + }); -// for (const issue of allIssues) { -// const masterId = issue.masterHardwareId || issue.hardwareId; -// const masterSensor = sensorMap[masterId]; -// if (!masterSensor || masterSensor.type !== "master") continue; + } catch (error) { + console.error("Error in raiseATicketSlave:", error); + return reply.code(500).send({ error: "Internal server error" }); + } +}; -// const stillUnresolved = allIssues.some(i => -// (i.hardwareId === masterSensor.hardwareId || i.masterHardwareId === masterSensor.hardwareId) && -// !i.resolved && !i.movedToCategory -// ); - -// if (!stillUnresolved) continue; - -// const latestMasterData = await IotData.findOne({ hardwareId: masterSensor.hardwareId }).sort({ date: -1 }).lean(); - -// let gsmConnected = false; -// if (latestMasterData?.date) { -// const gsmTime = moment.tz(latestMasterData.date, "Asia/Kolkata"); -// gsmConnected = now.diff(gsmTime, "minutes") <= 1; -// } - -// // Get latest lastTicketRaisedAt for this master -// const relatedIssues = allIssues.filter( -// i => -// i.hardwareId === masterSensor.hardwareId || -// i.masterHardwareId === masterSensor.hardwareId -// ); - -// const lastTicketRaisedAt = relatedIssues.reduce((latest, issue) => { -// if (!issue.lastTicketRaisedAt) return latest; -// const current = new Date(issue.lastTicketRaisedAt); -// return !latest || current > new Date(latest) ? issue.lastTicketRaisedAt : latest; -// }, null); - -// if (!masterMap[masterSensor.hardwareId]) { -// const enriched = orderMap[masterSensor.hardwareId] || {}; -// masterMap[masterSensor.hardwareId] = { -// hardwareId: masterSensor.hardwareId, -// masterName: enriched.masterName || masterSensor.masterName || "", -// location: enriched.location || masterSensor.location || "", -// type: "master", -// connected_status: gsmConnected ? "connected" : "disconnected", -// gsm_last_check_time: masterSensor.gsm_last_check_time, -// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time, -// connected_gsm_date: masterSensor.connected_gsm_date, -// connected_gsm_time: masterSensor.connected_gsm_time, -// connected_lora_date: masterSensor.connected_lora_date, -// connected_lora_time: masterSensor.connected_lora_time, -// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time, -// support_lora_last_check_time: masterSensor.support_lora_last_check_time, -// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time, -// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time, -// outDoor_status: masterSensor.outDoor_status || "inprogress", -// connected_slave_count: 0, -// connected_slaves: [], -// lastTicketRaisedAt: lastTicketRaisedAt -// }; -// } - -// const master = masterMap[masterSensor.hardwareId]; -// const connectedSlaves = await Insensors.find({ -// connected_to: masterSensor.hardwareId, -// type: "slave", -// customerId -// }).lean(); - -// const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId)); - -// for (const slave of connectedSlaves) { -// const slaveHardwareId = slave.tankhardwareId || slave.hardwareId; -// if (slaveSet.has(slaveHardwareId)) continue; -// slaveSet.add(slaveHardwareId); - -// const tankInfo = await Tank.findOne({ -// $or: [ -// { hardwareId: slaveHardwareId }, -// { tankhardwareId: slaveHardwareId } -// ] -// }).lean(); - -// const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {}; - -// const matchedTank = latestMasterData?.tanks?.find(t => t.tankhardwareId === slaveHardwareId); -// let loraConnected = false; -// if (matchedTank?.date && matchedTank.tankHeight !== "0") { -// const loraTime = moment.tz(matchedTank.date, "Asia/Kolkata"); -// loraConnected = now.diff(loraTime, "minutes") <= 1; -// } - -// // Get latest lastTicketRaisedAt for this slave -// const slaveRelatedIssues = allIssues.filter( -// i => i.hardwareId === slaveHardwareId -// ); - -// const slaveLastTicketRaisedAt = slaveRelatedIssues.reduce((latest, issue) => { -// if (!issue.lastTicketRaisedAt) return latest; -// const current = new Date(issue.lastTicketRaisedAt); -// return !latest || current > new Date(latest) ? issue.lastTicketRaisedAt : latest; -// }, null); - -// const slaveEnriched = { -// hardwareId: slaveHardwareId, -// tankName: slave.tankName || tankInfo?.tankName || "", -// location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "", -// connected_status: loraConnected ? "connected" : "disconnected", -// connected_lora_time: slave.connected_lora_time, -// connected_lora_date: slave.connected_lora_date, -// lora_last_check_time: slave.lora_last_check_time, -// lora_last_disconnect_time: slave.lora_last_disconnect_time, -// connected_to: slave.connected_to, -// masterName: master.masterName, -// type: "slave", -// typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "", -// tankHeight: slave.tankHeight, -// support_lora_last_check_time: slave.support_lora_last_check_time, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time, -// lastTicketRaisedAt: slaveLastTicketRaisedAt, -// outDoor_status: slave.outDoor_status || "inprogress", - -// }; - -// master.connected_slaves.push(slaveEnriched); -// master.connected_slave_count++; -// } -// } -// // Filter comments by customerId -// const comments = (supportRecord.comments || []) -// .filter(c => c.customerId === customerId) -// .map(c => ({ -// text: c.text, -// commentsTime: moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm") -// })); -// for (const master of Object.values(masterMap)) { -// master.comments = comments; -// } -// return reply.send({ -// status_code: 200, -// supportId, -// customerId, -// totalMasters: Object.keys(masterMap).length, -// disconnectedIssues: Object.values(masterMap) -// }); -// } catch (error) { -// console.error("Error fetching disconnected issues:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; exports.getDisconnectedIssuesBySupportId = async (req, reply) => { @@ -9403,153 +3858,6 @@ exports.getResolvedIssuesBySupportId = async (req, reply) => { }; -// exports.getRemoveConnectedMastersWithSlaves = async (req, reply) => { -// try { -// const { supportId } = req.params; -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const allIssues = supportRecord.issues || []; - -// // Gather all unique hardwareIds from issues -// const hardwareSet = new Set(); -// allIssues.forEach(issue => { -// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); -// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); -// if (issue.hardwareIds && Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach(id => hardwareSet.add(id)); -// } -// }); -// const hardwareIds = [...hardwareSet]; - -// // Fetch all sensors related to these hardwareIds -// const sensors = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: hardwareIds } }, -// { tankhardwareId: { $in: hardwareIds } } -// ] -// }).lean(); - -// // Map sensors by hardwareId and tankhardwareId -// const sensorMap = {}; -// sensors.forEach(sensor => { -// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; -// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; -// }); - -// // Determine customerId from support or sensors -// let customerId = supportRecord.customerId; -// if (!customerId) { -// const firstSensor = sensors.find(sensor => sensor.customerId); -// if (firstSensor) { -// customerId = firstSensor.customerId; -// } else { -// return reply.code(404).send({ message: "Unable to determine customerId" }); -// } -// } - -// // Fetch orders for enriching master/slave info -// const orders = await Order.find({ customerId }).lean(); - -// const orderMap = {}; -// orders.forEach(order => { -// (order.master_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// } -// }); -// }); - -// const slaveOrderMap = {}; -// orders.forEach(order => { -// (order.tank_connections || []).forEach(conn => { -// if (conn.hardwareId) { -// slaveOrderMap[conn.hardwareId] = { -// location: conn.location || null, -// typeOfWater: conn.typeOfWater || null -// }; -// } -// }); -// }); - -// const connectedMasters = []; -// const updatedIssues = []; - -// // Process each issue to check connection status -// for (const issue of allIssues) { -// const masterId = issue.masterHardwareId || issue.hardwareId; -// const masterSensor = sensorMap[masterId]; -// if (!masterSensor || masterSensor.type !== "master") { -// // If no master sensor found or not a master, keep the issue as is -// updatedIssues.push(issue); -// continue; -// } - -// // Get connected slaves of this master -// const connectedSlaves = await Insensors.find({ -// connected_to: masterSensor.hardwareId, -// type: "slave" -// }).lean(); - -// // Check if master is connected -// const isMasterConnected = masterSensor.connected_status === "connected"; - -// // Check if all slaves are connected -// const allSlavesConnected = connectedSlaves.every(slave => slave.connected_status === "connected"); - -// if (isMasterConnected && allSlavesConnected) { -// // All connected - prepare connected master object -// const enrichedMaster = { -// hardwareId: masterSensor.hardwareId, -// masterName: orderMap[masterSensor.hardwareId]?.masterName || masterSensor.masterName || "", -// location: orderMap[masterSensor.hardwareId]?.location || masterSensor.location || "", -// type: "master", -// connected_status: masterSensor.connected_status, -// connected_slave_count: connectedSlaves.length, -// connected_slaves: connectedSlaves.map(slave => ({ -// hardwareId: slave.tankhardwareId || slave.hardwareId, -// tankName: slave.tankName || "", -// location: slave.location || slaveOrderMap[slave.tankhardwareId || slave.hardwareId]?.location || "", -// connected_status: slave.connected_status, -// type: "slave", -// typeOfWater: slave.typeOfWater || slaveOrderMap[slave.tankhardwareId || slave.hardwareId]?.typeOfWater || "", -// connected_to: slave.connected_to -// })) -// }; - -// connectedMasters.push(enrichedMaster); -// // Do NOT add this issue to updatedIssues (removing it from issues) -// } else { -// // Not all connected, keep the issue in support issues -// updatedIssues.push(issue); -// } -// } - -// // Update the Support document issues with filtered updatedIssues -// await Support.updateOne({ supportId }, { $set: { issues: updatedIssues } }); - -// return reply.send({ -// status_code: 200, -// supportId, -// totalConnectedMasters: connectedMasters.length, -// connectedMasters -// }); - -// } catch (error) { -// console.error("Error in getConnectedMastersWithSlaves:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - exports.getRemoveConnectedMastersWithSlaves = async (req, reply) => { try { const { supportId, hardwareId } = req.params; @@ -9626,610 +3934,6 @@ exports.getRemoveConnectedMastersWithSlaves = async (req, reply) => { }; -// exports.getDisconnectedCustomerDetails = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const unresolvedIssues = (supportRecord.issues || []).filter( -// issue => issue.resolved === false && issue.movedToCategory !== true -// ); - -// const allHardwareIds = new Set(); -// for (const issue of unresolvedIssues) { -// if (issue.hardwareId) allHardwareIds.add(issue.hardwareId.trim().toLowerCase()); -// if (Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach(id => { -// if (typeof id === "string") allHardwareIds.add(id.trim().toLowerCase()); -// }); -// } -// } - -// if (allHardwareIds.size === 0) { -// return reply.code(404).send({ message: "No unresolved hardware IDs found in issues" }); -// } - -// const hardwareIdsArray = Array.from(allHardwareIds); - -// const disconnectedSensors = await Insensors.find({ -// connected_status: "disconnected", -// $or: [ -// { connected_to: { $in: hardwareIdsArray } }, -// { hardwareId: { $in: hardwareIdsArray } } -// ] -// }).lean(); - -// if (!disconnectedSensors.length) { -// return reply.code(404).send({ message: "No disconnected issues found" }); -// } - -// const customerIds = [...new Set(disconnectedSensors.map(s => s.customerId))]; -// const customers = await User.find({ customerId: { $in: customerIds } }).lean(); - -// const customerHardwareMap = {}; -// for (const sensor of disconnectedSensors) { -// const custId = sensor.customerId; -// if (!customerHardwareMap[custId]) { -// customerHardwareMap[custId] = new Set(); -// } - -// const sensorHw = sensor.tankhardwareId?.trim().toLowerCase(); -// const sensorConnected = sensor.connected_to?.trim().toLowerCase(); - -// for (const issue of unresolvedIssues) { -// const allIssueHardwareIds = [ -// ...(issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []), -// issue.hardwareId?.trim().toLowerCase() -// ]; - -// if ( -// allIssueHardwareIds.includes(sensorHw) || -// allIssueHardwareIds.includes(sensorConnected) -// ) { -// customerHardwareMap[custId].add(issue.hardwareId); -// } -// } -// } - -// const response = []; -// for (const user of customers) { -// const custId = user.customerId; -// const hardwareIdSet = customerHardwareMap[custId] || new Set(); - -// const relatedIssues = unresolvedIssues.filter(issue => { -// const issueHw = issue.hardwareId?.trim().toLowerCase(); -// const hardwareIds = issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []; -// const allIds = [issueHw, ...hardwareIds]; -// return Array.from(hardwareIdSet).some(hw => allIds.includes(hw?.trim().toLowerCase())); -// }); - -// let latestIssueTime = null; -// for (const issue of relatedIssues) { -// if (issue.lastTicketRaisedAt) { -// const issueTime = new Date(issue.lastTicketRaisedAt); -// if (!latestIssueTime || issueTime > latestIssueTime) { -// latestIssueTime = issueTime; -// } -// } -// } - -// response.push({ -// customer: { -// customerId: custId, -// username: user.username || "", -// firstName: user.profile?.firstName || "", -// lastName: user.profile?.lastName || "", -// phone: user.phone || user.profile?.contactNumber || "", -// email: user.emails?.[0]?.email || "", -// phoneVerified: user.phoneVerified || false, -// address1: user.profile?.address1 || "", -// address2: user.profile?.address2 || "", -// city: user.profile?.city || "", -// state: user.profile?.state || "", -// country: user.profile?.country || "", -// zip: user.profile?.zip || "", -// notes: user.profile?.notes || "", -// latitude: user.latitude, -// longitude: user.longitude, -// fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")), -// installationId: user.installationId || "", -// notificationPreferences: { -// allowNotifications: user.allowNotifications || false, -// automaticStartAndStopNotify: user.automaticStartAndStopNotify || false, -// manualStartAndStopNotify: user.manualStartAndStopNotify || false, -// criticalLowWaterAlert: user.criticalLowWaterAlert || false, -// lowWaterAlert: user.lowWaterAlert || false, -// notificationPreference: user.notificationPreference || "never" -// }, -// surveyStatus: user.survey_status || "pending", -// buildingName: user.buildingName, -// stripePaymentStatus: user.stripePaymentStatus || false, -// stripeSubscriptionStatus: user.stripeSubscriptionStatus || false, -// createdAt: user.createdAt, -// updatedAt: user.updatedAt, -// lastTicketRaisedAt: latestIssueTime ? moment(latestIssueTime).format("YYYY-MM-DD HH:mm:ss") : null, -// totalHardwareIdsCount: hardwareIdSet.size -// } -// }); -// } - -// return reply.send({ -// status_code: 200, -// data: response -// }); - -// } catch (error) { -// console.error("Error fetching disconnected customer details:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - - - - -// exports.getDisconnectedCustomerDetails = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// // 1. Get the support record by supportId -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// // 2. Extract all hardwareIds from issues -// const hardwareIds = []; -// for (const issue of supportRecord.issues) { -// if (issue.hardwareId) hardwareIds.push(issue.hardwareId); -// if (Array.isArray(issue.hardwareIds)) hardwareIds.push(...issue.hardwareIds); -// } - -// if (hardwareIds.length === 0) { -// return reply.code(404).send({ message: "No hardware IDs found in issues" }); -// } - -// // 3. Find disconnected Insensors -// const disconnectedSensors = await Insensors.find({ -// $or: [ -// // { hardwareId: { $in: hardwareIds } }, -// { connected_to: { $in: hardwareIds } } -// ], -// connected_status: "disconnected" -// }).lean(); - -// if (disconnectedSensors.length === 0) { -// return reply.code(404).send({ message: "No disconnected issues found" }); -// } - -// // 4. Get all unique customerIds -// const customerIds = [...new Set(disconnectedSensors.map(s => s.customerId))]; -// const customers = await User.find({ customerId: { $in: customerIds } }).lean(); - -// // 5. Map unique customers -// const uniqueCustomerMap = {}; -// for (const user of customers) { -// if (!uniqueCustomerMap[user.customerId]) { -// uniqueCustomerMap[user.customerId] = { -// customer: { -// customerId: user.customerId, -// username: user.username || "", -// firstName: user.profile?.firstName || "", -// lastName: user.profile?.lastName || "", -// phone: user.phone || user.profile?.contactNumber || "", -// email: user.emails?.[0]?.email || "", -// phoneVerified: user.phoneVerified || false, -// address1: user.profile?.address1 || "", -// address2: user.profile?.address2 || "", -// city: user.profile?.city || "", -// state: user.profile?.state || "", -// country: user.profile?.country || "", -// zip: user.profile?.zip || "", -// notes: user.profile?.notes || "", -// latitude: user.latitude, -// longitude: user.longitude, -// fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")), -// installationId: user.installationId || "", -// notificationPreferences: { -// allowNotifications: user.allowNotifications || false, -// automaticStartAndStopNotify: user.automaticStartAndStopNotify || false, -// manualStartAndStopNotify: user.manualStartAndStopNotify || false, -// criticalLowWaterAlert: user.criticalLowWaterAlert || false, -// lowWaterAlert: user.lowWaterAlert || false, -// notificationPreference: user.notificationPreference || "never" -// }, -// surveyStatus: user.survey_status || "pending", -// buildingName: user.buildingName, -// stripePaymentStatus: user.stripePaymentStatus || false, -// stripeSubscriptionStatus: user.stripeSubscriptionStatus || false, -// createdAt: user.createdAt, -// updatedAt: user.updatedAt -// } -// }; -// } -// } - -// const response = Object.values(uniqueCustomerMap); - -// return reply.send({ -// status_code: 200, -// data: response -// }); - -// } catch (error) { -// console.error("Error fetching disconnected customer details:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - - -// exports.getDisconnectedCustomerDetails = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const unresolvedIssues = supportRecord.issues?.filter( -// (issue) => issue.resolved === false && issue.movedToCategory === false -// ) || []; - -// const existingCategorizedHardwareIds = new Set(); -// (supportRecord.categorizedIssues || []).forEach(issue => { -// if (issue.hardwareId) existingCategorizedHardwareIds.add(issue.hardwareId.trim().toLowerCase()); -// if (Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach(id => { -// if (typeof id === "string") existingCategorizedHardwareIds.add(id.trim().toLowerCase()); -// }); -// } -// }); - -// const hardwareIdsArray = new Set(); -// unresolvedIssues.forEach((issue) => { -// if (issue.hardwareId) hardwareIdsArray.add(issue.hardwareId.trim()); -// if (Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach((id) => { -// if (typeof id === "string") hardwareIdsArray.add(id.trim()); -// }); -// } -// }); - -// const allHardwareIds = [...hardwareIdsArray]; - -// // const disconnectedSensorsRaw = await Insensors.find({ -// // connected_status: "disconnected", -// // $or: [ -// // { connected_to: { $in: allHardwareIds } }, -// // { hardwareId: { $in: allHardwareIds } }, -// // { tankhardwareId: { $in: allHardwareIds } } -// // ] -// // }).lean(); - -// const disconnectedSensorsRaw = await Insensors.find({ -// $or: [ -// { connected_to: { $in: allHardwareIds } }, -// { hardwareId: { $in: allHardwareIds } }, -// { tankhardwareId: { $in: allHardwareIds } } -// ] -// }).lean(); - -// const disconnectedSensors = disconnectedSensorsRaw.filter(sensor => { -// const ids = [ -// sensor.hardwareId?.trim().toLowerCase(), -// sensor.connected_to?.trim().toLowerCase(), -// sensor.tankhardwareId?.trim().toLowerCase() -// ]; -// return !ids.some(id => existingCategorizedHardwareIds.has(id)); -// }); - -// const customerHardwareMap = {}; -// for (const sensor of disconnectedSensors) { -// const custId = sensor.customerId; -// if (!customerHardwareMap[custId]) { -// customerHardwareMap[custId] = new Set(); -// } - -// const sensorHw = sensor.tankhardwareId?.trim().toLowerCase(); -// const sensorConnected = sensor.connected_to?.trim().toLowerCase(); -// const sensorHardwareId = sensor.hardwareId?.trim().toLowerCase(); - -// for (const issue of unresolvedIssues) { -// const allIssueHardwareIds = [ -// ...(issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []), -// issue.hardwareId?.trim().toLowerCase() -// ]; - -// const isCategorizedMatch = [sensorHw, sensorConnected, sensorHardwareId].some(id => -// id && existingCategorizedHardwareIds.has(id) -// ); -// if (isCategorizedMatch) continue; - -// if ( -// (sensorHw && allIssueHardwareIds.includes(sensorHw)) || -// (sensorConnected && allIssueHardwareIds.includes(sensorConnected)) || -// (sensorHardwareId && allIssueHardwareIds.includes(sensorHardwareId)) -// ) { -// for (const hw of allIssueHardwareIds) { -// if (hw && !existingCategorizedHardwareIds.has(hw)) { -// customerHardwareMap[custId].add(hw); -// } -// } -// } -// } -// } - -// const customerDetails = await User.find({ -// customerId: { $in: Object.keys(customerHardwareMap) } -// }).lean(); - -// const customerResults = customerDetails.map((customer) => { -// const customerId = customer.customerId; -// const affectedHardwareSet = customerHardwareMap[customerId] || new Set(); -// const affectedLowerSet = new Set([...affectedHardwareSet].map(id => id.toLowerCase().trim())); - -// const disconnectedSensorsForCustomer = disconnectedSensors.filter( -// s => s.customerId === customerId && s.connected_status === "disconnected" -// ); - -// const disconnectedSlaves = disconnectedSensorsForCustomer.filter(s => s.type === 'slave'); -// const disconnectedMasters = disconnectedSensorsForCustomer.filter(s => s.type === 'master'); -// console.log("disconnectedMasters",disconnectedMasters) -// const uniqueDisconnectedHardwareIds = new Set([ -// ...disconnectedMasters.map(s => s.hardwareId?.trim()), -// ...disconnectedSlaves.map(s => s.tankhardwareId?.trim() || s.hardwareId?.trim()) -// ].filter(Boolean)); - -// const disconnectedCount = disconnectedMasters.length + disconnectedSlaves.length; - -// const customerIssues = unresolvedIssues.filter(issue => { -// const allIssueHardwareIds = [ -// ...(issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []), -// issue.hardwareId?.trim().toLowerCase() -// ].filter(Boolean); -// return allIssueHardwareIds.some(hw => affectedLowerSet.has(hw)); -// }); - -// const lastTicketRaisedAt = customerIssues.reduce((latest, issue) => { -// const issueTime = new Date(issue.lastTicketRaisedAt); -// if (!isNaN(issueTime)) { -// return (!latest || issueTime > new Date(latest)) ? issue.lastTicketRaisedAt : latest; -// } -// return latest; -// }, null); - -// return { -// customerId: customer.customerId, -// buildingName: customer.buildingName || "", -// location: customer.location || "", -// username: customer.username || "", -// firstName: customer.profile?.firstName || "", -// lastName: customer.profile?.lastName || "", -// phone: customer.phone || customer.profile?.contactNumber || "", -// email: customer.emails?.[0]?.email || "", -// phoneVerified: customer.phoneVerified || false, -// address1: customer.profile?.address1 || "", -// address2: customer.profile?.address2 || "", -// city: customer.profile?.city || "", -// latitude: customer.latitude, -// longitude: customer.longitude, -// totalHardwareIdsCount: uniqueDisconnectedHardwareIds.size, -// hardwareIds: [...uniqueDisconnectedHardwareIds], -// lastTicketRaisedAt: lastTicketRaisedAt || null, -// disconnectedCount -// }; -// }); - -// return reply.code(200).send({ -// success: true, -// totalCustomers: customerResults.length, -// customers: customerResults -// }); - -// } catch (error) { -// console.error("Error in getDisconnectedCustomerDetails:", error); -// return reply.code(500).send({ -// success: false, -// message: "Internal Server Error" -// }); -// } -// }; - - -// exports.getDisconnectedCustomerDetails = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const unresolvedIssues = supportRecord.issues?.filter( -// (issue) => issue.resolved === false && issue.movedToCategory === false -// ) || []; - -// const existingCategorizedHardwareIds = new Set(); -// (supportRecord.categorizedIssues || []).forEach(issue => { -// if (issue.hardwareId) existingCategorizedHardwareIds.add(issue.hardwareId.trim().toLowerCase()); -// if (Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach(id => { -// if (typeof id === "string") existingCategorizedHardwareIds.add(id.trim().toLowerCase()); -// }); -// } -// }); - -// const hardwareIdsArray = new Set(); -// unresolvedIssues.forEach((issue) => { -// if (issue.hardwareId) hardwareIdsArray.add(issue.hardwareId.trim()); -// if (Array.isArray(issue.hardwareIds)) { -// issue.hardwareIds.forEach((id) => { -// if (typeof id === "string") hardwareIdsArray.add(id.trim()); -// }); -// } -// }); - -// const allHardwareIds = [...hardwareIdsArray]; - -// // const disconnectedSensorsRaw = await Insensors.find({ -// // connected_status: "disconnected", -// // $or: [ -// // { connected_to: { $in: allHardwareIds } }, -// // { hardwareId: { $in: allHardwareIds } }, -// // { tankhardwareId: { $in: allHardwareIds } } -// // ] -// // }).lean(); - -// const disconnectedSensorsRaw = await Insensors.find({ -// connected_status: "disconnected", -// $or: [ -// { connected_to: { $in: allHardwareIds } }, -// { hardwareId: { $in: allHardwareIds } }, -// { tankhardwareId: { $in: allHardwareIds } } -// ] -// }).lean(); - -// const disconnectedSensors = disconnectedSensorsRaw.filter(sensor => { -// const ids = [ -// sensor.hardwareId?.trim().toLowerCase(), -// sensor.connected_to?.trim().toLowerCase(), -// sensor.tankhardwareId?.trim().toLowerCase() -// ]; -// return !ids.some(id => existingCategorizedHardwareIds.has(id)); -// }); - -// const customerHardwareMap = {}; -// for (const sensor of disconnectedSensors) { -// const custId = sensor.customerId; -// if (!customerHardwareMap[custId]) { -// customerHardwareMap[custId] = new Set(); -// } - -// const sensorHw = sensor.tankhardwareId?.trim().toLowerCase(); -// const sensorConnected = sensor.connected_to?.trim().toLowerCase(); -// const sensorHardwareId = sensor.hardwareId?.trim().toLowerCase(); - -// for (const issue of unresolvedIssues) { -// const allIssueHardwareIds = [ -// ...(issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []), -// issue.hardwareId?.trim().toLowerCase() -// ]; - -// const isCategorizedMatch = [sensorHw, sensorConnected, sensorHardwareId].some(id => -// id && existingCategorizedHardwareIds.has(id) -// ); -// if (isCategorizedMatch) continue; - -// if ( -// (sensorHw && allIssueHardwareIds.includes(sensorHw)) || -// (sensorConnected && allIssueHardwareIds.includes(sensorConnected)) || -// (sensorHardwareId && allIssueHardwareIds.includes(sensorHardwareId)) -// ) { -// for (const hw of allIssueHardwareIds) { -// if (hw && !existingCategorizedHardwareIds.has(hw)) { -// customerHardwareMap[custId].add(hw); -// } -// } -// } -// } -// } - -// const customerDetails = await User.find({ -// customerId: { $in: Object.keys(customerHardwareMap) } -// }).lean(); - -// const customerResults = customerDetails.map((customer) => { -// const customerId = customer.customerId; -// const affectedHardwareSet = customerHardwareMap[customerId] || new Set(); -// const affectedLowerSet = new Set([...affectedHardwareSet].map(id => id.toLowerCase().trim())); - -// const disconnectedSensorsForCustomer = disconnectedSensors.filter( -// s => s.customerId === customerId && s.connected_status === "disconnected" -// ); - -// const disconnectedSlaves = disconnectedSensorsForCustomer.filter(s => s.type === 'slave'); -// const disconnectedMasters = disconnectedSensorsForCustomer.filter(s => s.type === 'master'); -// console.log("disconnectedMasters",disconnectedMasters) -// const uniqueDisconnectedHardwareIds = new Set([ -// ...disconnectedMasters.map(s => s.hardwareId?.trim()), -// ...disconnectedSlaves.map(s => s.tankhardwareId?.trim() || s.hardwareId?.trim()) -// ].filter(Boolean)); - -// const disconnectedCount = disconnectedMasters.length + disconnectedSlaves.length; - -// const customerIssues = unresolvedIssues.filter(issue => { -// const allIssueHardwareIds = [ -// ...(issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []), -// issue.hardwareId?.trim().toLowerCase() -// ].filter(Boolean); -// return allIssueHardwareIds.some(hw => affectedLowerSet.has(hw)); -// }); - -// const lastTicketRaisedAt = customerIssues.reduce((latest, issue) => { -// const issueTime = new Date(issue.lastTicketRaisedAt); -// if (!isNaN(issueTime)) { -// return (!latest || issueTime > new Date(latest)) ? issue.lastTicketRaisedAt : latest; -// } -// return latest; -// }, null); - -// return { -// customerId: customer.customerId, -// buildingName: customer.buildingName || "", -// location: customer.location || "", -// username: customer.username || "", -// firstName: customer.profile?.firstName || "", -// lastName: customer.profile?.lastName || "", -// phone: customer.phone || customer.profile?.contactNumber || "", -// email: customer.emails?.[0]?.email || "", -// phoneVerified: customer.phoneVerified || false, -// address1: customer.profile?.address1 || "", -// address2: customer.profile?.address2 || "", -// city: customer.profile?.city || "", -// latitude: customer.latitude, -// longitude: customer.longitude, -// totalHardwareIdsCount: uniqueDisconnectedHardwareIds.size, -// hardwareIds: [...uniqueDisconnectedHardwareIds], -// lastTicketRaisedAt: lastTicketRaisedAt || null, -// disconnectedCount -// }; -// }); - -// return reply.code(200).send({ -// success: true, -// totalCustomers: customerResults.length, -// customers: customerResults -// }); - -// } catch (error) { -// console.error("Error in getDisconnectedCustomerDetails:", error); -// return reply.code(500).send({ -// success: false, -// message: "Internal Server Error" -// }); -// } -// }; - exports.getDisconnectedCustomerDetails = async (req, reply) => { try { @@ -10510,341 +4214,8 @@ exports.getDisconnectedCustomerDetailsByTeamMemberId = async (req, reply) => { } catch (error) { console.error("Error in getDisconnectedCustomerDetailsByTeamMemberId:", error); return reply.code(500).send({ error: "Internal server error" }); - } -}; - - -// exports.getDisconnectedMoveCustomerDetails = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// // 1. Fetch support record -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// // 2. Only proceed if categorizedIssues exist -// if (!Array.isArray(supportRecord.categorizedIssues) || supportRecord.categorizedIssues.length === 0) { -// return reply.code(404).send({ message: "No categorized issues to process" }); -// } - -// // 3. Collect hardware IDs from categorized issues -// const categorizedHardwareIds = []; -// for (const issue of supportRecord.categorizedIssues) { -// if (issue.hardwareId) categorizedHardwareIds.push(issue.hardwareId); -// if (Array.isArray(issue.hardwareIds)) categorizedHardwareIds.push(...issue.hardwareIds); -// } - -// if (categorizedHardwareIds.length === 0) { -// return reply.code(404).send({ message: "No hardware IDs in categorized issues" }); -// } - -// // 4. Get disconnected sensors from Insensors -// const disconnectedSensors = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: categorizedHardwareIds } }, -// { connected_to: { $in: categorizedHardwareIds } } -// ], -// connected_status: "disconnected" -// }).lean(); - -// if (disconnectedSensors.length === 0) { -// return reply.code(404).send({ message: "No disconnected sensors found" }); -// } - -// // 5. Get unique customerIds -// const customerIds = [...new Set(disconnectedSensors.map(s => s.customerId))]; - -// // 6. Fetch corresponding customers -// const customers = await User.find({ customerId: { $in: customerIds } }).lean(); - -// const uniqueCustomerMap = {}; - -// for (const user of customers) { -// const cid = user.customerId; -// if (!uniqueCustomerMap[cid]) { -// uniqueCustomerMap[cid] = { -// customer: { -// customerId: cid, -// username: user.username || "", -// firstName: user.profile?.firstName || user.firstName || "", -// lastName: user.profile?.lastName || user.lastName || "", -// phone: user.phone || user.profile?.contactNumber || user.alternativeNumber || "", -// email: user.emails?.[0]?.email || user.email || "", -// phoneVerified: user.phoneVerified || false, -// address1: user.profile?.address1 || user.address1 || "", -// address2: user.profile?.address2 || user.address2 || "", -// city: user.profile?.city || user.city || "", -// state: user.profile?.state || user.state || "", -// country: user.profile?.country || user.country || "", -// zip: user.profile?.zip || "", -// notes: user.profile?.notes || "", -// latitude: user.latitude || 0, -// longitude: user.longitude || 0, -// fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")), -// installationId: user.installationId || "", -// notificationPreferences: { -// allowNotifications: user.allowNotifications || false, -// automaticStartAndStopNotify: user.automaticStartAndStopNotify || false, -// manualStartAndStopNotify: user.manualStartAndStopNotify || false, -// criticalLowWaterAlert: user.criticalLowWaterAlert || false, -// lowWaterAlert: user.lowWaterAlert || false, -// notificationPreference: user.notificationPreference || "never" -// }, -// surveyStatus: user.survey_status || "pending", -// buildingName: user.buildingName || "", -// stripePaymentStatus: user.stripePaymentStatus || false, -// stripeSubscriptionStatus: user.stripeSubscriptionStatus || false, -// createdAt: user.createdAt, -// updatedAt: user.updatedAt -// } -// }; -// } -// } - -// const response = Object.values(uniqueCustomerMap); - -// return reply.send({ -// status_code: 200, -// data: response -// }); - -// } catch (error) { -// console.error("Error fetching disconnected customer details:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -// exports.getDisconnectedMoveCustomerDetails = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// const categorizedHardwareIds = []; -// const resolvedHardwareIds = []; - -// for (const issue of supportRecord.categorizedIssues || []) { -// if (issue.hardwareId) categorizedHardwareIds.push(issue.hardwareId); -// if (Array.isArray(issue.hardwareIds)) categorizedHardwareIds.push(...issue.hardwareIds); -// } - -// for (const issue of supportRecord.resolvedIssues || []) { -// if (issue.hardwareId) resolvedHardwareIds.push(issue.hardwareId); -// if (Array.isArray(issue.hardwareIds)) resolvedHardwareIds.push(...issue.hardwareIds); -// } - -// const allHardwareIds = [...new Set([...categorizedHardwareIds, ...resolvedHardwareIds])]; -// if (allHardwareIds.length === 0) { -// return reply.code(404).send({ message: "No hardware IDs in support issues" }); -// } - -// const allSensors = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: allHardwareIds } }, -// { connected_to: { $in: allHardwareIds } } -// ] -// }).lean(); - -// if (allSensors.length === 0) { -// return reply.code(404).send({ message: "No sensors found for support issues" }); -// } - -// const customerStatusMap = {}; - -// for (const sensor of allSensors) { -// const cid = sensor.customerId; -// if (!cid) continue; - -// if (!customerStatusMap[cid]) { -// customerStatusMap[cid] = { status: "unknown" }; -// } - -// if (resolvedHardwareIds.includes(sensor.hardwareId) || resolvedHardwareIds.includes(sensor.connected_to)) { -// customerStatusMap[cid].status = "resolved"; -// } else if (sensor.connected_status === "disconnected") { -// customerStatusMap[cid].status = "disconnected"; -// } else if (sensor.connected_status === "connected" && customerStatusMap[cid].status !== "disconnected" && customerStatusMap[cid].status !== "resolved") { -// customerStatusMap[cid].status = "connected"; -// } -// } - -// const customerIds = Object.keys(customerStatusMap); -// const users = await User.find({ customerId: { $in: customerIds } }).lean(); - -// const combinedCustomerList = users.map(user => { -// const cid = user.customerId; -// return { -// customer : { -// customerId: cid, -// connectionStatus: customerStatusMap[cid]?.status || "unknown", -// username: user.username || "", -// firstName: user.profile?.firstName || user.firstName || "", -// lastName: user.profile?.lastName || user.lastName || "", -// phone: user.phone || user.profile?.contactNumber || user.alternativeNumber || "", -// email: user.emails?.[0]?.email || user.email || "", -// phoneVerified: user.phoneVerified || false, -// address1: user.profile?.address1 || user.address1 || "", -// address2: user.profile?.address2 || user.address2 || "", -// city: user.profile?.city || user.city || "", -// state: user.profile?.state || user.state || "", -// country: user.profile?.country || user.country || "", -// zip: user.profile?.zip || "", -// notes: user.profile?.notes || "", -// latitude: user.latitude || 0, -// longitude: user.longitude || 0, -// fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")), -// installationId: user.installationId || "", -// notificationPreferences: { -// allowNotifications: user.allowNotifications || false, -// automaticStartAndStopNotify: user.automaticStartAndStopNotify || false, -// manualStartAndStopNotify: user.manualStartAndStopNotify || false, -// criticalLowWaterAlert: user.criticalLowWaterAlert || false, -// lowWaterAlert: user.lowWaterAlert || false, -// notificationPreference: user.notificationPreference || "never" -// }, -// surveyStatus: user.survey_status || "pending", -// buildingName: user.buildingName || "", -// stripePaymentStatus: user.stripePaymentStatus || false, -// stripeSubscriptionStatus: user.stripeSubscriptionStatus || false, -// createdAt: user.createdAt, -// updatedAt: user.updatedAt - - -// } -// }; -// }); - -// return reply.send({ -// status_code: 200, -// data: combinedCustomerList -// }); - -// } catch (error) { -// console.error("Error in getDisconnectedMoveCustomerDetails:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -// exports.getDisconnectedMoveCustomerDetails = async (req, reply) => { -// try { -// const { supportId } = req.params; - -// if (!supportId) { -// return reply.code(400).send({ error: "supportId is required" }); -// } - -// const supportRecord = await Support.findOne({ supportId }).lean(); -// if (!supportRecord) { -// return reply.code(404).send({ message: "No support record found for this supportId" }); -// } - -// // Extract hardwareIds from categorizedIssues only (exclude resolvedIssues) -// const categorizedHardwareIds = []; -// for (const issue of supportRecord.categorizedIssues || []) { -// if (issue.hardwareId) categorizedHardwareIds.push(issue.hardwareId); -// if (Array.isArray(issue.hardwareIds)) categorizedHardwareIds.push(...issue.hardwareIds); -// } - -// if (categorizedHardwareIds.length === 0) { -// return reply.code(404).send({ message: "No hardware IDs in categorized issues" }); -// } - -// const allSensors = await Insensors.find({ -// $or: [ -// { hardwareId: { $in: categorizedHardwareIds } }, -// { connected_to: { $in: categorizedHardwareIds } } -// ] -// }).lean(); - -// if (allSensors.length === 0) { -// return reply.code(404).send({ message: "No sensors found for categorized hardware IDs" }); -// } - -// // Determine connection status per customer -// const customerStatusMap = {}; - -// for (const sensor of allSensors) { -// const cid = sensor.customerId; -// if (!cid) continue; - -// if (!customerStatusMap[cid]) { -// customerStatusMap[cid] = { status: "unknown" }; -// } - -// if (sensor.connected_status === "disconnected") { -// customerStatusMap[cid].status = "disconnected"; -// } else if (sensor.connected_status === "connected" && customerStatusMap[cid].status !== "disconnected") { -// customerStatusMap[cid].status = "connected"; -// } -// } - -// const customerIds = Object.keys(customerStatusMap); -// const users = await User.find({ customerId: { $in: customerIds } }).lean(); - -// const combinedCustomerList = users.map(user => { -// const cid = user.customerId; -// return { -// customer: { -// customerId: cid, -// connectionStatus: customerStatusMap[cid]?.status || "unknown", -// username: user.username || "", -// firstName: user.profile?.firstName || user.firstName || "", -// lastName: user.profile?.lastName || user.lastName || "", -// phone: user.phone || user.profile?.contactNumber || user.alternativeNumber || "", -// email: user.emails?.[0]?.email || user.email || "", -// phoneVerified: user.phoneVerified || false, -// address1: user.profile?.address1 || user.address1 || "", -// address2: user.profile?.address2 || user.address2 || "", -// city: user.profile?.city || user.city || "", -// state: user.profile?.state || user.state || "", -// country: user.profile?.country || user.country || "", -// zip: user.profile?.zip || "", -// notes: user.profile?.notes || "", -// latitude: user.latitude || 0, -// longitude: user.longitude || 0, -// fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")), -// installationId: user.installationId || "", -// notificationPreferences: { -// allowNotifications: user.allowNotifications || false, -// automaticStartAndStopNotify: user.automaticStartAndStopNotify || false, -// manualStartAndStopNotify: user.manualStartAndStopNotify || false, -// criticalLowWaterAlert: user.criticalLowWaterAlert || false, -// lowWaterAlert: user.lowWaterAlert || false, -// notificationPreference: user.notificationPreference || "never" -// }, -// surveyStatus: user.survey_status || "pending", -// buildingName: user.buildingName || "", -// stripePaymentStatus: user.stripePaymentStatus || false, -// stripeSubscriptionStatus: user.stripeSubscriptionStatus || false, -// createdAt: user.createdAt, -// updatedAt: user.updatedAt -// } -// }; -// }); - -// return reply.send({ -// status_code: 200, -// data: combinedCustomerList -// }); - -// } catch (error) { -// console.error("Error in getDisconnectedMoveCustomerDetails:", error); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; + } +}; exports.getDisconnectedMoveCustomerDetails = async (req, reply) => { try { @@ -11006,47 +4377,7 @@ exports.getResolvedCustomerDetails = async (req, reply) => { const customers = await User.find({ customerId: { $in: customerIds } }).lean(); const uniqueCustomerMap = {}; - // for (const user of customers) { - // const cid = user.customerId; - // if (!uniqueCustomerMap[cid]) { - // uniqueCustomerMap[cid] = { - // customer: { - // customerId: cid, - // username: user.username || "", - // firstName: user.profile?.firstName || user.firstName || "", - // lastName: user.profile?.lastName || user.lastName || "", - // phone: user.phone || user.profile?.contactNumber || user.alternativeNumber || "", - // email: user.emails?.[0]?.email || user.email || "", - // phoneVerified: user.phoneVerified || false, - // address1: user.profile?.address1 || user.address1 || "", - // address2: user.profile?.address2 || user.address2 || "", - // city: user.profile?.city || user.city || "", - // state: user.profile?.state || user.state || "", - // country: user.profile?.country || user.country || "", - // zip: user.profile?.zip || "", - // notes: user.profile?.notes || "", - // latitude: user.latitude || 0, - // longitude: user.longitude || 0, - // fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")), - // installationId: user.installationId || "", - // notificationPreferences: { - // allowNotifications: user.allowNotifications || false, - // automaticStartAndStopNotify: user.automaticStartAndStopNotify || false, - // manualStartAndStopNotify: user.manualStartAndStopNotify || false, - // criticalLowWaterAlert: user.criticalLowWaterAlert || false, - // lowWaterAlert: user.lowWaterAlert || false, - // notificationPreference: user.notificationPreference || "never" - // }, - // surveyStatus: user.survey_status || "pending", - // buildingName: user.buildingName || "", - // stripePaymentStatus: user.stripePaymentStatus || false, - // stripeSubscriptionStatus: user.stripeSubscriptionStatus || false, - // createdAt: user.createdAt, - // updatedAt: user.updatedAt - // } - // }; - // } - // } + // Step 1: Build map of resolvedAt per hardwareId const resolvedHardwareMap = {}; for (const issue of resolvedIssues) { @@ -12125,521 +5456,6 @@ exports.deleteTeamMemberSupport = async (req, reply)=> { } } -// exports.moveIssueToCategory = async (req, reply) => { -// try { -// const { supportId } = req.params; -// const { category, hardwareId } = req.body; - -// if (!supportId || !category || !hardwareId) { -// return reply.code(400).send({ -// message: "supportId (path), category and hardwareId (body) are required", -// }); -// } - -// const support = await Support.findOne({ supportId }); -// if (!support) { -// return reply.code(404).send({ message: "Support record not found" }); -// } - -// let issueMoved = false; -// const nowTime = moment().tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss"); - -// if (!Array.isArray(support.categorizedIssues)) { -// support.categorizedIssues = []; -// } - -// // Find the issue where hardwareId matches either hardwareId or inside hardwareIds array -// const index = support.issues.findIndex((issue) => { -// // Master hardwareId match -// if (issue.hardwareId === hardwareId) return true; -// // Slave hardwareIds array match -// if (Array.isArray(issue.hardwareIds) && issue.hardwareIds.includes(hardwareId)) return true; -// return false; -// }); - -// if (index === -1) { -// return reply.code(404).send({ message: "No matching issue found to move" }); -// } - -// const issue = support.issues[index]; - -// // If the hardwareId matches master hardwareId, move entire issue as is -// if (issue.hardwareId === hardwareId) { -// support.categorizedIssues.push({ -// ...issue, -// masterHardwareId: issue.masterHardwareId || issue.hardwareId, -// category, -// movedAt: nowTime, -// }); -// support.issues.splice(index, 1); -// issueMoved = true; -// } else { -// // hardwareId matches inside hardwareIds array — move that slave issue individually -// const slaveIndex = issue.hardwareIds.indexOf(hardwareId); -// if (slaveIndex !== -1) { -// const slaveName = issue.slaveNames?.[slaveIndex] || "Unknown"; - -// support.categorizedIssues.push({ -// type: issue.type, -// hardwareId, -// masterHardwareId: issue.masterHardwareId || issue.hardwareId, -// slaveName, -// category, -// movedAt: nowTime, -// }); - -// // Remove slave from issue -// issue.hardwareIds.splice(slaveIndex, 1); -// issue.slaveNames.splice(slaveIndex, 1); - -// // If no more slaves left, remove the issue completely -// if (issue.hardwareIds.length === 0) { -// support.issues.splice(index, 1); -// } - -// issueMoved = true; -// } -// } - -// if (issueMoved) { -// await support.save(); -// return reply.send({ message: "Issue moved to category successfully" }); -// } else { -// return reply.code(404).send({ message: "No matching issue found to move" }); -// } -// } catch (err) { -// console.error("Error moving issue:", err); -// return reply.code(500).send({ error: "Internal Server Error" }); -// } -// }; - - - -// exports.particularCategory = async (req, reply) => { -// const { supportId, category } = req.params; - -// const support = await Support.findOne({ supportId }); -// if (!support) { -// return reply.code(404).send({ message: 'Support record not found' }); -// } - -// const issues = (support.categorizedIssues || []).filter( -// (issue) => issue.category === category -// ); - -// if (issues.length === 0) { -// return reply.code(404).send({ message: `No issues found for category: ${category}` }); -// } - -// return reply.send({ category, issues }); -// }; - - -//final -// exports.particularCategory = async (req, reply) => { -// try { -// const { customerId, supportId, category } = req.params; - -// if (!customerId || !supportId || !category) { -// return reply.code(400).send({ error: "customerId, supportId, and category are required" }); -// } - -// const support = await Support.findOne({ supportId }).lean(); -// if (!support) { -// return reply.code(404).send({ message: "Support record not found" }); -// } - -// // Filter categorizedIssues by category and customerId -// const issues = (support.categorizedIssues || []).filter( -// issue => issue.category === category -// ); - -// if (issues.length === 0) { -// return reply.code(404).send({ message: `No issues found for category: ${category}` }); -// } - -// const hardwareIds = issues.map(issue => issue.hardwareId).filter(Boolean); - -// // Only fetch sensors that belong to the customerId -// const insensors = await Insensors.find({ -// customerId, -// hardwareId: { $in: hardwareIds }, -// connected_status: "disconnected" -// }).lean(); - -// if (!insensors.length) { -// return reply.code(404).send({ message: "No disconnected devices found for this category." }); -// } - -// const orderMap = {}; -// const orders = await Order.find({ customerId }).lean(); -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); - -// const disconnectedIssues = []; - -// for (const master of insensors.filter(i => i.type === "master")) { -// const slaves = await Insensors.find({ -// customerId, -// connected_to: master.hardwareId, -// connected_status: "disconnected" -// }).lean(); - -// const slaveDetails = slaves.map(slave => { -// const slaveIssue = issues.find(i => i.hardwareId === slave.hardwareId); -// return { -// hardwareId: slave.hardwareId, -// tankName: slave.tankName || "", -// location: slave.tankLocation || "", -// connected_status: slave.connected_status, -// lora_last_disconnect_time: slave.lora_last_disconnect_time || null, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time, -// connected_to: slave.connected_to || "", -// masterName: orderMap[master.hardwareId]?.masterName || "", -// type: "slave", -// typeOfWater: slave.typeOfWater || "", -// support_lora_last_check_time: null, -// category, -// assignedTo: slaveIssue?.assignedTo || null -// }; -// }); - -// const masterIssue = issues.find(i => i.hardwareId === master.hardwareId); - -// disconnectedIssues.push({ -// hardwareId: master.hardwareId, -// masterName: orderMap[master.hardwareId]?.masterName || "", -// location: orderMap[master.hardwareId]?.location || "", -// type: "master", -// connected_status: master.connected_status, -// gsm_last_disconnect_time: master.gsm_last_disconnect_time || null, -// team_member_support_gsm_last_check_time: master.team_member_support_gsm_last_check_time, -// support_gsm_last_check_time: null, -// connected_slave_count: slaveDetails.length, -// connected_slaves: slaveDetails, -// category, -// assignedTo: masterIssue?.assignedTo || null -// }); -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// customerId, -// totalMasters: disconnectedIssues.length, -// disconnectedIssues -// }); - -// } catch (err) { -// console.error("Error in particularCategory:", err); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -// exports.particularCategory = async (req, reply) => { -// try { -// const { supportId, category } = req.params; - -// if (!supportId || !category) { -// return reply.code(400).send({ error: "supportId and category are required" }); -// } - -// const support = await Support.findOne({ supportId }).lean(); -// if (!support) { -// return reply.code(404).send({ message: "Support record not found" }); -// } - -// const issues = (support.categorizedIssues || []).filter(issue => issue.category === category); -// if (issues.length === 0) { -// return reply.code(404).send({ message: `No issues found for category: ${category}` }); -// } - -// const hardwareIds = issues.map(issue => issue.hardwareId).filter(Boolean); -// const insensors = await Insensors.find({ -// hardwareId: { $in: hardwareIds }, -// connected_status: "disconnected" -// }).lean(); - -// if (!insensors.length) { -// return reply.code(404).send({ message: "No disconnected devices found for this category." }); -// } - -// const orderMap = {}; -// const customerId = insensors[0]?.customerId; -// if (customerId) { -// const orders = await Order.find({ customerId }).lean(); -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); -// } - -// const disconnectedIssues = []; - -// for (const master of insensors.filter(i => i.type === "master")) { -// const slaves = await Insensors.find({ -// connected_to: master.hardwareId, -// connected_status: "disconnected" -// }).lean(); - -// const slaveDetails = slaves.map(slave => { -// const slaveIssue = issues.find(i => i.hardwareId === slave.hardwareId); -// return { -// hardwareId: slave.hardwareId, -// tankName: slave.tankName || "", -// location: slave.tankLocation || "", -// connected_status: slave.connected_status, -// lora_last_disconnect_time: slave.lora_last_disconnect_time || null, -// connected_to: slave.connected_to || "", -// masterName: orderMap[master.hardwareId]?.masterName || "", -// type: "slave", -// typeOfWater: slave.typeOfWater || "", -// support_lora_last_check_time: null, -// category, -// assignedTo: slaveIssue?.assignedTo || null // <-- Include assigned details here -// }; -// }); - -// const masterIssue = issues.find(i => i.hardwareId === master.hardwareId); - -// disconnectedIssues.push({ -// hardwareId: master.hardwareId, -// masterName: orderMap[master.hardwareId]?.masterName || "", -// location: orderMap[master.hardwareId]?.location || "", -// type: "master", -// connected_status: master.connected_status, -// gsm_last_disconnect_time: master.gsm_last_disconnect_time || null, -// support_gsm_last_check_time: null, -// connected_slave_count: slaveDetails.length, -// connected_slaves: slaveDetails, -// category, -// assignedTo: masterIssue?.assignedTo || null // <-- Include assigned details here -// }); -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// totalMasters: disconnectedIssues.length, -// disconnectedIssues -// }); - -// } catch (err) { -// console.error("Error in particularCategory:", err); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -// exports.particularCategory = async (req, reply) => { -// try { -// const { supportId, category } = req.params; - -// if (!supportId || !category) { -// return reply.code(400).send({ error: "supportId and category are required" }); -// } - -// const support = await Support.findOne({ supportId }).lean(); -// if (!support) { -// return reply.code(404).send({ message: "Support record not found" }); -// } - -// const issues = (support.categorizedIssues || []).filter(issue => issue.category === category); -// if (issues.length === 0) { -// return reply.code(404).send({ message: `No issues found for category: ${category}` }); -// } - -// const hardwareIds = issues.map(issue => issue.hardwareId).filter(Boolean); - -// // Get all sensors related to the issues (including masters and potential slaves) -// const allRelatedSensors = await Insensors.find({ -// hardwareId: { $in: hardwareIds } -// }).lean(); - -// if (!allRelatedSensors.length) { -// return reply.code(404).send({ message: "No matching devices found for this category." }); -// } - -// const orderMap = {}; -// const customerId = allRelatedSensors[0]?.customerId; -// if (customerId) { -// const orders = await Order.find({ customerId }).lean(); -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); -// } - -// const disconnectedIssues = []; - -// for (const master of allRelatedSensors.filter(i => i.type === "master")) { -// const slaves = await Insensors.find({ -// connected_to: master.hardwareId -// }).lean(); - -// const disconnectedSlaves = slaves.filter(slave => slave.connected_status === "disconnected"); - -// // If master is disconnected OR any of its slaves are disconnected, include it -// if (master.connected_status === "disconnected" || disconnectedSlaves.length > 0) { -// const slaveDetails = disconnectedSlaves.map(slave => { -// const slaveIssue = issues.find(i => i.hardwareId === slave.hardwareId); -// return { -// hardwareId: slave.hardwareId, -// tankName: slave.tankName || "", -// location: slave.tankLocation || "", -// connected_status: slave.connected_status, -// lora_last_disconnect_time: slave.lora_last_disconnect_time || null, -// connected_to: slave.connected_to || "", -// masterName: orderMap[master.hardwareId]?.masterName || "", -// type: "slave", -// typeOfWater: slave.typeOfWater || "", -// support_lora_last_check_time: null, -// category, -// assignedTo: slaveIssue?.assignedTo || null -// }; -// }); - -// const masterIssue = issues.find(i => i.hardwareId === master.hardwareId); - -// disconnectedIssues.push({ -// hardwareId: master.hardwareId, -// masterName: orderMap[master.hardwareId]?.masterName || "", -// location: orderMap[master.hardwareId]?.location || "", -// type: "master", -// connected_status: master.connected_status, -// gsm_last_disconnect_time: master.gsm_last_disconnect_time || null, -// support_gsm_last_check_time: null, -// connected_slave_count: slaveDetails.length, -// connected_slaves: slaveDetails, -// category, -// assignedTo: masterIssue?.assignedTo || null -// }); -// } -// } - -// if (disconnectedIssues.length === 0) { -// return reply.code(404).send({ message: "No disconnected devices found for this category." }); -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// totalMasters: disconnectedIssues.length, -// disconnectedIssues -// }); - -// } catch (err) { -// console.error("Error in particularCategory:", err); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - -// exports.moveIssueToCategory = async (req, reply) => { -// try { -// const { supportId } = req.params; -// const { category, hardwareId } = req.body; - -// if (!supportId || !category || !hardwareId) { -// return reply.code(400).send({ -// message: "supportId (path), category and hardwareId (body) are required", -// }); -// } - -// const support = await Support.findOne({ supportId }); -// if (!support) { -// return reply.code(404).send({ message: "Support record not found" }); -// } - -// let issueMoved = false; -// const nowTime = moment().tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss"); - -// if (!Array.isArray(support.categorizedIssues)) { -// support.categorizedIssues = []; -// } - -// const index = support.issues.findIndex((issue) => { -// if (issue.hardwareId === hardwareId) return true; -// if (Array.isArray(issue.hardwareIds) && issue.hardwareIds.includes(hardwareId)) return true; -// return false; -// }); - -// if (index === -1) { -// return reply.code(404).send({ message: "No matching issue found to move" }); -// } - -// const issue = support.issues[index]; - -// // Normalize type if it's invalid -// const normalizedType = -// issue.type === "GSM or LoRa Disconnected" ? "GSM Disconnected" : issue.type; - -// if (issue.hardwareId === hardwareId) { -// issue.movedToCategory = true; - -// support.categorizedIssues.push({ -// type: normalizedType, -// hardwareId: issue.hardwareId, -// masterHardwareId: issue.masterHardwareId || issue.hardwareId, -// category, -// //ticketId : issue.ticketId, -// movedAt: nowTime, -// movedToCategory: true, -// }); - -// support.issues.splice(index, 1); -// issueMoved = true; -// } else { -// const slaveIndex = issue.hardwareIds.indexOf(hardwareId); -// if (slaveIndex !== -1) { -// const slaveName = issue.slaveNames?.[slaveIndex] || "Unknown"; - -// support.categorizedIssues.push({ -// type: normalizedType, -// hardwareId, -// masterHardwareId: issue.masterHardwareId || issue.hardwareId, -// slaveName, -// category, -// //ticketId : issue.ticketId, -// movedAt: nowTime, -// movedToCategory: true, -// }); - -// issue.hardwareIds.splice(slaveIndex, 1); -// issue.slaveNames.splice(slaveIndex, 1); - -// if (issue.hardwareIds.length === 0) { -// support.issues.splice(index, 1); -// } - -// issueMoved = true; -// } -// } - -// if (issueMoved) { -// await support.save(); -// return reply.send({ message: "Issue moved to category successfully" }); -// } else { -// return reply.code(404).send({ message: "No matching issue found to move" }); -// } -// } catch (err) { -// console.error("Error moving issue:", err); -// return reply.code(500).send({ error: "Internal Server Error" }); -// } -// }; - exports.moveIssueToCategory = async (req, reply) => { try { const { supportId } = req.params; @@ -12754,582 +5570,6 @@ exports.moveIssueToCategory = async (req, reply) => { -// exports.particularCategory = async (req, reply) => { -// try { -// const { supportId, category } = req.params; -// const { customerId: queryCustomerId } = req.query; - -// if (!supportId || !category) { -// return reply.code(400).send({ error: "supportId and category are required" }); -// } - -// const support = await Support.findOne({ supportId }).lean(); -// if (!support) { -// return reply.code(404).send({ message: "Support record not found" }); -// } -// console.log("support",support) -// // Choose the appropriate array based on category -// let issues = []; -// if (category === "Resolved") { -// issues = (support.resolvedIssues || []).filter(issue => issue.category === "Resolved"); -// } else { -// issues = (support.categorizedIssues || []).filter(issue => issue.category === category); -// } -// console.log("issues",issues) -// if (issues.length === 0) { -// return reply.code(404).send({ message: `No issues found for category: ${category}` }); -// } - -// const hardwareIds = [...new Set(issues.map(issue => issue.hardwareId).filter(Boolean))]; - -// if (hardwareIds.length === 0) { -// return reply.code(404).send({ message: "No hardware IDs found for these issues" }); -// } - -// let customerId = queryCustomerId; - -// if (!customerId) { -// const sensors = await Insensors.find({ hardwareId: { $in: hardwareIds } }).lean(); -// if (!sensors.length) { -// return reply.code(404).send({ message: "No sensors found matching these hardware IDs" }); -// } -// customerId = sensors[0].customerId; -// if (!customerId) { -// return reply.code(404).send({ message: "Customer ID not found for these sensors" }); -// } -// } - -// const allRelatedSensors = await Insensors.find({ -// customerId, -// hardwareId: { $in: hardwareIds } -// }).lean(); - -// if (!allRelatedSensors.length) { -// return reply.code(404).send({ message: "No sensors found for the provided customer and hardware IDs" }); -// } - -// const orders = await Order.find({ customerId }).lean(); -// const orderMap = {}; -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); - -// const disconnectedIssues = []; - -// // for (const master of allRelatedSensors.filter(i => i.type === "master")) { -// const allMasters = allRelatedSensors.filter(i => i.type === "master"); - -// for (const master of allMasters) { -// const slaves = await Insensors.find({ -// connected_to: master.hardwareId, -// customerId -// }).lean(); - -// const slaveDetails = await Promise.all(slaves.map(async (slave) => { -// const slaveHardwareId = slave.tankhardwareId; - -// const tankInfo = await Tank.findOne({ -// $or: [ -// { hardwareId: slaveHardwareId }, -// { tankhardwareId: slaveHardwareId } -// ] -// }).lean(); - -// const slaveComments = (support.comments || []) -// .filter(comment => comment.hardwareId === slave.hardwareId) -// .map(c => c.text); - -// return { -// hardwareId: slave.tankhardwareId, -// tankName: slave.tankName || "", -// location: slave.tankLocation || "", -// connected_status: slave.connected_status, -// connected_lora_time: slave.connected_lora_time || "", -// connected_lora_date: slave.connected_lora_date || "", -// lora_last_check_time: slave.lora_last_check_time || null, -// lora_last_disconnect_time: slave.lora_last_disconnect_time || null, -// connected_to: slave.connected_to || "", -// masterName: orderMap[master.hardwareId]?.masterName || "", -// type: "slave", -// typeOfWater: tankInfo?.typeOfWater || "", -// support_lora_last_check_time: slave.support_lora_last_check_time || null, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time || null, -// comments: slaveComments -// }; -// })); - -// const masterComments = (support.comments || []) -// .filter(comment => comment.hardwareId === master.hardwareId) -// .map(c => c.text); - -// disconnectedIssues.push({ -// hardwareId: master.hardwareId, -// masterName: orderMap[master.hardwareId]?.masterName || "", -// location: orderMap[master.hardwareId]?.location || "", -// type: "master", -// connected_status: master.connected_status, -// gsm_last_check_time: master.gsm_last_check_time || null, -// gsm_last_disconnect_time: master.gsm_last_disconnect_time || null, -// connected_gsm_date: master.connected_gsm_date || "", -// connected_gsm_time: master.connected_gsm_time || "", -// connected_lora_date: master.connected_lora_date || "", -// connected_lora_time: master.connected_lora_time || "", -// support_gsm_last_check_time: master.support_gsm_last_check_time || null, -// team_member_support_gsm_last_check_time: master.team_member_support_gsm_last_check_time || null, -// connected_slave_count: slaveDetails.length, -// connected_slaves: slaveDetails, -// comments: masterComments -// }); -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// customerId, -// totalMasters: disconnectedIssues.length, -// disconnectedIssues -// }); - -// } catch (err) { -// console.error("Error in particularCategory:", err); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - - - - - -// exports.assignCategorizeIssue = async (request, reply) => { -// const { supportId } = request.params; -// const { support_teamMemberId, startDate, endDate, category, masterHardwareId } = request.body; - -// if (!support_teamMemberId || !startDate || !endDate || !category || !masterHardwareId) { -// return reply.code(400).send({ error: 'support_teamMemberId, startDate, endDate, category, and masterHardwareId are required' }); -// } - -// const support = await Support.findOne({ supportId }); -// if (!support) { -// return reply.code(404).send({ error: 'Support record not found' }); -// } - -// const teamMembers = support.team_member?.team_member || []; -// const teamMember = teamMembers.find(m => m.support_teamMemberId === support_teamMemberId); - -// if (!teamMember) { -// return reply.code(400).send({ error: `Team member ID ${support_teamMemberId} not found` }); -// } - -// const start = new Date(startDate); -// const end = new Date(endDate); -// if (isNaN(start) || isNaN(end)) { -// return reply.code(400).send({ error: 'Invalid startDate or endDate' }); -// } - -// // ✅ Format to "DD-MM-YYYY HH:mm:ss" -// const formattedStart = moment(start).format("DD-MM-YYYY HH:mm:ss"); -// const formattedEnd = moment(end).format("DD-MM-YYYY HH:mm:ss"); - -// let assignedCount = 0; - -// support.categorizedIssues.forEach(issue => { -// if ( -// issue.masterHardwareId === masterHardwareId && -// issue.category === category -// ) { -// issue.assignedTo = { -// name: teamMember.name, -// support_teamMemberId: teamMember.support_teamMemberId, -// phone: teamMember.phone, -// email: teamMember.email, -// startDate: formattedStart, // 👈 use formatted date -// endDate: formattedEnd // 👈 use formatted date -// }; -// assignedCount++; -// } -// }); - -// if (assignedCount === 0) { -// return reply.code(404).send({ message: 'No matching issues found for assignment' }); -// } - -// await support.save(); - -// return reply.send({ -// message: `Assigned ${assignedCount} categorized issue(s) to ${teamMember.name}`, -// assignedTo: teamMember.support_teamMemberId -// }); -// }; - - - -// const moment = require('moment'); // Ensure moment is installed - - - -// exports.particularCategory = async (req, reply) => { -// try { -// const { supportId, category } = req.params; -// const { customerId: queryCustomerId } = req.query; - -// if (!supportId || !category) { -// return reply.code(400).send({ error: "supportId and category are required" }); -// } - -// const support = await Support.findOne({ supportId }).lean(); -// if (!support) return reply.code(404).send({ message: "Support record not found" }); - -// // Filter issues by category -// const issues = (category === "Resolved" ? support.resolvedIssues : support.categorizedIssues || []) -// .filter(issue => issue.category === category); -// if (!issues.length) return reply.code(404).send({ message: `No issues found for category: ${category}` }); - -// const hardwareIds = [...new Set(issues.map(issue => issue.hardwareId).filter(Boolean))]; -// if (!hardwareIds.length) return reply.code(404).send({ message: "No hardware IDs found for these issues" }); - -// let customerId = queryCustomerId; -// if (!customerId) { -// const sensorDoc = await Insensors.findOne({ hardwareId: { $in: hardwareIds } }).lean(); -// if (!sensorDoc || !sensorDoc.customerId) return reply.code(404).send({ message: "Customer ID not found" }); -// customerId = sensorDoc.customerId; -// } - -// const allRelatedSensors = await Insensors.find({ -// customerId, -// hardwareId: { $in: hardwareIds } -// }).lean(); - -// if (!allRelatedSensors.length) return reply.code(404).send({ message: "No sensors found" }); - -// // Order map -// const orders = await Order.find({ customerId }).lean(); -// const orderMap = {}; -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); - -// // Create map for issue -> movedAt/resolvedAt -// const issueMap = {}; -// issues.forEach(issue => { -// issueMap[issue.hardwareId] = issue; -// }); - -// const disconnectedIssues = []; - -// const allMasters = allRelatedSensors.filter(i => i.type === "master"); - -// for (const master of allMasters) { -// const slaves = await Insensors.find({ connected_to: master.hardwareId, customerId }).lean(); - -// // Get latest IoT data for master -// const latestIotData = await IotData.findOne({ hardwareId: master.hardwareId }).sort({ date: -1 }).lean(); - -// // GSM Status -// const now = moment.tz("Asia/Kolkata"); -// let gsm_last_check_time = null; -// let gsmConnected = false; - -// if (latestIotData?.date) { -// const gsmTime = moment.tz(latestIotData.date, "Asia/Kolkata"); -// const gsmDiff = now.diff(gsmTime, "minutes"); -// gsmConnected = gsmDiff <= 1; -// gsm_last_check_time = latestIotData.date; -// } - -// // Prepare slave details with LORA check -// const slaveDetails = await Promise.all(slaves.map(async (slave) => { -// const slaveHardwareId = slave.tankhardwareId?.trim(); -// const matchedTank = latestIotData?.tanks?.find(tank => tank.tankhardwareId === slaveHardwareId); - -// let loraConnected = false; -// let lora_last_check_time = null; - -// if (matchedTank?.date && matchedTank?.tankHeight !== "0") { -// const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata"); -// const loraDiff = now.diff(tankTime, "minutes"); -// loraConnected = loraDiff <= 1; -// lora_last_check_time = matchedTank.date; -// } - -// const tankInfo = await Tank.findOne({ -// $or: [ -// { hardwareId: slaveHardwareId }, -// { tankhardwareId: slaveHardwareId } -// ] -// }).lean(); - -// const slaveComments = (support.comments || []) -// .filter(comment => comment.hardwareId === slave.hardwareId) -// .map(c => c.text); - -// return { -// hardwareId: slave.tankhardwareId, -// tankName: slave.tankName || "", -// location: slave.tankLocation || "", -// connected_status: slave.connected_status, -// connected_lora_date: slave.connected_lora_date || "", -// connected_lora_time: slave.connected_lora_time || "", -// loraConnected, -// lora_last_check_time, -// lora_last_disconnect_time: slave.lora_last_disconnect_time || null, -// connected_to: slave.connected_to || "", -// masterName: orderMap[master.hardwareId]?.masterName || "", -// type: "slave", -// typeOfWater: tankInfo?.typeOfWater || "", -// support_lora_last_check_time: slave.support_lora_last_check_time || null, -// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time || null, -// comments: slaveComments -// }; -// })); - -// const masterComments = (support.comments || []) -// .filter(comment => comment.hardwareId === master.hardwareId) -// .map(c => c.text); - -// const issue = issueMap[master.hardwareId]; - -// disconnectedIssues.push({ -// hardwareId: master.hardwareId, -// masterName: orderMap[master.hardwareId]?.masterName || "", -// location: orderMap[master.hardwareId]?.location || "", -// type: "master", -// connected_status: master.connected_status, -// gsmConnected, -// gsm_last_check_time, -// gsm_last_disconnect_time: master.gsm_last_disconnect_time || null, -// connected_gsm_date: master.connected_gsm_date || "", -// connected_gsm_time: master.connected_gsm_time || "", -// connected_lora_date: master.connected_lora_date || "", -// connected_lora_time: master.connected_lora_time || "", -// support_gsm_last_check_time: master.support_gsm_last_check_time || null, -// team_member_support_gsm_last_check_time: master.team_member_support_gsm_last_check_time || null, -// connected_slave_count: slaveDetails.length, -// connected_slaves: slaveDetails, -// comments: masterComments, -// movedAt: category !== "Resolved" ? (issue?.movedAt || null) : null, -// resolvedAt: category === "Resolved" ? (issue?.resolvedAt || null) : null -// }); -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// customerId, -// totalMasters: disconnectedIssues.length, -// disconnectedIssues -// }); - -// } catch (err) { -// console.error("Error in particularCategory:", err); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - - -// exports.particularCategory = async (req, reply) => { -// try { -// const { supportId, category } = req.params; -// const { customerId: queryCustomerId } = req.query; - -// if (!supportId || !category) { -// return reply.code(400).send({ error: "supportId and category are required" }); -// } - -// const support = await Support.findOne({ supportId }).lean(); -// if (!support) return reply.code(404).send({ message: "Support record not found" }); - -// const issues = (category === "Resolved" ? support.resolvedIssues : support.categorizedIssues || []) -// .filter(issue => issue.category === category); -// if (!issues.length) return reply.code(404).send({ message: `No issues found for category: ${category}` }); - -// const hardwareIds = [...new Set(issues.map(issue => issue.hardwareId).filter(Boolean))]; -// if (!hardwareIds.length) return reply.code(404).send({ message: "No hardware IDs found for these issues" }); - -// let customerId = queryCustomerId; -// if (!customerId) { -// const sensorDoc = await Insensors.findOne({ hardwareId: { $in: hardwareIds } }).lean(); -// if (!sensorDoc || !sensorDoc.customerId) return reply.code(404).send({ message: "Customer ID not found" }); -// customerId = sensorDoc.customerId; -// } - -// const allRelatedSensors = await Insensors.find({ -// customerId, -// hardwareId: { $in: hardwareIds } -// }).lean(); - -// if (!allRelatedSensors.length) return reply.code(404).send({ message: "No sensors found" }); - -// const orders = await Order.find({ customerId }).lean(); -// const orderMap = {}; -// orders.forEach(order => { -// order.master_connections.forEach(conn => { -// orderMap[conn.hardwareId] = { -// masterName: conn.master_name || null, -// location: conn.location || null -// }; -// }); -// }); - -// const issueMap = {}; -// issues.forEach(issue => { -// issueMap[issue.hardwareId] = issue; -// }); - -// const disconnectedIssues = []; -// const allMasters = allRelatedSensors.filter(i => i.type === "master"); - -// for (const master of allMasters) { -// const slaves = await Insensors.find({ connected_to: master.hardwareId, customerId }).lean(); -// const latestIotData = await IotData.findOne({ hardwareId: master.hardwareId }).sort({ date: -1 }).lean(); - -// const now = moment.tz("Asia/Kolkata"); -// let gsmConnected = false; - -// if (latestIotData?.date) { -// const gsmTime = moment.tz(latestIotData.date, "Asia/Kolkata"); -// const gsmDiff = now.diff(gsmTime, "minutes"); -// gsmConnected = gsmDiff <= 1; -// } - -// // 🔄 Update master connected_status -// await Insensors.updateOne( -// { hardwareId: master.hardwareId }, -// { $set: { connected_status: gsmConnected ? "connected" : "disconnected" } } -// ); - -// const slaveDetails = await Promise.all(slaves.map(async (slave) => { -// const slaveHardwareId = slave.tankhardwareId?.trim(); -// const matchedTank = latestIotData?.tanks?.find(tank => tank.tankhardwareId === slaveHardwareId); - -// let loraConnected = false; - -// if (matchedTank?.date && matchedTank?.tankHeight !== "0") { -// const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata"); -// const loraDiff = now.diff(tankTime, "minutes"); -// loraConnected = loraDiff <= 1; -// } - -// // 🔄 Update slave connected_status -// await Insensors.updateOne( -// { tankhardwareId: slaveHardwareId }, -// { $set: { connected_status: loraConnected ? "connected" : "disconnected" } } -// ); - -// const tankInfo = await Tank.findOne({ -// $or: [ -// { hardwareId: slaveHardwareId }, -// { tankhardwareId: slaveHardwareId } -// ] -// }).lean(); - -// // const slaveComments = (support.comments || []) -// // .filter(comment => comment.hardwareId === slave.hardwareId) -// // .map(c => c.text); - -// const slaveComments = (support.comments || []) -// .filter(comment => -// comment.hardwareId === slave.hardwareId && -// comment.customerId === customerId // ✅ filter by customer -// ) -// .map(c => ({ -// text: c.text, -// commentsTime: c.createdAt -// ? moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm") -// : null -// })); - - -// return { -// hardwareId: slave.tankhardwareId, -// tankName: slave.tankName || "", -// location: slave.tankLocation || "", -// connected_status: loraConnected ? "connected" : "disconnected", -// connected_to: slave.connected_to || "", -// gsm_last_check_time: slave.gsm_last_check_time || null, -// gsm_last_disconnect_time: slave.gsm_last_disconnect_time || null, -// lora_last_disconnect_time: slave.lora_last_disconnect_time || null, -// connected_gsm_date: slave.connected_gsm_date || "", -// connected_gsm_time: slave.connected_gsm_time || "", -// connected_lora_date: slave.connected_lora_date || "", -// connected_lora_time: slave.connected_lora_time || "", -// support_lora_last_check_time: slave.support_lora_last_check_time || null, -// masterName: orderMap[master.hardwareId]?.masterName || "", -// type: "slave", -// typeOfWater: tankInfo?.typeOfWater || "", -// outDoor_status: slave.outDoor_status || "inprogress", -// //comments: slaveComments -// }; -// })); - -// // const masterComments = (support.comments || []) -// // .filter(comment => comment.hardwareId === master.hardwareId) -// // .map(c => c.text); - -// const masterComments = (support.comments || []) -// .filter(comment => -// comment.hardwareId === master.hardwareId && -// comment.customerId === customerId // ✅ filter by customer -// ) -// .map(c => ({ -// text: c.text, -// commentsTime: c.createdAt -// ? moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm") -// : null -// })); - - -// const issue = issueMap[master.hardwareId]; - -// disconnectedIssues.push({ -// hardwareId: master.hardwareId, -// masterName: orderMap[master.hardwareId]?.masterName || "", -// location: orderMap[master.hardwareId]?.location || "", -// type: "master", -// connected_status: gsmConnected ? "connected" : "disconnected", -// connected_slave_count: slaveDetails.length, -// gsm_last_check_time: master.gsm_last_check_time || null, -// gsm_last_disconnect_time: master.gsm_last_disconnect_time || null, -// lora_last_disconnect_time: master.lora_last_disconnect_time || null, -// connected_gsm_date: master.connected_gsm_date || "", -// connected_gsm_time: master.connected_gsm_time || "", -// connected_lora_date: master.connected_lora_date || "", -// connected_lora_time: master.connected_lora_time || "", -// support_gm_last_check_time: master.support_gsm_last_check_time || null, -// connected_slaves: slaveDetails, -// comments: masterComments, -// outDoor_status: master.outDoor_status || "inprogress", -// movedAt: category !== "Resolved" ? (issue?.movedAt || null) : null, -// resolvedAt: category === "Resolved" ? (issue?.resolvedAt || null) : null, -// category: issue?.category || category, -// hardwareList: master.hardwareList || {}, -// assignedTo: issue?.assignedTo || null, -// }); -// } - -// return reply.send({ -// status_code: 200, -// supportId, -// customerId, -// totalMasters: disconnectedIssues.length, -// disconnectedIssues -// }); - -// } catch (err) { -// console.error("Error in particularCategory:", err); -// return reply.code(500).send({ error: "Internal server error" }); -// } -// }; - exports.particularCategory = async (req, reply) => { try { const { supportId, category } = req.params; @@ -13482,18 +5722,7 @@ if (!orders.length) { : null })); - // const masterCallRecords = (support.callRecord || []) - // .filter(call => - // call.hardwareId === master.hardwareId && - // call.customerId === customerId - // ) - // .map(call => ({ - // call_status: call.call_status, - // call_time: call.call_time, - // createdAt: call.createdAt - // ? moment(call.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm") - // : null - // })); + const trimmedMasterId = (master.hardwareId || "").trim(); @@ -14114,17 +6343,7 @@ exports.updateComments = async (req, reply) => { supportRecord.comments = supportRecord.comments || []; supportRecord.comments.push(commentObj); - // Step 5: Add call record - // const callRecordObj = { - // call_status, - // call_time, - // customerId, - // hardwareId, - // createdAt: new Date() - // }; - - // supportRecord.callRecord = supportRecord.callRecord || []; - // supportRecord.callRecord.push(callRecordObj); + // Save support record await supportRecord.save(); diff --git a/src/routes/adminRoute.js b/src/routes/adminRoute.js index 184370ea..bb7e74db 100644 --- a/src/routes/adminRoute.js +++ b/src/routes/adminRoute.js @@ -211,23 +211,6 @@ fastify.route({ }); -// fastify.post("/api/createUser", { -// schema: { -// description: "This is for Create sale/store", -// tags: ["createUser for sale/sore"], -// summary: "This is for Create sale/store", -// body: { -// type: "object", -// required: ["phone", "password", "role"], -// properties: { -// phone : { type: "string" }, -// password: { type: "string" }, -// role: { type: "string", enum: ["sales", "store"] } -// }, -// }, -// }, -// handler: adminController.createUser, -// }); diff --git a/src/routes/departmentRoute.js b/src/routes/departmentRoute.js index 6da23f7c..6cf64308 100644 --- a/src/routes/departmentRoute.js +++ b/src/routes/departmentRoute.js @@ -473,21 +473,7 @@ fastify.route({ handler: departmentController.editdepartment, }); - // fastify.get("/api/getalldesignationsParticularFileds", { - // schema: { - // tags: ["Department"], - // description: "This is for Get all Designation particular fileds", - // summary: "This is for to Get all Designation particular fields", - - // security: [ - // { - // basicAuth: [], - // }, - // ], - // }, - // //preHandler: fastify.auth([fastify.authenticate]), - // handler: departmentController.getAllDesignationsParticularFields, - // }); + fastify.route({ method: "GET", @@ -527,25 +513,7 @@ fastify.route({ handler:departmentController.getLocationsByZone }); - // fastify.route({ - // method: "GET", - // url: "/api/zonebasedcity/:city/:officeName", - // schema: { - // tags: ["Department"], - // description: "Get the zones by city", - // summary: "Get the zones by city", - // params: { - // type: "object", - // properties: { - // city: { type: "string" }, - // officeName: { type: "string" }, - - // }, - // }, - // }, - // handler:departmentController.getZonesByCity - // }); - + fastify.route({ method: "GET", url: "/api/zonebasedcity/:city/:officeName", diff --git a/src/routes/installationRoute.js b/src/routes/installationRoute.js index 307fbc25..cd46810f 100644 --- a/src/routes/installationRoute.js +++ b/src/routes/installationRoute.js @@ -53,38 +53,6 @@ fastify.get("/api/getAllDepartments/:officeName", { }); - // fastify.get("/api/getTeamMembers/:officeName/:city/:departmentName/:departmentId", { - // schema: { - // description: "Get all team members under a specific department", - // tags: ["Installation"], - // summary: "Get Team Members by Department ID", - // params: { - // type: "object", - // properties: { - // officeName: { - // type: "string", - // description: "fetch team members from" - // }, - // city: { - // type: "string", - // description: "fetch team members from" - // }, - // departmentName:{ - // type: "string", - // description: "Department Name to fetch team members from" - // }, - // departmentId: { - // type: "string", - // description: "Department ID to fetch team members from" - // } - // }, - - // required: ["departmentId"] - // }, - // }, - // handler: installationController.getTeamMembers - // }); - fastify.get("/api/getTeamMembers/:officeName/:city/:departmentId", { schema: { description: "Get all team members under a specific department", @@ -615,67 +583,12 @@ fastify.put('/api/Updatetanksdimensisons/:customerId/:teamMemberId/:hardwareId/: } } }, - // response: { - // 200: { - // type: 'object', - // properties: { - // success: { type: 'boolean' }, - // message: { type: 'string' }, - // orderMatchedCount: { type: 'integer' }, - // orderModifiedCount: { type: 'integer' }, - // masterModifiedCount: { type: 'integer' }, - // slaveModifiedCount: { type: 'integer' } - // } - // }, - // 400: { - // type: 'object', - // properties: { - // success: { type: 'boolean' }, - // message: { type: 'string' } - // } - // }, - // 500: { - // type: 'object', - // properties: { - // success: { type: 'boolean' }, - // message: { type: 'string' } - // } - // } - // } + }, handler: installationController.updateWorkStatusAndProductStatus } ); -// fastify.put('/api/tanks/:customerId/:teamMemberId/:hardwareId/:tankHardwareId', { -// schema: { -// tags: ['Installation'], -// summary: 'Update tank dimensions', -// description: 'Edit tank details (height, width, length) by customerId, teamMemberId, hardwareId and tankHardwareId.', -// params: { -// type: 'object', -// required: ['customerId', 'teamMemberId', 'hardwareId', 'tankHardwareId'], -// properties: { -// customerId: { type: 'string', description: 'Customer ID' }, -// teamMemberId: { type: 'string', description: 'Team member ID' }, -// hardwareId: { type: 'string', description: 'Master hardwareId' }, -// tankHardwareId: { type: 'string', description: 'Tank hardwareId' } -// } -// }, -// body: { -// type: 'object', -// //required: ['height', 'width', 'length'], -// properties: { -// height: { type: 'number', description: 'New tank height (in cm)' }, -// width: { type: 'number', description: 'New tank width (in cm)' }, -// length: { type: 'number', description: 'New tank length (in cm)' } -// } -// }, - -// }, -// handler : installationController.editTankDimensions -// }); - fastify.post( '/api/insensors/media/:customerId', @@ -721,31 +634,7 @@ fastify.post( // at least one of video, material, workStatus required }, - // response: { - // 200: { - // type: 'object', - // properties: { - // success: { type: 'boolean' }, - // message: { type: 'string' }, - // data: { - // type: 'object', - // description: 'Updated Insensor document' - // } - // } - // }, - // 400: { - // type: 'object', - // properties: { success: { type: 'boolean' }, message: { type: 'string' } } - // }, - // 404: { - // type: 'object', - // properties: { success: { type: 'boolean' }, message: { type: 'string' } } - // }, - // 500: { - // type: 'object', - // properties: { success: { type: 'boolean' }, message: { type: 'string' } } - // } - // } + }, handler: installationController.addMediaToInsensor } @@ -892,23 +781,7 @@ fastify.post( handler: installationController.getIotDataByCustomerAndHardwareId, }); - // fastify.get("/api/getraiseAticket/:customerId/:connected_to", { - // schema: { - // description: "Raise A Ticket for Support", - // tags: ["Support"], - // summary: "Raise A Ticket for Support", - // params: { - // type: "object", - // properties: { - // customerId: { type: "string" }, - // connected_to: { type: "string" }, - - // }, - // required: [ "customerId"], - // }, - // }, - // handler: installationController.raiseATicket, - // }); + fastify.get("/api/getraiseAticketBuildingDetails/:customerId/:connected_to/:installationId", { schema: { @@ -1315,27 +1188,7 @@ fastify.post( handler: installationController.moveIssueToCategory }); - // fastify.get('/api/support/categorizedIssues/:supportId/:category', { - // schema: { - // description: 'Get all issues in a particular category for a support record', - // tags: ['Support'], - // summary: 'Fetch issues by category', - // params: { - // type: 'object', - // required: ['supportId', 'category'], - // properties: { - // supportId: { type: 'string' }, - // //customerId: { type: 'string' }, - // category: { - // type: 'string', - // enum: ['Power Outage', 'Level1', 'Pending', 'Onsite Issues'] // your allowed categories - // } - // } - // }, - - // }, - // handler: installationController.particularCategory - // }); + fastify.get('/api/support/categorizedIssues/:supportId/:category', { schema: {