diff --git a/src/controllers/installationController.js b/src/controllers/installationController.js index b93762a8..072def60 100644 --- a/src/controllers/installationController.js +++ b/src/controllers/installationController.js @@ -9710,6 +9710,195 @@ if (!orders.length) { } }; +exports.sendToStoreHardwareList = async (req, reply) => { + try { + const { supportId, customerId } = req.params; + const { storeId } = req.body; + + if (!supportId || !customerId) { + return reply.code(400).send({ error: "supportId and customerId are required in path params" }); + } + + const support = await Support.findOne({ supportId }).lean(); + if (!support) return reply.code(404).send({ message: "Support record not found" }); + + const issues = [...(support.categorizedIssues || []), ...(support.resolvedIssues || [])]; + if (!issues.length) return reply.code(404).send({ message: "No issues found for this support ID" }); + + 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" }); + + const allRelatedSensors = await Insensors.find({ + customerId, + hardwareId: { $in: hardwareIds } + }).lean(); + + if (!allRelatedSensors.length) return reply.code(404).send({ message: "No sensors found" }); + + // 🔍 Filter orders by optional storeId + let orders = []; + if (storeId) { + orders = await Order.find({ customerId, storeId }).lean(); + } else { + orders = await Order.find({ customerId }).lean(); + } + + if (!orders.length) { + const fallbackOrder = await Order.findOne({ "master_connections.hardwareId": { $in: hardwareIds } }).lean(); + if (fallbackOrder) orders = [fallbackOrder]; + } + + const orderMap = {}; + orders.forEach(order => { + (order.master_connections || []).forEach(conn => { + const trimmedId = (conn.hardwareId || "").trim(); + if (trimmedId) { + orderMap[trimmedId] = { + masterName: conn.master_name?.trim() || "", + location: conn.location?.trim() || "" + }; + } + }); + }); + + 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"); + gsmConnected = now.diff(gsmTime, "minutes") <= 1; + } + + 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"); + loraConnected = now.diff(tankTime, "minutes") <= 1; + } + + 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 && comment.customerId === customerId + ).map(c => ({ + text: c.text, + commentsTime: c.createdAt ? moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm") : null + })); + + return { + hardwareId: slave.tankhardwareId, + tankName: slave.tankName || "", + location: slave.tankLocation || "", + connected_status: loraConnected ? "connected" : "disconnected", + connected_to: slave.connected_to || "", + gsm_last_check_time: slave.gsm_last_check_time || null, + gsm_last_disconnect_time: slave.gsm_last_disconnect_time || null, + lora_last_disconnect_time: slave.lora_last_disconnect_time || null, + connected_gsm_date: slave.connected_gsm_date || "", + connected_gsm_time: slave.connected_gsm_time || "", + connected_lora_date: slave.connected_lora_date || "", + connected_lora_time: slave.connected_lora_time || "", + support_lora_last_check_time: slave.support_lora_last_check_time || null, + masterName: orderMap[master.hardwareId?.trim()]?.masterName || "", + type: "slave", + typeOfWater: tankInfo?.typeOfWater || "", + outDoor_status: slave.outDoor_status || "inprogress" + }; + })); + + const masterComments = (support.comments || []).filter( + comment => comment.hardwareId === master.hardwareId && comment.customerId === customerId + ).map(c => ({ + text: c.text, + commentsTime: c.createdAt ? moment(c.createdAt).tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm") : null + })); + + const trimmedMasterId = (master.hardwareId || "").trim(); + const orderDetails = orderMap[trimmedMasterId] || {}; + const issue = issueMap[master.hardwareId]; + + disconnectedIssues.push({ + hardwareId: master.hardwareId, + masterName: orderDetails.masterName || "", + location: orderDetails.location || "", + type: "master", + connected_status: gsmConnected ? "connected" : "disconnected", + connected_slave_count: slaveDetails.length, + gsm_last_check_time: master.gsm_last_check_time || null, + gsm_last_disconnect_time: master.gsm_last_disconnect_time || null, + lora_last_disconnect_time: master.lora_last_disconnect_time || null, + connected_gsm_date: master.connected_gsm_date || "", + connected_gsm_time: master.connected_gsm_time || "", + connected_lora_date: master.connected_lora_date || "", + connected_lora_time: master.connected_lora_time || "", + support_gm_last_check_time: master.support_gsm_last_check_time || null, + connected_slaves: slaveDetails, + comments: masterComments, + outDoor_status: master.outDoor_status || "inprogress", + movedAt: issue?.movedAt || null, + resolvedAt: issue?.resolvedAt || null, + category: issue?.category || "Uncategorized", + hardwareList: master.hardwareList || {}, + assignedTo: issue?.assignedTo || null + }); + } + + // ✅ Step: Update storeId in Orders where matching master_connections.hardwareId + const updatedHardwareIds = disconnectedIssues.map(item => item.hardwareId); + await Order.updateMany( + { + customerId, + "master_connections.hardwareId": { $in: updatedHardwareIds } + }, + { + $set: { storeId } + } + ); + + return reply.send({ + status_code: 200, + supportId, + customerId, + storeId, + totalMasters: disconnectedIssues.length, + disconnectedIssues + }); + + } catch (err) { + console.error("❌ Error in sendToStoreHardwareList:", err); + return reply.code(500).send({ error: "Internal server error" }); + } +}; + exports.updateHardwareList = async (req, reply) => { try { diff --git a/src/routes/installationRoute.js b/src/routes/installationRoute.js index 258c0942..8390282f 100644 --- a/src/routes/installationRoute.js +++ b/src/routes/installationRoute.js @@ -858,6 +858,30 @@ module.exports = function (fastify, opts, next) { handler: installationController.particularCategory }); + fastify.post('/api/support/sendToStoreHardwareList/:supportId/:customerId', { + schema: { + description: 'Send to store the hardware list', + tags: ['Support'], + summary: 'Send to store the hardware list', + params: { + type: 'object', + required: ['supportId', 'customerId'], + properties: { + supportId: { type: 'string' }, + customerId: { type: 'string' }, + } + }, + body: { + type: "object", + required: ["storeId"], + properties: { + storeId: { type: "string" }, + }, + }, + }, + handler: installationController.sendToStoreHardwareList + }); + fastify.post("/api/assignTeamMemberIssueToCategory/:supportId", { schema: {