You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8835 lines
306 KiB

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 normalizedConnectedTo = connected_to.trim().toLowerCase();
// const sensors = await Insensors.find({ customerId }).lean();
// if (!sensors.length) return;
// const masterSensor = sensors.find(
// (s) => s.hardwareId?.trim().toLowerCase() === normalizedConnectedTo && s.type === "master"
// );
// if (!masterSensor) return;
// const orders = await Order.find({ customerId }).lean();
// const connectedSlaves = sensors.filter(
// (s) => s.connected_to?.trim().toLowerCase() === normalizedConnectedTo && s.type === "slave"
// );
// const disconnectedSlaves = connectedSlaves
// .filter((s) => s.connected_status === "disconnected")
// .map((s) => ({
// slaveHardwareId: s.tankhardwareId?.trim().toLowerCase(),
// slaveName: s.tankName || "Unknown Slave",
// }));
// const supportRecord = await Support.findOne({ supportId: "AWHYSU64" });
// if (!supportRecord) return;
// const now = moment.tz("Asia/Kolkata");
// const formattedNow = now.format("YYYY-MM-DD HH:mm:ss");
// const existingMasterIssue = supportRecord.issues.find(
// (issue) =>
// issue.hardwareId?.trim().toLowerCase() === normalizedConnectedTo &&
// issue.type === "GSM or LoRa Disconnected" &&
// !issue.resolved &&
// !issue.movedToCategory
// );
// if (existingMasterIssue) {
// if (masterSensor.connected_status === "connected") {
// return;
// }
// return;
// }
// const existingSlaveHardwareIds = new Set();
// supportRecord.issues
// .filter(
// (issue) =>
// issue.hardwareId?.trim().toLowerCase() === normalizedConnectedTo &&
// !issue.movedToCategory
// )
// .forEach((issue) => {
// (issue.hardwareIds || []).forEach((id) => {
// if (typeof id === "string") {
// existingSlaveHardwareIds.add(id.trim().toLowerCase());
// }
// });
// });
// const newSlaveHardwareIds = [];
// const newSlaveNames = [];
// for (const slave of disconnectedSlaves) {
// const sensorCurrent = sensors.find(
// (s) => s.tankhardwareId?.trim().toLowerCase() === slave.slaveHardwareId
// );
// console.log("sensorCurrent",sensorCurrent)
// if (
// sensorCurrent &&
// sensorCurrent.connected_status === "disconnected" &&
// !existingSlaveHardwareIds.has(slave.slaveHardwareId)
// ) {
// newSlaveHardwareIds.push(slave.slaveHardwareId);
// newSlaveNames.push(slave.slaveName);
// }
// }
// // 👇 Even if no new slaves found, if master is disconnected, still raise a ticket
// const masterDisconnected = masterSensor.connected_status !== "connected";
// if (!masterDisconnected && newSlaveHardwareIds.length === 0) {
// return;
// }
// const lastDataTime =
// masterSensor.connected_gsm_date && masterSensor.connected_gsm_time
// ? `${masterSensor.connected_gsm_date} ${masterSensor.connected_gsm_time}`
// : "No data";
// const message = `Master ${connected_to} is ${masterSensor.connected_status || "disconnected"}${newSlaveHardwareIds.length > 0
// ? ` with ${newSlaveHardwareIds.length} disconnected slave(s)`
// : ""}`;
// const newIssue = {
// type: "GSM or LoRa Disconnected",
// masterHardwareId: normalizedConnectedTo,
// hardwareId: normalizedConnectedTo,
// hardwareIds: newSlaveHardwareIds,
// slaveNames: newSlaveNames,
// message,
// disconnectedAt: lastDataTime,
// lastTicketRaisedAt: formattedNow,
// resolved: false,
// movedToCategory: false,
// createdAt: formattedNow,
// };
// await Support.findOneAndUpdate(
// { supportId: "AWHYSU64" },
// {
// $push: { issues: newIssue },
// $set: { updatedAt: new Date() },
// }
// );
// } catch (error) {
// console.error("Error in raiseATicketLikeLogic:", error);
// }
// };
// Your existing raiseATicketLikeLogic function must be accessible
// ⬇️ Include the function here or import it if it's in another file
const updateConnectedStatusOnly = async (customerId, hardwareId) => {
try {
const sensors = await Insensors.find({ customerId });
if (!sensors.length) return;
const now = moment.tz("Asia/Kolkata");
const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean();
if (!latestRecord) return;
const gsmTime = moment.tz(latestRecord.date, "Asia/Kolkata");
const gsmDiff = now.diff(gsmTime, "minutes");
const gsmConnected = gsmDiff <= 1;
const connectedSlaves = sensors.filter(s => s.connected_to?.trim() === hardwareId);
const tankMap = {};
(latestRecord.tanks || []).forEach(t => {
if (t.tankhardwareId) {
tankMap[t.tankhardwareId.trim()] = t;
}
});
const allSlavesConnected = connectedSlaves.every(slave => {
const slaveId = slave.tankhardwareId?.trim();
const tank = tankMap[slaveId];
if (!tank || !tank.date || tank.tankHeight === "0") return false;
const loraTime = moment.tz(tank.date, "Asia/Kolkata");
return now.diff(loraTime, "minutes") <= 1;
});
const masterStatus = gsmConnected && allSlavesConnected ? "connected" : "disconnected";
await Insensors.updateOne({ hardwareId, customerId }, { $set: { connected_status: masterStatus } });
for (const slave of connectedSlaves) {
const slaveId = slave.tankhardwareId?.trim();
const tank = tankMap[slaveId];
let status = "disconnected";
if (tank && tank.date && tank.tankHeight !== "0") {
const loraTime = moment.tz(tank.date, "Asia/Kolkata");
if (now.diff(loraTime, "minutes") <= 1) status = "connected";
}
await Insensors.updateOne({ hardwareId: slave.hardwareId }, { $set: { connected_status: status } });
}
} catch (error) {
console.error("❌ updateConnectedStatusOnly error:", error);
}
};
// const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => {
// const now = new Date();
// const formattedNow = new Date(now.getTime() + 19800000) // +05:30 offset in ms
// .toISOString()
// .replace("T", " ")
// .substring(0, 19);
// // Check if already categorized
// const alreadyCategorized = supportRecord.categorizedIssues.some(
// (catIssue) => catIssue.hardwareId === masterHardwareId
// );
// // Check if already raised and unresolved & not categorized
// const alreadyRaisedUnresolved = supportRecord.issues.some(
// (issue) =>
// issue.hardwareId === masterHardwareId &&
// issue.resolved === false &&
// issue.movedToCategory === false
// );
// if (alreadyCategorized) {
// console.log(`⛔ Ticket for ${masterHardwareId} already categorized. Skipping.`);
// return;
// }
// if (alreadyRaisedUnresolved) {
// console.log(`⛔ Unresolved ticket already exists for ${masterHardwareId}. Skipping.`);
// return;
// }
// const slaveHardwareIds = slaveData.map((slave) => slave.tankhardwareId);
// const slaveNames = slaveData.map((slave) => slave.sensorName || slave.tankName || "");
// const newIssue = {
// type: "GSM or LoRa Disconnected",
// masterHardwareId,
// hardwareId: masterHardwareId,
// hardwareIds: slaveHardwareIds,
// slaveNames: slaveNames,
// resolved: false,
// movedToCategory: false,
// lastTicketRaisedAt: formattedNow,
// createdAt: formattedNow,
// };
// supportRecord.issues.push(newIssue);
// supportRecord.lastTicketRaisedAt = formattedNow;
// await supportRecord.save();
// console.log(`✅ New ticket raised for ${masterHardwareId}`);
// };
// exports.raiseATicket = async (req, reply) => {
// try {
// const { customerId, connected_to } = req.params;
// if (!customerId || !connected_to) {
// return reply.code(400).send({ error: "customerId and connected_to are required" });
// }
// const masterDevice = await Insensors.findOne({
// customerId,
// hardwareId: connected_to,
// type: "master"
// }).lean();
// if (!masterDevice) {
// return reply.code(404).send({ message: "Master device not found" });
// }
// const allSlaves = await Insensors.find({
// connected_to,
// customerId,
// type: "slave"
// }).lean();
// const disconnectedSlaves = allSlaves.filter(
// slave => slave.connected_status === "disconnected"
// );
// const hasDisconnectedSlaves = disconnectedSlaves.length > 0;
// const isMasterDisconnected = masterDevice.connected_status === "disconnected";
// // If nothing is disconnected, no ticket should be raised
// if (!isMasterDisconnected && !hasDisconnectedSlaves) {
// return reply.code(200).send({ message: "All devices are connected. No ticket needed." });
// }
// const supportId = `${customerId}_${connected_to}`;
// const existingSupport = await Support.findOne({ supportId });
// // Helper to check if hardwareId is already in unresolved & not moved
// const isIssueAlreadyTracked = (supportDoc, hardwareId) => {
// return supportDoc.issues?.some(issue => {
// const allHwIds = [
// issue.hardwareId?.toLowerCase(),
// ...(issue.hardwareIds?.map(id => id?.toLowerCase()) || [])
// ];
// return (
// allHwIds.includes(hardwareId.toLowerCase()) &&
// !issue.resolved &&
// issue.movedToCategory !== true
// );
// });
// };
// const nowTime = moment().tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss");
// if (existingSupport) {
// let updated = false;
// // Add master if disconnected and not already tracked
// if (isMasterDisconnected && !isIssueAlreadyTracked(existingSupport, masterDevice.hardwareId)) {
// existingSupport.issues.push({
// type: "master",
// hardwareId: masterDevice.hardwareId,
// masterName: masterDevice.deviceName || "",
// resolved: false,
// movedToCategory: false,
// createdAt: nowTime,
// lastTicketRaisedAt: nowTime
// });
// updated = true;
// }
// // Add each disconnected slave if not already tracked
// for (const slave of disconnectedSlaves) {
// if (isIssueAlreadyTracked(existingSupport, slave.hardwareId)) continue;
// // If issue for this master already exists, append slave
// let masterIssue = existingSupport.issues.find(issue =>
// issue.type === "master" &&
// issue.hardwareId === masterDevice.hardwareId &&
// !issue.resolved
// );
// if (!masterIssue) {
// // create new slave-type issue
// existingSupport.issues.push({
// type: "slave",
// hardwareId: slave.hardwareId,
// masterHardwareId: masterDevice.hardwareId,
// slaveName: slave.deviceName || "",
// resolved: false,
// movedToCategory: false,
// createdAt: nowTime,
// lastTicketRaisedAt: nowTime
// });
// } else {
// if (!masterIssue.hardwareIds) masterIssue.hardwareIds = [];
// if (!masterIssue.slaveNames) masterIssue.slaveNames = [];
// masterIssue.hardwareIds.push(slave.hardwareId);
// masterIssue.slaveNames.push(slave.deviceName || "");
// masterIssue.lastTicketRaisedAt = nowTime;
// }
// updated = true;
// }
// if (updated) {
// await existingSupport.save();
// return reply.code(201).send({ message: "Support ticket updated with new disconnected issues." });
// } else {
// return reply.code(200).send({ message: "No new disconnected issues to add." });
// }
// } else {
// // Create new ticket
// const issues = [];
// if (isMasterDisconnected) {
// issues.push({
// type: "master",
// hardwareId: masterDevice.hardwareId,
// masterName: masterDevice.deviceName || "",
// resolved: false,
// movedToCategory: false,
// createdAt: nowTime,
// lastTicketRaisedAt: nowTime
// });
// }
// for (const slave of disconnectedSlaves) {
// issues.push({
// type: "slave",
// hardwareId: slave.hardwareId,
// masterHardwareId: masterDevice.hardwareId,
// slaveName: slave.deviceName || "",
// resolved: false,
// movedToCategory: false,
// createdAt: nowTime,
// lastTicketRaisedAt: nowTime
// });
// }
// const newSupport = new Support({
// supportId,
// customerId,
// connected_to,
// createdAt: nowTime,
// updatedAt: nowTime,
// status: "open",
// issues
// });
// await newSupport.save();
// return reply.code(201).send({ message: "Support ticket created successfully." });
// }
// } catch (error) {
// console.error("Error in raiseATicket:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
// cron.schedule("* * * * *", async () => {
// console.log("Running auto ticket check...");
// const allMasters = await Insensors.find({ }).lean();
// for (const master of allMasters) {
// await raiseATicketLikeLogic(master.customerId, master.hardwareId);
// }
// });
// cron.schedule("*/1 * * * *", async () => {
// try {
// console.log("🔁 Running auto-disconnect ticket check...");
// // Find all master sensors
// const allMasters = await Insensors.find({ type: "master" }).lean();
// for (const master of allMasters) {
// const customerId = master.customerId;
// const hardwareId = master.hardwareId;
// if (!customerId || !hardwareId) continue;
// // Find slaves connected to this master
// const connectedSlaves = await Insensors.find({
// connected_to: hardwareId,
// type: "slave"
// }).lean();
// // Filter disconnected slaves
// const disconnectedSlaves = connectedSlaves.filter(
// (s) => s.connected_status === "disconnected"
// );
// const masterIsDisconnected = master.connected_status === "disconnected";
// // Only raise ticket if master is disconnected or has disconnected slaves
// if (masterIsDisconnected || disconnectedSlaves.length > 0) {
// await raiseATicketLikeLogic(customerId, hardwareId);
// }
// }
// console.log("✅ Auto ticket check completed.");
// } catch (err) {
// console.error("Cron error:", err);
// }
// });
const raiseATicketLikeLogic = async (supportRecord, masterHardwareId, slaveData = []) => {
const now = new Date();
const formattedNow = new Date(now.getTime() + 19800000) // +05:30 offset in ms
.toISOString()
.replace("T", " ")
.substring(0, 19);
// Check if already categorized
const alreadyCategorized = supportRecord.categorizedIssues.some(
(catIssue) => catIssue.hardwareId === masterHardwareId
);
if (alreadyCategorized) {
console.log(`⛔ Ticket for ${masterHardwareId} already categorized. Skipping.`);
return;
}
// Prepare slave hardwareIds and names
const slaveHardwareIds = slaveData.map((slave) => slave.tankhardwareId).sort();
const slaveNames = slaveData.map((slave) => slave.sensorName || slave.tankName || "").sort();
// Check for existing unresolved and not moved-to-category issue
const duplicateExists = supportRecord.issues.some((issue) => {
const existingSlaveIds = (issue.hardwareIds || []).sort();
const existingSlaveNames = (issue.slaveNames || []).sort();
return (
issue.hardwareId === masterHardwareId &&
issue.masterHardwareId === masterHardwareId &&
issue.resolved === false &&
issue.movedToCategory === false &&
JSON.stringify(existingSlaveIds) === JSON.stringify(slaveHardwareIds) &&
JSON.stringify(existingSlaveNames) === JSON.stringify(slaveNames)
);
});
if (duplicateExists) {
console.log(`⛔ Duplicate unresolved issue already exists for ${masterHardwareId}. Skipping.`);
return;
}
// Create new issue
const newIssue = {
type: "GSM or LoRa Disconnected",
masterHardwareId,
hardwareId: masterHardwareId,
hardwareIds: slaveHardwareIds,
slaveNames: slaveNames,
resolved: false,
movedToCategory: false,
lastTicketRaisedAt: formattedNow,
createdAt: formattedNow,
};
supportRecord.issues.push(newIssue);
supportRecord.lastTicketRaisedAt = formattedNow;
await supportRecord.save();
console.log(`✅ New ticket raised for ${masterHardwareId}`);
};
cron.schedule("*/1 * * * *", async () => {
try {
console.log("🔁 Running auto-disconnect ticket check...");
// Step 1: Get all support profiles
const allSupportProfiles = await Support.find({});
for (const supportRecord of allSupportProfiles) {
const supportId = supportRecord.supportId;
if (!supportId) continue;
// Step 2: Find all master sensors
const allMasters = await Insensors.find({ type: "master" }).lean();
for (const master of allMasters) {
const customerId = master.customerId;
const hardwareId = master.hardwareId;
if (!customerId || !hardwareId) continue;
// ✅ Update GSM and LoRa connection statuses
await updateConnectedStatusOnly(customerId, hardwareId);
// 🔄 Re-fetch updated master and slaves
const updatedMaster = await Insensors.findOne({ hardwareId, customerId }).lean();
const connectedSlaves = await Insensors.find({
connected_to: hardwareId,
type: "slave"
}).lean();
// Step 3: Check disconnections
const disconnectedSlaves = connectedSlaves.filter(
(s) => s.connected_status === "disconnected"
);
const masterIsDisconnected = updatedMaster.connected_status === "disconnected";
// Step 4: Raise ticket if needed
if (masterIsDisconnected || disconnectedSlaves.length > 0) {
await raiseATicketLikeLogic(supportRecord, hardwareId, disconnectedSlaves);
}
}
}
console.log("✅ Auto ticket check completed.");
} catch (err) {
console.error("❌ Cron error:", err);
}
});
exports.raiseATicketBuildingDetails = async (req, reply) => {
try {
const { customerId, connected_to, installationId } = req.params;
if (!customerId || !connected_to || !installationId) {
return reply.code(400).send({ error: "customerId, connected_to, and installationId are required" });
}
const customer = await User.findOne({ customerId, installationId }).lean();
if (!customer) {
return reply.code(404).send({ message: "Customer not found." });
}
const sensors = await Insensors.find({ customerId });
if (!sensors.length) {
return reply.code(404).send({ message: "No sensors found for this customer." });
}
const masterSensor = sensors.find(s => (s.hardwareId?.trim() === connected_to.trim()));
if (!masterSensor) {
return reply.code(404).send({ message: "Master hardwareId not found." });
}
const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean();
if (!latestMasterRecord) {
return reply.code(404).send({ message: "No IoT data found for this hardwareId." });
}
const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata");
const now = moment.tz("Asia/Kolkata");
const formattedNow = now.format("YYYY-MM-DD HH:mm:ss");
const diffInMinutesMaster = now.diff(indiaTime, "minutes");
if (diffInMinutesMaster > 1) {
await Insensors.updateOne(
{ hardwareId: connected_to },
{ $set: { lastTicketRaisedAt: formattedNow } }
);
}
const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === connected_to.trim());
// ✅ Check if any slave is disconnected
const disconnectedSlave = connectedSlaves.find(slave => slave.connected_status === "disconnected");
if (disconnectedSlave) {
return reply.code(400).send({
error: `Slave device ${disconnectedSlave.hardwareId} is disconnected. Cannot raise ticket.`
});
}
for (const slave of connectedSlaves) {
const slaveId = slave.hardwareId?.trim();
const matchedTank = latestMasterRecord.tanks.find(tank => tank.tankhardwareId === slaveId);
if (matchedTank && matchedTank.date) {
const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata");
const loraDiffInMinutes = now.diff(tankTime, "minutes");
if (loraDiffInMinutes > 1) {
await Insensors.updateOne(
{ hardwareId: slaveId },
{ $set: { lastTicketRaisedAt: formattedNow } }
);
}
}
}
await Support.updateOne(
{ supportId: "AWHYSU64" },
{ $set: { lastTicketRaisedAt: formattedNow } }
);
// Fetch updated values
const updatedMasterSensor = await Insensors.findOne({ hardwareId: connected_to }).lean();
const updatedSupport = await Support.findOne({ supportId: "AWHYSU64" }).lean();
return reply.send({
status_code: 200,
customer,
lastTicketRaisedAt: {
masterSensor: updatedMasterSensor?.lastTicketRaisedAt || null,
support: updatedSupport?.lastTicketRaisedAt || null
}
});
} catch (error) {
console.error("Error raising ticket:", error);
return reply.code(500).send({ error: "Internal server error" });
}
};
exports.raiseATicketSlave = async (req, reply) => {
try {
const { customerId, connected_to } = req.params;
if (!customerId || !connected_to) {
return reply.code(400).send({ error: "customerId and connected_to are required" });
}
const sensors = await Insensors.find({ customerId });
const masterSensor = sensors.find(s => s.hardwareId?.trim() === connected_to.trim());
if (!masterSensor) {
return reply.code(404).send({ message: "Master hardwareId not found." });
}
const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean();
if (!latestMasterRecord) {
return reply.code(404).send({ message: "No IoT data found for this hardwareId." });
}
const now = moment().tz("Asia/Kolkata");
const masterTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata");
const diff = now.diff(masterTime, "minutes");
const gsm_connected_status = diff <= 1 ? "connected" : "disconnected";
const gsmStatus = gsm_connected_status === "connected" ? "GSM Connected" : "GSM Disconnected";
const formattedTime = masterTime.format("HH:mm:ss");
const formattedDate = masterTime.format("DD-MM-YYYY");
const tanks = (latestMasterRecord.tanks || []).map(tank => {
const tankTime = moment.tz(tank.date, "Asia/Kolkata");
const timeDiff = now.diff(tankTime, "minutes");
return {
...tank,
time: tankTime.format("HH:mm:ss"),
connected_status: timeDiff <= 1 ? "connected" : "disconnected"
};
});
const responseData = {
hardwareId: connected_to,
gsm_connected_status,
gsmStatus,
connected_gsm_date: formattedDate,
connected_gsm_time: formattedTime,
gsm_last_check_time: now.format("DD-MM-YYYY HH:mm:ss"),
tanks,
date: latestMasterRecord.date,
time: formattedTime
};
return reply.send({
status_code: 200,
message: "Success",
data: responseData
});
} catch (error) {
console.error("Error in raiseATicketSlave:", error);
return reply.code(500).send({ error: "Internal server error" });
}
};
// exports.getDisconnectedIssuesBySupportId = async (req, reply) => {
// try {
// const { supportId } = req.params;
// if (!supportId) {
// return reply.code(400).send({ error: "supportId is required" });
// }
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId" });
// }
// const allIssues = supportRecord.issues || [];
// const hardwareSet = new Set();
// // Collect all hardware IDs from issues
// for (const issue of allIssues) {
// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); // GSM
// if (Array.isArray(issue.hardwareIds)) {
// issue.hardwareIds.forEach(id => hardwareSet.add(id)); // LoRa slaves
// }
// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); // LoRa master
// }
// const hardwareIds = [...hardwareSet];
// const sensors = await Insensors.find({ hardwareId: { $in: hardwareIds } }).lean();
// console.log("sensors",sensors)
// // Map sensors by hardwareId
// const sensorMap = {};
// for (const sensor of sensors) {
// sensorMap[sensor.hardwareId] = sensor;
// }
// const masterMap = {};
// for (const issue of allIssues) {
// // GSM Disconnected
// if (issue.type === "GSM or LoRa Disconnected" && issue.hardwareId) {
// const sensor = sensorMap[issue.hardwareId];
// if (sensor && sensor.type === "master") {
// masterMap[sensor.hardwareId] = {
// hardwareId: sensor.hardwareId,
// masterName: sensor.masterName || null,
// location: sensor.location || "",
// type: "master",
// connected_status: sensor.connected_status,
// gsm_last_check_time: sensor.gsm_last_check_time,
// gsm_last_disconnect_time: sensor.gsm_last_disconnect_time,
// connected_gsm_date: sensor.connected_gsm_date,
// connected_gsm_time: sensor.connected_gsm_time,
// connected_lora_date: sensor.connected_lora_date,
// connected_lora_time: sensor.connected_lora_time,
// support_gsm_last_check_time: sensor.support_gsm_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// }
// // LoRa Disconnected
// if (issue.type === "GSM or LoRa Disconnected" && issue.masterHardwareId) {
// const masterSensor = sensorMap[issue.masterHardwareId];
// if (!masterSensor || masterSensor.type !== "master") continue;
// if (!masterMap[masterSensor.hardwareId]) {
// masterMap[masterSensor.hardwareId] = {
// hardwareId: masterSensor.hardwareId,
// masterName: masterSensor.masterName || null,
// location: masterSensor.location || "",
// type: "master",
// connected_status: masterSensor.connected_status,
// gsm_last_check_time: masterSensor.gsm_last_check_time,
// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time,
// connected_gsm_date: masterSensor.connected_gsm_date,
// connected_gsm_time: masterSensor.connected_gsm_time,
// connected_lora_date: masterSensor.connected_lora_date,
// connected_lora_time: masterSensor.connected_lora_time,
// support_lora_last_check_time: masterSensor.support_lora_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// const master = masterMap[masterSensor.hardwareId];
// // First try from issue.hardwareIds
// let slaveIds = Array.isArray(issue.hardwareIds) ? issue.hardwareIds : [];
// // If empty, fallback to slaves connected to this master
// // If empty, fallback to slaves connected to this master's tankHardwareId
// console.log("slaveIds",slaveIds)
// if (slaveIds.length === 0) {
// // fallback: find slaves connected to this master hardwareId
// const fallbackSlaves = await Insensors.find({
// connected_to: issue.masterHardwareId, // or masterSensor.hardwareId
// type: "slave"
// }).lean();
// console.log("fallbackSlaves", fallbackSlaves);
// for (const slaveSensor of fallbackSlaves) {
// master.connected_slaves.push({
// hardwareId: slaveSensor.hardwareId,
// tankName: slaveSensor.tankName || "",
// location: slaveSensor.location || "",
// connected_status: slaveSensor.connected_status,
// connected_lora_time: slaveSensor.connected_lora_time,
// connected_lora_date: slaveSensor.connected_lora_date,
// lora_last_check_time: slaveSensor.lora_last_check_time,
// lora_last_disconnect_time: slaveSensor.lora_last_disconnect_time,
// connected_to: slaveSensor.connected_to,
// masterName: master.masterName,
// type: "slave",
// typeOfWater: slaveSensor.typeOfWater,
// tankHeight: slaveSensor.tankHeight,
// support_lora_last_check_time: slaveSensor.support_lora_last_check_time,
// });
// master.connected_slave_count++;
// }
// }
// else {
// // Populate slaves based on provided hardwareIds
// for (const slaveId of slaveIds) {
// const slaveSensor = sensorMap[slaveId];
// if (slaveSensor && slaveSensor.type === "slave") {
// master.connected_slaves.push({
// hardwareId: slaveSensor.hardwareId,
// tankName: slaveSensor.tankName || "",
// location: slaveSensor.location || "",
// connected_status: slaveSensor.connected_status,
// connected_lora_time: slaveSensor.connected_lora_time,
// connected_lora_date: slaveSensor.connected_lora_date,
// lora_last_check_time: slaveSensor.lora_last_check_time,
// lora_last_disconnect_time: slaveSensor.lora_last_disconnect_time,
// connected_to: slaveSensor.connected_to,
// masterName: master.masterName,
// type: "slave",
// typeOfWater: slaveSensor.typeOfWater,
// tankHeight: slaveSensor.tankHeight,
// support_lora_last_check_time: slaveSensor.support_lora_last_check_time,
// });
// master.connected_slave_count++;
// }
// }
// }
// }
// }
// const finalResponse = Object.values(masterMap);
// return reply.send({
// status_code: 200,
// supportId,
// totalMasters: finalResponse.length,
// disconnectedIssues: finalResponse
// });
// } catch (error) {
// console.error("Error fetching disconnected issues:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
// exports.getDisconnectedIssuesBySupportId = async (req, reply) => {
// try {
// const { supportId } = req.params;
// if (!supportId) {
// return reply.code(400).send({ error: "supportId is required" });
// }
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId" });
// }
// const allIssues = supportRecord.issues || [];
// const hardwareSet = new Set();
// // Collect all hardware IDs and tankHardwareIds from issues
// for (const issue of allIssues) {
// if (issue.hardwareId) hardwareSet.add(issue.hardwareId); // GSM
// if (Array.isArray(issue.hardwareIds)) {
// issue.hardwareIds.forEach(id => hardwareSet.add(id)); // LoRa slaves
// }
// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); // LoRa master
// }
// const hardwareIds = [...hardwareSet];
// const sensors = await Insensors.find({
// $or: [
// { hardwareId: { $in: hardwareIds } },
// { tankHardwareId: { $in: hardwareIds } }
// ]
// }).lean();
// const customerId = supportRecord.customerId;
// const orders = await Order.find({ customerId }).lean();
// const orderMap = {};
// for (const order of orders) {
// if (Array.isArray(order.master_connections)) {
// order.master_connections.forEach(conn => {
// if (conn.hardwareId) {
// orderMap[conn.hardwareId] = {
// masterName: conn.master_name || null,
// location: conn.location || null
// };
// }
// });
// }
// }
// // Map sensors by both hardwareId and tankHardwareId
// const sensorMap = {};
// for (const sensor of sensors) {
// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor;
// if (sensor.tankHardwareId) sensorMap[sensor.tankHardwareId] = sensor;
// }
// const masterMap = {};
// for (const issue of allIssues) {
// // GSM Disconnected
// if (issue.type === "GSM or LoRa Disconnected" && issue.hardwareId) {
// const sensor = sensorMap[issue.hardwareId];
// if (sensor && sensor.type === "master") {
// const enriched = orderMap[sensor.hardwareId] || {};
// masterMap[sensor.hardwareId] = {
// hardwareId: sensor.hardwareId,
// masterName: enriched.masterName || sensor.masterName || null,
// location: enriched.location || sensor.location || "",
// type: "master",
// connected_status: sensor.connected_status,
// gsm_last_check_time: sensor.gsm_last_check_time,
// gsm_last_disconnect_time: sensor.gsm_last_disconnect_time,
// connected_gsm_date: sensor.connected_gsm_date,
// connected_gsm_time: sensor.connected_gsm_time,
// connected_lora_date: sensor.connected_lora_date,
// connected_lora_time: sensor.connected_lora_time,
// support_gsm_last_check_time: sensor.support_gsm_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// }
// // LoRa Disconnected
// if (issue.type === "GSM or LoRa Disconnected" && issue.masterHardwareId) {
// const masterSensor = sensorMap[issue.masterHardwareId];
// if (!masterSensor || masterSensor.type !== "master") continue;
// if (!masterMap[masterSensor.hardwareId]) {
// masterMap[masterSensor.hardwareId] = {
// hardwareId: masterSensor.hardwareId,
// masterName: masterSensor.masterName || null,
// location: masterSensor.location || "",
// type: "master",
// connected_status: masterSensor.connected_status,
// gsm_last_check_time: masterSensor.gsm_last_check_time,
// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time,
// connected_gsm_date: masterSensor.connected_gsm_date,
// connected_gsm_time: masterSensor.connected_gsm_time,
// connected_lora_date: masterSensor.connected_lora_date,
// connected_lora_time: masterSensor.connected_lora_time,
// support_lora_last_check_time: masterSensor.support_lora_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// const master = masterMap[masterSensor.hardwareId];
// let slaveIds = Array.isArray(issue.hardwareIds) ? issue.hardwareIds : [];
// console.log("slaveIds",slaveIds)
// let fallbackSlaves = [];
// if (slaveIds.length > 0) {
// // Try to fetch slaves by hardwareId or tankHardwareId
// fallbackSlaves = await Insensors.find({
// $or: [
// { hardwareId: { $in: slaveIds } },
// { tankhardwareId: { $in: slaveIds } }
// ],
// type: "slave"
// }).lean();
// } else {
// // Fallback: find by connected_to field
// fallbackSlaves = await Insensors.find({
// connected_to: issue.masterHardwareId,
// type: "slave"
// }).lean();
// }
// for (const slaveSensor of fallbackSlaves) {
// master.connected_slaves.push({
// hardwareId: slaveSensor.hardwareId,
// tankName: slaveSensor.tankName || "",
// location: slaveSensor.location || "",
// connected_status: slaveSensor.connected_status,
// connected_lora_time: slaveSensor.connected_lora_time,
// connected_lora_date: slaveSensor.connected_lora_date,
// lora_last_check_time: slaveSensor.lora_last_check_time,
// lora_last_disconnect_time: slaveSensor.lora_last_disconnect_time,
// connected_to: slaveSensor.connected_to,
// masterName: master.masterName,
// type: "slave",
// typeOfWater: slaveSensor.typeOfWater,
// tankHeight: slaveSensor.tankHeight,
// support_lora_last_check_time: slaveSensor.support_lora_last_check_time,
// });
// master.connected_slave_count++;
// }
// }
// }
// const finalResponse = Object.values(masterMap);
// return reply.send({
// status_code: 200,
// supportId,
// totalMasters: finalResponse.length,
// disconnectedIssues: finalResponse
// });
// } catch (error) {
// console.error("Error fetching disconnected issues:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
// exports.getDisconnectedIssuesBySupportId = async (req, reply) => {
// try {
// const { supportId } = req.params;
// if (!supportId) {
// return reply.code(400).send({ error: "supportId is required" });
// }
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId" });
// }
// const allIssues = [...(supportRecord.issues || []), ...(supportRecord.categorizedIssues || [])];
// const hardwareSet = new Set();
// for (const issue of allIssues) {
// if (issue.hardwareId) hardwareSet.add(issue.hardwareId);
// if (Array.isArray(issue.hardwareIds)) {
// issue.hardwareIds.forEach(id => hardwareSet.add(id));
// }
// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId);
// }
// const hardwareIds = [...hardwareSet];
// const sensors = await Insensors.find({
// $or: [
// { hardwareId: { $in: hardwareIds } },
// { tankhardwareId: { $in: hardwareIds } }
// ]
// }).lean();
// const sensorMap = {};
// for (const sensor of sensors) {
// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor;
// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor;
// }
// const customerId = sensors.length > 0 ? sensors[0].customerId : null;
// const orders = customerId ? await Order.find({ customerId }).lean() : [];
// const orderMap = {};
// for (const order of orders) {
// if (Array.isArray(order.master_connections)) {
// for (const conn of order.master_connections) {
// if (conn.hardwareId) {
// orderMap[conn.hardwareId] = {
// masterName: conn.master_name || null,
// location: conn.location || null
// };
// }
// }
// }
// }
// const masterMap = {};
// const assignedSlaves = new Set();
// // ✅ Step 1: Get all unique master hardware IDs involved in the issues
// const masterHardwareIds = new Set();
// for (const issue of allIssues) {
// const masterId = issue.masterHardwareId || issue.hardwareId;
// const sensor = sensorMap[masterId];
// if (sensor?.type === "master") {
// masterHardwareIds.add(sensor.hardwareId);
// }
// }
// // ✅ Step 2: Process each unique master once
// for (const masterId of masterHardwareIds) {
// const masterSensor = sensorMap[masterId];
// if (!masterSensor) continue;
// const enriched = orderMap[masterSensor.hardwareId] || {};
// if (!masterMap[masterSensor.hardwareId]) {
// masterMap[masterSensor.hardwareId] = {
// hardwareId: masterSensor.hardwareId,
// masterName: masterSensor.masterName || enriched.masterName || "",
// location: masterSensor.location || enriched.location || "",
// type: "master",
// connected_status: masterSensor.connected_status,
// gsm_last_check_time: masterSensor.gsm_last_check_time,
// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time,
// connected_gsm_date: masterSensor.connected_gsm_date,
// connected_gsm_time: masterSensor.connected_gsm_time,
// connected_lora_date: masterSensor.connected_lora_date,
// connected_lora_time: masterSensor.connected_lora_time,
// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// const master = masterMap[masterSensor.hardwareId];
// const fallbackSlaves = await Insensors.find({
// connected_to: masterSensor.hardwareId,
// type: "slave"
// }).lean();
// for (const slaveSensor of fallbackSlaves) {
// const slaveKey = slaveSensor.tankhardwareId || slaveSensor.hardwareId;
// if (!slaveKey || assignedSlaves.has(slaveKey)) continue;
// if (slaveSensor.connected_status !== "disconnected") continue;
// assignedSlaves.add(slaveKey);
// let typeOfWater = "";
// if (customerId && slaveSensor.tankhardwareId) {
// const tank = await Tank.findOne({
// customerId,
// tankhardwareId: slaveSensor.tankhardwareId
// }).lean();
// if (tank?.typeOfWater) typeOfWater = tank.typeOfWater;
// }
// master.connected_slaves.push({
// hardwareId: slaveSensor.tankhardwareId || slaveSensor.hardwareId,
// tankName: slaveSensor.tankName || "",
// location: slaveSensor.location || "",
// connected_status: slaveSensor.connected_status,
// connected_lora_time: slaveSensor.connected_lora_time,
// connected_lora_date: slaveSensor.connected_lora_date,
// lora_last_check_time: slaveSensor.lora_last_check_time,
// lora_last_disconnect_time: slaveSensor.lora_last_disconnect_time,
// connected_to: slaveSensor.connected_to,
// masterName: master.masterName,
// type: "slave",
// typeOfWater,
// tankHeight: slaveSensor.tankHeight,
// support_lora_last_check_time: slaveSensor.support_lora_last_check_time
// });
// master.connected_slave_count++;
// }
// }
// return reply.send({
// status_code: 200,
// supportId,
// totalMasters: Object.keys(masterMap).length,
// disconnectedIssues: Object.values(masterMap)
// });
// } catch (error) {
// console.error("Error fetching disconnected issues:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
// exports.getDisconnectedIssuesBySupportId = async (req, reply) => {
// try {
// const { supportId } = req.params;
// if (!supportId) {
// return reply.code(400).send({ error: "supportId is required" });
// }
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId" });
// }
// const allIssues = supportRecord.issues || [];
// const hardwareSet = new Set();
// // Collect hardwareId and masterHardwareId
// for (const issue of allIssues) {
// if (issue.hardwareId) hardwareSet.add(issue.hardwareId);
// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId);
// }
// const hardwareIds = [...hardwareSet];
// const sensors = await Insensors.find({
// $or: [
// { hardwareId: { $in: hardwareIds } },
// { tankhardwareId: { $in: hardwareIds } }
// ]
// }).lean();
// const sensorMap = {};
// for (const sensor of sensors) {
// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor;
// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor;
// }
// const customerId = supportRecord.customerId;
// const orders = await Order.find({ customerId }).lean();
// const orderMap = {};
// for (const order of orders) {
// (order.master_connections || []).forEach(conn => {
// if (conn.hardwareId) {
// orderMap[conn.hardwareId] = {
// masterName: conn.master_name || null,
// location: conn.location || null
// };
// }
// });
// }
// console.log("order",orderMap)
// const masterMap = {};
// for (const issue of allIssues) {
// const masterId = issue.masterHardwareId || issue.hardwareId;
// const masterSensor = sensorMap[masterId];
// if (!masterSensor || masterSensor.type !== "master") continue;
// // If master not already added
// if (!masterMap[masterSensor.hardwareId]) {
// const enriched = orderMap[masterSensor.hardwareId] || {};
// masterMap[masterSensor.hardwareId] = {
// hardwareId: masterSensor.hardwareId,
// masterName: enriched.masterName || masterSensor.masterName || "",
// location: enriched.location || masterSensor.location || "",
// type: "master",
// connected_status: masterSensor.connected_status,
// gsm_last_check_time: masterSensor.gsm_last_check_time,
// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time,
// connected_gsm_date: masterSensor.connected_gsm_date,
// connected_gsm_time: masterSensor.connected_gsm_time,
// connected_lora_date: masterSensor.connected_lora_date,
// connected_lora_time: masterSensor.connected_lora_time,
// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time,
// support_lora_last_check_time: masterSensor.support_lora_last_check_time,
// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time,
// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// const master = masterMap[masterSensor.hardwareId];
// console.log("master",master)
// // ✅ Always fetch slaves using connected_to
// const connectedSlaves = await Insensors.find({
// connected_to: masterSensor.hardwareId,
// type: "slave"
// }).lean();
// for (const slave of connectedSlaves) {
// // Only include disconnected slaves
// if (slave.connected_status !== "disconnected") continue;
// master.connected_slaves.push({
// hardwareId: slave.tankhardwareId || slave.hardwareId,
// tankName: slave.tankName || "",
// location: slave.location || "",
// connected_status: slave.connected_status,
// connected_lora_time: slave.connected_lora_time,
// connected_lora_date: slave.connected_lora_date,
// lora_last_check_time: slave.lora_last_check_time,
// lora_last_disconnect_time: slave.lora_last_disconnect_time,
// connected_to: slave.connected_to,
// masterName: master.masterName,
// type: "slave",
// typeOfWater: slave.typeOfWater || "",
// tankHeight: slave.tankHeight,
// support_lora_last_check_time: slave.support_lora_last_check_time,
// //team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time,
// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time,
// });
// master.connected_slave_count++;
// }
// }
// return reply.send({
// status_code: 200,
// supportId,
// totalMasters: Object.keys(masterMap).length,
// disconnectedIssues: Object.values(masterMap)
// });
// } catch (error) {
// console.error("Error fetching disconnected issues:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
//final
// exports.getDisconnectedIssuesBySupportId = async (req, reply) => {
// try {
// const { supportId } = req.params;
// if (!supportId) {
// return reply.code(400).send({ error: "supportId is required" });
// }
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId" });
// }
// const allIssues = supportRecord.issues || [];
// const hardwareSet = new Set();
// for (const issue of allIssues) {
// if (issue.hardwareId) hardwareSet.add(issue.hardwareId);
// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId);
// }
// const hardwareIds = [...hardwareSet];
// const sensors = await Insensors.find({
// $or: [
// { hardwareId: { $in: hardwareIds } },
// { tankhardwareId: { $in: hardwareIds } }
// ]
// }).lean();
// const sensorMap = {};
// for (const sensor of sensors) {
// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor;
// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor;
// }
// let customerId = supportRecord.customerId;
// if (!customerId) {
// const firstSensor = sensors.find(sensor => sensor.customerId);
// if (firstSensor) {
// customerId = firstSensor.customerId;
// } else {
// return reply.code(404).send({ message: "Unable to determine customerId from support or sensors." });
// }
// }
// const orders = await Order.find({ customerId }).lean();
// const orderMap = {};
// for (const order of orders) {
// (order.master_connections || []).forEach(conn => {
// if (conn.hardwareId) {
// orderMap[conn.hardwareId] = {
// masterName: conn.master_name || null,
// location: conn.location || null
// };
// }
// });
// }
// const slaveOrderMap = {};
// for (const order of orders) {
// (order.tank_connections || []).forEach(conn => {
// if (conn.hardwareId) {
// slaveOrderMap[conn.hardwareId] = {
// location: conn.location || null,
// typeOfWater: conn.typeOfWater || null
// };
// }
// });
// }
// const masterMap = {};
// for (const issue of allIssues) {
// const masterId = issue.masterHardwareId || issue.hardwareId;
// const masterSensor = sensorMap[masterId];
// if (!masterSensor || masterSensor.type !== "master") continue;
// if (!masterMap[masterSensor.hardwareId]) {
// const enriched = orderMap[masterSensor.hardwareId] || {};
// masterMap[masterSensor.hardwareId] = {
// hardwareId: masterSensor.hardwareId,
// masterName: enriched.masterName || masterSensor.masterName || "",
// location: enriched.location || masterSensor.location || "",
// type: "master",
// connected_status: masterSensor.connected_status,
// gsm_last_check_time: masterSensor.gsm_last_check_time,
// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time,
// connected_gsm_date: masterSensor.connected_gsm_date,
// connected_gsm_time: masterSensor.connected_gsm_time,
// connected_lora_date: masterSensor.connected_lora_date,
// connected_lora_time: masterSensor.connected_lora_time,
// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time,
// support_lora_last_check_time: masterSensor.support_lora_last_check_time,
// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time,
// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// const master = masterMap[masterSensor.hardwareId];
// const connectedSlaves = await Insensors.find({
// connected_to: masterSensor.hardwareId,
// type: "slave"
// }).lean();
// const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId));
// for (const slave of connectedSlaves) {
// const slaveHardwareId = slave.tankhardwareId || slave.hardwareId;
// if (slaveSet.has(slaveHardwareId)) continue;
// slaveSet.add(slaveHardwareId);
// const tankInfo = await Tank.findOne({
// $or: [
// { hardwareId: slaveHardwareId },
// { tankhardwareId: slaveHardwareId }
// ]
// }).lean();
// const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {};
// const slaveEnriched = {
// hardwareId: slaveHardwareId,
// tankName: slave.tankName || (tankInfo?.tankName ?? ""),
// location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "",
// connected_status: slave.connected_status,
// connected_lora_time: slave.connected_lora_time,
// connected_lora_date: slave.connected_lora_date,
// lora_last_check_time: slave.lora_last_check_time,
// lora_last_disconnect_time: slave.lora_last_disconnect_time,
// connected_to: slave.connected_to,
// masterName: master.masterName,
// type: "slave",
// typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "",
// tankHeight: slave.tankHeight,
// support_lora_last_check_time: slave.support_lora_last_check_time,
// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time
// };
// master.connected_slaves.push(slaveEnriched);
// master.connected_slave_count++;
// }
// }
// return reply.send({
// status_code: 200,
// supportId,
// totalMasters: Object.keys(masterMap).length,
// disconnectedIssues: Object.values(masterMap)
// });
// } catch (error) {
// console.error("Error fetching disconnected issues:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
// exports.getDisconnectedIssuesBySupportId = async (req, reply) => {
// try {
// const { supportId, customerId } = req.params;
// if (!supportId || !customerId) {
// return reply.code(400).send({ error: "supportId and customerId are required" });
// }
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId and customerId" });
// }
// const allIssues = supportRecord.issues || [];
// const hardwareSet = new Set();
// for (const issue of allIssues) {
// if (issue.hardwareId) hardwareSet.add(issue.hardwareId);
// if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId);
// }
// const hardwareIds = [...hardwareSet];
// const sensors = await Insensors.find({
// customerId,
// $or: [
// { hardwareId: { $in: hardwareIds } },
// { tankhardwareId: { $in: hardwareIds } }
// ]
// }).lean();
// const sensorMap = {};
// for (const sensor of sensors) {
// if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor;
// if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor;
// }
// const orders = await Order.find({ customerId }).lean();
// const orderMap = {};
// for (const order of orders) {
// (order.master_connections || []).forEach(conn => {
// if (conn.hardwareId) {
// orderMap[conn.hardwareId] = {
// masterName: conn.master_name || null,
// location: conn.location || null
// };
// }
// });
// }
// const slaveOrderMap = {};
// for (const order of orders) {
// (order.tank_connections || []).forEach(conn => {
// if (conn.hardwareId) {
// slaveOrderMap[conn.hardwareId] = {
// location: conn.location || null,
// typeOfWater: conn.typeOfWater || null
// };
// }
// });
// }
// const masterMap = {};
// for (const issue of allIssues) {
// const masterId = issue.masterHardwareId || issue.hardwareId;
// const masterSensor = sensorMap[masterId];
// if (!masterSensor || masterSensor.type !== "master") continue;
// if (!masterMap[masterSensor.hardwareId]) {
// const enriched = orderMap[masterSensor.hardwareId] || {};
// masterMap[masterSensor.hardwareId] = {
// hardwareId: masterSensor.hardwareId,
// masterName: enriched.masterName || masterSensor.masterName || "",
// location: enriched.location || masterSensor.location || "",
// type: "master",
// connected_status: masterSensor.connected_status,
// gsm_last_check_time: masterSensor.gsm_last_check_time,
// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time,
// connected_gsm_date: masterSensor.connected_gsm_date,
// connected_gsm_time: masterSensor.connected_gsm_time,
// connected_lora_date: masterSensor.connected_lora_date,
// connected_lora_time: masterSensor.connected_lora_time,
// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time,
// support_lora_last_check_time: masterSensor.support_lora_last_check_time,
// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time,
// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// const master = masterMap[masterSensor.hardwareId];
// const connectedSlaves = await Insensors.find({
// connected_to: masterSensor.hardwareId,
// type: "slave",
// customerId
// }).lean();
// const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId));
// for (const slave of connectedSlaves) {
// const slaveHardwareId = slave.tankhardwareId || slave.hardwareId;
// if (slaveSet.has(slaveHardwareId)) continue;
// slaveSet.add(slaveHardwareId);
// const tankInfo = await Tank.findOne({
// $or: [
// { hardwareId: slaveHardwareId },
// { tankhardwareId: slaveHardwareId }
// ]
// }).lean();
// const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {};
// const slaveEnriched = {
// hardwareId: slaveHardwareId,
// tankName: slave.tankName || (tankInfo?.tankName ?? ""),
// location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "",
// connected_status: slave.connected_status,
// connected_lora_time: slave.connected_lora_time,
// connected_lora_date: slave.connected_lora_date,
// lora_last_check_time: slave.lora_last_check_time,
// lora_last_disconnect_time: slave.lora_last_disconnect_time,
// connected_to: slave.connected_to,
// masterName: master.masterName,
// type: "slave",
// typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "",
// tankHeight: slave.tankHeight,
// support_lora_last_check_time: slave.support_lora_last_check_time,
// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time
// };
// master.connected_slaves.push(slaveEnriched);
// master.connected_slave_count++;
// }
// }
// return reply.send({
// status_code: 200,
// supportId,
// customerId,
// totalMasters: Object.keys(masterMap).length,
// comments: supportRecord.comments || "",
// disconnectedIssues: Object.values(masterMap)
// });
// } catch (error) {
// console.error("Error fetching disconnected issues:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
// 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;
// const latestMasterData = await IotData.findOne({ hardwareId: masterSensor.hardwareId }).sort({ date: -1 }).lean();
// const now = moment.tz("Asia/Kolkata");
// let gsmConnected = false;
// if (latestMasterData?.date) {
// const gsmTime = moment.tz(latestMasterData.date, "Asia/Kolkata");
// gsmConnected = now.diff(gsmTime, "minutes") <= 1;
// }
// if (!masterMap[masterSensor.hardwareId]) {
// const enriched = orderMap[masterSensor.hardwareId] || {};
// masterMap[masterSensor.hardwareId] = {
// hardwareId: masterSensor.hardwareId,
// masterName: enriched.masterName || masterSensor.masterName || "",
// location: enriched.location || masterSensor.location || "",
// type: "master",
// connected_status: gsmConnected ? "connected" : "disconnected",
// gsm_last_check_time: masterSensor.gsm_last_check_time,
// gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time,
// connected_gsm_date: masterSensor.connected_gsm_date,
// connected_gsm_time: masterSensor.connected_gsm_time,
// connected_lora_date: masterSensor.connected_lora_date,
// connected_lora_time: masterSensor.connected_lora_time,
// support_gsm_last_check_time: masterSensor.support_gsm_last_check_time,
// support_lora_last_check_time: masterSensor.support_lora_last_check_time,
// team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time,
// team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time,
// connected_slave_count: 0,
// connected_slaves: []
// };
// }
// const master = masterMap[masterSensor.hardwareId];
// const connectedSlaves = await Insensors.find({
// connected_to: masterSensor.hardwareId,
// type: "slave",
// customerId
// }).lean();
// const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId));
// for (const slave of connectedSlaves) {
// const slaveHardwareId = slave.tankhardwareId || slave.hardwareId;
// if (slaveSet.has(slaveHardwareId)) continue;
// slaveSet.add(slaveHardwareId);
// const tankInfo = await Tank.findOne({
// $or: [
// { hardwareId: slaveHardwareId },
// { tankhardwareId: slaveHardwareId }
// ]
// }).lean();
// const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {};
// const matchedTank = latestMasterData?.tanks?.find(t => t.tankhardwareId === slaveHardwareId);
// let loraConnected = false;
// if (matchedTank?.date && matchedTank.tankHeight !== "0") {
// const loraTime = moment.tz(matchedTank.date, "Asia/Kolkata");
// loraConnected = now.diff(loraTime, "minutes") <= 1;
// }
// const slaveEnriched = {
// hardwareId: slaveHardwareId,
// tankName: slave.tankName || tankInfo?.tankName || "",
// location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "",
// connected_status: loraConnected ? "connected" : "disconnected",
// connected_lora_time: slave.connected_lora_time,
// connected_lora_date: slave.connected_lora_date,
// lora_last_check_time: slave.lora_last_check_time,
// lora_last_disconnect_time: slave.lora_last_disconnect_time,
// connected_to: slave.connected_to,
// masterName: master.masterName,
// type: "slave",
// typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "",
// tankHeight: slave.tankHeight,
// support_lora_last_check_time: slave.support_lora_last_check_time,
// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time
// };
// master.connected_slaves.push(slaveEnriched);
// master.connected_slave_count++;
// }
// }
// // const commentTexts = (supportRecord.comments || []).map(c => c.text);
// // for (const master of Object.values(masterMap)) {
// // master.comments = commentTexts;
// // }
// const comments = (supportRecord.comments || []).map(c => ({
// text: c.text,
// commentsTime: moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm")
// }));
// for (const master of Object.values(masterMap)) {
// master.comments = comments;
// }
// return reply.send({
// status_code: 200,
// supportId,
// customerId,
// totalMasters: Object.keys(masterMap).length,
// disconnectedIssues: Object.values(masterMap)
// });
// } catch (error) {
// console.error("Error fetching disconnected issues:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
exports.getDisconnectedIssuesBySupportId = async (req, reply) => {
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 = {};
const now = moment.tz("Asia/Kolkata");
for (const issue of allIssues) {
const masterId = issue.masterHardwareId || issue.hardwareId;
const masterSensor = sensorMap[masterId];
if (!masterSensor || masterSensor.type !== "master") continue;
const latestMasterData = await IotData.findOne({ hardwareId: masterSensor.hardwareId }).sort({ date: -1 }).lean();
let gsmConnected = false;
if (latestMasterData?.date) {
const gsmTime = moment.tz(latestMasterData.date, "Asia/Kolkata");
gsmConnected = now.diff(gsmTime, "minutes") <= 1;
}
if (!masterMap[masterSensor.hardwareId]) {
const enriched = orderMap[masterSensor.hardwareId] || {};
masterMap[masterSensor.hardwareId] = {
hardwareId: masterSensor.hardwareId,
masterName: enriched.masterName || masterSensor.masterName || "",
location: enriched.location || masterSensor.location || "",
type: "master",
connected_status: gsmConnected ? "connected" : "disconnected",
gsm_last_check_time: masterSensor.gsm_last_check_time,
gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_time,
connected_gsm_date: masterSensor.connected_gsm_date,
connected_gsm_time: masterSensor.connected_gsm_time,
connected_lora_date: masterSensor.connected_lora_date,
connected_lora_time: masterSensor.connected_lora_time,
support_gsm_last_check_time: masterSensor.support_gsm_last_check_time,
support_lora_last_check_time: masterSensor.support_lora_last_check_time,
team_member_support_gsm_last_check_time: masterSensor.team_member_support_gsm_last_check_time,
team_member_support_lora_last_check_time: masterSensor.team_member_support_lora_last_check_time,
connected_slave_count: 0,
connected_slaves: []
};
}
const master = masterMap[masterSensor.hardwareId];
const connectedSlaves = await Insensors.find({
connected_to: masterSensor.hardwareId,
type: "slave",
customerId
}).lean();
const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId));
for (const slave of connectedSlaves) {
const slaveHardwareId = slave.tankhardwareId || slave.hardwareId;
if (slaveSet.has(slaveHardwareId)) continue;
slaveSet.add(slaveHardwareId);
const tankInfo = await Tank.findOne({
$or: [
{ hardwareId: slaveHardwareId },
{ tankhardwareId: slaveHardwareId }
]
}).lean();
const slaveOrderInfo = slaveOrderMap[slaveHardwareId] || {};
const matchedTank = latestMasterData?.tanks?.find(t => t.tankhardwareId === slaveHardwareId);
let loraConnected = false;
if (matchedTank?.date && matchedTank.tankHeight !== "0") {
const loraTime = moment.tz(matchedTank.date, "Asia/Kolkata");
loraConnected = now.diff(loraTime, "minutes") <= 1;
}
const slaveEnriched = {
hardwareId: slaveHardwareId,
tankName: slave.tankName || tankInfo?.tankName || "",
location: slave.location || tankInfo?.tankLocation || slaveOrderInfo.location || "",
connected_status: loraConnected ? "connected" : "disconnected",
connected_lora_time: slave.connected_lora_time,
connected_lora_date: slave.connected_lora_date,
lora_last_check_time: slave.lora_last_check_time,
lora_last_disconnect_time: slave.lora_last_disconnect_time,
connected_to: slave.connected_to,
masterName: master.masterName,
type: "slave",
typeOfWater: slave.typeOfWater || tankInfo?.typeOfWater || slaveOrderInfo.typeOfWater || "",
tankHeight: slave.tankHeight,
support_lora_last_check_time: slave.support_lora_last_check_time,
team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time
};
master.connected_slaves.push(slaveEnriched);
master.connected_slave_count++;
}
}
// 🔍 Filter comments by customerId
const comments = (supportRecord.comments || [])
.filter(c => c.customerId === customerId)
.map(c => ({
text: c.text,
commentsTime: moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm")
}));
for (const master of Object.values(masterMap)) {
master.comments = comments;
}
return reply.send({
status_code: 200,
supportId,
customerId,
totalMasters: Object.keys(masterMap).length,
disconnectedIssues: Object.values(masterMap)
});
} catch (error) {
console.error("Error fetching disconnected issues:", error);
return reply.code(500).send({ error: "Internal server error" });
}
};
exports.getResolvedIssuesBySupportId = 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" });
}
const resolvedIssues = (supportRecord.resolvedIssues || []).filter(issue => issue.currentlyResolved !== false);
const hardwareSet = new Set();
for (const issue of resolvedIssues) {
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 resolvedIssues) {
const masterId = issue.masterHardwareId || issue.hardwareId;
const masterSensor = sensorMap[masterId];
if (!masterSensor || masterSensor.type !== "master") continue;
const enriched = orderMap[masterId] || {};
const masterEntry = {
hardwareId: masterSensor.hardwareId,
masterName: enriched.masterName || masterSensor.masterName || "",
location: enriched.location || masterSensor.location || "",
type: "master",
connected_status: "connected",
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,
gsm_last_check_time: masterSensor.gsm_last_check_time,
gsm_last_disconnect_time: masterSensor.gsm_last_disconnect_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: [],
resolvedAt: issue.resolvedAt,
originalMovedAt: issue.originalMovedAt
};
const connectedSlaves = await Insensors.find({
connected_to: masterId,
type: "slave",
customerId
}).lean();
for (const slave of connectedSlaves) {
const slaveHardwareId = slave.tankhardwareId || slave.hardwareId;
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: "connected",
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: masterEntry.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
};
masterEntry.connected_slaves.push(slaveEnriched);
masterEntry.connected_slave_count++;
}
masterMap[masterSensor.hardwareId] = masterEntry;
}
// Format and attach comments
const comments = (supportRecord.comments || []).map(c => ({
text: c.text,
commentsTime: moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm")
}));
for (const master of Object.values(masterMap)) {
master.comments = comments;
}
return reply.send({
status_code: 200,
supportId,
customerId,
totalResolved: Object.keys(masterMap).length,
resolvedIssues: Object.values(masterMap)
});
} catch (err) {
console.error("Error in getResolvedIssuesBySupportId:", err);
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" });
// }
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId" });
// }
// const unresolvedIssues = (supportRecord.issues || []).filter(
// issue => issue.resolved === false && issue.movedToCategory !== true
// );
// const allHardwareIds = new Set();
// for (const issue of unresolvedIssues) {
// if (issue.hardwareId) allHardwareIds.add(issue.hardwareId.trim().toLowerCase());
// if (Array.isArray(issue.hardwareIds)) {
// issue.hardwareIds.forEach(id => {
// if (typeof id === "string") allHardwareIds.add(id.trim().toLowerCase());
// });
// }
// }
// if (allHardwareIds.size === 0) {
// return reply.code(404).send({ message: "No unresolved hardware IDs found in issues" });
// }
// const hardwareIdsArray = Array.from(allHardwareIds);
// const disconnectedSensors = await Insensors.find({
// connected_status: "disconnected",
// $or: [
// { connected_to: { $in: hardwareIdsArray } },
// { hardwareId: { $in: hardwareIdsArray } }
// ]
// }).lean();
// if (!disconnectedSensors.length) {
// return reply.code(404).send({ message: "No disconnected issues found" });
// }
// const customerIds = [...new Set(disconnectedSensors.map(s => s.customerId))];
// const customers = await User.find({ customerId: { $in: customerIds } }).lean();
// const customerHardwareMap = {};
// for (const sensor of disconnectedSensors) {
// const custId = sensor.customerId;
// if (!customerHardwareMap[custId]) {
// customerHardwareMap[custId] = new Set();
// }
// const sensorHw = sensor.tankhardwareId?.trim().toLowerCase();
// const sensorConnected = sensor.connected_to?.trim().toLowerCase();
// for (const issue of unresolvedIssues) {
// const allIssueHardwareIds = [
// ...(issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []),
// issue.hardwareId?.trim().toLowerCase()
// ];
// if (
// allIssueHardwareIds.includes(sensorHw) ||
// allIssueHardwareIds.includes(sensorConnected)
// ) {
// customerHardwareMap[custId].add(issue.hardwareId);
// }
// }
// }
// const response = [];
// for (const user of customers) {
// const custId = user.customerId;
// const hardwareIdSet = customerHardwareMap[custId] || new Set();
// const relatedIssues = unresolvedIssues.filter(issue => {
// const issueHw = issue.hardwareId?.trim().toLowerCase();
// const hardwareIds = issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || [];
// const allIds = [issueHw, ...hardwareIds];
// return Array.from(hardwareIdSet).some(hw => allIds.includes(hw?.trim().toLowerCase()));
// });
// let latestIssueTime = null;
// for (const issue of relatedIssues) {
// if (issue.lastTicketRaisedAt) {
// const issueTime = new Date(issue.lastTicketRaisedAt);
// if (!latestIssueTime || issueTime > latestIssueTime) {
// latestIssueTime = issueTime;
// }
// }
// }
// response.push({
// customer: {
// customerId: custId,
// username: user.username || "",
// firstName: user.profile?.firstName || "",
// lastName: user.profile?.lastName || "",
// phone: user.phone || user.profile?.contactNumber || "",
// email: user.emails?.[0]?.email || "",
// phoneVerified: user.phoneVerified || false,
// address1: user.profile?.address1 || "",
// address2: user.profile?.address2 || "",
// city: user.profile?.city || "",
// state: user.profile?.state || "",
// country: user.profile?.country || "",
// zip: user.profile?.zip || "",
// notes: user.profile?.notes || "",
// latitude: user.latitude,
// longitude: user.longitude,
// fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")),
// installationId: user.installationId || "",
// notificationPreferences: {
// allowNotifications: user.allowNotifications || false,
// automaticStartAndStopNotify: user.automaticStartAndStopNotify || false,
// manualStartAndStopNotify: user.manualStartAndStopNotify || false,
// criticalLowWaterAlert: user.criticalLowWaterAlert || false,
// lowWaterAlert: user.lowWaterAlert || false,
// notificationPreference: user.notificationPreference || "never"
// },
// surveyStatus: user.survey_status || "pending",
// buildingName: user.buildingName,
// stripePaymentStatus: user.stripePaymentStatus || false,
// stripeSubscriptionStatus: user.stripeSubscriptionStatus || false,
// createdAt: user.createdAt,
// updatedAt: user.updatedAt,
// lastTicketRaisedAt: latestIssueTime ? moment(latestIssueTime).format("YYYY-MM-DD HH:mm:ss") : null,
// totalHardwareIdsCount: hardwareIdSet.size
// }
// });
// }
// return reply.send({
// status_code: 200,
// data: response
// });
// } catch (error) {
// console.error("Error fetching disconnected customer details:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
// exports.getDisconnectedCustomerDetails = async (req, reply) => {
// try {
// const { supportId } = req.params;
// if (!supportId) {
// return reply.code(400).send({ error: "supportId is required" });
// }
// // 1. Get the support record by supportId
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId" });
// }
// // 2. Extract all hardwareIds from issues
// const hardwareIds = [];
// for (const issue of supportRecord.issues) {
// if (issue.hardwareId) hardwareIds.push(issue.hardwareId);
// if (Array.isArray(issue.hardwareIds)) hardwareIds.push(...issue.hardwareIds);
// }
// if (hardwareIds.length === 0) {
// return reply.code(404).send({ message: "No hardware IDs found in issues" });
// }
// // 3. Find disconnected Insensors
// const disconnectedSensors = await Insensors.find({
// $or: [
// // { hardwareId: { $in: hardwareIds } },
// { connected_to: { $in: hardwareIds } }
// ],
// connected_status: "disconnected"
// }).lean();
// if (disconnectedSensors.length === 0) {
// return reply.code(404).send({ message: "No disconnected issues found" });
// }
// // 4. Get all unique customerIds
// const customerIds = [...new Set(disconnectedSensors.map(s => s.customerId))];
// const customers = await User.find({ customerId: { $in: customerIds } }).lean();
// // 5. Map unique customers
// const uniqueCustomerMap = {};
// for (const user of customers) {
// if (!uniqueCustomerMap[user.customerId]) {
// uniqueCustomerMap[user.customerId] = {
// customer: {
// customerId: user.customerId,
// username: user.username || "",
// firstName: user.profile?.firstName || "",
// lastName: user.profile?.lastName || "",
// phone: user.phone || user.profile?.contactNumber || "",
// email: user.emails?.[0]?.email || "",
// phoneVerified: user.phoneVerified || false,
// address1: user.profile?.address1 || "",
// address2: user.profile?.address2 || "",
// city: user.profile?.city || "",
// state: user.profile?.state || "",
// country: user.profile?.country || "",
// zip: user.profile?.zip || "",
// notes: user.profile?.notes || "",
// latitude: user.latitude,
// longitude: user.longitude,
// fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")),
// installationId: user.installationId || "",
// notificationPreferences: {
// allowNotifications: user.allowNotifications || false,
// automaticStartAndStopNotify: user.automaticStartAndStopNotify || false,
// manualStartAndStopNotify: user.manualStartAndStopNotify || false,
// criticalLowWaterAlert: user.criticalLowWaterAlert || false,
// lowWaterAlert: user.lowWaterAlert || false,
// notificationPreference: user.notificationPreference || "never"
// },
// surveyStatus: user.survey_status || "pending",
// buildingName: user.buildingName,
// stripePaymentStatus: user.stripePaymentStatus || false,
// stripeSubscriptionStatus: user.stripeSubscriptionStatus || false,
// createdAt: user.createdAt,
// updatedAt: user.updatedAt
// }
// };
// }
// }
// const response = Object.values(uniqueCustomerMap);
// return reply.send({
// status_code: 200,
// data: response
// });
// } catch (error) {
// console.error("Error fetching disconnected customer details:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
exports.getDisconnectedCustomerDetails = async (req, reply) => {
try {
const { supportId } = req.params;
if (!supportId) {
return reply.code(400).send({ error: "supportId is required" });
}
const supportRecord = await Support.findOne({ supportId }).lean();
if (!supportRecord) {
return reply.code(404).send({ message: "No support record found for this supportId" });
}
const unresolvedIssues = supportRecord.issues?.filter(
(issue) => issue.resolved === false && issue.movedToCategory === false
) || [];
// Create set of categorized hardwareIds (masters and slaves)
const existingCategorizedHardwareIds = new Set();
(supportRecord.categorizedIssues || []).forEach(issue => {
if (issue.hardwareId) existingCategorizedHardwareIds.add(issue.hardwareId.trim().toLowerCase());
if (Array.isArray(issue.hardwareIds)) {
issue.hardwareIds.forEach(id => {
if (typeof id === "string") existingCategorizedHardwareIds.add(id.trim().toLowerCase());
});
}
});
// Extract all unresolved hardwareIds
const hardwareIdsArray = new Set();
unresolvedIssues.forEach((issue) => {
if (issue.hardwareId) hardwareIdsArray.add(issue.hardwareId.trim());
if (Array.isArray(issue.hardwareIds)) {
issue.hardwareIds.forEach((id) => {
if (typeof id === "string") hardwareIdsArray.add(id.trim());
});
}
});
const allHardwareIds = [...hardwareIdsArray];
// Fetch disconnected sensors, excluding those already categorized
const disconnectedSensorsRaw = await Insensors.find({
connected_status: "disconnected",
$or: [
{ connected_to: { $in: allHardwareIds } },
{ hardwareId: { $in: allHardwareIds } },
{ tankhardwareId: { $in: allHardwareIds } }
]
}).lean();
const disconnectedSensors = disconnectedSensorsRaw.filter(sensor => {
const ids = [
sensor.hardwareId?.trim().toLowerCase(),
sensor.connected_to?.trim().toLowerCase(),
sensor.tankhardwareId?.trim().toLowerCase()
];
return !ids.some(id => existingCategorizedHardwareIds.has(id));
});
// Map customerId -> Set of affected hardwareIds
const customerHardwareMap = {};
for (const sensor of disconnectedSensors) {
const custId = sensor.customerId;
if (!customerHardwareMap[custId]) {
customerHardwareMap[custId] = new Set();
}
const sensorHw = sensor.tankhardwareId?.trim().toLowerCase();
const sensorConnected = sensor.connected_to?.trim().toLowerCase();
const sensorHardwareId = sensor.hardwareId?.trim().toLowerCase();
for (const issue of unresolvedIssues) {
const allIssueHardwareIds = [
...(issue.hardwareIds?.map(id => id?.trim().toLowerCase()) || []),
issue.hardwareId?.trim().toLowerCase()
];
const isCategorizedMatch = [sensorHw, sensorConnected, sensorHardwareId].some(id =>
id && existingCategorizedHardwareIds.has(id)
);
if (isCategorizedMatch) continue;
if (
(sensorHw && allIssueHardwareIds.includes(sensorHw)) ||
(sensorConnected && allIssueHardwareIds.includes(sensorConnected)) ||
(sensorHardwareId && allIssueHardwareIds.includes(sensorHardwareId))
) {
for (const hw of allIssueHardwareIds) {
if (hw && !existingCategorizedHardwareIds.has(hw)) {
customerHardwareMap[custId].add(hw);
}
}
}
}
}
const customerDetails = await User.find({
customerId: { $in: Object.keys(customerHardwareMap) }
}).lean();
const customerResults = customerDetails.map((customer) => {
const affectedHardwareSet = customerHardwareMap[customer.customerId] || new Set();
return {
customerId: customer.customerId,
buildingName: customer.buildingName || "",
location: customer.location || "",
username: customer.username || "",
firstName: customer.profile?.firstName || "",
lastName: customer.profile?.lastName || "",
phone: customer.phone || user.profile?.contactNumber || "",
email: customer.emails?.[0]?.email || "",
phoneVerified: customer.phoneVerified || false,
address1: customer.profile?.address1 || "",
address2: customer.profile?.address2 || "",
city: customer.profile?.city || "",
latitude: customer.latitude,
longitude: customer.longitude,
totalHardwareIdsCount: affectedHardwareSet.size,
hardwareIds: [...affectedHardwareSet]
};
});
return reply.code(200).send({
success: true,
totalCustomers: customerResults.length,
customers: customerResults
});
} catch (error) {
console.error("Error in getDisconnectedCustomerDetails:", error);
return reply.code(500).send({
success: false,
message: "Internal Server Error"
});
}
};
exports.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" });
// }
// };
// exports.getDisconnectedMoveCustomerDetails = async (req, reply) => {
// try {
// const { supportId } = req.params;
// if (!supportId) {
// return reply.code(400).send({ error: "supportId is required" });
// }
// const supportRecord = await Support.findOne({ supportId }).lean();
// if (!supportRecord) {
// return reply.code(404).send({ message: "No support record found for this supportId" });
// }
// const categorizedHardwareIds = [];
// const resolvedHardwareIds = [];
// for (const issue of supportRecord.categorizedIssues || []) {
// if (issue.hardwareId) categorizedHardwareIds.push(issue.hardwareId);
// if (Array.isArray(issue.hardwareIds)) categorizedHardwareIds.push(...issue.hardwareIds);
// }
// for (const issue of supportRecord.resolvedIssues || []) {
// if (issue.hardwareId) resolvedHardwareIds.push(issue.hardwareId);
// if (Array.isArray(issue.hardwareIds)) resolvedHardwareIds.push(...issue.hardwareIds);
// }
// const allHardwareIds = [...new Set([...categorizedHardwareIds, ...resolvedHardwareIds])];
// if (allHardwareIds.length === 0) {
// return reply.code(404).send({ message: "No hardware IDs in support issues" });
// }
// const allSensors = await Insensors.find({
// $or: [
// { hardwareId: { $in: allHardwareIds } },
// { connected_to: { $in: allHardwareIds } }
// ]
// }).lean();
// if (allSensors.length === 0) {
// return reply.code(404).send({ message: "No sensors found for support issues" });
// }
// const customerStatusMap = {};
// for (const sensor of allSensors) {
// const cid = sensor.customerId;
// if (!cid) continue;
// if (!customerStatusMap[cid]) {
// customerStatusMap[cid] = { status: "unknown" };
// }
// if (resolvedHardwareIds.includes(sensor.hardwareId) || resolvedHardwareIds.includes(sensor.connected_to)) {
// customerStatusMap[cid].status = "resolved";
// } else if (sensor.connected_status === "disconnected") {
// customerStatusMap[cid].status = "disconnected";
// } else if (sensor.connected_status === "connected" && customerStatusMap[cid].status !== "disconnected" && customerStatusMap[cid].status !== "resolved") {
// customerStatusMap[cid].status = "connected";
// }
// }
// const customerIds = Object.keys(customerStatusMap);
// const users = await User.find({ customerId: { $in: customerIds } }).lean();
// const combinedCustomerList = users.map(user => {
// const cid = user.customerId;
// return {
// customer : {
// customerId: cid,
// connectionStatus: customerStatusMap[cid]?.status || "unknown",
// username: user.username || "",
// firstName: user.profile?.firstName || user.firstName || "",
// lastName: user.profile?.lastName || user.lastName || "",
// phone: user.phone || user.profile?.contactNumber || user.alternativeNumber || "",
// email: user.emails?.[0]?.email || user.email || "",
// phoneVerified: user.phoneVerified || false,
// address1: user.profile?.address1 || user.address1 || "",
// address2: user.profile?.address2 || user.address2 || "",
// city: user.profile?.city || user.city || "",
// state: user.profile?.state || user.state || "",
// country: user.profile?.country || user.country || "",
// zip: user.profile?.zip || "",
// notes: user.profile?.notes || "",
// latitude: user.latitude || 0,
// longitude: user.longitude || 0,
// fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")),
// installationId: user.installationId || "",
// notificationPreferences: {
// allowNotifications: user.allowNotifications || false,
// automaticStartAndStopNotify: user.automaticStartAndStopNotify || false,
// manualStartAndStopNotify: user.manualStartAndStopNotify || false,
// criticalLowWaterAlert: user.criticalLowWaterAlert || false,
// lowWaterAlert: user.lowWaterAlert || false,
// notificationPreference: user.notificationPreference || "never"
// },
// surveyStatus: user.survey_status || "pending",
// buildingName: user.buildingName || "",
// stripePaymentStatus: user.stripePaymentStatus || false,
// stripeSubscriptionStatus: user.stripeSubscriptionStatus || false,
// createdAt: user.createdAt,
// updatedAt: user.updatedAt
// }
// };
// });
// return reply.send({
// status_code: 200,
// data: combinedCustomerList
// });
// } catch (error) {
// console.error("Error in getDisconnectedMoveCustomerDetails:", error);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
exports.getDisconnectedMoveCustomerDetails = async (req, reply) => {
try {
const { supportId } = req.params;
if (!supportId) {
return reply.code(400).send({ error: "supportId is required" });
}
const supportRecord = await Support.findOne({ supportId }).lean();
if (!supportRecord) {
return reply.code(404).send({ message: "No support record found for this supportId" });
}
// Extract hardwareIds from categorizedIssues only (exclude resolvedIssues)
const categorizedHardwareIds = [];
for (const issue of supportRecord.categorizedIssues || []) {
if (issue.hardwareId) categorizedHardwareIds.push(issue.hardwareId);
if (Array.isArray(issue.hardwareIds)) categorizedHardwareIds.push(...issue.hardwareIds);
}
if (categorizedHardwareIds.length === 0) {
return reply.code(404).send({ message: "No hardware IDs in categorized issues" });
}
const allSensors = await Insensors.find({
$or: [
{ hardwareId: { $in: categorizedHardwareIds } },
{ connected_to: { $in: categorizedHardwareIds } }
]
}).lean();
if (allSensors.length === 0) {
return reply.code(404).send({ message: "No sensors found for categorized hardware IDs" });
}
// Determine connection status per customer
const customerStatusMap = {};
for (const sensor of allSensors) {
const cid = sensor.customerId;
if (!cid) continue;
if (!customerStatusMap[cid]) {
customerStatusMap[cid] = { status: "unknown" };
}
if (sensor.connected_status === "disconnected") {
customerStatusMap[cid].status = "disconnected";
} else if (sensor.connected_status === "connected" && customerStatusMap[cid].status !== "disconnected") {
customerStatusMap[cid].status = "connected";
}
}
const customerIds = Object.keys(customerStatusMap);
const users = await User.find({ customerId: { $in: customerIds } }).lean();
const combinedCustomerList = users.map(user => {
const cid = user.customerId;
return {
customer: {
customerId: cid,
connectionStatus: customerStatusMap[cid]?.status || "unknown",
username: user.username || "",
firstName: user.profile?.firstName || user.firstName || "",
lastName: user.profile?.lastName || user.lastName || "",
phone: user.phone || user.profile?.contactNumber || user.alternativeNumber || "",
email: user.emails?.[0]?.email || user.email || "",
phoneVerified: user.phoneVerified || false,
address1: user.profile?.address1 || user.address1 || "",
address2: user.profile?.address2 || user.address2 || "",
city: user.profile?.city || user.city || "",
state: user.profile?.state || user.state || "",
country: user.profile?.country || user.country || "",
zip: user.profile?.zip || "",
notes: user.profile?.notes || "",
latitude: user.latitude || 0,
longitude: user.longitude || 0,
fcmIds: (user.fcmIds || []).filter(fcm => typeof fcm === "string" && fcm.startsWith("d")),
installationId: user.installationId || "",
notificationPreferences: {
allowNotifications: user.allowNotifications || false,
automaticStartAndStopNotify: user.automaticStartAndStopNotify || false,
manualStartAndStopNotify: user.manualStartAndStopNotify || false,
criticalLowWaterAlert: user.criticalLowWaterAlert || false,
lowWaterAlert: user.lowWaterAlert || false,
notificationPreference: user.notificationPreference || "never"
},
surveyStatus: user.survey_status || "pending",
buildingName: user.buildingName || "",
stripePaymentStatus: user.stripePaymentStatus || false,
stripeSubscriptionStatus: user.stripeSubscriptionStatus || false,
createdAt: user.createdAt,
updatedAt: user.updatedAt
}
};
});
return reply.send({
status_code: 200,
data: combinedCustomerList
});
} catch (error) {
console.error("Error in getDisconnectedMoveCustomerDetails:", error);
return reply.code(500).send({ error: "Internal server error" });
}
};
exports.getResolvedCustomerDetails = 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" });
}
console.log("✅ Support Record:", JSON.stringify(supportRecord, null, 2));
const resolvedIssues = supportRecord.resolvedIssues || [];
if (!Array.isArray(resolvedIssues) || resolvedIssues.length === 0) {
return reply.code(404).send({ message: "No resolved issues to process" });
}
const resolvedHardwareIds = [];
for (const issue of resolvedIssues) {
if (issue.hardwareId) resolvedHardwareIds.push(issue.hardwareId);
if (Array.isArray(issue.hardwareIds)) resolvedHardwareIds.push(...issue.hardwareIds);
}
if (resolvedHardwareIds.length === 0) {
return reply.code(404).send({ message: "No hardware IDs in resolved issues" });
}
const sensors = await Insensors.find({
$or: [
{ hardwareId: { $in: resolvedHardwareIds } },
{ connected_to: { $in: resolvedHardwareIds } }
]
}).lean();
if (sensors.length === 0) {
return reply.code(404).send({ message: "No sensors found for resolved hardware" });
}
const customerIds = [...new Set(sensors.map(s => s.customerId))];
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
}
};
}
}
return reply.send({
status_code: 200,
data: Object.values(uniqueCustomerMap)
});
} catch (error) {
console.error("❌ Error fetching resolved 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.moveIssueToCategory = async (req, reply) => {
try {
const { supportId } = req.params;
const { category, hardwareId } = req.body;
if (!supportId || !category || !hardwareId) {
return reply.code(400).send({
message: "supportId (path), category and hardwareId (body) are required",
});
}
const support = await Support.findOne({ supportId });
if (!support) {
return reply.code(404).send({ message: "Support record not found" });
}
let issueMoved = false;
const nowTime = moment().tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss");
if (!Array.isArray(support.categorizedIssues)) {
support.categorizedIssues = [];
}
const index = support.issues.findIndex((issue) => {
if (issue.hardwareId === hardwareId) return true;
if (Array.isArray(issue.hardwareIds) && issue.hardwareIds.includes(hardwareId)) return true;
return false;
});
if (index === -1) {
return reply.code(404).send({ message: "No matching issue found to move" });
}
const issue = support.issues[index];
// Normalize type if it's invalid
const normalizedType =
issue.type === "GSM or LoRa Disconnected" ? "GSM Disconnected" : issue.type;
if (issue.hardwareId === hardwareId) {
issue.movedToCategory = true;
support.categorizedIssues.push({
type: normalizedType,
hardwareId: issue.hardwareId,
masterHardwareId: issue.masterHardwareId || issue.hardwareId,
category,
movedAt: nowTime,
movedToCategory: true,
});
support.issues.splice(index, 1);
issueMoved = true;
} else {
const slaveIndex = issue.hardwareIds.indexOf(hardwareId);
if (slaveIndex !== -1) {
const slaveName = issue.slaveNames?.[slaveIndex] || "Unknown";
support.categorizedIssues.push({
type: normalizedType,
hardwareId,
masterHardwareId: issue.masterHardwareId || issue.hardwareId,
slaveName,
category,
movedAt: nowTime,
movedToCategory: true,
});
issue.hardwareIds.splice(slaveIndex, 1);
issue.slaveNames.splice(slaveIndex, 1);
if (issue.hardwareIds.length === 0) {
support.issues.splice(index, 1);
}
issueMoved = true;
}
}
if (issueMoved) {
await support.save();
return reply.send({ message: "Issue moved to category successfully" });
} else {
return reply.code(404).send({ message: "No matching issue found to move" });
}
} catch (err) {
console.error("Error moving issue:", err);
return reply.code(500).send({ error: "Internal Server Error" });
}
};
// exports.particularCategory = async (req, reply) => {
// try {
// const { supportId, category } = req.params;
// const { customerId: queryCustomerId } = req.query;
// if (!supportId || !category) {
// return reply.code(400).send({ error: "supportId and category are required" });
// }
// const support = await Support.findOne({ supportId }).lean();
// if (!support) {
// return reply.code(404).send({ message: "Support record not found" });
// }
// console.log("support",support)
// // Choose the appropriate array based on category
// let issues = [];
// if (category === "Resolved") {
// issues = (support.resolvedIssues || []).filter(issue => issue.category === "Resolved");
// } else {
// issues = (support.categorizedIssues || []).filter(issue => issue.category === category);
// }
// console.log("issues",issues)
// if (issues.length === 0) {
// return reply.code(404).send({ message: `No issues found for category: ${category}` });
// }
// const hardwareIds = [...new Set(issues.map(issue => issue.hardwareId).filter(Boolean))];
// if (hardwareIds.length === 0) {
// return reply.code(404).send({ message: "No hardware IDs found for these issues" });
// }
// let customerId = queryCustomerId;
// if (!customerId) {
// const sensors = await Insensors.find({ hardwareId: { $in: hardwareIds } }).lean();
// if (!sensors.length) {
// return reply.code(404).send({ message: "No sensors found matching these hardware IDs" });
// }
// customerId = sensors[0].customerId;
// if (!customerId) {
// return reply.code(404).send({ message: "Customer ID not found for these sensors" });
// }
// }
// const allRelatedSensors = await Insensors.find({
// customerId,
// hardwareId: { $in: hardwareIds }
// }).lean();
// if (!allRelatedSensors.length) {
// return reply.code(404).send({ message: "No sensors found for the provided customer and hardware IDs" });
// }
// const orders = await Order.find({ customerId }).lean();
// const orderMap = {};
// orders.forEach(order => {
// order.master_connections.forEach(conn => {
// orderMap[conn.hardwareId] = {
// masterName: conn.master_name || null,
// location: conn.location || null
// };
// });
// });
// const disconnectedIssues = [];
// // for (const master of allRelatedSensors.filter(i => i.type === "master")) {
// const allMasters = allRelatedSensors.filter(i => i.type === "master");
// for (const master of allMasters) {
// const slaves = await Insensors.find({
// connected_to: master.hardwareId,
// customerId
// }).lean();
// const slaveDetails = await Promise.all(slaves.map(async (slave) => {
// const slaveHardwareId = slave.tankhardwareId;
// const tankInfo = await Tank.findOne({
// $or: [
// { hardwareId: slaveHardwareId },
// { tankhardwareId: slaveHardwareId }
// ]
// }).lean();
// const slaveComments = (support.comments || [])
// .filter(comment => comment.hardwareId === slave.hardwareId)
// .map(c => c.text);
// return {
// hardwareId: slave.tankhardwareId,
// tankName: slave.tankName || "",
// location: slave.tankLocation || "",
// connected_status: slave.connected_status,
// connected_lora_time: slave.connected_lora_time || "",
// connected_lora_date: slave.connected_lora_date || "",
// lora_last_check_time: slave.lora_last_check_time || null,
// lora_last_disconnect_time: slave.lora_last_disconnect_time || null,
// connected_to: slave.connected_to || "",
// masterName: orderMap[master.hardwareId]?.masterName || "",
// type: "slave",
// typeOfWater: tankInfo?.typeOfWater || "",
// support_lora_last_check_time: slave.support_lora_last_check_time || null,
// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time || null,
// comments: slaveComments
// };
// }));
// const masterComments = (support.comments || [])
// .filter(comment => comment.hardwareId === master.hardwareId)
// .map(c => c.text);
// disconnectedIssues.push({
// hardwareId: master.hardwareId,
// masterName: orderMap[master.hardwareId]?.masterName || "",
// location: orderMap[master.hardwareId]?.location || "",
// type: "master",
// connected_status: master.connected_status,
// gsm_last_check_time: master.gsm_last_check_time || null,
// gsm_last_disconnect_time: master.gsm_last_disconnect_time || null,
// connected_gsm_date: master.connected_gsm_date || "",
// connected_gsm_time: master.connected_gsm_time || "",
// connected_lora_date: master.connected_lora_date || "",
// connected_lora_time: master.connected_lora_time || "",
// support_gsm_last_check_time: master.support_gsm_last_check_time || null,
// team_member_support_gsm_last_check_time: master.team_member_support_gsm_last_check_time || null,
// connected_slave_count: slaveDetails.length,
// connected_slaves: slaveDetails,
// comments: masterComments
// });
// }
// return reply.send({
// status_code: 200,
// supportId,
// customerId,
// totalMasters: disconnectedIssues.length,
// disconnectedIssues
// });
// } catch (err) {
// console.error("Error in particularCategory:", err);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
// exports.assignCategorizeIssue = async (request, reply) => {
// const { supportId } = request.params;
// const { support_teamMemberId, startDate, endDate, category, masterHardwareId } = request.body;
// if (!support_teamMemberId || !startDate || !endDate || !category || !masterHardwareId) {
// return reply.code(400).send({ error: 'support_teamMemberId, startDate, endDate, category, and masterHardwareId are required' });
// }
// const support = await Support.findOne({ supportId });
// if (!support) {
// return reply.code(404).send({ error: 'Support record not found' });
// }
// const teamMembers = support.team_member?.team_member || [];
// const teamMember = teamMembers.find(m => m.support_teamMemberId === support_teamMemberId);
// if (!teamMember) {
// return reply.code(400).send({ error: `Team member ID ${support_teamMemberId} not found` });
// }
// const start = new Date(startDate);
// const end = new Date(endDate);
// if (isNaN(start) || isNaN(end)) {
// return reply.code(400).send({ error: 'Invalid startDate or endDate' });
// }
// // ✅ Format to "DD-MM-YYYY HH:mm:ss"
// const formattedStart = moment(start).format("DD-MM-YYYY HH:mm:ss");
// const formattedEnd = moment(end).format("DD-MM-YYYY HH:mm:ss");
// let assignedCount = 0;
// support.categorizedIssues.forEach(issue => {
// if (
// issue.masterHardwareId === masterHardwareId &&
// issue.category === category
// ) {
// issue.assignedTo = {
// name: teamMember.name,
// support_teamMemberId: teamMember.support_teamMemberId,
// phone: teamMember.phone,
// email: teamMember.email,
// startDate: formattedStart, // 👈 use formatted date
// endDate: formattedEnd // 👈 use formatted date
// };
// assignedCount++;
// }
// });
// if (assignedCount === 0) {
// return reply.code(404).send({ message: 'No matching issues found for assignment' });
// }
// await support.save();
// return reply.send({
// message: `Assigned ${assignedCount} categorized issue(s) to ${teamMember.name}`,
// assignedTo: teamMember.support_teamMemberId
// });
// };
// const moment = require('moment'); // Ensure moment is installed
// exports.particularCategory = async (req, reply) => {
// try {
// const { supportId, category } = req.params;
// const { customerId: queryCustomerId } = req.query;
// if (!supportId || !category) {
// return reply.code(400).send({ error: "supportId and category are required" });
// }
// const support = await Support.findOne({ supportId }).lean();
// if (!support) return reply.code(404).send({ message: "Support record not found" });
// // Filter issues by category
// const issues = (category === "Resolved" ? support.resolvedIssues : support.categorizedIssues || [])
// .filter(issue => issue.category === category);
// if (!issues.length) return reply.code(404).send({ message: `No issues found for category: ${category}` });
// const hardwareIds = [...new Set(issues.map(issue => issue.hardwareId).filter(Boolean))];
// if (!hardwareIds.length) return reply.code(404).send({ message: "No hardware IDs found for these issues" });
// let customerId = queryCustomerId;
// if (!customerId) {
// const sensorDoc = await Insensors.findOne({ hardwareId: { $in: hardwareIds } }).lean();
// if (!sensorDoc || !sensorDoc.customerId) return reply.code(404).send({ message: "Customer ID not found" });
// customerId = sensorDoc.customerId;
// }
// const allRelatedSensors = await Insensors.find({
// customerId,
// hardwareId: { $in: hardwareIds }
// }).lean();
// if (!allRelatedSensors.length) return reply.code(404).send({ message: "No sensors found" });
// // Order map
// const orders = await Order.find({ customerId }).lean();
// const orderMap = {};
// orders.forEach(order => {
// order.master_connections.forEach(conn => {
// orderMap[conn.hardwareId] = {
// masterName: conn.master_name || null,
// location: conn.location || null
// };
// });
// });
// // Create map for issue -> movedAt/resolvedAt
// const issueMap = {};
// issues.forEach(issue => {
// issueMap[issue.hardwareId] = issue;
// });
// const disconnectedIssues = [];
// const allMasters = allRelatedSensors.filter(i => i.type === "master");
// for (const master of allMasters) {
// const slaves = await Insensors.find({ connected_to: master.hardwareId, customerId }).lean();
// // Get latest IoT data for master
// const latestIotData = await IotData.findOne({ hardwareId: master.hardwareId }).sort({ date: -1 }).lean();
// // GSM Status
// const now = moment.tz("Asia/Kolkata");
// let gsm_last_check_time = null;
// let gsmConnected = false;
// if (latestIotData?.date) {
// const gsmTime = moment.tz(latestIotData.date, "Asia/Kolkata");
// const gsmDiff = now.diff(gsmTime, "minutes");
// gsmConnected = gsmDiff <= 1;
// gsm_last_check_time = latestIotData.date;
// }
// // Prepare slave details with LORA check
// const slaveDetails = await Promise.all(slaves.map(async (slave) => {
// const slaveHardwareId = slave.tankhardwareId?.trim();
// const matchedTank = latestIotData?.tanks?.find(tank => tank.tankhardwareId === slaveHardwareId);
// let loraConnected = false;
// let lora_last_check_time = null;
// if (matchedTank?.date && matchedTank?.tankHeight !== "0") {
// const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata");
// const loraDiff = now.diff(tankTime, "minutes");
// loraConnected = loraDiff <= 1;
// lora_last_check_time = matchedTank.date;
// }
// const tankInfo = await Tank.findOne({
// $or: [
// { hardwareId: slaveHardwareId },
// { tankhardwareId: slaveHardwareId }
// ]
// }).lean();
// const slaveComments = (support.comments || [])
// .filter(comment => comment.hardwareId === slave.hardwareId)
// .map(c => c.text);
// return {
// hardwareId: slave.tankhardwareId,
// tankName: slave.tankName || "",
// location: slave.tankLocation || "",
// connected_status: slave.connected_status,
// connected_lora_date: slave.connected_lora_date || "",
// connected_lora_time: slave.connected_lora_time || "",
// loraConnected,
// lora_last_check_time,
// lora_last_disconnect_time: slave.lora_last_disconnect_time || null,
// connected_to: slave.connected_to || "",
// masterName: orderMap[master.hardwareId]?.masterName || "",
// type: "slave",
// typeOfWater: tankInfo?.typeOfWater || "",
// support_lora_last_check_time: slave.support_lora_last_check_time || null,
// team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time || null,
// comments: slaveComments
// };
// }));
// const masterComments = (support.comments || [])
// .filter(comment => comment.hardwareId === master.hardwareId)
// .map(c => c.text);
// const issue = issueMap[master.hardwareId];
// disconnectedIssues.push({
// hardwareId: master.hardwareId,
// masterName: orderMap[master.hardwareId]?.masterName || "",
// location: orderMap[master.hardwareId]?.location || "",
// type: "master",
// connected_status: master.connected_status,
// gsmConnected,
// gsm_last_check_time,
// gsm_last_disconnect_time: master.gsm_last_disconnect_time || null,
// connected_gsm_date: master.connected_gsm_date || "",
// connected_gsm_time: master.connected_gsm_time || "",
// connected_lora_date: master.connected_lora_date || "",
// connected_lora_time: master.connected_lora_time || "",
// support_gsm_last_check_time: master.support_gsm_last_check_time || null,
// team_member_support_gsm_last_check_time: master.team_member_support_gsm_last_check_time || null,
// connected_slave_count: slaveDetails.length,
// connected_slaves: slaveDetails,
// comments: masterComments,
// movedAt: category !== "Resolved" ? (issue?.movedAt || null) : null,
// resolvedAt: category === "Resolved" ? (issue?.resolvedAt || null) : null
// });
// }
// return reply.send({
// status_code: 200,
// supportId,
// customerId,
// totalMasters: disconnectedIssues.length,
// disconnectedIssues
// });
// } catch (err) {
// console.error("Error in particularCategory:", err);
// return reply.code(500).send({ error: "Internal server error" });
// }
// };
exports.particularCategory = async (req, reply) => {
try {
const { supportId, category } = req.params;
const { customerId: queryCustomerId } = req.query;
if (!supportId || !category) {
return reply.code(400).send({ error: "supportId and category are required" });
}
const support = await Support.findOne({ supportId }).lean();
if (!support) return reply.code(404).send({ message: "Support record not found" });
const issues = (category === "Resolved" ? support.resolvedIssues : support.categorizedIssues || [])
.filter(issue => issue.category === category);
if (!issues.length) return reply.code(404).send({ message: `No issues found for category: ${category}` });
const hardwareIds = [...new Set(issues.map(issue => issue.hardwareId).filter(Boolean))];
if (!hardwareIds.length) return reply.code(404).send({ message: "No hardware IDs found for these issues" });
let customerId = queryCustomerId;
if (!customerId) {
const sensorDoc = await Insensors.findOne({ hardwareId: { $in: hardwareIds } }).lean();
if (!sensorDoc || !sensorDoc.customerId) return reply.code(404).send({ message: "Customer ID not found" });
customerId = sensorDoc.customerId;
}
const allRelatedSensors = await Insensors.find({
customerId,
hardwareId: { $in: hardwareIds }
}).lean();
if (!allRelatedSensors.length) return reply.code(404).send({ message: "No sensors found" });
const orders = await Order.find({ customerId }).lean();
const orderMap = {};
orders.forEach(order => {
order.master_connections.forEach(conn => {
orderMap[conn.hardwareId] = {
masterName: conn.master_name || null,
location: conn.location || null
};
});
});
const issueMap = {};
issues.forEach(issue => {
issueMap[issue.hardwareId] = issue;
});
const disconnectedIssues = [];
const allMasters = allRelatedSensors.filter(i => i.type === "master");
for (const master of allMasters) {
const slaves = await Insensors.find({ connected_to: master.hardwareId, customerId }).lean();
const latestIotData = await IotData.findOne({ hardwareId: master.hardwareId }).sort({ date: -1 }).lean();
const now = moment.tz("Asia/Kolkata");
let gsmConnected = false;
if (latestIotData?.date) {
const gsmTime = moment.tz(latestIotData.date, "Asia/Kolkata");
const gsmDiff = now.diff(gsmTime, "minutes");
gsmConnected = gsmDiff <= 1;
}
// 🔄 Update master connected_status
await Insensors.updateOne(
{ hardwareId: master.hardwareId },
{ $set: { connected_status: gsmConnected ? "connected" : "disconnected" } }
);
const slaveDetails = await Promise.all(slaves.map(async (slave) => {
const slaveHardwareId = slave.tankhardwareId?.trim();
const matchedTank = latestIotData?.tanks?.find(tank => tank.tankhardwareId === slaveHardwareId);
let loraConnected = false;
if (matchedTank?.date && matchedTank?.tankHeight !== "0") {
const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata");
const loraDiff = now.diff(tankTime, "minutes");
loraConnected = loraDiff <= 1;
}
// 🔄 Update slave connected_status
await Insensors.updateOne(
{ tankhardwareId: slaveHardwareId },
{ $set: { connected_status: loraConnected ? "connected" : "disconnected" } }
);
const tankInfo = await Tank.findOne({
$or: [
{ hardwareId: slaveHardwareId },
{ tankhardwareId: slaveHardwareId }
]
}).lean();
// const slaveComments = (support.comments || [])
// .filter(comment => comment.hardwareId === slave.hardwareId)
// .map(c => c.text);
const slaveComments = (support.comments || [])
.filter(comment =>
comment.hardwareId === slave.hardwareId &&
comment.customerId === customerId // ✅ filter by customer
)
.map(c => ({
text: c.text,
commentsTime: c.createdAt
? moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm")
: null
}));
return {
hardwareId: slave.tankhardwareId,
tankName: slave.tankName || "",
location: slave.tankLocation || "",
connected_status: loraConnected ? "connected" : "disconnected",
connected_to: slave.connected_to || "",
masterName: orderMap[master.hardwareId]?.masterName || "",
type: "slave",
typeOfWater: tankInfo?.typeOfWater || "",
comments: slaveComments
};
}));
// const masterComments = (support.comments || [])
// .filter(comment => comment.hardwareId === master.hardwareId)
// .map(c => c.text);
const masterComments = (support.comments || [])
.filter(comment =>
comment.hardwareId === master.hardwareId &&
comment.customerId === customerId // ✅ filter by customer
)
.map(c => ({
text: c.text,
commentsTime: c.createdAt
? moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm")
: null
}));
const issue = issueMap[master.hardwareId];
disconnectedIssues.push({
hardwareId: master.hardwareId,
masterName: orderMap[master.hardwareId]?.masterName || "",
location: orderMap[master.hardwareId]?.location || "",
type: "master",
connected_status: gsmConnected ? "connected" : "disconnected",
connected_slave_count: slaveDetails.length,
connected_slaves: slaveDetails,
comments: masterComments,
movedAt: category !== "Resolved" ? (issue?.movedAt || null) : null,
resolvedAt: category === "Resolved" ? (issue?.resolvedAt || null) : null
});
}
return reply.send({
status_code: 200,
supportId,
customerId,
totalMasters: disconnectedIssues.length,
disconnectedIssues
});
} catch (err) {
console.error("Error in particularCategory:", err);
return reply.code(500).send({ error: "Internal server error" });
}
};
exports.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 with formatted createdAt
const commentObj = {
text: trimmedComment,
customerId,
hardwareId,
createdAt: moment().format("DD-MM-YYYY HH:mm")
};
if (!Array.isArray(supportRecord.comments)) {
supportRecord.comments = [];
}
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" });
}
};
exports.resolvedIssuesForSupport = 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" });
}
if (!Array.isArray(support.categorizedIssues)) support.categorizedIssues = [];
if (!Array.isArray(support.resolvedIssues)) support.resolvedIssues = [];
const nowTime = moment().tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss");
// Try to find issue in categorizedIssues
let categorizedIndex = support.categorizedIssues.findIndex(
(issue) => issue.hardwareId === hardwareId
);
// Try to find issue in resolvedIssues
let resolvedIndex = support.resolvedIssues.findIndex(
(issue) => issue.hardwareId === hardwareId
);
// Get the issue object from categorized or resolved
let issue =
categorizedIndex !== -1
? support.categorizedIssues[categorizedIndex]
: resolvedIndex !== -1
? support.resolvedIssues[resolvedIndex]
: null;
if (!issue) {
return reply.code(404).send({
message: `No issue found with hardwareId: ${hardwareId}`,
});
}
const masterHardwareId = issue.masterHardwareId || issue.hardwareId;
// Fetch master and slaves
const master = await Insensors.findOne({ hardwareId: masterHardwareId }).lean();
if (!master) {
return reply
.code(404)
.send({ message: `Master device not found with hardwareId ${masterHardwareId}` });
}
const slaves = await Insensors.find({ connected_to: masterHardwareId }).lean();
const allConnected =
master.connected_status === "connected" &&
slaves.every((s) => s.connected_status === "connected");
if (allConnected) {
// If fully connected
if (resolvedIndex === -1) {
// Add to resolvedIssues only if not already present
support.resolvedIssues.push({
type: issue.type,
hardwareId: issue.hardwareId,
masterHardwareId,
category: "Resolved",
resolvedAt: nowTime,
originalMovedAt: issue.movedAt || null,
movedToCategory: true,
slaveName: issue.slaveName || null,
currentlyResolved: true,
invalidatedAt: null,
});
} else {
// If already in resolvedIssues, just mark as currently resolved again
support.resolvedIssues[resolvedIndex].currentlyResolved = true;
support.resolvedIssues[resolvedIndex].invalidatedAt = null;
support.resolvedIssues[resolvedIndex].resolvedAt = nowTime;
}
// Remove from categorizedIssues if present
if (categorizedIndex !== -1) {
support.categorizedIssues.splice(categorizedIndex, 1);
}
await support.save();
return reply.send({ message: "Issue moved to resolved category successfully" });
} else {
// One or more devices still disconnected
// Mark in resolvedIssues as not currently resolved, don't remove it
if (resolvedIndex !== -1) {
support.resolvedIssues[resolvedIndex].currentlyResolved = false;
support.resolvedIssues[resolvedIndex].invalidatedAt = nowTime;
}
if (categorizedIndex === -1) {
// Not in categorized — add with Escalation category
support.categorizedIssues.push({
type: issue.type,
hardwareId: issue.hardwareId,
masterHardwareId,
category: "Escalation",
movedAt: nowTime,
movedToCategory: true,
slaveName: issue.slaveName || null,
});
} else {
// Already in categorized — update if category not "Escalation"
if (support.categorizedIssues[categorizedIndex].category !== "Escalation") {
support.categorizedIssues[categorizedIndex].category = "Escalation";
support.categorizedIssues[categorizedIndex].movedAt = nowTime;
support.categorizedIssues[categorizedIndex].movedToCategory = true;
}
}
await support.save();
return reply.send({
message: "Master or some slaves are disconnected. Issue moved/kept in escalation category.",
});
}
} catch (err) {
console.error("Error in resolvedIssuesForSupport:", err);
return reply.code(500).send({ error: "Internal Server Error" });
}
};