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.

2814 lines
90 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("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 ? "connected" : "disconnected";
const gsmLastCheckTime = now.format("DD-MM-YYYY HH:mm:ss"); // formatted current time
// ✅ Step 1: Update Insensors with GSM date/time/status and last check time
await Insensors.findOneAndUpdate(
{ connected_to: hardwareId },
{
$set: {
connected_gsm_date,
connected_gsm_time,
connected_status: gsmStatus,
gsm_last_check_time: gsmLastCheckTime
}
},
{ new: true }
);
// ✅ Step 2: Annotate tanks with LoRa connection status based on tank date
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"
};
});
// ✅ Step 3: 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,
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.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 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 updateFields = {
connected_status: isLoraConnected ? "connected" : "disconnected"
};
let connected_lora_date = null;
let connected_lora_time = null;
let lora_last_check_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;
}
// ✅ Format LoRa last check time in "YYYY-MM-DD HH:mm:ss"
lora_last_check_time = moment.tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss");
updateFields.lora_last_check_time = lora_last_check_time;
await Insensors.findOneAndUpdate(
{ connected_to: hardwareId, hardwareId: tankhardwareId },
{ $set: updateFields },
{ new: true }
);
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,
lora_last_check_time
});
} catch (err) {
console.error("Error in getByHardwareAndTankId:", 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' });
}
const allDevices = await Insensors.find({ customerId }).lean();
const masters = allDevices.filter(dev => dev.type === 'master');
const slaves = allDevices.filter(dev => dev.type === 'slave');
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;
const master = masters.find(m => m.hardwareId === masterId);
const masterName = master ? master.masterName : 'Unknown';
// If disconnected, update LoRa last disconnect time
let loraLastDisconnect = slave.lora_last_disconnect_time || null;
if (slave.connected_status === 'disconnected') {
// If connected_lora_date and connected_lora_time are available, combine them
const loraDate = slave.connected_lora_date; // e.g., "23-04-2025"
const loraTime = slave.connected_lora_time; // e.g., "15:38:07"
if (loraDate && loraTime) {
// Combine to get formatted lora_last_disconnect_time
const formattedTime = `${loraDate} ${loraTime}`; // e.g., "23-04-2025 15:38:07"
// Update the database with this formatted value
await Insensors.updateOne(
{ hardwareId: slave.hardwareId },
{ $set: { lora_last_disconnect_time: formattedTime } }
);
loraLastDisconnect = formattedTime; // Save the updated value to loraLastDisconnect
}
}
// Get tankHeight from IotData
const tankHeight = await getTankHeight(slave.hardwareId);
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,
lora_last_check_time: slave.lora_last_check_time || null,
lora_last_disconnect_time: loraLastDisconnect,
connected_to: slave.connected_to,
masterName: masterName,
type: slave.type || 'N/A',
typeOfWater: slave.typeOfWater || 'N/A',
tankHeight: tankHeight || null
});
}
const response = [];
for (const master of masters) {
const connectedSlaves = slaveMap[master.hardwareId] || [];
// If disconnected, update GSM last disconnect time
let gsmLastDisconnect = master.gsm_last_disconnect_time || null;
if (master.connected_status === 'disconnected') {
// If connected_gsm_date and connected_gsm_time are available, combine them
const gsmDate = master.connected_gsm_date; // e.g., "23-04-2025"
const gsmTime = master.connected_gsm_time; // e.g., "15:38:07"
if (gsmDate && gsmTime) {
// Combine to get formatted gsm_last_disconnect_time
const formattedTime = `${gsmDate} ${gsmTime}`; // e.g., "23-04-2025 15:38:07"
// Update the database with this formatted value
await Insensors.updateOne(
{ hardwareId: master.hardwareId },
{ $set: { gsm_last_disconnect_time: formattedTime } }
);
gsmLastDisconnect = formattedTime; // Save the updated value to gsmLastDisconnect
}
}
const enriched = {
hardwareId: master.hardwareId,
masterName: master.masterName || null,
location: master.location || null,
type: master.type || 'master',
connected_status: master.connected_status || 'disconnected',
connected_slave_count: connectedSlaves.length,
connected_slaves: connectedSlaves,
gsm_last_check_time: master.gsm_last_check_time || null,
gsm_last_disconnect_time: gsmLastDisconnect || null
};
if (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 (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' });
}
};
// 🔍 Helper to get tankHeight from latest IotData record
async function getTankHeight(hardwareId) {
const iotData = await IotData.findOne({ 'tanks.tankhardwareId': hardwareId })
.sort({ date: -1 })
.lean();
if (!iotData) return null;
const matchedTank = iotData.tanks.find(t => t.tankhardwareId === hardwareId);
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" });
}
const sensors = await Insensors.find({ customerId });
if (!sensors.length) {
return reply.code(404).send({ message: "No sensors found for this customer." });
}
const masterHardwareIds = [
...new Set(sensors.map(s => s.connected_to?.trim()).filter(Boolean))
];
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: []
};
}
// ✅ Use timestamp to check GSM connection
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 all connected slaves
const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId);
// Enrich tanks
let tanks = connectedSlaves.map(slave => {
const slaveId = slave.hardwareId?.trim();
const matchedTank = latestRecord.tanks.find(tank => tank.tankhardwareId === slaveId);
let loraConnected = false;
let loraMessage = "LORA is not connected"; // Default message for LoRa not connected
// If matchedTank exists and tankHeight is not zero, check LoRa connection
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 ?? null,
location: slave.location ?? null,
loraMessage, // Updated LoRa message
latestTankData: matchedTank ?? null
};
});
// ✅ Remove the first tank
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.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" });
}
// 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 IoT data for that master hardwareId
const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean();
if (!latestRecord) {
return reply.code(404).send({
hardwareId,
message: "No IoT data found",
tanks: []
});
}
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 all slaves connected to this master
const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId);
// Enrich slave tanks with tank data and LoRa status
const tanks = connectedSlaves.map(slave => {
const slaveId = slave.hardwareId?.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 ?? null,
location: slave.location ?? null,
message: loraMessage,
latestTankData: matchedTank ?? null
};
});
return reply.send({
status_code: 200,
message: "Success",
data: {
hardwareId,
message,
masterName: connectedSlaves[0]?.masterName ?? null,
location: connectedSlaves[0]?.location ?? null,
tanks
}
});
} catch (err) {
console.error("Error fetching IoT data by customerId and hardwareId:", err);
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()));
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." });
}
// Debugging log to check the fetched date and current time
console.log("Latest Master Record Date:", latestMasterRecord.date);
const indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata");
const now = moment.tz("Asia/Kolkata");
// Log the current time and difference
console.log("Current Time:", now.format("DD-MM-YYYY HH:mm:ss"));
const diffInMinutesMaster = now.diff(indiaTime, "minutes");
// Log the time difference
console.log("Time difference in minutes (Master):", diffInMinutesMaster);
// Update masterDisconnected to store details
const masterDisconnected = diffInMinutesMaster > 1 ? [{
hardwareId: connected_to,
masterName: masterSensor.tankName,
disconnectedAt: moment().tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss"),
}] : [];
// Log the disconnected status
console.log("Master Disconnected:", masterDisconnected);
const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === connected_to.trim());
const disconnectedSlaves = [];
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) {
disconnectedSlaves.push({
slaveHardwareId: slaveId,
slaveName: slave.tankName
});
}
}
}
const issuesToAdd = [];
if (masterDisconnected.length > 0) {
issuesToAdd.push({
type: "GSM Disconnected",
hardwareId: connected_to,
message: `Master GSM disconnected - ${connected_to}`,
disconnectedAt: moment().tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss")
});
}
if (disconnectedSlaves.length > 0) {
issuesToAdd.push({
type: "LoRa Disconnected",
hardwareIds: disconnectedSlaves.map(d => d.slaveHardwareId),
slaveNames: disconnectedSlaves.map(d => d.slaveName),
message: `Slaves LoRa disconnected`,
disconnectedAt: moment().tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss")
});
}
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
});
} catch (error) {
console.error("Error raising ticket:", error);
return reply.code(500).send({ error: "Internal server error" });
}
};
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());
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 `lastTicketRaisedAt` values
const updatedMasterSensor = await Insensors.findOne({ hardwareId: connected_to }).lean();
const updatedSupport = await Support.findOne({ supportId: "AWHYSU64" }).lean();
console.log("updatedMasterSensor",updatedMasterSensor)
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, tankHardwareId } = req.params; // Now tankHardwareId from 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()));
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 diffInMinutesMaster = now.diff(indiaTime, "minutes");
const masterDisconnected = diffInMinutesMaster > 1 ? [{
hardwareId: connected_to,
masterName: masterSensor.tankName,
disconnectedAt: now.format("DD-MM-YYYY HH:mm:ss"),
}] : [];
let connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === connected_to.trim());
// If tankHardwareId is provided, filter for that specific slave
if (tankHardwareId) {
connectedSlaves = connectedSlaves.filter(s => s.hardwareId?.trim() === tankHardwareId.trim());
}
const disconnectedSlaves = [];
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) {
disconnectedSlaves.push({
slaveHardwareId: slaveId,
slaveName: slave.tankName
});
}
}
}
const issuesToAdd = [];
if (masterDisconnected.length > 0) {
issuesToAdd.push({
type: "GSM Disconnected",
hardwareId: connected_to,
message: `Master GSM disconnected - ${connected_to}`,
disconnectedAt: now.format("DD-MM-YYYY HH:mm:ss")
});
}
if (disconnectedSlaves.length > 0) {
issuesToAdd.push({
type: "LoRa Disconnected",
hardwareIds: disconnectedSlaves.map(d => d.slaveHardwareId),
slaveNames: disconnectedSlaves.map(d => d.slaveName),
message: "Slaves LoRa disconnected",
disconnectedAt: now.format("DD-MM-YYYY HH:mm:ss")
});
}
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
});
} catch (error) {
console.error("Error raising ticket:", 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 master and slave hardware IDs
for (const issue of allIssues) {
if (issue.hardwareId) hardwareSet.add(issue.hardwareId);
if (Array.isArray(issue.hardwareIds)) {
issue.hardwareIds.forEach(id => hardwareSet.add(id));
}
}
const hardwareIds = [...hardwareSet];
const sensors = await Insensors.find({ hardwareId: { $in: hardwareIds } }).lean();
// Map sensors by hardwareId
const sensorMap = {};
for (const sensor of sensors) {
sensorMap[sensor.hardwareId] = sensor;
}
const masterMap = {};
// Structure data
for (const sensor of sensors) {
if (sensor.type === "master") {
masterMap[sensor.hardwareId] = {
hardwareId: sensor.hardwareId,
masterName: sensor.masterName || sensor.tankName || "",
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,
connected_slave_count: 0,
connected_slaves: []
};
}
}
// Add slaves under corresponding masters
for (const sensor of sensors) {
if (sensor.type === "slave" && sensor.connected_to) {
const master = masterMap[sensor.connected_to];
if (master) {
master.connected_slaves.push({
hardwareId: sensor.hardwareId,
tankName: sensor.tankName || "",
location: sensor.location || "",
connected_status: sensor.connected_status,
connected_lora_time: sensor.connected_lora_time,
connected_lora_date: sensor.connected_lora_date,
lora_last_check_time: sensor.lora_last_check_time,
lora_last_disconnect_time: sensor.lora_last_disconnect_time,
connected_to: sensor.connected_to,
masterName: master.masterName,
type: "slave",
typeOfWater: sensor.typeOfWater,
tankHeight: sensor.tankHeight
});
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.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",
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" });
}
};