diff --git a/src/controllers/installationController.js b/src/controllers/installationController.js index 8d6d30c2..efd60268 100644 --- a/src/controllers/installationController.js +++ b/src/controllers/installationController.js @@ -2450,6 +2450,145 @@ exports.getIotDataByCustomerAndHardwareId = async (req, reply) => { //const moment = require("moment-timezone"); +// exports.raiseATicket = async (req, reply) => { +// try { +// const { customerId, connected_to } = req.params; + +// if (!customerId || !connected_to) { +// return reply.code(400).send({ error: "customerId and connected_to are required" }); +// } + +// const sensors = await Insensors.find({ customerId }); + +// if (!sensors.length) { +// return reply.code(404).send({ message: "No sensors found for this customer." }); +// } + +// const masterSensor = sensors.find(s => s.hardwareId?.trim() === connected_to.trim() && s.type === "master"); + +// if (!masterSensor) { +// return reply.code(404).send({ message: "Master hardwareId not found." }); +// } + +// const latestMasterRecord = await IotData.findOne({ hardwareId: connected_to }).sort({ date: -1 }).lean(); + +// if (!latestMasterRecord) { +// return reply.code(404).send({ message: "No IoT data found for this hardwareId." }); +// } + +// const 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 || masterSensor.tankName || "Unknown Master", +// // disconnectedAt: now.format("DD-MM-YYYY HH:mm:ss") +// }] : []; + +// const connectedSlaves = sensors.filter(sensor => +// sensor.connected_to?.trim() === connected_to.trim() && +// sensor.type === "slave" +// ); + +// 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({ +// hardwareId: connected_to, +// slaveHardwareId: slaveId, +// slaveName: slave.tankName || "Unknown Slave" +// }); +// } +// } +// } + +// const issuesToAdd = []; + +// if (masterDisconnected.length > 0) { +// const existingGsmIssue = await Support.findOne({ +// "issues.hardwareId": connected_to, +// "issues.type": "GSM Disconnected" +// }); + +// if (!existingGsmIssue) { +// issuesToAdd.push({ +// type: "GSM Disconnected", +// hardwareId: connected_to, +// message: `Master GSM disconnected - ${connected_to}`, +// //disconnectedAt: now.format("DD-MM-YYYY HH:mm:ss") +// }); +// } +// } + +// // Check for already existing slave issues +// const newHardwareIds = []; +// const newSlaveNames = []; + +// for (const slave of disconnectedSlaves) { +// const existingSlaveIssue = await Support.findOne({ +// "issues.hardwareIds": slave.slaveHardwareId, +// "issues.masterHardwareId": connected_to, +// "issues.type": "LoRa Disconnected" +// }); + +// if (!existingSlaveIssue) { +// newHardwareIds.push(slave.slaveHardwareId); +// newSlaveNames.push(slave.slaveName); +// } +// } + +// if (newHardwareIds.length > 0) { +// issuesToAdd.push({ +// type: "LoRa Disconnected", +// masterHardwareId: connected_to, +// hardwareIds: newHardwareIds, +// slaveNames: newSlaveNames, +// message: `Slaves LoRa disconnected under master ${connected_to}`, +// // 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.raiseATicket = async (req, reply) => { try { const { customerId, connected_to } = req.params; @@ -2476,39 +2615,54 @@ exports.raiseATicket = async (req, reply) => { 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 indiaTime = moment.tz(latestMasterRecord.date, "Asia/Kolkata"); const diffInMinutesMaster = now.diff(indiaTime, "minutes"); const masterDisconnected = diffInMinutesMaster > 1 ? [{ hardwareId: connected_to, - masterName: masterSensor.tankName || masterSensor.tankName || "Unknown Master", - // disconnectedAt: now.format("DD-MM-YYYY HH:mm:ss") + masterName: masterSensor.tankName || "Unknown Master", + connected_status: "disconnected", + last_seen_minutes_ago: diffInMinutesMaster }] : []; - const connectedSlaves = sensors.filter(sensor => + const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === connected_to.trim() && sensor.type === "slave" ); const disconnectedSlaves = []; + const slaveStatusList = []; for (const slave of connectedSlaves) { const slaveId = slave.hardwareId?.trim(); const matchedTank = latestMasterRecord.tanks.find(tank => tank.tankhardwareId === slaveId); + let isDisconnected = true; + let loraDiffInMinutes = null; + if (matchedTank && matchedTank.date) { const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata"); - const loraDiffInMinutes = now.diff(tankTime, "minutes"); + loraDiffInMinutes = now.diff(tankTime, "minutes"); - if (loraDiffInMinutes > 1) { - disconnectedSlaves.push({ - hardwareId: connected_to, - slaveHardwareId: slaveId, - slaveName: slave.tankName || "Unknown Slave" - }); + if (loraDiffInMinutes <= 1) { + isDisconnected = false; } } + + const slaveInfo = { + hardwareId: connected_to, + slaveHardwareId: slaveId, + slaveName: slave.tankName || "Unknown Slave", + connected_status: isDisconnected ? "disconnected" : "connected", + last_seen_minutes_ago: loraDiffInMinutes + }; + + slaveStatusList.push(slaveInfo); + + if (isDisconnected) { + disconnectedSlaves.push(slaveInfo); + } } const issuesToAdd = []; @@ -2523,13 +2677,11 @@ exports.raiseATicket = async (req, reply) => { issuesToAdd.push({ type: "GSM Disconnected", hardwareId: connected_to, - message: `Master GSM disconnected - ${connected_to}`, - //disconnectedAt: now.format("DD-MM-YYYY HH:mm:ss") + message: `Master GSM disconnected - ${connected_to}` }); } } - // Check for already existing slave issues const newHardwareIds = []; const newSlaveNames = []; @@ -2552,8 +2704,7 @@ exports.raiseATicket = async (req, reply) => { masterHardwareId: connected_to, hardwareIds: newHardwareIds, slaveNames: newSlaveNames, - message: `Slaves LoRa disconnected under master ${connected_to}`, - // disconnectedAt: now.format("DD-MM-YYYY HH:mm:ss") + message: `Slaves LoRa disconnected under master ${connected_to}` }); } @@ -2580,7 +2731,8 @@ exports.raiseATicket = async (req, reply) => { status_code: 200, message: "Checked connection and updated support if needed.", masterDisconnected, - disconnectedSlaves + disconnectedSlaves, + connectedSlaves: slaveStatusList }); } catch (error) { @@ -2591,7 +2743,6 @@ exports.raiseATicket = async (req, reply) => { - exports.raiseATicketBuildingDetails = async (req, reply) => { try { const { customerId, connected_to, installationId } = req.params; @@ -3055,3 +3206,79 @@ exports.getDisconnectedCustomerDetails = async (req, reply) => { + + +// const bcrypt = require("bcrypt"); + +exports.createTeamMemberSupport = async (req, reply) => { + try { + const { supportId } = req.params; + + const c_id = await generateTeamMemberId(); + const support_teamMemberId = `AWTMSU${c_id}`; + + const { + name, + phone, + installationTeamMemId, + password, + email, + alternativePhone, + status + } = req.body; + + if (!supportId || !support_teamMemberId || !name || !phone || !password) { + return reply.code(400).send({ error: "Missing required fields" }); + } + + const supportRecord = await Support.findOne({ supportId }); + + if (!supportRecord) { + return reply.code(404).send({ error: "Support record not found" }); + } + + const existingMember = supportRecord.team_member?.team_member.find( + member => member.phone === phone || member.support_teamMemberId === support_teamMemberId + ); + + if (existingMember) { + return reply.code(400).send({ error: "Team member with this phone or ID already exists" }); + } + + const hashedPassword = await bcrypt.hash(password, 10); + + const newTeamMember = { + support_teamMemberId, + name, + phone, + installationTeamMemId, + password: hashedPassword, + status: status || "active", + email: email || null, + alternativePhone: alternativePhone || null, + }; + + await Support.findOneAndUpdate( + { supportId }, + { + $push: { + "team_member.team_member": newTeamMember + }, + $set: { + updatedAt: new Date() + } + }, + { new: true } + ); + + return reply.send({ + status_code: 200, + message: "Team member added successfully", + teamMember: newTeamMember + }); + + } catch (error) { + console.error("Error adding team member:", error); + return reply.code(500).send({ error: "Internal server error" }); + } +}; diff --git a/src/index.js b/src/index.js index 049fe255..b2fd6a0f 100644 --- a/src/index.js +++ b/src/index.js @@ -1526,7 +1526,73 @@ fastify.post("/api/teamMemberLogin", { } }, }); - + fastify.post("/api/supportTeamMemberLogin", { + schema: { + description: "Login Support TeamMember", + tags: ["Support"], + summary: "Login for Support TeamMember", + body: { + type: "object", + required: ["phone", "password"], + properties: { + phone: { type: "string", description: "Registered phone number" }, + password: { type: "string", description: "Password for authentication" }, + }, + }, + }, + async handler(req, reply) { + try { + const { phone, password } = req.body; + + const support = await Support.findOne({ + "team_member.team_member.phone": phone + }); + + if (!support) { + return reply.code(404).send({ error: 'Team member not found' }); + } + + const teamMember = support.team_member.team_member.find( + member => member.phone === phone + ); + + if (!teamMember) { + return reply.code(404).send({ error: 'Team member not found' }); + } + + if (!teamMember.password) { + return reply.code(401).send({ error: 'Password not set' }); + } + + const isPasswordValid = await bcrypt.compare(password, teamMember.password); + if (!isPasswordValid) { + return reply.code(401).send({ error: 'Invalid credentials' }); + } + + const token = fastify.jwt.sign( + { + support_teamMemberId: teamMember.support_teamMemberId, + name: teamMember.name, + phone: teamMember.phone + }, + "JWT_SECRET", + { expiresIn: '7d' } + ); + + return reply.send({ + status_code: 200, + message: 'Login successful', + token, + teamMember + }); + + } catch (error) { + console.error("Error during team member login:", error); + return reply.code(500).send({ error: "Internal server error" }); + } + } + }); + fastify.post("/api/storelogin", { schema: { diff --git a/src/routes/installationRoute.js b/src/routes/installationRoute.js index 90615793..2bdcba8a 100644 --- a/src/routes/installationRoute.js +++ b/src/routes/installationRoute.js @@ -548,6 +548,37 @@ module.exports = function (fastify, opts, next) { }, handler: installationController.getDisconnectedCustomerDetails, }); + + fastify.route({ + method: 'POST', + url: '/support/:supportId/team-member', + schema: { + tags: ['Support'], + summary: 'Create a new team member under a support record', + params: { + type: 'object', + properties: { + supportId: { type: 'string', description: 'Support ID' }, + }, + required: ['supportId'], + }, + body: { + type: 'object', + properties: { + name: { type: 'string' }, + phone: { type: 'string' }, + password: { type: 'string' }, + email: { type: 'string' }, + alternativePhone: { type: 'string' }, + status: { type: 'string', enum: ['active', 'inactive'], default: 'active' } + }, + required: [ 'name', 'phone'] + }, + }, + handler: installationController.createTeamMemberSupport + }); + + next(); } \ No newline at end of file