diff --git a/src/controllers/installationController.js b/src/controllers/installationController.js index a13481b9..355bb976 100644 --- a/src/controllers/installationController.js +++ b/src/controllers/installationController.js @@ -3870,7 +3870,10 @@ const raiseATicketLikeLogic = async (customerId, connected_to) => { const normalizedConnectedTo = connected_to.trim().toLowerCase(); const masterSensor = sensors.find( - s => s.hardwareId?.trim().toLowerCase() === normalizedConnectedTo && s.type === "master" + s => + s.hardwareId?.trim().toLowerCase() === normalizedConnectedTo && + s.type === "master" && + s.support_issue_status !== "inactive" ); if (!masterSensor) return; @@ -3885,16 +3888,17 @@ const raiseATicketLikeLogic = async (customerId, connected_to) => { }); const now = moment.tz("Asia/Kolkata"); - const masterConnectedStatus = masterSensor.connected_status || "disconnected"; const lastDataTime = masterSensor.connected_gsm_date && masterSensor.connected_gsm_time ? `${masterSensor.connected_gsm_date} ${masterSensor.connected_gsm_time}` : "No data"; - // Get all slaves connected to this master const connectedSlaves = sensors.filter( - s => s.connected_to?.trim().toLowerCase() === normalizedConnectedTo && s.type === "slave" + s => + s.connected_to?.trim().toLowerCase() === normalizedConnectedTo && + s.type === "slave" && + s.support_issue_status !== "inactive" ); const disconnectedSlaves = connectedSlaves @@ -3917,10 +3921,8 @@ const raiseATicketLikeLogic = async (customerId, connected_to) => { issue.type === "GSM or LoRa Disconnected" && issue.resolved === false ); - if (unresolvedMasterIssue) return; - // Check both unresolved and resolved issues for previously reported slaves const allSlaveHardwareIdsAlreadyReported = new Set(); existingIssues .filter(issue => issue.hardwareId?.trim().toLowerCase() === normalizedConnectedTo) @@ -3942,7 +3944,6 @@ const raiseATicketLikeLogic = async (customerId, connected_to) => { } } - // Still raise the issue if master is disconnected, even if no new slaves if (newSlaveHardwareIds.length === 0 && masterConnectedStatus === "connected") return; const formattedNow = now.format("YYYY-MM-DD HH:mm:ss"); @@ -3967,11 +3968,21 @@ const raiseATicketLikeLogic = async (customerId, connected_to) => { } ); + // ✅ Mark all involved sensors as "active" + await Insensors.updateMany( + { + $or: [ + { hardwareId: normalizedConnectedTo }, + { tankhardwareId: { $in: newSlaveHardwareIds } } + ] + }, + { $set: { support_issue_status: "active" } } + ); } catch (error) { console.error("Error in raiseATicketLikeLogic:", error); } }; -; + @@ -3987,6 +3998,7 @@ const raiseATicketLikeLogic = async (customerId, connected_to) => { cron.schedule("* * * * *", async () => { try { console.log("🔁 Running auto-disconnect ticket check..."); + const allMasters = await Insensors.find({ type: "master" }).lean(); for (const master of allMasters) { @@ -4004,8 +4016,23 @@ cron.schedule("* * * * *", async () => { const masterIsDisconnected = master.connected_status === "disconnected"; - if (masterIsDisconnected || disconnectedSlaves.length > 0) { + // ✅ Check if master already has unresolved ticket + const masterAlreadyActive = master.support_issue_status === "active"; + + // ✅ Check if any disconnected slave already has unresolved ticket + const anySlaveAlreadyActive = disconnectedSlaves.some( + slave => slave.support_issue_status === "active" + ); + + // ✅ Only raise a ticket if not already active + const shouldRaiseTicket = + (masterIsDisconnected && !masterAlreadyActive) || + (disconnectedSlaves.length > 0 && !anySlaveAlreadyActive); + + if (shouldRaiseTicket) { await raiseATicketLikeLogic(customerId, hardwareId); + } else { + console.log(`Skipping ticket for ${hardwareId} — already active.`); } } } catch (err) { @@ -4013,6 +4040,7 @@ cron.schedule("* * * * *", async () => { } }); + exports.raiseATicketBuildingDetails = async (req, reply) => { try { const { customerId, connected_to, installationId } = req.params; @@ -5116,6 +5144,7 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { const allIssues = supportRecord.issues || []; const hardwareSet = new Set(); + // Collect all hardwareIds and masterHardwareIds from issues for (const issue of allIssues) { if (issue.hardwareId) hardwareSet.add(issue.hardwareId); if (issue.masterHardwareId) hardwareSet.add(issue.masterHardwareId); @@ -5123,6 +5152,7 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { const hardwareIds = [...hardwareSet]; + // Fetch all relevant sensors (masters and slaves) for customer const sensors = await Insensors.find({ customerId, $or: [ @@ -5131,14 +5161,17 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { ] }).lean(); + // Map sensors by their hardwareId and tankhardwareId for quick lookup const sensorMap = {}; for (const sensor of sensors) { if (sensor.hardwareId) sensorMap[sensor.hardwareId] = sensor; if (sensor.tankhardwareId) sensorMap[sensor.tankhardwareId] = sensor; } + // Fetch all orders for the customer const orders = await Order.find({ customerId }).lean(); + // Map master order connections by hardwareId for master info const orderMap = {}; for (const order of orders) { (order.master_connections || []).forEach(conn => { @@ -5151,6 +5184,7 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { }); } + // Map slave order connections by hardwareId for slave info const slaveOrderMap = {}; for (const order of orders) { (order.tank_connections || []).forEach(conn => { @@ -5170,6 +5204,14 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { const masterSensor = sensorMap[masterId]; if (!masterSensor || masterSensor.type !== "master") continue; + // Only process masters with active support_issue_status + const masterIssueStatus = masterSensor.support_issue_status || "inactive"; + if (masterIssueStatus !== "active") { + // Skip this master and its slaves if issue inactive + continue; + } + + // Get latest IotData for master to check GSM connection const latestMasterData = await IotData.findOne({ hardwareId: masterSensor.hardwareId }).sort({ date: -1 }).lean(); const now = moment.tz("Asia/Kolkata"); let gsmConnected = false; @@ -5198,11 +5240,14 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { 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: [] + connected_slaves: [], + support_issue_status: masterIssueStatus }; } const master = masterMap[masterSensor.hardwareId]; + + // Find slaves connected to this master with active issues only const connectedSlaves = await Insensors.find({ connected_to: masterSensor.hardwareId, type: "slave", @@ -5212,6 +5257,10 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { const slaveSet = new Set(master.connected_slaves.map(s => s.hardwareId)); for (const slave of connectedSlaves) { + // Only add slave if its issue status is active + const slaveIssueStatus = slave.support_issue_status || "inactive"; + if (slaveIssueStatus !== "active") continue; + const slaveHardwareId = slave.tankhardwareId || slave.hardwareId; if (slaveSet.has(slaveHardwareId)) continue; slaveSet.add(slaveHardwareId); @@ -5247,7 +5296,8 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { 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 + team_member_support_lora_last_check_time: slave.team_member_support_lora_last_check_time, + support_issue_status: slaveIssueStatus }; master.connected_slaves.push(slaveEnriched); @@ -5267,6 +5317,7 @@ exports.getDisconnectedIssuesBySupportId = async (req, reply) => { 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" }); @@ -6126,11 +6177,8 @@ exports.moveIssueToCategory = async (req, reply) => { 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; }); @@ -6141,18 +6189,28 @@ exports.moveIssueToCategory = async (req, reply) => { const issue = support.issues[index]; - // If the hardwareId matches master hardwareId, move entire issue as is if (issue.hardwareId === hardwareId) { + // Master issue moved + issue.resolved = true; + support.categorizedIssues.push({ ...issue, masterHardwareId: issue.masterHardwareId || issue.hardwareId, category, movedAt: nowTime, }); + support.issues.splice(index, 1); + + // ✅ Mark master as inactive + await Insensors.updateOne( + { hardwareId }, + { $set: { support_issue_status: "inactive" } } + ); + issueMoved = true; } else { - // hardwareId matches inside hardwareIds array — move that slave issue individually + // Slave hardware match const slaveIndex = issue.hardwareIds.indexOf(hardwareId); if (slaveIndex !== -1) { const slaveName = issue.slaveNames?.[slaveIndex] || "Unknown"; @@ -6166,12 +6224,18 @@ exports.moveIssueToCategory = async (req, reply) => { 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 + // ✅ Mark slave as inactive + await Insensors.updateOne( + { tankhardwareId: hardwareId }, + { $set: { support_issue_status: "inactive" } } + ); + + // If no more slaves, remove the whole issue if (issue.hardwareIds.length === 0) { + issue.resolved = true; support.issues.splice(index, 1); } @@ -6192,6 +6256,7 @@ exports.moveIssueToCategory = async (req, reply) => { }; + // exports.particularCategory = async (req, reply) => { // const { supportId, category } = req.params; diff --git a/src/models/store.js b/src/models/store.js index 3edf3178..ec2797ed 100644 --- a/src/models/store.js +++ b/src/models/store.js @@ -495,6 +495,11 @@ const insensorsSchema = new mongoose.Schema({ masterName: { type: String, default: null }, location: { type: String, default: null }, tankhardwareId: { type: String, default: null }, + support_issue_status: { + type: String, + enum: ['active', 'inactive'], + default: 'inactive' + }, motor_switches: [ { from_tank: { type: String, default: null },