const boom = require("boom"); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const customJwtAuth = require("../customAuthJwt"); const { Deparments } = require("../models/Department"); const { Install, SensorStock, SensorQuotation, Order, Insensors, MasterSlaveData, ElectrictyWorkPictures, PlumbingWorkPictures, MaterialRecievedPictures, Support } = require("../models/store"); const { Counter, User } = require("../models/User"); const { IotData, Tank } = require("../models/tanks"); const moment = require('moment-timezone'); const fastify = require("fastify")({ logger: true, //disableRequestLogging: true, genReqId(req) { // you get access to the req here if you need it - must be a synchronous function return uuidv4(); }, }); const generateTeamMemberId = async () => { var result = await Counter.findOneAndUpdate( { _id: 'teamMemberId_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return result.seq; }; exports.createTeamMember = async (request, reply) => { try { const { departmentId, firstName, phone, password,email,alternativePhone ,status} = request.body; // Check if installation exists const installation = await Deparments.findOne({ departmentId }); if (!installation) { return reply.status(404).send({ simplydata: { error: true, message: "Installation not found", }, }); } // Check if phone number already exists in the team const existingMember = installation.team_member.team_member.find( (member) => member.phone === phone ); if (existingMember) { return reply.status(400).send({ simplydata: { error: true, message: "Phone number already exists in the team", }, }); } // Hash password const hashedPassword = await bcrypt.hash(password, 10); const c_id = await generateTeamMemberId(); const teamMemberId = `AWTM${c_id}`; // Create new team member const newTeamMember = { teamMemberId, firstName, phone, email, alternativePhone, installationTeamMemId: departmentId, password: hashedPassword, status, }; // Add to team members array installation.team_member.team_member.push(newTeamMember); await installation.save(); return reply.send({ simplydata: { error: false, message: "Team member created successfully", teamMemberId: newTeamMember.teamMemberId, }, }); } catch (err) { console.error("Error creating team member:", err); reply.status(500).send({ simplydata: { error: true, message: "Internal server error", }, }); } }; exports.getTeamMembers = async (request, reply) => { try { const { departmentId } = 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.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.assignTeamMemberToQuotation = async (request, reply) => { try { const { installationId } = request.params; const { teamMemberId, quotationId } = request.body; if (!teamMemberId || !quotationId) { return reply.status(400).send({ simplydata: { error: true, message: "Both teamMemberId and quotationId are 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 the 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", }, }); } // 🔹 Find or create the quotation for the given installationId let quotation = await Order.findOne({ installationId, quatationId: quotationId }); if (!quotation) { quotation = new Order({ installationId, quatationId: quotationId, assignedTeamMembers: [], // Ensure assignedTeamMembers array is initialized quatation_status: "Pending", // Default status when created }); } // 🔹 Assign the team member to the quotation if (!quotation.assignedTeamMembers) { quotation.assignedTeamMembers = []; } if (!quotation.assignedTeamMembers.includes(teamMemberId)) { quotation.assignedTeamMembers.push(teamMemberId); } // 🔹 Update order status when a team member is assigned quotation.quatation_status = "Assigned"; // Update status // 🔹 Save the updated quotation in the Order schema await quotation.save(); // 🔹 Update Installation schema with quotationId installation.quatationId = quotationId; await installation.save(); 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.getAllInstallers = async (request, reply) => { try { const { departmentName } = request.params; // Get installationId from request params // Check if installation exists const installationList = await Deparments.find({ departmentName }); if (!installationList) { return reply.status(404).send({ simplydata: { error: true, message: "Installation not found", }, }); } return reply.send({ simplydata: { error: false, installationList, // 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.editTeamMember = async (request, reply) => { try { const { installationId, teamMemberId } = request.params; const updateData = request.body; // Find the installation const installation = await Install.findOne({ installationId }); if (!installation) { return reply.status(404).send({ simplydata: { error: true, message: "Installation not found", }, }); } // Find the team member let teamMember = installation.team_member.team_member.find( (member) => member.teamMemberId === teamMemberId ); if (!teamMember) { return reply.status(404).send({ simplydata: { error: true, message: "Team member not found", }, }); } // Update fields Object.assign(teamMember, updateData); // Save changes await installation.markModified("team_member.team_member"); await installation.save(); return reply.send({ simplydata: { error: false, message: "Team member updated successfully", }, }); } catch (err) { console.error("Error updating team member:", err); reply.status(500).send({ simplydata: { error: true, message: "Internal server error", }, }); } }; exports.deleteTeamMember = async (request, reply) => { try { const { installationId, teamMemberId } = request.params; // Find the installation const installation = await Install.findOne({ installationId }); if (!installation) { return reply.status(404).send({ simplydata: { error: true, message: "Installation not found", }, }); } // Find index of the team member const memberIndex = installation.team_member.team_member.findIndex( (member) => member.teamMemberId === teamMemberId ); if (memberIndex === -1) { return reply.status(404).send({ simplydata: { error: true, message: "Team member not found", }, }); } // Remove the team member from the array installation.team_member.team_member.splice(memberIndex, 1); // Save changes await installation.markModified("team_member.team_member"); await installation.save(); return reply.send({ simplydata: { error: false, message: "Team member deleted successfully", }, }); } catch (err) { console.error("Error deleting team member:", err); reply.status(500).send({ simplydata: { error: true, message: "Internal server error", }, }); } }; exports.getQuotationsByInstallationId = async (request, reply) => { try { const { installationId } = request.params; if (!installationId) { return reply.status(400).send({ simplydata: { error: true, message: "Installation ID is required", }, }); } // 🔹 Fetch quotations based on installationId const quotations = await Order.find({ installationId }); if (!quotations || quotations.length === 0) { return reply.status(404).send({ simplydata: { error: true, message: "No quotations found for this installation ID", }, }); } 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", }, }); } // 🔹 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.getDepartmentByFirstName = async (req, reply) => { try { let { firstName } = req.params; if (!firstName) { return reply.status(400).send({ simplydata: { error: true, message: "firstName is required" }, }); } // Trim and convert to lowercase firstName = firstName.trim().toLowerCase(); console.log("Searching for firstName:", firstName); // Debugging log // Search for the department with case-insensitive and space-tolerant regex const department = await Deparments.findOne({ firstName: { $regex: `^\\s*${firstName}\\s*$`, $options: "i" } }).lean(); console.log("Department found:", department); // Debugging log if (!department) { return reply.status(404).send({ simplydata: { error: true, message: "Department not found" }, }); } return reply.send({ simplydata: { error: false, message: "Department details fetched successfully", firstName: department.firstName, phone: department.phone, }, }); } catch (err) { console.error("Error fetching department details:", err); return reply.status(500).send({ simplydata: { error: true, message: "Internal server error" }, }); } }; // const moment = require('moment-timezone'); exports.getByHardwareId = async (req, reply) => { try { const { hardwareId } = req.params; if (!hardwareId) { return reply.status(400).send({ error: "hardwareId is required" }); } console.log("Fetching details for hardwareId:", hardwareId); const iotData = await IotData.find({ hardwareId }) .sort({ date: -1 }) .limit(3) .lean(); if (!iotData || iotData.length === 0) { return reply.send({ status_code: 404, message: "IoT Data not found", data: null }); } const latestRecord = iotData[0]; const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata"); const connected_gsm_date = indiaTime.format("DD-MM-YYYY"); 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 ? "connected" : "disconnected"; const gsmLastCheckTime = now.format("DD-MM-YYYY HH:mm:ss"); await Insensors.findOneAndUpdate( { hardwareId }, { $set: { connected_gsm_date, connected_gsm_time, connected_status: gsmStatus, gsm_last_check_time: gsmLastCheckTime } } ); const tanksWithConnectionStatus = latestRecord.tanks.map(tank => { const tankMoment = moment.tz(tank.date, "Asia/Kolkata"); const tankDiff = now.diff(tankMoment, "minutes"); return { ...tank, connected_status: tankDiff <= 1 ? "connected" : "disconnected" }; }); // 🔁 Raise ticket if applicable const sensor = await Insensors.findOne({ hardwareId }).lean(); if (sensor?.customerId) { await raiseATicketLikeLogic(sensor.customerId, hardwareId); } return reply.send({ status_code: 200, message: "Success", data: { hardwareId, gsm_connected_status: gsmStatus, gsmStatus: isGSMConnected ? "GSM Connected" : "GSM Not Connected", connected_gsm_date, connected_gsm_time, gsm_last_check_time: gsmLastCheckTime, tanks: tanksWithConnectionStatus, date: latestRecord.date, time: latestRecord.time } }); } catch (err) { console.error("Error in getByHardwareId:", err); return reply.status(500).send({ error: "Internal Server Error" }); } }; exports.getByHardwareIdSupport = async (req, reply) => { try { const { hardwareId } = req.params; if (!hardwareId) { return reply.status(400).send({ error: "hardwareId is required" }); } console.log("Fetching details for hardwareId:", hardwareId); const iotData = await IotData.find({ hardwareId }) .sort({ date: -1 }) .limit(3) .lean(); if (!iotData || iotData.length === 0) { return reply.send({ status_code: 404, message: "IoT Data not found", data: null }); } const latestRecord = iotData[0]; const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata"); const connected_gsm_date = indiaTime.format("DD-MM-YYYY"); 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 ? "connected" : "disconnected"; const gsmLastCheckTime = now.format("DD-MM-YYYY HH:mm:ss"); await Insensors.findOneAndUpdate( { hardwareId }, { $set: { connected_gsm_date, connected_gsm_time, connected_status: gsmStatus, support_gsm_last_check_time: gsmLastCheckTime } } ); const tanksWithConnectionStatus = latestRecord.tanks.map(tank => { const tankMoment = moment.tz(tank.date, "Asia/Kolkata"); const tankDiff = now.diff(tankMoment, "minutes"); return { ...tank, connected_status: tankDiff <= 1 ? "connected" : "disconnected" }; }); // 🔁 Raise ticket if applicable const sensor = await Insensors.findOne({ hardwareId }).lean(); if (sensor?.customerId) { await raiseATicketLikeLogic(sensor.customerId, hardwareId); } return reply.send({ status_code: 200, message: "Success", data: { hardwareId, gsm_connected_status: gsmStatus, gsmStatus: isGSMConnected ? "GSM Connected" : "GSM Not Connected", connected_gsm_date, connected_gsm_time, support_gsm_last_check_time: gsmLastCheckTime, tanks: tanksWithConnectionStatus, date: latestRecord.date, time: latestRecord.time } }); } catch (err) { console.error("Error in getByHardwareId:", err); return reply.status(500).send({ error: "Internal Server Error" }); } }; exports.getByHardwareIdSupportTeamMember = async (req, reply) => { try { const { hardwareId } = req.params; if (!hardwareId) { return reply.status(400).send({ error: "hardwareId is required" }); } console.log("Fetching details for hardwareId:", hardwareId); const iotData = await IotData.find({ hardwareId }) .sort({ date: -1 }) .limit(3) .lean(); if (!iotData || iotData.length === 0) { return reply.send({ status_code: 404, message: "IoT Data not found", data: null }); } const latestRecord = iotData[0]; const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata"); const connected_gsm_date = indiaTime.format("DD-MM-YYYY"); 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 ? "connected" : "disconnected"; const gsmLastCheckTime = now.format("DD-MM-YYYY HH:mm:ss"); // formatted current time // ✅ Update slaves connected to this master hardwareId await Insensors.updateMany( { connected_to: hardwareId }, { $set: { connected_gsm_date, connected_gsm_time, connected_status: gsmStatus, team_member_support_gsm_last_check_time: gsmLastCheckTime } } ); // ✅ Update the master device itself (if it's a master) await Insensors.updateOne( { hardwareId }, { $set: { connected_gsm_date, connected_gsm_time, connected_status: gsmStatus, team_member_support_gsm_last_check_time: gsmLastCheckTime } } ); // ✅ Annotate tanks with LoRa connection status const tanksWithConnectionStatus = latestRecord.tanks.map(tank => { const tankMoment = moment.tz(tank.date, "Asia/Kolkata"); const tankDiff = now.diff(tankMoment, "minutes"); return { ...tank, connected_status: tankDiff <= 1 ? "connected" : "disconnected" }; }); // ✅ Response return reply.send({ status_code: 200, message: "Success", data: { hardwareId, gsm_connected_status: gsmStatus, gsmStatus: isGSMConnected ? "GSM Connected" : "GSM Not Connected", connected_gsm_date, connected_gsm_time, team_member_support_gsm_last_check_time: gsmLastCheckTime, tanks: tanksWithConnectionStatus, date: latestRecord.date, time: latestRecord.time } }); } catch (err) { console.error("Error in getByHardwareIdSupport:", err); return reply.status(500).send({ error: "Internal Server Error" }); } }; exports.getByHardwareAndTankId = async (req, reply) => { try { const { hardwareId, tankhardwareId } = req.params; if (!hardwareId || !tankhardwareId) { return reply.status(400).send({ error: "Both hardwareId and tankhardwareId are required" }); } console.log("📡 Fetching data for:", { hardwareId, tankhardwareId }); // Get the latest IoT data for the master hardwareId const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); if (!latestData || !Array.isArray(latestData.tanks)) { return reply.code(404).send({ message: "No data found for given hardwareId and tankhardwareId" }); } const now = new Date(); const dataDate = new Date(latestData.date); // Check master GSM connection (threshold 60 sec) const isGSMConnected = now - dataDate <= 60000; // Find the tank for the slave const matchedTank = latestData.tanks.find(tank => tank.tankhardwareId === tankhardwareId); if (!matchedTank) { return reply.code(404).send({ message: "Tank not found in latest record" }); } const tankHeight = parseFloat(matchedTank.tankHeight || "0"); // If master is disconnected => slave is disconnected too let isLoraConnected = false; if (!isGSMConnected) { isLoraConnected = false; } else { // Otherwise use tankHeight to determine LoRa connection isLoraConnected = tankHeight > 0; } // Format tank date/time to IST const matchedTankDateObj = new Date(matchedTank.date); const formattedDate = moment(matchedTankDateObj).tz("Asia/Kolkata").format("DD-MM-YYYY"); const formattedTime = matchedTank.time || moment(matchedTankDateObj).tz("Asia/Kolkata").format("HH:mm:ss"); matchedTank.date = formattedDate; matchedTank.time = formattedTime; // Prepare update object for Insensors collection const updateFields = { connected_status: isLoraConnected ? "connected" : "disconnected", connected_lora_date: formattedDate, connected_lora_time: formattedTime, lora_last_check_time: moment().tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss") }; const sensorDoc = await Insensors.findOne({ tankhardwareId: tankhardwareId, connected_to: hardwareId }); if (!sensorDoc) { console.warn("⚠️ No Insensors doc found for LoRa update:", { tankhardwareId, connected_to: hardwareId }); const fallbackDoc = await Insensors.findOne({ tankhardwareId: tankhardwareId }); if (fallbackDoc) { await Insensors.updateOne({ _id: fallbackDoc._id }, { $set: updateFields }); console.log("⚠️ Fallback Insensors updated by tankhardwareId:", fallbackDoc._id); } } else { await Insensors.updateOne({ _id: sensorDoc._id }, { $set: updateFields }); console.log("✅ Insensors LoRa status updated:", sensorDoc._id); } return reply.send({ status_code: 200, message: isLoraConnected ? "LoRa connected" : "LoRa not connected", data: matchedTank, lora_connected_status: updateFields.connected_status, connected_lora_date: updateFields.connected_lora_date, connected_lora_time: updateFields.connected_lora_time, lora_last_check_time: updateFields.lora_last_check_time }); } catch (err) { console.error("❌ Error in getByHardwareAndTankId:", err); return reply.status(500).send({ error: "Internal Server Error" }); } }; exports.getByHardwareAndTankIdSupport = async (req, reply) => { try { const { hardwareId, tankhardwareId } = req.params; if (!hardwareId || !tankhardwareId) { return reply.status(400).send({ error: "Both hardwareId and tankhardwareId are required" }); } console.log("Fetching tank data for:", { hardwareId, tankhardwareId }); const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); if (!latestData || !Array.isArray(latestData.tanks)) { return reply.code(404).send({ message: "No data found for given hardwareId and tankhardwareId" }); } const now = new Date(); const dataDate = new Date(latestData.date); const diffInMs = now - dataDate; const isGSMConnected = diffInMs <= 60000; const matchedTank = latestData.tanks.find(tank => tank.tankhardwareId === tankhardwareId); if (!matchedTank) { return reply.code(404).send({ message: "Tank not found in latest record" }); } const tankHeight = parseFloat(matchedTank.tankHeight || "0"); const isLoraConnected = isGSMConnected && tankHeight > 0; const matchedTankDateObj = new Date(matchedTank.date); const day = String(matchedTankDateObj.getDate()).padStart(2, '0'); const month = String(matchedTankDateObj.getMonth() + 1).padStart(2, '0'); const year = matchedTankDateObj.getFullYear(); const formattedDate = `${day}-${month}-${year}`; matchedTank.date = formattedDate; const support_lora_last_check_time = moment.tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss"); const updateFields = { connected_status: isLoraConnected ? "connected" : "disconnected", support_lora_last_check_time }; let connected_lora_date = null; let connected_lora_time = null; if (isLoraConnected) { connected_lora_date = formattedDate; connected_lora_time = matchedTank.time || matchedTankDateObj.toTimeString().split(" ")[0]; updateFields.connected_lora_date = connected_lora_date; updateFields.connected_lora_time = connected_lora_time; } // Support both slave and master structure const updatedSensor = await Insensors.findOneAndUpdate( { $or: [ { connected_to: hardwareId, tankhardwareId: tankhardwareId }, // slave { hardwareId: tankhardwareId } // master ] }, { $set: updateFields }, { new: true } ); if (!updatedSensor) { console.warn("No matching Insensors document found for update"); } else { console.log("Updated support_lora_last_check_time for:", updatedSensor.hardwareId); } const displayMessage = isLoraConnected ? "LoRa connected" : "LoRa not connected"; return reply.send({ status_code: 200, message: displayMessage, data: matchedTank, lora_connected_status: updateFields.connected_status, connected_lora_date, connected_lora_time, support_lora_last_check_time }); } catch (err) { console.error("Error in getByHardwareAndTankIdSupport:", err); return reply.status(500).send({ error: "Internal Server Error" }); } }; exports.getByHardwareAndTankIdSupportTeamMember = async (req, reply) => { try { const { hardwareId, tankhardwareId } = req.params; if (!hardwareId || !tankhardwareId) { return reply.status(400).send({ error: "Both hardwareId and tankhardwareId are required" }); } console.log("Fetching tank data for:", { hardwareId, tankhardwareId }); const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); if (!latestData || !Array.isArray(latestData.tanks)) { return reply.code(404).send({ message: "No data found for given hardwareId and tankhardwareId" }); } const now = new Date(); const dataDate = new Date(latestData.date); const diffInMs = now - dataDate; const isGSMConnected = diffInMs <= 60000; const matchedTank = latestData.tanks.find(tank => tank.tankhardwareId === tankhardwareId); if (!matchedTank) { return reply.code(404).send({ message: "Tank not found in latest record" }); } const tankHeight = parseFloat(matchedTank.tankHeight || "0"); const isLoraConnected = isGSMConnected && tankHeight > 0; const matchedTankDateObj = new Date(matchedTank.date); const day = String(matchedTankDateObj.getDate()).padStart(2, '0'); const month = String(matchedTankDateObj.getMonth() + 1).padStart(2, '0'); const year = matchedTankDateObj.getFullYear(); const formattedDate = `${day}-${month}-${year}`; matchedTank.date = formattedDate; const team_member_support_lora_last_check_time = moment.tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss"); const updateFields = { connected_status: isLoraConnected ? "connected" : "disconnected", team_member_support_lora_last_check_time }; let connected_lora_date = null; let connected_lora_time = null; if (isLoraConnected) { connected_lora_date = formattedDate; connected_lora_time = matchedTank.time || matchedTankDateObj.toTimeString().split(" ")[0]; updateFields.connected_lora_date = connected_lora_date; updateFields.connected_lora_time = connected_lora_time; } // Support both slave and master structure const updatedSensor = await Insensors.findOneAndUpdate( { $or: [ { connected_to: hardwareId, tankhardwareId: tankhardwareId }, // slave { hardwareId: tankhardwareId } // master ] }, { $set: updateFields }, { new: true } ); if (!updatedSensor) { console.warn("No matching Insensors document found for update"); } else { console.log("Updated support_lora_last_check_time for:", updatedSensor.hardwareId); } const displayMessage = isLoraConnected ? "LoRa connected" : "LoRa not connected"; return reply.send({ status_code: 200, message: displayMessage, data: matchedTank, lora_connected_status: updateFields.connected_status, connected_lora_date, connected_lora_time, team_member_support_lora_last_check_time }); } catch (err) { console.error("Error in getByHardwareAndTankIdSupport:", err); return reply.status(500).send({ error: "Internal Server Error" }); } }; exports.getAllocatedSensorsByTank = async (req, reply) => { try { let { customerId, tankName } = req.params; if (!customerId || !tankName) { return reply.status(400).send({ error: "customerId and tankName are required" }); } tankName = tankName.trim(); // Trim spaces console.log("Querying MongoDB with:", { customerId, tankName, status: "blocked" }); const allocatedSensors = await Insensors.find({ customerId, tankName: { $regex: `^${tankName}$`, $options: "i" }, // Case-insensitive search status: "blocked", }).lean(); if (!allocatedSensors.length) { return reply.send({ status_code: 200, message: "No allocated sensors found for this tank", allocatedSensors: [], }); } return reply.send({ status_code: 200, message: "Allocated sensors fetched successfully", allocatedSensors, }); } catch (err) { console.error("Error fetching allocated sensors:", err); return reply.status(500).send({ error: "Internal server error" }); } }; exports.createMasterSlaveData = async (req, reply) => { try { const { installationId } = req.params; const { type, customerId, hardwareId, batchno, masterId, tankName, tankLocation, materialRecived, electricityWork, plumbingWork, loraCheck } = req.body; if (!installationId || !hardwareId || !masterId) { return reply.status(400).send({ message: "installationId, hardwareId, and masterId are required." }); } // 🔹 Fetch stored electricity work pictures const electricityWorkData = await ElectrictyWorkPictures.findOne({ installationId, customerId }); const electricityWorkPictures = electricityWorkData ? electricityWorkData.pictureUrl.map(pic => ({ url: pic.url, uploadedAt: new Date() })) : []; // 🔹 Fetch stored plumbing work pictures const plumbingWorkData = await PlumbingWorkPictures.findOne({ installationId, customerId }); const plumbingWorkPictures = plumbingWorkData ? plumbingWorkData.pictureUrl.map(pic => ({ url: pic.url, uploadedAt: new Date() })) : []; const materialRecievedData = await MaterialRecievedPictures.findOne({ installationId, customerId }); const materialRecievedPictures = materialRecievedData ? materialRecievedData.pictureUrl.map(pic => ({ url: pic.url, uploadedAt: new Date() })) : []; // 🔹 Save all data to MasterSlaveData const newData = new MasterSlaveData({ installationId, type, customerId, hardwareId, batchno, masterId, tankName, tankLocation, materialRecived, electricityWork, plumbingWork, loraCheck, electricityWorkPictures, plumbingWorkPictures, materialRecievedPictures }); await newData.save(); reply.status(201).send({ message: "Master-Slave data created successfully", data: newData }); } catch (err) { reply.status(500).send({ message: err.message }); } }; 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.mastrerList = async (req, reply) => { try { const { customerId, installationId } = req.params; // Step 1: Get User and extract buildingName const user = await User.findOne({ customerId , installationId }); if (!user) { return reply.status(404).send({ success: false, message: "User not found" }); } const { buildingName } = user; // Step 2: Get Tanks with matching customerId const tanks = await Tank.find({ customerId }); if (!tanks.length) { return reply.status(404).send({ success: false, message: "No tanks found for this customer" }); } const {tankLocation,typeOfWater} = tanks //console.log(tanks) // Step 3: Extract hardwareId from tanks const hardwareIds = tanks.map(tank => tank.hardwareId); // Step 4: Find master tanks in InSensors with both customerId and installationId const masterTanks = await Insensors.find({ customerId, connected_to: { $in: hardwareIds }, type: "master" }); if (!masterTanks.length) { return reply.status(404).send({ success: false, message: "No master tanks found" }); } return reply.send({ success: true,tankLocation,typeOfWater ,buildingName, data: masterTanks, user }); } catch (error) { console.error("Error fetching master tanks:", error); return reply.status(500).send({ success: false, message: "Internal Server Error" }); } }; //const Insensor = mongoose.model('insensors', insensorsSchema); // if not already defined // exports.getMasterSlaveSummary = async (req, reply) => { // const { customerId } = req.params; // 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 }); // } // } // 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(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 // }; // }); // 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 for the customer const masters = await Insensors.find({ customerId, type: "master" }).lean(); // Fetch orders to map hardwareId to masterName/location const orders = await Order.find({ customerId }).lean(); const orderMap = {}; orders.forEach(order => { order.master_connections.forEach(connection => { orderMap[connection.hardwareId] = { masterName: connection.master_name || null, location: connection.location || null, }; }); }); const result = []; for (const master of masters) { const orderInfo = orderMap[master.hardwareId] || {}; // Prefer Insensors info, fallback to order info const masterName = master.masterName || orderInfo.masterName || null; const location = master.location || orderInfo.location || null; // Fetch the latest GSM data for the master device const latestGsmData = await IotData.findOne({ hardwareId: master.hardwareId }) .sort({ date: -1, time: -1 }) .lean(); let connectedGsmDate = null; let connectedGsmTime = null; let gsmStatus = "unknown"; let gsmLastCheckTime = null; let gsmLastDisconnect = master.gsm_last_disconnect_time || null; if (latestGsmData?.date && latestGsmData?.time) { // Combine date + time and parse as Asia/Kolkata timezone const indiaTime = moment.tz( `${moment(latestGsmData.date).format("YYYY-MM-DD")} ${latestGsmData.time}`, "YYYY-MM-DD HH:mm:ss", "Asia/Kolkata" ); connectedGsmDate = indiaTime.format("DD-MM-YYYY"); connectedGsmTime = indiaTime.format("HH:mm:ss"); const now = moment.tz("Asia/Kolkata"); const diffInMinutes = now.diff(indiaTime, "minutes"); gsmStatus = diffInMinutes <= 1 ? "connected" : "disconnected"; gsmLastCheckTime =master.gsm_last_check_time; if (gsmStatus === "disconnected") { // Update disconnect time with latest disconnect timestamp gsmLastDisconnect = `${connectedGsmDate} ${connectedGsmTime}`; } // Update master device with latest GSM info await Insensors.updateOne( { hardwareId: master.hardwareId }, { $set: { connected_status: gsmStatus, connected_gsm_date: connectedGsmDate, connected_gsm_time: connectedGsmTime, gsm_last_check_time: gsmLastCheckTime, gsm_last_disconnect_time: gsmLastDisconnect, }, } ); } // Process connected slave devices for the master const connectedSlaves = []; const slaves = await Insensors.find({ connected_to: master.hardwareId, type: "slave" }).lean(); console.log("slaves",slaves) for (const slave of slaves) { const now = moment.tz("Asia/Kolkata"); let connectedLoraDate = null; let connectedLoraTime = null; let loraStatus = "disconnected"; let loraLastDisconnect = slave.lora_last_disconnect_time || null; let loraLastCheckTime = slave.lora_last_check_time; let tankHeight = null; // Fetch latest IotData for slave's hardwareId (NOT master's) const slaveIot = await IotData.findOne({ hardwareId: slave.connected_to }) .sort({ date: -1, time: -1 }) .lean(); if (slaveIot?.tanks?.length && slave.tankhardwareId) { const matchedTank = slaveIot.tanks.find( t => t.tankhardwareId === slave.tankhardwareId ); if (matchedTank) { const indiaTime = moment.tz( `${moment(matchedTank.date).format("YYYY-MM-DD")} ${matchedTank.time}`, "YYYY-MM-DD HH:mm:ss", "Asia/Kolkata" ); connectedLoraDate = indiaTime.format("DD-MM-YYYY"); connectedLoraTime = indiaTime.format("HH:mm:ss"); tankHeight = parseFloat(matchedTank.tankHeight) || 0; const diffMinutes = now.diff(indiaTime, "minutes"); // Connected if tankHeight > 0 and data not older than 5 mins loraStatus = (tankHeight > 0 && diffMinutes <= 1) ? "connected" : "disconnected"; if (loraStatus === "disconnected") { loraLastDisconnect = `${connectedLoraDate} ${connectedLoraTime}`; } } } const matchedTankDetails = await Tank.findOne({ customerId, tankhardwareId: slave.tankhardwareId, }).lean(); if (matchedTankDetails?.typeOfWater) { typeOfWater = matchedTankDetails.typeOfWater; } // Update DB with new status and timestamps await Insensors.updateOne( { hardwareId: slave.hardwareId }, { $set: { connected_status: loraStatus, connected_lora_date: connectedLoraDate, connected_lora_time: connectedLoraTime, lora_last_check_time: loraLastCheckTime, lora_last_disconnect_time: loraLastDisconnect, }, } ); connectedSlaves.push({ hardwareId: slave.hardwareId, tankhardwareId: slave.tankhardwareId || null, tankName: slave.tankName || null, location: slave.tankLocation || null, connected_status: loraStatus, connected_lora_date: connectedLoraDate, connected_lora_time: connectedLoraTime, lora_last_check_time: loraLastCheckTime, lora_last_disconnect_time: loraLastDisconnect, type: slave.type || "slave", typeOfWater, connected_to: slave.connected_to || null, }); } result.push({ hardwareId: master.hardwareId, masterName, location, type: master.type || "master", connected_status: gsmStatus, connected_slave_count: connectedSlaves.length, connected_slaves: connectedSlaves, connected_gsm_date: connectedGsmDate, connected_gsm_time: connectedGsmTime, gsm_last_check_time: gsmLastCheckTime, 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" }); } }; // 🔍 Helper to get tankHeight from latest IotData record async function getTankHeight(tankhardwareId) { const iotData = await IotData.findOne({ 'tanks.tankhardwareId': tankhardwareId }) .sort({ date: -1 }) .lean(); if (!iotData) return null; const matchedTank = iotData.tanks.find(t => t.tankhardwareId === 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()); // }); // outputConnections.forEach(conn => { // if (conn.motor_id) motorIdSet.add(conn.motor_id.trim()); // }); // } // const motorIds = Array.from(motorIdSet); // console.log("Unique motorIds collected:", motorIds); // if (motorIds.length === 0) { // return reply.send({ status_code: 200, message: "No motors connected", data: [] }); // } // // 3. Fetch the latest IotData for each unique hardwareId // const latestIotDataPromises = motorIds.map(hardwareId => // IotData.findOne({ hardwareId }).sort({ date: -1 }).lean() // ); // const iotDataResults = await Promise.all(latestIotDataPromises); // const filteredData = iotDataResults.filter(doc => doc); // remove nulls // console.log("Latest IotData entries found:", filteredData.length); // 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." }); } // ✅ Get only master hardware IDs from Insensors directly const masterSensors = sensors.filter(s => s.type === 'master'); const masterHardwareIds = masterSensors.map(m => m.hardwareId?.trim()); // ✅ Map for masterName/location from Order const orders = await Order.find({ customerId }).lean(); const orderMap = {}; orders.forEach(order => { order.master_connections.forEach(connection => { orderMap[connection.hardwareId] = { masterName: connection.master_name || null, location: connection.location || null }; }); }); // ✅ Prepare final enriched master data const enrichedMasters = await Promise.all(masterHardwareIds.map(async (hardwareId) => { const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); const orderInfo = orderMap[hardwareId] || {}; if (!latestRecord) { return { hardwareId, message: "No IoT data found", masterName: orderInfo.masterName ?? null, location: orderInfo.location ?? null, tanks: [] }; } // ✅ Check GSM status const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata"); const now = moment.tz("Asia/Kolkata"); const diffInMinutes = now.diff(indiaTime, "minutes"); const gsmConnected = diffInMinutes <= 1; const message = gsmConnected ? "GSM is connected" : "GSM is not connected"; // ✅ Get slaves connected to this master const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId); // ✅ Prepare tank info const tanks = connectedSlaves.map(slave => { const slaveId = slave.tankhardwareId?.trim(); const matchedTank = latestRecord.tanks?.find(t => t.tankhardwareId === slaveId); let loraMessage = "LORA is not connected"; if (matchedTank?.date && matchedTank.tankHeight !== "0") { const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata"); const loraDiff = now.diff(tankTime, "minutes"); loraMessage = loraDiff <= 1 ? "LORA is connected" : "LORA is not connected"; } return { tankhardwareId: slaveId, tankName: slave.tankName ?? null, tankLocation: slave.tankLocation ?? null, masterName: orderInfo.masterName ?? null, location: orderInfo.location ?? null, loraMessage, latestTankData: matchedTank ?? null }; }); return { hardwareId, message, masterName: orderInfo.masterName ?? null, location: orderInfo.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.getIotDataByCustomerAndHardwareId = async (req, reply) => { try { const { customerId, hardwareId } = req.params; if (!customerId || !hardwareId) { return reply.code(400).send({ error: "Both customerId and hardwareId are required" }); } // Step 1: Get all sensors const sensors = await Insensors.find({ customerId }); if (!sensors.length) { return reply.code(404).send({ message: "No sensors found for this customer." }); } // Step 2: Get latest IoT data const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean(); if (!latestRecord) { return reply.code(404).send({ hardwareId, message: "No IoT data found", tanks: [] }); } // Step 3: Calculate GSM connection status const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata"); const now = moment.tz("Asia/Kolkata"); const diffInMinutes = now.diff(indiaTime, "minutes"); const gsmConnected = diffInMinutes <= 1; const gsmMessage = gsmConnected ? "GSM is connected" : "GSM is not connected"; // Step 4: Get all connected slaves const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId); // Step 5: Get orderMap for fallback master info const orders = await Order.find({ customerId }).lean(); const orderMap = {}; orders.forEach(order => { order.master_connections?.forEach(connection => { orderMap[connection.hardwareId] = { masterName: connection.master_name || null, location: connection.location || null }; }); }); // Step 6: Fallback master info from orderMap const fallbackMasterInfo = orderMap[hardwareId] || { masterName: null, location: null }; // Step 7: Map tanks data const tanks = connectedSlaves.map(slave => { const slaveId = slave.tankhardwareId?.trim(); const matchedTank = latestRecord.tanks?.find(tank => tank.tankhardwareId === slaveId); let loraConnected = false; let loraMessage = "LORA is not connected"; if (matchedTank?.date && matchedTank.tankHeight !== "0") { const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata"); const loraDiff = now.diff(tankTime, "minutes"); loraConnected = loraDiff <= 1; loraMessage = loraConnected ? "LORA is connected" : "LORA is not connected"; } return { tankhardwareId: slaveId, tankName: slave.tankName ?? null, tankLocation: slave.tankLocation ?? null, masterName: slave.masterName ?? fallbackMasterInfo.masterName, location: slave.location ?? fallbackMasterInfo.location, message: loraMessage, latestTankData: matchedTank ?? null }; }); // Step 8: Send response return reply.send({ status_code: 200, message: "Success", data: { hardwareId, message: gsmMessage, masterName: connectedSlaves[0]?.masterName ?? fallbackMasterInfo.masterName, location: connectedSlaves[0]?.location ?? fallbackMasterInfo.location, tanks } }); } catch (err) { console.error("Error fetching IoT data by customerId and hardwareId:", err); return reply.code(500).send({ error: "Internal Server Error" }); } }; //const moment = require("moment-timezone"); // 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 }).lean(); // const orders = await Order.find({ customerId }).lean(); // 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 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 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; // } // 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 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 // }); // } // } // } // 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" }); // } // // Fetch all sensors and orders for the customer // const sensors = await Insensors.find({ customerId }).lean(); // const orders = await Order.find({ customerId }).lean(); // if (!sensors.length) { // return reply.code(404).send({ message: "No sensors found for this customer." }); // } // // 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." }); // } // // 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 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 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"); const masterConnectedStatus = masterSensor.connected_status || "disconnected"; const lastDataTime = masterSensor.connected_gsm_date && masterSensor.connected_gsm_time ? `${masterSensor.connected_gsm_date} ${masterSensor.connected_gsm_time}` : "No data"; // Get all slaves connected to this master const connectedSlaves = sensors.filter( s => s.connected_to?.trim() === connected_to.trim() && s.type === "slave" ); const disconnectedSlaves = connectedSlaves.filter( s => s.connected_status === "disconnected" ).map(s => ({ slaveHardwareId: s.tankhardwareId, slaveName: s.tankName || "Unknown Slave" })); // No ticket needed if everything is connected if (disconnectedSlaves.length === 0 && masterConnectedStatus === "connected") return; const supportRecord = await Support.findOne({ supportId: "AWHYSU64" }); if (!supportRecord) return; const existingIssues = supportRecord.issues || []; const unresolvedMasterIssue = existingIssues.find( issue => issue.hardwareId === connected_to && issue.type === "GSM or LoRa Disconnected" && issue.resolved === false ); // Skip raising a ticket if unresolved issue already exists if (unresolvedMasterIssue) return; const resolvedMasterIssue = existingIssues.find( issue => issue.hardwareId === connected_to && issue.type === "GSM or LoRa Disconnected" && issue.resolved === true ); const alreadyReportedSlaves = new Set(resolvedMasterIssue?.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 a new issue 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() } } ); } catch (error) { console.error("Error in raiseATicketLikeLogic:", 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("* * * * *", async () => { try { console.log("🔁 Running auto-disconnect ticket check..."); const allMasters = await Insensors.find({ type: "master" }).lean(); for (const master of allMasters) { const customerId = master.customerId; const hardwareId = master.hardwareId; const connectedSlaves = await Insensors.find({ connected_to: hardwareId, type: "slave" }).lean(); const disconnectedSlaves = connectedSlaves.filter( s => s.connected_status === "disconnected" ); const masterIsDisconnected = master.connected_status === "disconnected"; if (masterIsDisconnected || disconnectedSlaves.length > 0) { await raiseATicketLikeLogic(customerId, hardwareId); } } } 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" }); // } // }; 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++; } } // Map comments to only the text strings const commentTexts = (supportRecord.comments || []).map(c => c.text); // Add these comments to each master in disconnectedIssues for (const master of Object.values(masterMap)) { master.comments = commentTexts; } 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.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; if (!supportId || !hardwareId) { return reply.code(400).send({ error: "supportId and hardwareId are required" }); } // Find the support record const supportRecord = await Support.findOne({ supportId }).lean(); if (!supportRecord) { return reply.code(404).send({ message: "No support record found for this supportId" }); } const originalIssues = supportRecord.issues || []; // Filter out issues where hardwareId matches hardwareId or masterHardwareId const filteredIssues = originalIssues.filter(issue => { return !( issue.hardwareId === hardwareId || issue.masterHardwareId === hardwareId ); }); // Update the support record await Support.updateOne( { supportId }, { $set: { issues: filteredIssues } } ); return reply.send({ status_code: 200, message: `Issue(s) with hardwareId "${hardwareId}" removed successfully.`, remainingIssues: filteredIssues }); } catch (error) { console.error("Error in removeIssueByHardwareId:", 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. 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. Filter only unresolved issues const unresolvedIssues = (supportRecord.issues || []).filter(issue => issue.resolved === false); // 3. Collect all unique hardwareIds (from hardwareId and hardwareIds arrays) from unresolved issues 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); console.log("hardwareIdsArray",hardwareIdsArray) // 4. Find disconnected insensors using connected_to match const disconnectedSensors = await Insensors.find({ connected_to: { $in: hardwareIdsArray }, connected_status: "disconnected" }).lean(); if (!disconnectedSensors.length) { return reply.code(404).send({ message: "No disconnected issues found" }); } // 5. Get unique customerIds from disconnected sensors const customerIds = [...new Set(disconnectedSensors.map(s => s.customerId))]; const customers = await User.find({ customerId: { $in: customerIds } }).lean(); // 6. For each customer, calculate total unique hardwareIds involved in their disconnected sensors 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); } console.log("allIssueHardwareIds",allIssueHardwareIds) } } // 7. Build final response const response = []; for (const user of customers) { const custId = user.customerId; const hardwareIdSet = customerHardwareMap[custId] || new Set(); // Extract latest unresolved issue-specific lastTicketRaisedAt const relatedIssues = unresolvedIssues.filter(issue => { const issueHw = issue.hardwareId?.trim().toLowerCase(); const hardwareIds = issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []; const allIds = [issueHw, ...hardwareIds]; console.log("allIds",allIds) console.log("Array.from(hardwareIdSet).some(hw => allIds.includes(hw?.trim().toLowerCase()))",Array.from(hardwareIdSet).some(hw => allIds.includes(hw?.trim().toLowerCase()))) return Array.from(hardwareIdSet).some(hw => allIds.includes(hw?.trim().toLowerCase())); }); //console.log("relatedIssues",relatedIssues) 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.getDisconnectedCustomerDetailsByTeamMemberId = async (req, reply) => { try { const { support_teamMemberId } = req.params; if (!support_teamMemberId) { return reply.code(400).send({ error: "support_teamMemberId is required" }); } // Step 1: Get support record with categorized issues assigned to the team member const supportRecord = await Support.findOne({ "team_member.team_member.support_teamMemberId": support_teamMemberId }).lean(); if (!supportRecord) { return reply.code(404).send({ message: "Support record not found" }); } // Step 2: Filter categorized issues assigned to this team member const assignedIssues = (supportRecord.categorizedIssues || []).filter( issue => issue.assignedTo?.support_teamMemberId === support_teamMemberId ); // Step 3: Extract unique hardwareIds from assigned issues const assignedHardwareIds = [ ...new Set( assignedIssues.map(issue => issue.hardwareId || issue.masterHardwareId).filter(Boolean) ) ]; if (assignedHardwareIds.length === 0) { return reply.code(404).send({ message: "No categorized issues assigned to this team member" }); } // Step 4: Find disconnected insensors (either masters or slaves) const disconnectedDevices = await Insensors.find({ $or: [ { hardwareId: { $in: assignedHardwareIds } }, { connected_to: { $in: assignedHardwareIds } } ], connected_status: "disconnected" }).lean(); if (disconnectedDevices.length === 0) { return reply.code(404).send({ message: "No disconnected devices assigned to this team member" }); } // Step 5: Extract unique customerIds const customerIds = [...new Set(disconnectedDevices.map(d => d.customerId))]; const users = await User.find({ customerId: { $in: customerIds } }).lean(); console.log("users",users) // Step 6: Prepare final response const response = users.map(user => ({ customerId: user.customerId, firstName: user.profile?.firstName || "", lastName: user.profile?.lastName || "", address1: user.profile?.address1 || "", address2: user.profile?.address2 || "", phone: user.phone || user.profile?.contactNumber || "", email: user.emails?.[0]?.email || "", latitude: user.latitude, longitude: user.longitude, fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string"), installationId: user.installationId || "", username: user.username || "", buildingName: user.buildingName || "", 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" }, createdAt: user.createdAt, updatedAt: user.updatedAt })); return reply.send({ status_code: 200, data: response }); } 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" }); } }; // const bcrypt = require("bcrypt"); exports.createTeamMemberSupport = async (req, reply) => { try { const { supportId } = req.params; const c_id = await generateTeamMemberId(); const support_teamMemberId = `AWTMSU${c_id}`; const { name, phone, installationTeamMemId, password, email, alternativePhone, status } = req.body; if (!supportId || !support_teamMemberId || !name || !phone || !password) { return reply.code(400).send({ error: "Missing required fields" }); } const supportRecord = await Support.findOne({ supportId }); if (!supportRecord) { return reply.code(404).send({ error: "Support record not found" }); } const existingMember = supportRecord.team_member?.team_member.find( member => member.phone === phone || member.support_teamMemberId === support_teamMemberId ); if (existingMember) { return reply.code(400).send({ error: "Team member with this phone or ID already exists" }); } const hashedPassword = await bcrypt.hash(password, 10); const newTeamMember = { support_teamMemberId, name, phone, installationTeamMemId, password: hashedPassword, status: status || "active", email: email || null, alternativePhone: alternativePhone || null, }; await Support.findOneAndUpdate( { supportId }, { $push: { "team_member.team_member": newTeamMember }, $set: { updatedAt: new Date() } }, { new: true } ); return reply.send({ status_code: 200, message: "Team member added successfully", teamMember: newTeamMember }); } catch (error) { console.error("Error adding team member:", error); return reply.code(500).send({ error: "Internal server error" }); } }; exports.getAllTeamMembersListSupport = async (req, reply) => { try { const { supportId } = req.params; 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 || []; return reply.send({ status_code: 200, message: "Team members fetched successfully", count: teamMembers.length, teamMembers }); } catch (error) { console.error("Error fetching team members:", error); return reply.code(500).send({ error: "Internal server error" }); } } exports.updateTeamMemberSupport = async (req, reply) => { try { const { supportId, teamMemberId } = req.params; const updateData = req.body; 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 memberIndex = teamMembers.findIndex(m => m.support_teamMemberId === teamMemberId); if (memberIndex === -1) { return reply.code(404).send({ error: "Team member not found" }); } Object.assign(teamMembers[memberIndex], updateData); await Support.updateOne( { supportId }, { $set: { "team_member.team_member": teamMembers, updatedAt: new Date() } } ); return reply.send({ status_code: 200, message: "Team member updated successfully", teamMember: teamMembers[memberIndex] }); } catch (error) { console.error("Error updating team member:", error); return reply.code(500).send({ error: "Internal server error" }); } }; exports.deleteTeamMemberSupport = async (req, reply)=> { try { const { supportId, teamMemberId } = req.params; const support = await Support.findOne({ supportId }); if (!support) { return reply.code(404).send({ error: "Support record not found" }); } const originalLength = support.team_member?.team_member.length || 0; const updatedTeam = support.team_member?.team_member.filter( m => m.support_teamMemberId !== teamMemberId ); if (originalLength === updatedTeam.length) { return reply.code(404).send({ error: "Team member not found" }); } await Support.updateOne( { supportId }, { $set: { "team_member.team_member": updatedTeam, updatedAt: new Date() } } ); return reply.send({ status_code: 200, message: "Team member deleted successfully" }); } catch (error) { console.error("Error deleting team member:", error); 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 = []; } // 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.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 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 slaveDetails = await Promise.all(slaves.map(async (slave) => { const slaveHardwareId = slave.tankhardwareId; const tankInfo = await Tank.findOne({ $or: [ { hardwareId: slaveHardwareId }, { tankhardwareId: slaveHardwareId } ] }).lean(); console.log("tankInfo",tankInfo) 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.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` }); } // ✅ Parse using moment with expected format const start = moment(startDate, "DD-MM-YYYY HH:mm", true); const end = moment(endDate, "DD-MM-YYYY HH:mm", true); if (!start.isValid() || !end.isValid()) { return reply.code(400).send({ error: 'Invalid startDate or endDate format. Use DD-MM-YYYY HH:mm' }); } const formattedStart = start.format("DD-MM-YYYY HH:mm:ss"); const formattedEnd = 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, endDate: formattedEnd }; 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 }); }; exports.getCategorizedIssue = async (request, reply) => { try { const { support_teamMemberId, customerId } = request.params; if (!support_teamMemberId || !customerId) { return reply.code(400).send({ error: "support_teamMemberId and customerId are required" }); } const supportRecords = await Support.find({ 'categorizedIssues.assignedTo.support_teamMemberId': support_teamMemberId }).lean(); if (!supportRecords.length) { return reply.code(404).send({ message: 'No categorized issues assigned to this team member.' }); } const allIssues = supportRecords.flatMap(s => s.categorizedIssues .filter(i => i.assignedTo?.support_teamMemberId === support_teamMemberId) .map(i => ({ ...i, supportId: s.supportId })) ); if (!allIssues.length) { return reply.code(404).send({ message: 'No categorized issues found for this team member.' }); } const supportId = allIssues[0].supportId; const hardwareIds = allIssues.map(i => i.hardwareId).filter(Boolean); const masterHardwareIds = allIssues.map(i => i.masterHardwareId).filter(Boolean); const insensors = await Insensors.find({ customerId, $or: [ { hardwareId: { $in: hardwareIds } }, { hardwareId: { $in: masterHardwareIds } } ], connected_status: "disconnected" }).lean(); if (!insensors.length) { return reply.code(404).send({ message: "No disconnected devices found for this customer and team member." }); } 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 formatDateIfValid = (value) => { const date = moment(value, "DD-MM-YYYY HH:mm:ss", true); return date.isValid() ? date.format("DD-MM-YYYY HH:mm:ss") : null; }; const formatDateIfValidShort = (date, time) => { if (!date || !time) return null; const dateTime = `${date} ${time}`; const parsed = moment(dateTime, "DD-MM-YYYY HH:mm:ss", true); return parsed.isValid() ? parsed.format("DD-MM-YYYY HH:mm:ss") : null; }; const disconnectedIssues = []; const masters = insensors.filter(d => d.type === "master"); for (const master of masters) { const masterIssue = allIssues.find(i => i.masterHardwareId === master.hardwareId); if (!masterIssue) continue; const slaves = await Insensors.find({ customerId, connected_to: master.hardwareId, connected_status: "disconnected", type: "slave" }).lean(); const slaveDetails = []; for (const slave of slaves) { const issue = allIssues.find(i => i.hardwareId === slave.hardwareId || (Array.isArray(i.hardwareIds) && i.hardwareIds.includes(slave.hardwareId)) ); slaveDetails.push({ hardwareId: slave.tankhardwareId, tankName: slave.tankName || "", location: slave.location || "", connected_status: slave.connected_status, team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time || null, lora_last_disconnect_time: formatDateIfValid(slave.lora_last_disconnect_time) || formatDateIfValidShort(slave.connected_lora_date, slave.connected_lora_time), connected_to: slave.connected_to || "", masterName: orderMap[master.hardwareId]?.masterName || "", type: "slave", typeOfWater: "", support_lora_last_check_time: null, category: issue?.category || "", startDate: issue?.assignedTo?.startDate ? moment(issue.assignedTo.startDate).format("YYYY-MM-DD HH:mm:ss") : null, endDate: issue?.assignedTo?.endDate ? moment(issue.assignedTo.endDate).format("YYYY-MM-DD HH:mm:ss") : null }); } 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: formatDateIfValid(master.gsm_last_disconnect_time) || formatDateIfValidShort(master.connected_gsm_date, master.connected_gsm_time), 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, category: masterIssue?.category || "", startDate: masterIssue?.assignedTo?.startDate ? moment(masterIssue.assignedTo.startDate).format("YYYY-MM-DD HH:mm:ss") : null, endDate: masterIssue?.assignedTo?.endDate ? moment(masterIssue.assignedTo.endDate).format("YYYY-MM-DD HH:mm:ss") : null }); } return reply.send({ status_code: 200, supportId, totalMasters: disconnectedIssues.length, disconnectedIssues }); } catch (error) { console.error("Error in getCategorizedIssue:", error); return reply.code(500).send({ error: "Internal server error" }); } }; exports.StatusTeamMember = async (request, reply) => { try { const { support_teamMemberId } = request.params; const { status } = request.body; if ( !support_teamMemberId || !status) { return reply.code(400).send({ success: false, message: " support_teamMemberId, and status are required." }); } const result = await Support.findOneAndUpdate( { 'team_member.team_member.support_teamMemberId': support_teamMemberId }, { $set: { 'team_member.team_member.$.status': status } }, { new: true } ); if (!result) { return reply.code(404).send({ success: false, message: "Team member not found with given supportId and support_teamMemberId." }); } return reply.send({ success: true, message: "Team member status updated successfully.", updatedMember: result.team_member.team_member.find( tm => tm.support_teamMemberId === support_teamMemberId ) }); } catch (error) { console.error("Error updating team member status:", error); return reply.code(500).send({ success: false, message: "Internal Server Error" }); } }; exports.updateComments = async (req, reply) => { try { const { supportId } = req.params; const { comments, customerId, hardwareId } = req.body; console.log("Incoming request body:", req.body); console.log("typeof comments:", typeof comments); console.log("value of comments:", comments); if (!supportId || !customerId || !hardwareId) { return reply.code(400).send({ error: "supportId, customerId and hardwareId are required" }); } const trimmedComment = typeof comments === "string" ? comments.trim() : ""; if (!trimmedComment) { return reply.code(400).send({ error: "comments must be a non-empty string" }); } // Step 1: Validate sensor const sensor = await Insensors.findOne({ customerId, $or: [{ hardwareId }, { tankhardwareId: hardwareId }] }).lean(); if (!sensor) { return reply.code(404).send({ error: "No sensor found with this hardwareId for this customerId" }); } // Step 2: Load support record const supportRecord = await Support.findOne({ supportId }); if (!supportRecord) { return reply.code(404).send({ error: "Support record not found" }); } // Step 3: Validate issue exists const issueExists = supportRecord.issues.some(issue => issue.hardwareId === hardwareId || issue.masterHardwareId === hardwareId ); if (!issueExists) { return reply.code(404).send({ error: "HardwareId not found in this support record's issues" }); } // Step 4: Append comment object correctly const commentObj = { text: trimmedComment, customerId, hardwareId, createdAt: new Date() }; if (!Array.isArray(supportRecord.comments)) { supportRecord.comments = []; } // Use push instead of spreading to keep Mongoose subdoc validation intact supportRecord.comments.push(commentObj); await supportRecord.save(); return reply.send({ message: "Comment added successfully", comment: commentObj }); } catch (error) { console.error("Error updating comments:", error); return reply.code(500).send({ error: "Internal server error" }); } };