From 6e5fcba6b828e4bb070deb62cf9665257eba2d75 Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Thu, 6 Mar 2025 15:56:34 +0530 Subject: [PATCH 1/4] forced manually notifications --- src/controllers/tanksController.js | 175 +++++++++++++++++++++-------- 1 file changed, 130 insertions(+), 45 deletions(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index 1f3bb7ba..b1835507 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -1713,71 +1713,75 @@ eventEmitter.on('sendThresholdTimeNotification', async (customerId, fcmTokens, t // ); // 🚀 Motor Start Notification -eventEmitter.on("sendMotorStartNotification", async (hw_Id, customerId, fcmTokens, waterLevel, blockName, tankName, motorOnType, stopCriteria, typeOfWater, manualThresholdTime) => { + +eventEmitter.on("sendMotorStartNotification", async (hw_Id, customerId, fcmTokens, waterLevel, blockName, tankName, motorOnType, manualThresholdTime) => { try { - const formattedTime = new Date().toLocaleTimeString("en-IN", { timeZone: "Asia/Kolkata" }); + console.log(`✅ Received sendMotorStartNotification event for ${customerId}`); + + const formattedTime = new Date().toLocaleTimeString("en-IN", { timeZone: "Asia/Kolkata" }); - const normalizedMotorOnType = motorOnType.toLowerCase(); - if (normalizedMotorOnType !== "forced_manual") { - console.log(`⚠️ Skipping notification: Motor started in **${motorOnType}** mode.`); - return; - } + const normalizedMotorOnType = motorOnType.toLowerCase(); + if (normalizedMotorOnType !== "forced_manual") { + console.log(`⚠️ Skipping notification: Motor started in **${motorOnType}** mode.`); + return; + } - if (!Array.isArray(fcmTokens) || fcmTokens.length === 0) { - console.warn(`⚠️ No valid FCM tokens found for Customer ID: ${customerId}`); - return; - } + if (!Array.isArray(fcmTokens) || fcmTokens.length === 0) { + console.warn(`⚠️ No valid FCM tokens found for Customer ID: ${customerId}`); + return; + } - const stopConditionMessage = stopCriteria === "level" - ? `🚨 Pump will stop when the water level reaches **${manualThresholdTime}%**.` - : `⚠️ Pump will stop **manually**.`; + // const stopConditionMessage = stopCriteria === "level" + // ? `🚨 Pump will stop when the water level reaches **${manualThresholdTime}%**.` + // : `⚠️ Pump will stop **manually**.`; - const message = `🚰 Motor Started 🚀\n` + - `👤 Customer ID: ${customerId}\n` + - `🔹 Motor Name: ${tankName} - ${blockName}\n` + - `💧 Water Level: ${waterLevel}\n` + - `📱 Mode: Manually Started\n` + - `🕒 Pump started at: ${formattedTime}\n` - + const message = `🚰 Motor Started Manually 🚀\n` + + `👤 Customer ID: ${customerId}\n` + + `🔹 Motor Name: ${tankName} - ${blockName}\n` + + `💧 Water Level: ${waterLevel}\n` + + `📱 Mode: Manually Started\n` + + `🕒 Pump started at: ${formattedTime}\n`; - await sendNotification(hw_Id, customerId, fcmTokens, "Motor Started 🚀", message); - console.log(`✅ Motor start notification sent for Customer ID: ${customerId}`); + await sendNotification(hw_Id, customerId, fcmTokens, "Motor Started 🚀", message); + console.log(`✅ Motor start notification sent for Customer ID: ${customerId}`); } catch (error) { - console.error(`❌ Error in sendMotorStartNotification for Customer ID: ${customerId}`, error); + console.error(`❌ Error in sendMotorStartNotification for Customer ID: ${customerId}`, error); } }); -// 🛑 Motor Stop Notification -eventEmitter.on("sendMotorStopNotification", async (hw_Id, customerId, fcmTokens, waterLevel, blockName, tankName, motorOnType, typeOfWater) => { +eventEmitter.on("sendMotorStopNotification", async (hw_Id, customerId, fcmTokens, waterLevel, blockName, tankName, motorOnType) => { try { - const formattedTime = new Date().toLocaleTimeString("en-IN", { timeZone: "Asia/Kolkata" }); + console.log(`✅ Received sendMotorStopNotification event for ${customerId}`); - const normalizedMotorOnType = motorOnType.toLowerCase(); - if (normalizedMotorOnType !== "forced_manual") { - console.log(`⚠️ Skipping notification: Motor stopped in **${motorOnType}** mode.`); - return; - } + const formattedTime = new Date().toLocaleTimeString("en-IN", { timeZone: "Asia/Kolkata" }); - if (!Array.isArray(fcmTokens) || fcmTokens.length === 0) { - console.warn(`⚠️ No valid FCM tokens found for Customer ID: ${customerId}`); - return; - } + const normalizedMotorOnType = motorOnType.toLowerCase(); + if (normalizedMotorOnType !== "forced_manual") { + console.log(`⚠️ Skipping notification: Motor stopped in **${motorOnType}** mode.`); + return; + } - const message = `🛑 Motor Stopped ❌\n` + - `👤 Customer ID: ${customerId}\n` + - `🔹 Motor Name: ${tankName} - ${blockName}\n` + - `💧 Water Level: ${waterLevel}\n` + - `📱 Mode: Manually Stopped\n` + - `🕒 Pump stopped at: ${formattedTime}`; + if (!Array.isArray(fcmTokens) || fcmTokens.length === 0) { + console.warn(`⚠️ No valid FCM tokens found for Customer ID: ${customerId}`); + return; + } + + const message = `🛑 Motor Stopped Manually ❌\n` + + `👤 Customer ID: ${customerId}\n` + + `🔹 Motor Name: ${tankName} - ${blockName}\n` + + `💧 Water Level: ${waterLevel}\n` + + `📱 Mode: Manually Stopped\n` + + `🕒 Pump stopped at: ${formattedTime}`; - await sendNotification(hw_Id, customerId, fcmTokens, "Motor Stopped ❌", message); - console.log(`✅ Motor stop notification sent for Customer ID: ${customerId}`); + await sendNotification(hw_Id, customerId, fcmTokens, "Motor Stopped ❌", message); + console.log(`✅ Motor stop notification sent for Customer ID: ${customerId}`); } catch (error) { - console.error(`❌ Error in sendMotorStopNotification for Customer ID: ${customerId}`, error); + console.error(`❌ Error in sendMotorStopNotification for Customer ID: ${customerId}`, error); } }); + // eventEmitter.on('sendLowWaterNotification', (fcmTokens, message) => { // const notificationMessage = `Warning: Water level is low in the tank. // Tank Name: ${tankName}, @@ -5987,6 +5991,87 @@ client.on('message', async (topic, message) => { +const sendMotorNotifications = async () => { + // console.log("🔄 Checking for motor notifications..."); + + // Find motors that need a start or stop notification + const motors = await Tank.find({ + "connections.inputConnections.motor_id": { $exists: true }, + }); + + for (const motorTank of motors) { + const inputConnection = motorTank.connections.inputConnections.find( + (conn) => conn.motor_id + ); + + if (!inputConnection) continue; + + const { customerId, blockName, tankName } = motorTank; + const fcmTokens = await getFcmTokens(customerId); // Get FCM tokens for this customer + if (!fcmTokens.length) continue; + + // 🔹 Motor Start Condition + if ( + inputConnection.motor_stop_status === "2" && + !motorTank.motor_start_notified + ) { + console.log("✅ Sending Motor Start Notification..."); + + eventEmitter.emit( + "sendMotorStartNotification", + inputConnection.motor_id, + customerId, + fcmTokens, + inputConnection.water_level || 0, + blockName, + tankName, + "forced_manual", + inputConnection.manual_threshold_time + ); + + // Mark notification as sent + motorTank.motor_start_notified = true; + motorTank.motor_stop_notified = false; // Reset stop notification flag + await motorTank.save(); + } + + // 🔹 Motor Stop Condition + if ( + inputConnection.motor_stop_status === "1" && + !motorTank.motor_stop_notified + ) { + console.log("✅ Sending Motor Stop Notification..."); + + eventEmitter.emit( + "sendMotorStopNotification", + inputConnection.motor_id, + customerId, + fcmTokens, + inputConnection.water_level || 0, + blockName, + tankName, + "forced_manual" + ); + + // Mark notification as sent + motorTank.motor_stop_notified = true; + motorTank.motor_start_notified = false; // Reset start notification flag + await motorTank.save(); + } + } + }; + + const getFcmTokens = async (customerId) => { + const user = await User.findOne({ customerId }).select("fcmIds"); + return user?.fcmIds?.filter((token) => token) || []; + }; + + // Run the notification check every second + cron.schedule("* * * * * *", async () => { + await sendMotorNotifications(); + }); + + // // API function to get survey data for a particular installer From 6f93671e64843dfa47f333eb7eb2f736c15e24d5 Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Thu, 6 Mar 2025 15:57:01 +0530 Subject: [PATCH 2/4] forced manual notifications --- src/models/tanks.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/models/tanks.js b/src/models/tanks.js index ebaebd42..a5fede93 100644 --- a/src/models/tanks.js +++ b/src/models/tanks.js @@ -109,7 +109,10 @@ const tanksSchema = new mongoose.Schema({ ], inputWaterlevelPercentage: { type: String, default: null }, outputWaterlevelPercentage: { type: String, default: null } - } + }, + motor_start_notified: { type: Boolean, default: false }, + motor_stop_notified: { type: Boolean, default: false } + }); const customerautopercentages = ({ From 55310b1407fc02f4e0ba1edbc4d0f5dbfbd99c6b Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Thu, 6 Mar 2025 16:04:27 +0530 Subject: [PATCH 3/4] installer assigned quation teamMember --- src/controllers/installationController.js | 195 +++++++++++++++------- src/routes/installationRoute.js | 6 +- 2 files changed, 143 insertions(+), 58 deletions(-) diff --git a/src/controllers/installationController.js b/src/controllers/installationController.js index 76d5f1b6..1658bf1f 100644 --- a/src/controllers/installationController.js +++ b/src/controllers/installationController.js @@ -3,7 +3,7 @@ const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const customJwtAuth = require("../customAuthJwt"); const { Deparments } = require("../models/Department"); -const { Install } = require("../models/store"); +const { Install, SensorStock, SensorQuotation, Order } = require("../models/store"); const { Counter } = require("../models/User") const fastify = require("fastify")({ logger: true, @@ -135,73 +135,154 @@ exports.createTeamMember = async (request, reply) => { } }; - exports.assignTeamMemberToQuotation = async (request, reply) => { - try { - const { installationId } = request.params; // Get installationId from URL params - const { teamMemberId } = request.body; // Get teamMemberId from request body +// 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", - }, - }); - } +// if (!teamMemberId) { +// return reply.status(400).send({ +// simplydata: { +// error: true, +// message: "teamMemberId is required", +// }, +// }); +// } - // Find installation by installationId - const installation = await Install.findOne({ installationId }); +// // Find installation by installationId +// const installation = await Install.findOne({ installationId }); - if (!installation) { - return reply.status(404).send({ - simplydata: { - error: true, - message: "Installation not found", - }, - }); - } +// 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; +// // 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); +// // 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", - }, - }); - } +// 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 - }; +// // 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 - }, - }); +// 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", - }, - }); - } -}; +// } 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: [], + }); + } + + // Assign the team member to the quotation + if (!quotation.assignedTeamMembers) { + quotation.assignedTeamMembers = []; + } + + if (!quotation.assignedTeamMembers.includes(teamMemberId)) { + quotation.assignedTeamMembers.push(teamMemberId); + } + + // Save the updated quotation + await quotation.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 diff --git a/src/routes/installationRoute.js b/src/routes/installationRoute.js index 57e2a102..0e4f0fa0 100644 --- a/src/routes/installationRoute.js +++ b/src/routes/installationRoute.js @@ -67,9 +67,13 @@ module.exports = function (fastify, opts, next) { teamMemberId: { type: "string", description: "The team member ID to assign" + }, + quotationId: { + type: "string", + description: "The team member ID to assign" } }, - required: ["teamMemberId"] + // required: ["teamMemberId"] }, }, handler: installationController.assignTeamMemberToQuotation From 3d33e2e4652feddc4bc2590e0fa6129543424a81 Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Thu, 6 Mar 2025 16:15:16 +0530 Subject: [PATCH 4/4] status maintain in order schema --- src/controllers/installationController.js | 137 ++++++++++++---------- 1 file changed, 72 insertions(+), 65 deletions(-) diff --git a/src/controllers/installationController.js b/src/controllers/installationController.js index 1658bf1f..39dc86b7 100644 --- a/src/controllers/installationController.js +++ b/src/controllers/installationController.js @@ -203,86 +203,93 @@ exports.createTeamMember = async (request, reply) => { 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", - }, - }); - } + const { installationId } = request.params; + const { teamMemberId, quotationId } = request.body; - // Find installation by installationId - const installation = await Install.findOne({ installationId }); + if (!teamMemberId || !quotationId) { + return reply.status(400).send({ + simplydata: { + error: true, + message: "Both teamMemberId and quotationId are required", + }, + }); + } - if (!installation) { - return reply.status(404).send({ - simplydata: { - error: true, - message: "Installation not found", - }, - }); - } + // 🔹 Find installation by installationId + const installation = await Install.findOne({ installationId }); - // Extract team members list - const teamMembers = installation.team_member?.team_member || []; + if (!installation) { + return reply.status(404).send({ + simplydata: { + error: true, + message: "Installation not found", + }, + }); + } - // Check if the provided teamMemberId exists in the installation's team - const assignedTeamMember = teamMembers.find(member => member.teamMemberId === teamMemberId); + // 🔹 Extract team members list + const teamMembers = installation.team_member?.team_member || []; - if (!assignedTeamMember) { - return reply.status(404).send({ - simplydata: { - error: true, - message: "Team member not found in this installation", - }, - }); - } + // 🔹 Check if the provided teamMemberId exists in the installation's team + const assignedTeamMember = teamMembers.find( + (member) => member.teamMemberId === teamMemberId + ); - // Find or create the quotation for the given installationId - let quotation = await Order.findOne({ installationId, quatationId: quotationId }); + if (!assignedTeamMember) { + return reply.status(404).send({ + simplydata: { + error: true, + message: "Team member not found in this installation", + }, + }); + } - if (!quotation) { - quotation = new Order({ - installationId, - quatationId: quotationId, - // assignedTeamMembers: [], - }); - } + // 🔹 Find or create the quotation for the given installationId + let quotation = await Order.findOne({ installationId, quatationId: quotationId }); - // Assign the team member to the quotation - if (!quotation.assignedTeamMembers) { - quotation.assignedTeamMembers = []; - } + if (!quotation) { + quotation = new Order({ + installationId, + quatationId: quotationId, + assignedTeamMembers: [], + status: "Pending", // Default status when created + }); + } - if (!quotation.assignedTeamMembers.includes(teamMemberId)) { - quotation.assignedTeamMembers.push(teamMemberId); - } + // 🔹 Assign the team member to the quotation + if (!quotation.assignedTeamMembers) { + quotation.assignedTeamMembers = []; + } - // Save the updated quotation - await quotation.save(); + if (!quotation.assignedTeamMembers.includes(teamMemberId)) { + quotation.assignedTeamMembers.push(teamMemberId); + } - return reply.send({ - simplydata: { - error: false, - message: "Team member assigned to quotation successfully", - quotation, - }, - }); + // 🔹 Update order status when a team member is assigned + quotation.status = "Assigned"; // Update status + + // 🔹 Save the updated quotation + await quotation.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", - }, - }); + 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