const boom = require("boom"); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const customJwtAuth = require("../customAuthJwt"); 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 { Tankerbooking} = require("../models/tankers") const {Repairorder,SensorStock,Order,EstimationOrder,Iotprice, Install, ProfilePictureInstall, SensorQuotation,generateinstallationId,Store,WaterLeverSensor,MotorSwitchSenso,Insensors,generatequatationId, HardwareCart, ServiceCart, Sales} = require("../models/store"); const { User,Counter, generateBookingId,resetCounter,generateCustomerId,ProfilePicture} = require('../models/User') exports.installSignUp = async (request, reply) => { try { const i_id = await generateinstallationId(); const installationId = `AWIN${i_id}`; const { // name, phone, address, address1, address2, emails, password, profile, team, manager, longitude, latitude, fcmId, alternativeNumber, firstName, lastName, city, designation, reportingManager, departmentName, zone, createdBy, updatedBy, } = request.body; // Check if a user with the same phone number already exists const existingInstall = await Install.findOne({ phone }); if (existingInstall) { return reply.status(400).send({ message: 'Phone is already registered' }); } // Hash the password using bcrypt const hashedPassword = await bcrypt.hash(password, 10); // Create a new install object with the hashed password and other details const install = new Install({ // name, installationId, phone, address, address1, address2, emails, services: { password: { bcrypt: hashedPassword } }, profile, team, manager, longitude, latitude, fcmId, alternativeNumber, firstName, lastName, city, designation, reportingManager, departmentName, zone, createdBy, updatedBy, }); // Save the new install to the database await install.save(); reply.send({ message: 'Install Account Created Successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.installationVerifyPhone = async (req, reply) => { console.log("-------------------------------------------------"); try { phone = req.body.phone; phoneVerificationCode = req.body.phoneVerificationCode; // check if user exists in the system. If user exists , display message that // username is not available console.log( "this is the phone and verification code", phone, phoneVerificationCode ); deliveryBoyExists = await Install.findOne({ phone: phone, //phoneVerified: false, phoneVerificationCode: phoneVerificationCode, }); console.log(deliveryBoyExists); if (deliveryBoyExists) { // update the phoneVerified flag to true. const filter = { phone: phone, phoneVerificationCode: phoneVerificationCode, }; const update = { phoneVerified: true }; const doc = await Install.findOneAndUpdate(filter, update); updatedDeliveryBoy = await Install.findOne({ phone: phone }); if (updatedDeliveryBoy.phoneVerified) { loginObject = await supplierController.loginInstallation(req); console.log("loginObject...", loginObject); if (loginObject.same) { const phoneVerified = loginObject.delivery.phoneVerified; const oneTimePasswordSetFlag = loginObject.delivery.oneTimePasswordSetFlag; console.log( "oneTimePasswordSetFlag is ......", oneTimePasswordSetFlag, typeof oneTimePasswordSetFlag, typeof phoneVerified ); if (!phoneVerified) { reply.send({ simplydata: { error: false, phoneVerified: false, phone: loginObject.delivery.phone, oneTimePasswordSetFlag: oneTimePasswordSetFlag, message: "Please Verify your phone number", }, }); } else if (oneTimePasswordSetFlag) { reply.send({ simplydata: { error: false, phoneVerified: phoneVerified, phone: loginObject.delivery.phone, oneTimePasswordSetFlag: true, message: "Password must be reset", }, }); } else { const token = fastify.jwt.sign( { name: loginObject.delivery.name, }, //expiresIn: expressed in seconds or a string describing a time span zeit/ms. Eg: 60, "2 days", "10h", "7d". //A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), //otherwise milliseconds unit is used by default ("120" is equal to "120ms"). { expiresIn: "30d" } ); console.log(token, "..token"); var d_id = loginObject.delivery._id; console.log(d_id, "deliveryId"); var profilePicture = await ProfilePictureInstall.findOne({ installationId: d_id, }); // request.session.set('supplierId', loginObject.supplier._id) if (!profilePicture) { reply.send({ simplydata: { error: false, apiversion: fastify.config.APIVERSION, access_token: token, phone: loginObject.delivery.phone, installationId: loginObject.delivery.installationId, name: loginObject.delivery.name, address: loginObject.delivery.address, phoneVerified: loginObject.delivery.phoneVerified, oneTimePasswordSetFlag: loginObject.delivery.oneTimePasswordSetFlag, }, }); } if (profilePicture) { reply.send({ simplydata: { error: false, apiversion: fastify.config.APIVERSION, access_token: token, picture: profilePicture.picture, phone: loginObject.delivery.phone, installationId: loginObject.delivery.installationId, name: loginObject.delivery.name, address: loginObject.delivery.address, phoneVerified: loginObject.delivery.phoneVerified, oneTimePasswordSetFlag: loginObject.delivery.oneTimePasswordSetFlag, }, }); } } } else { error = { simplydata: { error: true, code: 400, message: "Invalid Details", }, }; reply.send(error); } } }else { error = { armintatankdata: { error: true, code: 10005, message: "10005 - Verification code entered cannot be validated.", }, }; req.body.regError = error; reply.send(error); } } catch (err) { throw boom.boomify(err); } }; const generateStoreId = async () => { const result = await Counter.findOneAndUpdate( { _id: 'store_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return result.seq; }; const saltRounds = 10; const generateSalesId = async () => { const result = await Counter.findOneAndUpdate( { _id: 'sales_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return result.seq; }; async function bcryptPassword(password) { encryptedPwd = bcrypt.hash(password, saltRounds); return encryptedPwd; } async function bcryptComparePassword(pwd, encpassword) { isSame = bcrypt.compare(pwd, encpassword); return isSame; } exports.addStore = async (request, reply) => { try { // Generate a unique store ID const s_id = await generateStoreId(); const storeId = `AWST${s_id}`; const { storename, phone, zone, departmentName, designation, reportingManager, contactPersonName, contactPersonPhone, emails, password, description, startingPrice, longitude, latitude, fcmId, isActive, createdBy, updatedBy, profile = {}, // Default to an empty object to prevent errors } = request.body; const { firstName = null, lastName = null, contactNumber = null, alternativeContactNumber = null, store_address = null, city = null, state = null, zip = null, country = null, address1 = null, address2 = null } = profile; // Extract profile fields // Check if the phone is already registered const existingStore = await Store.findOne({ phone }); if (existingStore) { return reply.status(400).send({ message: 'Phone is already registered' }); } // Check if the contact person phone is already registered const existingContactPhone = await Store.findOne({ contactPersonPhone }); if (existingContactPhone) { return reply.status(400).send({ message: 'Contact Person Phone is already registered' }); } // Hash the password const hashedPassword = await bcrypt.hash(password, 10); // Create a new store document const store = new Store({ storename, phone, zone, departmentName, designation, reportingManager, contactPersonName, contactPersonPhone, storeId, emails, services: { password: { bcrypt: hashedPassword } }, description, startingPrice, profile: { store_address, firstName, lastName, contactNumber, alternativeContactNumber, city, state, zip, country, address1, address2 }, longitude, latitude, fcmId, isActive: isActive ?? true, // Default to true if not provided createdBy, updatedBy, }); // Save the store document await store.save(); reply.send({ message: 'Store Account Created Successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.addSales = async (request, reply) => { try { const s_id = await generateSalesId(); const sales_id = `AWSL${s_id}`; const { phone, username, emails, password, zone, departmentName, designation, reportingManager, profile, createdBy, updatedBy, } = request.body; const { firstName, lastName ,address,city,state,country,zip,address1,address2} = profile || {}; const existingStore = await Sales.findOne({ phone }); if (existingStore) { return reply.status(400).send({ message: 'Phone is already registered' }); } const hashedPassword = await bcrypt.hash(password, 10); const store = new Sales({ salesId: sales_id, username, phone, address, emails, zone, departmentName, designation, reportingManager, services: { password: { bcrypt: hashedPassword } }, profile: { firstName, lastName, address, city, state, country, zip, address1, address2, ...profile, }, createdBy, updatedBy, }); await store.save(); reply.send({ message: 'Account Created Successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.getallsales = async (req, reply) => { try { await Sales.find() .exec() .then((docs) => { reply.send({ status_code: 200, data: docs, count: docs.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; exports.getallstore = async (req, reply) => { try { await Store.find() .exec() .then((docs) => { reply.send({ status_code: 200, data: docs, count: docs.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; exports.deleteUserInfo = async (req, reply) => { try { const salesId = req.params.salesId; const sales = await Sales.findOneAndDelete({ salesId:salesId }); reply.send({ status_code: 200, message: 'Delete Sucessfully'}); } catch (err) { throw boom.boomify(err); } }; exports.deleteStoreInfo = async (req, reply) => { try { const storeId = req.params.storeId; const store = await Store.findOneAndDelete({ storeId:storeId }); reply.send({ status_code: 200, message: 'Delete Sucessfully'}); } catch (err) { throw boom.boomify(err); } }; exports.editSalesUser = async (request, reply) => { try { const { salesId } = request.params; const { username, phone, emails, address, profile, zone, reportingManager, designation, departmentName } = request.body; const existingSales = await Sales.findOne({ salesId }); if (!existingSales) { return reply.status(404).send({ message: 'Sales user not found' }); } const phoneExists = await Sales.findOne({ phone, salesId: { $ne: salesId } }); if (phoneExists) { return reply.status(400).send({ message: 'Phone is already registered to another user' }); } existingSales.username = username || existingSales.username; existingSales.phone = phone || existingSales.phone; existingSales.emails = emails || existingSales.emails; existingSales.zone = zone || existingSales.zone; existingSales.reportingManager = reportingManager || existingSales.reportingManager; existingSales.designation = designation || existingSales.designation; existingSales.departmentName = departmentName || existingSales.departmentName; if (profile) { existingSales.profile.firstName = profile.firstName || existingSales.profile.firstName; existingSales.profile.lastName = profile.lastName || existingSales.profile.lastName; existingSales.profile.address = profile.address || existingSales.profile.address; existingSales.profile.city = profile.city || existingSales.profile.city; existingSales.profile.state = profile.state || existingSales.profile.state; existingSales.profile.country = profile.country || existingSales.profile.country; existingSales.profile.zip = profile.zip || existingSales.profile.zip; existingSales.profile.address1 = profile.address1 || existingSales.profile.address1; existingSales.profile.address2 = profile.address2 || existingSales.profile.address2; } if (request.body.password) { const hashedPassword = await bcrypt.hash(request.body.password, 10); existingSales.services.password.bcrypt = hashedPassword; } await existingSales.save(); reply.send({ message: 'Sales user updated successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.editStore = async (request, reply) => { try { const { storeId } = request.params; const { storename, phone, address, address1, address2, emails, profile, alternativeNumber, longitude, latitude, fcmId, description, startingPrice, password, contactPersonPhone, zone, reportingManager, designation, departmentName } = request.body; const existingStore = await Store.findOne({ storeId: storeId }); if (!existingStore) { return reply.status(404).send({ message: 'Store not found' }); } const phoneExists = await Store.findOne({ phone, storeId: { $ne: storeId } }); if (phoneExists) { return reply.status(400).send({ message: 'Phone is already registered to another store' }); } existingStore.storename = storename || existingStore.storename; existingStore.phone = phone || existingStore.phone; existingStore.address = address || existingStore.address; existingStore.address1 = address1 || existingStore.address1; existingStore.address2 = address2 || existingStore.address2; existingStore.emails = emails || existingStore.emails; existingStore.alternativeNumber = alternativeNumber || existingStore.alternativeNumber; existingStore.longitude = longitude || existingStore.longitude; existingStore.latitude = latitude || existingStore.latitude; existingStore.fcmId = fcmId || existingStore.fcmId; existingStore.description = description || existingStore.description; existingStore.startingPrice = startingPrice || existingStore.startingPrice; existingStore.contactPersonPhone = contactPersonPhone || existingStore.contactPersonPhone; existingStore.zone = zone || existingStore.zone; existingStore.reportingManager = reportingManager || existingStore.reportingManager; existingStore.designation = designation || existingStore.designation; existingStore.departmentName = departmentName || existingStore.departmentName; if (profile) { existingStore.profile.firstName = profile.firstName || existingStore.profile.firstName; existingStore.profile.lastName = profile.lastName || existingStore.profile.lastName; existingStore.profile.contactNumber = profile.contactNumber || existingStore.profile.contactNumber; existingStore.profile.alternativeContactNumber = profile.alternativeContactNumber || existingStore.profile.alternativeContactNumber; existingStore.profile.store_address = profile.store_address || existingStore.profile.store_address; existingStore.profile.city = profile.city || existingStore.profile.city; existingStore.profile.state = profile.state || existingStore.profile.state; existingStore.profile.country = profile.country || existingStore.profile.country; existingStore.profile.zip = profile.zip || existingStore.profile.zip; existingStore.profile.address1 = profile.address1 || existingStore.profile.address1; existingStore.profile.address2 = profile.address2 || existingStore.profile.address2; } if (password) { const hashedPassword = await bcrypt.hash(password, 10); existingStore.services.password.bcrypt = hashedPassword; } await existingStore.save(); reply.send({ message: 'Store updated successfully' }); } catch (err) { reply.status(500).send({ message: err.message }); } }; exports.getAllUsers = async (request, reply) => { try { const users = await Install.find({}); reply.send(users); } catch (error) { reply.status(500).send({ message: "Error retrieving users" }); } }, exports.deleteUserByInstallationId = async (request, reply) => { const { installationId } = request.params; try { await Install.findOneAndDelete({ installationId }); reply.send({ message: "User deleted successfully" }); } catch (error) { reply.status(500).send({ message: "Error deleting user" }); } }, exports.updateUserByInstallationId = async (request, reply) => { const { installationId } = request.params; const updatedData = request.body; try { await Install.findOneAndUpdate({ installationId }, updatedData, { new: true }); reply.send({ message: "User updated successfully" }); } catch (error) { reply.status(500).send({ message: "Error updating user" }); } } const generatewaterlevelheightsensorId = async () => { const result = await Counter.findOneAndUpdate( { _id: 'waterlevelheightsensor_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return result.seq; }; const generatewaterlevelsensorId = async () => { const result = await Counter.findOneAndUpdate( { _id: 'waterlevelsensor_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return result.seq; }; const generatewaterlevelslavesensorId = async () => { const result = await Counter.findOneAndUpdate( { _id: 'waterlevelslavesensor_id' }, { $inc: { seq: 1 } }, { upsert: true, new: true } ); return result.seq; }; const moment = require('moment'); // exports.createwaterlevelSensor = async (req, reply) => { // try { // const storeId = req.params.storeId // const { hardwareId,hardwareId_company, type, indate } = req.body; // var mater_seq_id = await generatewaterlevelsensorId(); // const date = moment().format('MM-DD'); // const prefix = 'AS' + date + 'MALOV1'; // var masterId = `${prefix}${mater_seq_id}`; // const newSensor = new WaterLeverSensor({ // storeId, // hardwareId, // masterId, // type, // indate // }); // const savedSensor = await newSensor.save(); // reply.code(200).send(savedSensor); // } catch (err) { // reply.code(500).send(err); // } // }; // exports.editWaterLevelSensor = async (req, reply) => { // try { // const { storeId } = req.params; // const updates = req.body; // const updatedSensor = await WaterLeverSensor.findOneAndUpdate( // { storeId:storeId,hardwareId: req.body.hardwareId }, // updates, // { new: true } // ); // if (!updatedSensor) { // reply.code(404).send({ message: "Sensor not found" }); // } else { // reply.code(200).send(updatedSensor); // } // } catch (err) { // reply.code(500).send(err); // } // }; exports.deleteWaterLevelSensor = async (req, reply) => { try { const { storeId } = req.params; const deletedSensor = await WaterLeverSensor.findOneAndDelete( { storeId,hardwareId: req.body.hardwareId } ); if (!deletedSensor) { reply.code(404).send({ message: "Sensor not found" }); } else { reply.code(200).send({ message: "Sensor deleted successfully" }); } } catch (err) { reply.code(500).send(err); } }; exports.installwaterlevelSensor = async (request, reply) => { try { const { storeId } = request.params; const updateData = request.body; // Find the document by hardwareId and update it with the fields received in the body const updatedSensor = await WaterLeverSensor.findOneAndUpdate( { storeId:storeId,hardwareId: request.body.hardwareId, }, { $set: updateData }, { new: true } // Return the updated document ); if (!updatedSensor) { return reply.status(404).send({ error: 'Sensor not found' }); } return reply.status(200).send(updatedSensor); } catch (error) { console.error(error); return reply.status(500).send({ error: 'An error occurred while updating the sensor' }); } }; // exports.qccheckwaterlevelSensor = async (request, reply) => { // try { // const { hardwareId } = request.params; // const updateData = request.body; // // Find the document by hardwareId and update it with the fields received in the body // const updatedSensor = await WaterLeverSensor.findOneAndUpdate( // { hardwareId: hardwareId }, // { $set: updateData }, // { new: true } // Return the updated document // ); // if (!updatedSensor) { // return reply.status(404).send({ error: 'Sensor not found' }); // } // return reply.status(200).send(updatedSensor); // } catch (error) { // console.error(error); // return reply.status(500).send({ error: 'An error occurred while updating the sensor' }); // } // }; exports.getHardware = async (req, reply) => { try { await WaterLeverSensor.find({storeId: req.params.storeId}) .exec() .then((docs) => { reply.send({ status_code: 200, data: docs, count: docs.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; exports.getHardwaremotorswitch = async (req, reply) => { try { await MotorSwitchSensor.find({storeId: req.params.storeId}) .exec() .then((docs) => { reply.send({ status_code: 200, data: docs, count: docs.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; exports.getHardwareqc = async (req, reply) => { try { await WaterLeverSensor.find({storeId: req.params.storeId,hardwareId:req.body.hardwareId}) .exec() .then((docs) => { reply.send({ status_code: 200, data: docs, count: docs.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; exports.addSlave = async (req, reply) => { try { const hardwareId = req.params.hardwareId; const { tankhardwareId, type, indate, hardwareId_company } = req.body; // Find the main hardware by hardwareId const mainHardware = await WaterLeverSensor.findOne({ hardwareId }); if (!mainHardware) { reply.code(404).send({ message: "Main hardware not found" }); return; } // Check if the slave's hardwareId already exists const existingSlave = mainHardware.slaves.tankhardware.find(slave => slave.tankhardwareId === tankhardwareId); if (existingSlave) { reply.code(400).send({ message: "Slave hardware ID already exists for this main hardware" }); return; } var slave_seq_id = await generatewaterlevelslavesensorId(); const date = moment().format('MM-DD'); const prefix = 'AS' + date + 'SLAOV1'; var slaveId = `${prefix}${slave_seq_id}`; // Create new slave const newSlave = { tankhardwareId, slaveId: slaveId, type, indate, hardwareId_company }; // Add the new slave to the main hardware's slaves array mainHardware.slaves.tankhardware.push(newSlave); // Save the updated main hardware const updatedHardware = await mainHardware.save(); reply.code(200).send(updatedHardware); } catch (err) { reply.code(500).send(err); } }; // exports.editSlave = async (req, reply) => { // try { // const { hardwareId } = req.params; // const updates = req.body; // const mainHardware = await WaterLeverSensor.findOne({ hardwareId }); // if (!mainHardware) { // reply.code(404).send({ message: "Main hardware not found" }); // return; // } // const slaveIndex = mainHardware.slaves.tankhardware.findIndex( // (slave) => slave.tankhardwareId === req.body.tankhardwareId // ); // if (slaveIndex === -1) { // reply.code(404).send({ message: "Slave not found" }); // return; // } // mainHardware.slaves.tankhardware[slaveIndex] = { // ...mainHardware.slaves.tankhardware[slaveIndex], // ...updates, // }; // const updatedHardware = await mainHardware.save(); // reply.code(200).send(updatedHardware); // } catch (err) { // reply.code(500).send(err); // } // }; exports.deleteSlave = async (req, reply) => { try { const { hardwareId } = req.params; const mainHardware = await WaterLeverSensor.findOne({ hardwareId }); if (!mainHardware) { reply.code(404).send({ message: "Main hardware not found" }); return; } const slaveIndex = mainHardware.slaves.tankhardware.findIndex( (slave) => slave.tankhardwareId === req.body.tankhardwareId ); if (slaveIndex === -1) { reply.code(404).send({ message: "Slave not found" }); return; } mainHardware.slaves.tankhardware.splice(slaveIndex, 1); const updatedHardware = await mainHardware.save(); reply.code(200).send(updatedHardware); } catch (err) { reply.code(500).send(err); } }; exports.qccheckwaterlevelSensorSlave = async (request, reply) => { try { const { storeId } = request.params; const updateData = request.body; // Find the document by storeId and tankhardwareId, and update the corresponding slave const updatedSensor = await WaterLeverSensor.findOneAndUpdate( { storeId: storeId, hardwareId:request.body.hardwareId, "slaves.tankhardware.tankhardwareId": request.body.tankhardwareId }, { $set: { "slaves.tankhardware.$.qccheck": updateData.qccheck, "slaves.tankhardware.$.qccheckdate": updateData.qccheckdate, "slaves.tankhardware.$.qcby": updateData.qcby, "slaves.tankhardware.$.comment": updateData.comment, "slaves.tankhardware.$.outforrepairdate": updateData.outforrepairdate, "slaves.tankhardware.$.sendto": updateData.sendto, "slaves.tankhardware.$.repairfeedback": updateData.repairfeedback } }, { new: true } // Return the updated document ); if (!updatedSensor) { return reply.status(404).send({ error: 'Slave not found' }); } return reply.status(200).send(updatedSensor); } catch (error) { console.error(error); return reply.status(500).send({ error: 'An error occurred while updating the slave' }); } }; exports.installwaterlevelSensorSlave = async (request, reply) => { try { const { storeId } = request.params; const { hardwareId, tankhardwareId, dateofinstallation, customerId, installedby } = request.body; // Find the document by storeId and hardwareId, then update the specific slave with tankhardwareId const updatedSensor = await WaterLeverSensor.findOneAndUpdate( { storeId: storeId, hardwareId: hardwareId, "slaves.tankhardware.tankhardwareId": tankhardwareId }, { $set: { "slaves.tankhardware.$.dateofinstallation": dateofinstallation, "slaves.tankhardware.$.customerId": customerId, "slaves.tankhardware.$.installedby": installedby } }, { new: true } // Return the updated document ); if (!updatedSensor) { return reply.status(404).send({ error: 'Sensor or Slave not found' }); } return reply.status(200).send(updatedSensor); } catch (error) { console.error(error); return reply.status(500).send({ error: 'An error occurred while installing the sensor' }); } }; exports.getHardwareqcslave = async (req, reply) => { try { const { storeId } = req.params; const { hardwareId, tankhardwareId } = req.body; let query; if (tankhardwareId) { // If tankhardwareId is provided, query for the specific slave query = { storeId: storeId, hardwareId: hardwareId, "slaves.tankhardware.tankhardwareId": tankhardwareId, }; } else { // Otherwise, query for the main hardware query = { storeId: storeId, hardwareId: hardwareId, }; } const docs = await WaterLeverSensor.find(query).exec(); if (docs.length === 0) { return reply.status(404).send({ error: 'No hardware found' }); } reply.send({ status_code: 200, data: docs, count: docs.length }); } catch (err) { console.error(err); reply.status(500).send({ error: 'An error occurred while retrieving the hardware QC data' }); } }; exports.createmotorswitchSensor = async (req, reply) => { try { const storeId = req.params.storeId const { motorId, type, indate } = req.body; var mater_seq_id = await generatewaterlevelsensorId(); const date = moment().format('MM-DD'); const prefix = 'AS' + date + 'PSV1'; var masterId = `${prefix}${mater_seq_id}`; const newSensor = new MotorSwitchSensor({ storeId, motorId, masterId, type, indate }); const savedSensor = await newSensor.save(); reply.code(200).send(savedSensor); } catch (err) { reply.code(500).send(err); } }; exports.qccheckmotorswitch = async (request, reply) => { try { const { motorId } = request.params; const updateData = request.body; // Find the document by hardwareId and update it with the fields received in the body const updatedSensor = await MotorSwitchSensor.findOneAndUpdate( { motorId: motorId }, { $set: updateData }, { new: true } // Return the updated document ); if (!updatedSensor) { return reply.status(404).send({ error: 'Sensor not found' }); } return reply.status(200).send(updatedSensor); } catch (error) { console.error(error); return reply.status(500).send({ error: 'An error occurred while updating the sensor' }); } }; exports.installmotorswitch = async (request, reply) => { try { const { storeId } = request.params; const updateData = request.body; // Find the document by hardwareId and update it with the fields received in the body const updatedSensor = await MotorSwitchSensor.findOneAndUpdate( { storeId:storeId,motorId: request.body.motorId, }, { $set: updateData }, { new: true } // Return the updated document ); if (!updatedSensor) { return reply.status(404).send({ error: 'Sensor not found' }); } return reply.status(200).send(updatedSensor); } catch (error) { console.error(error); return reply.status(500).send({ error: 'An error occurred while updating the sensor' }); } }; exports.generateHardwareMasterId = async (req, reply) => { try { const storeId = req.params.storeId const { from, to, type, quantity } = req.body; const sensorType = type.toLowerCase(); const fromInt = parseInt(from, 10); const toInt = parseInt(to, 10); if (isNaN(fromInt) || isNaN(toInt) || fromInt > toInt) { return reply.code(400).send({ message: 'Invalid from/to values' }); } // Fetch pending sensors of the given type and storeId whose hardwareId is null const pendingSensors = await Insensors.find({ status: 'pending', type: sensorType, storeId, hardwareId: null }); if (!pendingSensors.length) { return reply.code(404).send({ message: 'No pending sensors found for the given type and storeId' }); } if (quantity > pendingSensors.length) { return reply.code(400).send({ message: `Available quantity is less than requested: ${pendingSensors.length} available.` }); } let hardwareIdSequence = fromInt; const date = moment().format('MM-DD'); for (let i = 0; i < quantity && i < pendingSensors.length; i++) { let sensor = pendingSensors[i]; if (hardwareIdSequence > toInt) break; sensor.hardwareId = hardwareIdSequence.toString().padStart(8, '0'); let mater_seq_id; if (sensorType === 'master') { mater_seq_id = await generatewaterlevelsensorId(); sensor.masterId = `AS${date}MALOV1${mater_seq_id}`; } else if (sensorType === 'slave') { mater_seq_id = await generatewaterlevelslavesensorId(); sensor.masterId = `AS${date}SLLOV1${mater_seq_id}`; } else if (sensorType === 'sensor') { mater_seq_id = await generatewaterlevelheightsensorId(); sensor.masterId = `AS${date}SELOV1${mater_seq_id}`; } await sensor.save(); // Save updated sensor in the database hardwareIdSequence++; } return reply.code(200).send({ message: 'HardwareId and MasterId assigned successfully' }); } catch (error) { console.error('Error generating IDs:', error); return reply.code(500).send({ message: 'Internal Server Error' }); } }; exports.getSensorByHardwareId = async (req, reply) => { try { const { storeId } = req.params; const { hardwareId } = req.body; if (!hardwareId) { return reply.code(400).send({ message: 'hardwareId is required' }); } const sensor = await Insensors.findOne({ storeId, hardwareId }); if (!sensor) { return reply.code(404).send({ message: 'Sensor not found' }); } return reply.code(200).send(sensor); } catch (error) { console.error('Error fetching sensor by hardwareId:', error); return reply.code(500).send({ message: 'Internal Server Error' }); } }; exports.updateSensorById = async (req, reply) => { try { const { _id } = req.params; let updateData = req.body; const allowedFields = ["model", "type", "hardwareId_company", "hardwareId","masterId"]; // Filter out unwanted fields and convert type to lowercase if present const filteredUpdateData = Object.keys(updateData) .filter((key) => allowedFields.includes(key)) .reduce((obj, key) => { obj[key] = key === "type" ? updateData[key].toLowerCase() : updateData[key]; return obj; }, {}); const updatedSensor = await Insensors.findByIdAndUpdate(_id, filteredUpdateData, { new: true }); if (!updatedSensor) { return reply.code(404).send({ message: "Sensor not found" }); } return reply.code(200).send(updatedSensor); } catch (error) { console.error("Error updating sensor:", error); return reply.code(500).send({ message: "Internal Server Error" }); } }; exports.deleteSensorById = async (req, reply) => { try { const { _id } = req.params; const deletedSensor = await Insensors.findByIdAndDelete(_id); if (!deletedSensor) { return reply.code(404).send({ message: "Sensor not found" }); } return reply.code(200).send({ message: "Sensor deleted successfully" }); } catch (error) { console.error("Error deleting sensor:", error); return reply.code(500).send({ message: "Internal Server Error" }); } }; exports.updateSensorQC = async (req, reply) => { try { const { hardwareId } = req.params; let updateData = req.body; const allowedFields = ['qccheck', 'qcby', 'comment', 'status', 'quality_check_details']; // Filter only allowed fields const filteredUpdateData = Object.keys(updateData) .filter((key) => allowedFields.includes(key)) .reduce((obj, key) => { obj[key] = updateData[key]; return obj; }, {}); // Ensure qccheck is handled properly if (filteredUpdateData.qccheck) { const qccheckLower = filteredUpdateData.qccheck.toLowerCase(); filteredUpdateData.status = qccheckLower === 'pass' ? 'available' : 'qcfailed'; } // Update qccheckdate with the current date in "DD-MMM-YYYY - HH:MM" format filteredUpdateData.qccheckdate = moment().format('DD-MMM-YYYY - HH:mm'); // Find the sensor by ID const updatedSensor = await Insensors.findOneAndUpdate( { hardwareId }, // correct query filter filteredUpdateData, { new: true } ); if (!updatedSensor) { return reply.code(409).send({ message: 'Sensor not found' }); } // Update stock based on QC result const stockRecord = await SensorStock.findOne({ storeId: updatedSensor.storeId, type: updatedSensor.type }); if (stockRecord) { if (filteredUpdateData.qccheck && filteredUpdateData.qccheck.toLowerCase() === 'ok') { // If QC is "ok", move 1 from total_count_before_qc to total_available await SensorStock.updateOne( { storeId: updatedSensor.storeId, type: updatedSensor.type }, { $inc: { total_count_before_qc: -1, total_available: 1 } } ); } else { // If QC is failed, move 1 from total_count_before_qc to total_repair await SensorStock.updateOne( { storeId: updatedSensor.storeId, type: updatedSensor.type }, { $inc: { total_count_before_qc: -1, total_repair: 1 } } ); } } return reply.code(200).send(updatedSensor); } catch (error) { console.error('Error updating QC fields:', error); return reply.code(500).send({ message: 'Internal Server Error' }); } }; exports.getSensorsByStatus = async (req, reply) => { try { const { storeId } = req.params; const statuses = ["pending", "available", "rejected","blocked"]; let result = {}; for (const status of statuses) { result[status] = await Insensors.find({ storeId, status }); } const sensorStock = await SensorStock.find({ storeId }).lean(); return reply.code(200).send({ status_code: 200, message: "Sensors and stock fetched successfully", data: { sensors: result, stock: sensorStock } }); } catch (error) { console.error("Error fetching sensors:", error); return reply.code(500).send({ message: "Internal Server Error" }); } }; exports.getpumpswitchqc = async (req, reply) => { try { await MotorSwitchSensor.find({storeId: req.params.storeId,motorId:req.body.motorId}) .exec() .then((docs) => { reply.send({ status_code: 200, data: docs, count: docs.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; const generateBatchNo = (type, hardwareIdCompany) => { const date = new Date(); const ddmmyy = `${date.getDate().toString().padStart(2, '0')}${(date.getMonth() + 1).toString().padStart(2, '0')}${date.getFullYear().toString().slice(-2)}`; const companyPrefix = hardwareIdCompany.slice(0, 2).toUpperCase(); const randomNumbers = Math.floor(100 + Math.random() * 900).toString(); // 3 random digits if (type === 'SENSOR') { return `SN${ddmmyy}${companyPrefix}${randomNumbers}`; } if (type === 'SLAVE') { return `SL${ddmmyy}${companyPrefix}${randomNumbers}`; } if (type === 'MASTER') { return `MA${ddmmyy}${companyPrefix}${randomNumbers}`; } if (type === 'MOTOR_SWITCH') { return `MS${ddmmyy}${companyPrefix}${randomNumbers}`; } // Add other type conditions if needed return null; }; exports.createSensor = async (req, reply) => { try { const storeId = req.params.storeId; const { indate, batchno, hardwareId_company, quantity, model, type } = req.body; const sensorType = type.toLowerCase(); let finalBatchNo = batchno; // Generate unique batch number if 'New' is received if (batchno === "New") { let isUnique = false; while (!isUnique) { finalBatchNo = generateBatchNo(type, hardwareId_company); const existingBatchNo = await Insensors.findOne({ batchno: finalBatchNo }); if (!existingBatchNo) { isUnique = true; } } } let entries = []; for (let i = 0; i < quantity; i++) { entries.push({ storeId, model, batchno: finalBatchNo, type: sensorType, indate, hardwareId_company, }); } // Insert new sensors into Insensors collection const savedSensors = await Insensors.insertMany(entries); // Update stock information in SensorStock const stockRecord = await SensorStock.findOne({ storeId, type: sensorType }); if (stockRecord) { // If stock record exists, update total_count await SensorStock.updateOne( { storeId, type: sensorType }, { $inc: { total_count: quantity, total_count_before_qc: quantity } } ); } else { // If no stock record exists, create a new one await SensorStock.create({ storeId, type: sensorType, total_count: quantity, total_available: 0, total_blocked: 0, total_repair: 0, total_installed: 0, total_count_before_qc:quantity }); } reply.code(200).send(savedSensors); } catch (err) { reply.code(500).send(err); } }; exports.getbatchnumbers = async (req, reply) => { try { const { storeId, type } = req.params; let prefix = ""; switch (type.toUpperCase()) { case "SLAVE": prefix = "SL"; break; case "MASTER": prefix = "MA"; break; case "SENSOR": prefix = "SN"; break; case "MOTOR_SWITCH": prefix = "MS"; break; default: reply.send({ status_code: 400, message: "Invalid type" }); return; } await Insensors.distinct('batchno', { storeId: storeId, batchno: { $regex: `^${prefix}` }, }) .then((batchNumbers) => { reply.send({ status_code: 200, data: batchNumbers, count: batchNumbers.length }); }) .catch((err) => { console.error(err); reply.send({ status_code: 500, error: err }); }); } catch (err) { console.error(err); reply.send({ status_code: 500, error: err }); } }; exports.getbatquotationsforparticularstore = async (req, reply) => { try { const storeId = req.params.storeId; let query = { storeId: storeId }; // Fetch data based on the query const result = await SensorQuotation.find(query); if (!result ) { return reply.send({ status_code: 404, error: "not found" }); } reply.send({ status_code: 200, data: result }); } catch (err) { throw boom.boomify(err); } }; exports.getiots = async (req, reply) => { try { const storeId = req.params.storeId; let type = req.params.type ? req.params.type.toLowerCase() : null; // Convert type to uppercase let query = { storeId: storeId }; if (type !== "ALL") { query.type = type; } // Fetch data based on the query const result = await Insensors.find(query); if (!result ) { return reply.send({ status_code: 404, error: "not found" }); } reply.send({ status_code: 200, data: result }); } catch (err) { throw boom.boomify(err); } }; exports.getusersofParticularInstaller = async (req, reply) => { try { await User.find({installationId: req.query.InstallerId}) .exec() .then((docs) => { reply.send({ status_code: 200, data: docs, count: docs.length }); }) .catch((err) => { console.log(err); reply.send({ error: err }); }); } catch (err) { throw boom.boomify(err); } }; const dayjs = require('dayjs'); const utc = require('dayjs/plugin/utc'); const timezone = require('dayjs/plugin/timezone'); // Extend dayjs with UTC and timezone plugins dayjs.extend(utc); dayjs.extend(timezone); exports.createquotationforSensor = async (req, reply) => { try { const i_id = await generatequatationId(); const quatationId = `AWQU${i_id}`; const { surveyId } = req.params; const { customerId, masters, slaves, sensors, motor_switches, electricals,master_connections } = req.body; // Format electricals field const formattedElectricals = electricals.map((item) => ({ type: item.type || "", wire: item.wire || "", switch: item.switch || "", text: item.text || "", })); const formattedMasterDetails = master_connections.map((item) => ({ master_name: item.master_name || "", slaves: item.slaves || "", location: item.location || "", googleLocation: item.googleLocation || "", latitude: item.latitude || "", longitude: item.longitude || "", tanks: Array.isArray(item.tanks) ? item.tanks.map(tank => ({ tankName: tank.tankName || "", tankLocation: tank.tankLocation || "" })) : [], motor_switches: Array.isArray(item.motor_switches) ? item.motor_switches.map(motor_switch => ({ from_tank: motor_switch.from_tank || "", from_location: motor_switch.from_location || "", to_tank: motor_switch.to_tank || "", to_location: motor_switch.to_location || "", })) : [], })); // Fetch pricing data from Iotprice database const getPrice = async (name, type) => { const priceData = await Iotprice.findOne({ name, type }); return priceData ? priceData.cost : 0; // Default to 0 if not found }; // Calculate price for masters, slaves, sensors, motor switches const masterPrice = await getPrice("master", "master"); const slavePrice = await getPrice("slave", "slave"); const sensorPrice = await getPrice("sensor", "sensor"); const motorSwitchPrice = await getPrice("motor_switch", "motor_switches"); // Calculate price for electricals let electricalPrice = 0; for (const item of formattedElectricals) { if (item.type === "cable") { electricalPrice += await getPrice("cable", item.wire); // wire field is type } else if (item.type === "switch") { electricalPrice += await getPrice("switch", item.switch); // switch field is type } } // Calculate total estimation price const totalEstimatedPrice = masterPrice + slavePrice + sensorPrice + motorSwitchPrice + electricalPrice; // Format current date and time in IST const formattedDateTime = dayjs().tz("Asia/Kolkata").format('DD-MMM-YYYY - HH:mm'); // Create a new SensorQuotation document const newQuotation = new SensorQuotation({ quatationId, customerId, master_connections: formattedMasterDetails, surveyId, quote_status: "sentfromsurvey", masters, slaves, sensors, motor_switches, electricals: formattedElectricals, datetime: formattedDateTime, estimated_price: totalEstimatedPrice, // Store estimated price }); const savedQuotation = await newQuotation.save(); reply.code(200).send({ success: true, message: 'Quotation for sensors created successfully.', data: savedQuotation, }); } catch (error) { console.error('Error creating quotation:', error); reply.code(500).send({ success: false, message: 'Failed to create quotation for sensors.', error: error.message, }); } }; exports.editQuotationForSensor = async (req, reply) => { try { const { quatationId } = req.params; // Get the ID of the quotation to edit const { masters, slaves, sensors, motor_switches, electricals, master_connections } = req.body; // Format electricals field const formattedElectricals = electricals.map((item) => ({ type: item.type || "", wire: item.wire || "", switch: item.switch || "", text: item.text || "", })); // Format master_connections field const formattedMasterDetails = master_connections.map((item) => ({ master_name: item.master_name || "", slaves: item.slaves || "", location: item.location || "", tanks: Array.isArray(item.tanks) ? item.tanks.map(tank => ({ tankName: tank.tankName || "", tankLocation: tank.tankLocation || "" })) : [] })); console.log("Formatted Master Connections:", formattedMasterDetails); // Debugging // Find and update the quotation const updatedQuotation = await SensorQuotation.findOneAndUpdate( { quatationId }, { masters, slaves, sensors, motor_switches, electricals: formattedElectricals, master_connections: formattedMasterDetails, // <- Ensure it's included updated_at: dayjs().tz("Asia/Kolkata").format('DD-MMM-YYYY - HH:mm'), }, { new: true } // Return the updated document ); if (!updatedQuotation) { return reply.code(404).send({ success: false, message: 'Quotation not found.', }); } reply.code(200).send({ success: true, message: 'Quotation updated successfully.', data: updatedQuotation, }); } catch (error) { console.error('Error updating quotation:', error); reply.code(500).send({ success: false, message: 'Failed to update quotation.', error: error.message, }); } }; exports.createEstimationPrice = async (req, reply) => { try { const { customerId,items } = req.body; const user = await User.findOne({ customerId }); if (!Array.isArray(items) || items.length === 0) { return reply.code(400).send({ message: "Items array is required and cannot be empty" }); } let totalEstimation = 0; const itemDetails = []; for (const item of items) { const { name, type, quantity } = item; // Fetch the unit price from IotPrice collection const priceEntry = await Iotprice.findOne({ name, type }); if (!priceEntry) { itemDetails.push({ name, type, quantity, unitPrice: null, totalCost: null, message: "Price not found" }); continue; } const unitPrice = priceEntry.cost; const totalCost = unitPrice * quantity; totalEstimation += totalCost; itemDetails.push({ name, type, quantity, unitPrice, totalCost }); } return reply.code(200).send({ items: itemDetails, estimatedTotal: totalEstimation, userDetails: user || null // Include user details in the response }); } catch (error) { console.error("Error calculating estimation:", error); return reply.code(500).send({ message: "Failed to calculate estimation" }); } }; exports.getallquotationdata = async (req, reply) => { try { const quotations = await SensorQuotation.find({}).lean(); // Use lean() for better performance // Extract unique customerIds from quotations const customerIds = [...new Set(quotations.map((q) => q.customerId).filter(Boolean))]; // Fetch customer details for all unique customerIds const customers = await User.find({ customerId: { $in: customerIds } }).lean(); // Convert customer array to a dictionary for quick lookup const customerMap = customers.reduce((acc, customer) => { acc[customer.customerId] = customer; return acc; }, {}); // Attach customer details to quotations const enrichedQuotations = quotations.map((quotation) => ({ ...quotation, customerDetails: customerMap[quotation.customerId] || null, // Attach customer details if found })); reply.send({ status_code: 200, data: enrichedQuotations, count: enrichedQuotations.length }); } catch (err) { console.error(err); reply.send({ error: err.message }); } }; exports.saveQuotationData = async (req, reply) => { try { const { quotationId } = req.params; // Retrieve the quotationId from the request parameters // Fetch the quotation data from the database const quotation = await SensorQuotation.findOne({ quatationId: quotationId }); console.log(quotation) if (!quotation) { return reply.code(404).send({ success: false, message: 'Quotation not found.' }); } // Extract the price-per-unit and total price values from the request body const { masters_quantity_price, masters_total_price, slaves_quantity_price, slaves_total_price, motor_switches_quantity_price, motor_switches_total_price, electricals_quantity_price, electricals_total_price, master_type_quantity_price, master_type_total_price, sensor_type_quantity_price, sensor_type_total_price, switch_type_quantity_price, switch_type_total_price, quotation_total_price } = req.body; // Update the quotation document with the data from the request body quotation.masters_quantity_price = masters_quantity_price; quotation.masters_total_price = masters_total_price; quotation.slaves_quantity_price = slaves_quantity_price; quotation.slaves_total_price = slaves_total_price; quotation.motor_switches_quantity_price = motor_switches_quantity_price; quotation.motor_switches_total_price = motor_switches_total_price; quotation.electricals_quantity_price = electricals_quantity_price; quotation.electricals_total_price = electricals_total_price; quotation.master_type_quantity_price = master_type_quantity_price; quotation.master_type_total_price = master_type_total_price; quotation.sensor_type_quantity_price = sensor_type_quantity_price; quotation.sensor_type_total_price = sensor_type_total_price; quotation.switch_type_quantity_price = switch_type_quantity_price; quotation.switch_type_total_price = switch_type_total_price; quotation.qutation_total_price = quotation_total_price; // Save the updated document back to the database await quotation.save(); // Send back the updated data reply.code(200).send({ success: true, message: 'Quotation data saved successfully.', data: quotation }); } catch (error) { console.error('Error saving quotation data to the database:', error); reply.code(500).send({ success: false, message: 'Failed to save quotation data.', error: error.message, }); } }; exports.getSinleQuotationData = async (req, reply) => { try { const { quotationId } = req.params; // Correct the parameter name // Fetch the quotation data from the database const quotation = await SensorQuotation.findOne({ quatationId: quotationId }); // Correctly referencing quotationId if (!quotation) { return reply.code(404).send({ success: false, message: 'Quotation not found.' }); } reply.code(200).send({ success: true, message: 'Quotation data retrieved successfully.', data: quotation }); } catch (error) { console.error('Error fetching quotation data:', error); reply.code(500).send({ success: false, message: 'Failed to retrieve quotation data.', error: error.message, }); } }; exports.addToCartHardwareItems = async (req, reply) => { try { const { productId, productName, description, GST, unitPrice, quantity, totalAmount, serialId } = req.body; const gstAmount = (GST / 100) * totalAmount; const grandTotal = totalAmount + gstAmount; const newCartItem = new HardwareCart({ productId, productName, description, GST, unitPrice, quantity, totalAmount, grandTotal, serialId }); const savedItem = await newCartItem.save(); reply.code(201).send({ message: 'Item added to cart', data: savedItem }); } catch (error) { console.error(error); reply.code(500).send({ message: 'Error adding item to cart', error }); } }; exports.addToCartService = async (req, reply) => { try { const { productId, productName, description, GST, unitPrice, quantity, totalAmount, serialId,installationId } = req.body; const gstAmount = (GST / 100) * totalAmount; const grandTotal = totalAmount + gstAmount; const newCartItem = new ServiceCart({ installationId, productId, productName, description, GST, unitPrice, quantity, totalAmount, grandTotal, serialId }); const savedItem = await newCartItem.save(); reply.code(201).send({ message: 'Item added to cart', data: savedItem }); } catch (error) { console.error(error); reply.code(500).send({ message: 'Error adding item to cart', error }); } }; exports.getquotationofinstalleranduser = async (req, reply) => { try { const surveyId = req.params.surveyId; const customerId = req.body.customerId; // Find the specific tank const result = await SensorQuotation.find({ surveyId: surveyId, customerId: customerId, }); if (!result) { return reply.send({ status_code: 404, error: "not found" }); } reply.send({ status_code: 200, data: result }); } catch (err) { throw boom.boomify(err); } }; exports.updateInstallationId = async (req, reply) => { try { const { _id } = req.params; const { installationId } = req.body; if (!_id || !installationId) { return reply.status(400).send({ error: "orderId and installationId are required" }); } // Update the order with the new installationId const updatedOrder = await Order.findByIdAndUpdate( _id, { installationId, status: "installer_assigned", // Updating the status updated_at: new Date().toISOString(), // Updating timestamp }, { new: true } ); if (!updatedOrder) { return reply.status(404).send({ error: "Order not found" }); } return reply.send({ status_code: 200, message: "Installation ID updated successfully", data: updatedOrder, }); } catch (err) { console.error("Error updating installationId:", err); return reply.status(500).send({ error: "Internal server error" }); } }; exports.getPendingOrders = async (req, reply) => { try { const pendingOrders = await Order.find({ status: "pending" }); if (!pendingOrders.length) { return reply.send({ status_code: 200, message: "No pending orders found", data: [], }); } return reply.send({ status_code: 200, message: "Pending orders fetched successfully", data: pendingOrders, }); } catch (err) { console.error("Error fetching pending orders:", err); return reply.status(500).send({ error: "Internal server error" }); } }; exports.handleEstimation = async (req, reply) => { try { const { customerId, items, estimatedTotal, action } = req.body; if (!customerId) { return reply.code(400).send({ message: "customerId is required" }); } if (!Array.isArray(items) || items.length === 0) { return reply.code(400).send({ message: "Items array is required and cannot be empty" }); } if (!estimatedTotal) { return reply.code(400).send({ message: "Estimated total is required" }); } if (!["accept", "reject"].includes(action)) { return reply.code(400).send({ message: "Invalid action, must be 'accept' or 'reject'" }); } // If rejected, return a response without creating an order if (action === "reject") { return reply.code(200).send({ message: "Estimation rejected" }); } // If accepted, generate unique Order ID const lastOrder = await EstimationOrder.findOne().sort({ createdAt: -1 }); let orderId = "AWS001"; if (lastOrder) { const lastNumber = parseInt(lastOrder.orderId.replace("AWS", ""), 10) + 1; orderId = `AWS${String(lastNumber).padStart(3, "0")}`; } // Create a new order in the database const newOrder = new EstimationOrder({ orderId, customerId, items, estimatedTotal, status: "pending" }); await newOrder.save(); return reply.code(200).send({ message: "Order created successfully", orderId, customerId, estimatedTotal, items, status: "pending" }); } catch (error) { console.error("Error handling estimation:", error); return reply.code(500).send({ message: "Failed to process estimation" }); } }; exports.editOrder = async (req, reply) => { try { const { orderId, customerId, items, estimatedTotal } = req.body; if (!orderId) { return reply.code(400).send({ message: "orderId is required" }); } // Find the existing order const existingOrder = await EstimationOrder.findOne({ orderId }); if (!existingOrder) { return reply.code(404).send({ message: "Order not found" }); } // Update the order in the database existingOrder.customerId = customerId; existingOrder.items = items; existingOrder.estimatedTotal = estimatedTotal; await existingOrder.save(); return reply.code(200).send({ message: "Order updated successfully", orderId, updatedItems: items, estimatedTotal }); } catch (error) { console.error("Error updating order:", error); return reply.code(500).send({ message: "Failed to update order" }); } }; exports.getOrdersByCustomer = async (req, reply) => { try { const { customerId } = req.params; if (!customerId) { return reply.code(400).send({ message: "customerId is required" }); } // Fetch orders with status 'pending' or 'accepted' for the given customer const orders = await EstimationOrder.find({ customerId, status: { $in: ["pending", "accepted"] } }); if (orders.length === 0) { return reply.code(404).send({ message: "No orders found for this customer" }); } return reply.code(200).send({ message: "Orders retrieved successfully", customerId, orders }); } catch (error) { console.error("Error fetching orders:", error); return reply.code(500).send({ message: "Failed to fetch orders" }); } }; exports.acceptQuotation = async (req, reply) => { try { const { quotationId } = req.params; let { action, storeId } = req.body; action = action.toLowerCase(); const quotation = await SensorQuotation.findOne({ quatationId: quotationId }); if (!quotation) { return reply.status(404).send({ error: "Quotation not found" }); } if (action === "reject") { await SensorQuotation.updateOne({ quatationId: quotationId }, { $set: { status: "rejected" } }); return reply.send({ status_code: 200, message: "Quotation rejected successfully", }); } else if (action === "accept") { const { customerId, masters, slaves, sensors, master_connections } = quotation; // Step 1: Block Masters let blockedMasters = []; if (parseInt(masters) > 0) { const availableMasters = await Insensors.find({ storeId, type: "master", status: "available" }) .limit(parseInt(masters)) .lean(); const masterIds = availableMasters.map(master => master._id); blockedMasters = availableMasters.map(master => ({ _id: master._id, hardwareId: master.hardwareId })); if (masterIds.length > 0) { await Insensors.updateMany( { _id: { $in: masterIds } }, { $set: { status: "blocked", customerId } } ); } } // Step 2: Assign Slaves to Masters let blockedSlaveIds = []; let blockedSlaves = []; for (let i = 0; i < master_connections.length; i++) { const masterData = master_connections[i]; if (i >= blockedMasters.length) break; const masterHardwareId = blockedMasters[i].hardwareId; const masterId = blockedMasters[i]._id; const slaveCount = parseInt(masterData.slaves) || 0; // Assign Slaves if (slaveCount > 0) { const availableSlaves = await Insensors.find({ storeId, type: "slave", status: "available" }) .limit(slaveCount) .lean(); const slaveIds = availableSlaves.map(slave => slave._id); blockedSlaveIds.push(...slaveIds); blockedSlaves.push(...availableSlaves.map(slave => ({ _id: slave._id, hardwareId: slave.hardwareId }))); for (let j = 0; j < availableSlaves.length; j++) { const slave = availableSlaves[j]; const tank = masterData.tanks?.[j] || {}; await Insensors.updateOne( { _id: slave._id }, { $set: { status: "blocked", customerId, connected_to: masterHardwareId, tankhardwareId: `tank-${j + 1}`, hardwareId: slave.hardwareId, tankName: tank.tankName || "", tankLocation: tank.tankLocation || "", }, } ); } } // Update tanks and motor switches for master await Insensors.updateOne( { _id: masterId }, { $set: { hardwareId: masterHardwareId, tanks: (masterData.tanks || []).map(tank => ({ tankName: tank.tankName || "", tankLocation: tank.tankLocation || "", })), motor_switches: masterData.motor_switches || [], }, } ); } // Step 2.5: Update master_connections.hardwareId const updatedMasterConnections = quotation.master_connections.map((conn, index) => { const plain = conn.toObject ? conn.toObject() : conn; return { ...plain, hardwareId: blockedMasters[index]?.hardwareId || null, }; }); // Step 3: Assign Sensors to Slaves if (parseInt(sensors) > 0 && blockedSlaves.length > 0) { const availableSensors = await Insensors.find({ storeId, type: "sensor", status: "available" }) .limit(parseInt(sensors)) .lean(); const sensorIds = availableSensors.map(sensor => sensor._id); for (let i = 0; i < sensorIds.length; i++) { const assignedSlave = blockedSlaves[i % blockedSlaves.length]; await Insensors.updateOne( { _id: sensorIds[i] }, { $set: { status: "blocked", customerId, connected_to: assignedSlave.hardwareId, }, } ); } } // Step 4: Update Sensor Stock const sensorTypes = [ { type: "master", count: parseInt(masters || 0) }, { type: "slave", count: parseInt(slaves || 0) }, { type: "sensor", count: parseInt(sensors || 0) }, ]; for (const sensor of sensorTypes) { if (sensor.count > 0) { const stock = await SensorStock.findOne({ storeId, type: sensor.type }); if (stock) { let available = stock.total_available || 0; let needed = sensor.count; let toBlock = Math.min(available, needed); let excessNeeded = needed - toBlock; if (toBlock > 0) { const availableSensors = await Insensors.find({ storeId, type: sensor.type, status: "available" }) .limit(toBlock) .lean(); const sensorIds = availableSensors.map(sensor => sensor._id); if (sensorIds.length > 0) { await Insensors.updateMany( { _id: { $in: sensorIds } }, { $set: { status: "blocked", customerId } } ); } } await SensorStock.updateOne( { storeId, type: sensor.type }, { $inc: { total_available: -toBlock, total_blocked: toBlock, excess_needed: excessNeeded > 0 ? excessNeeded : 0, }, } ); } } } // Step 5: Create Order const plainQuotation = quotation.toObject(); plainQuotation.master_connections = updatedMasterConnections; const newOrder = new Order({ ...plainQuotation, storeId, status: "pending", }); await newOrder.save(); // Step 6: Delete Quotation await SensorQuotation.deleteOne({ quatationId: quotationId }); return reply.send({ status_code: 200, message: "Quotation accepted, sensors blocked, and moved to Orders", data: newOrder, }); } else { return reply.status(400).send({ error: "Invalid action" }); } } catch (err) { console.error("Error processing quotation:", err); return reply.status(500).send({ error: "Internal server error" }); } }; exports.getOrdersByStoreId = async (req, reply) => { try { const { storeId } = req.params; if (!storeId) { return reply.status(400).send({ error: "storeId is required" }); } // Fetch orders with the matching storeId const orders = await Order.find({ storeId }); if (!orders.length) { return reply.send({ status_code: 200, message: "No orders found for this store", data: [], }); } // Fetch customer details & allocated sensors for each order const ordersWithDetails = await Promise.all( orders.map(async (order) => { // Fetch customer details const customer = await User.findOne({ customerId: order.customerId }).lean(); // Fetch allocated sensors for this customer const allocatedSensors = await Insensors.find({ storeId, customerId: order.customerId, // Match only sensors allocated to this customer status: "blocked", // Only fetch sensors that are allocated (blocked) }).lean(); return { ...order.toObject(), customer: customer || null, // Include customer details or null if not found allocated_sensors: allocatedSensors, // List of allocated sensors }; }) ); return reply.send({ status_code: 200, message: "Orders fetched successfully", data: ordersWithDetails, }); } catch (err) { console.error("Error fetching orders:", err); return reply.status(500).send({ error: "Internal server error" }); } }; // exports.getOrdersByInstallationId = async (req, reply) => { // try { // const { installationId } = req.params; // if (!installationId) { // return reply.status(400).send({ error: "installationId is required" }); // } // // Fetch all orders by installationId // const orders = await Order.find({ installationId }); // if (!orders.length) { // return reply.send({ // status_code: 200, // message: "No orders found for this installation", // data: { // customers: [], // orders: [] // } // }); // } // // Get unique customerIds from orders // const uniqueCustomerIds = [...new Set(orders.map(order => order.customerId))]; // // Fetch all customers in a single query // const customers = await User.find({ customerId: { $in: uniqueCustomerIds } }).lean(); // // Map customerId -> customer object // const customerMap = {}; // customers.forEach(c => { // customerMap[c.customerId] = c; // }); // // For each order, attach allocated sensors only // const ordersWithSensors = await Promise.all( // orders.map(async (order) => { // const allocatedSensors = await Insensors.find({ // storeId: order.storeId, // customerId: order.customerId, // status: "blocked" // }).lean(); // return { // ...order.toObject(), // allocated_sensors: allocatedSensors // }; // }) // ); // return reply.send({ // status_code: 200, // message: "Orders fetched successfully", // data: customers // // data: { // // customers, // // // orders: ordersWithSensors // // } // }); // } catch (err) { // console.error("Error fetching orders:", err); // return reply.status(500).send({ error: "Internal server error" }); // } // }; // exports.getOrdersByInstallationId = async (req, reply) => { // try { // const { installationId } = req.params; // if (!installationId) { // return reply.status(400).send({ error: "installationId is required" }); // } // // Fetch orders with the matching installationId // const orders = await Order.find({ installationId }); // if (!orders.length) { // return reply.send({ // status_code: 200, // message: "No orders found for this installation", // data: [], // }); // } // const uniqueCustomersMap = new Map(); // // Build unique customerId-based map // for (const order of orders) { // if (!uniqueCustomersMap.has(order.customerId)) { // uniqueCustomersMap.set(order.customerId, order); // } // } // // Only keep one order per customerId // const uniqueOrders = Array.from(uniqueCustomersMap.values()); // // Enrich with customer and sensor info // const ordersWithDetails = await Promise.all( // uniqueOrders.map(async (order) => { // const customer = await User.findOne({ customerId: order.customerId }).lean(); // const allocatedSensors = await Insensors.find({ // storeId: order.storeId, // customerId: order.customerId, // status: "blocked", // }).lean(); // return { // ...order.toObject(), // customer: customer || null, // allocated_sensors: allocatedSensors, // }; // }) // ); // return reply.send({ // status_code: 200, // message: "Orders fetched successfully", // data: ordersWithDetails, // }); // } catch (err) { // console.error("Error fetching orders:", err); // return reply.status(500).send({ error: "Internal server error" }); // } // }; exports.getOrdersByInstallationId = async (req, reply) => { try { const { installationId } = req.params; if (!installationId) { return reply.status(400).send({ error: "installationId is required" }); } // Fetch orders with the matching installationId const orders = await Order.find({ installationId }); if (!orders.length) { return reply.send({ status_code: 200, message: "No orders found for this installation", data: [], }); } const uniqueCustomersMap = new Map(); // Build unique customerId-based map for (const order of orders) { if (!uniqueCustomersMap.has(order.customerId)) { uniqueCustomersMap.set(order.customerId, order); } } // Only keep one order per customerId const uniqueOrders = Array.from(uniqueCustomersMap.values()); // Enrich with customer and sensor info, AND update work_status if missing const ordersWithDetails = await Promise.all( uniqueOrders.map(async (order) => { const customer = await User.findOne({ customerId: order.customerId }).lean(); const allocatedSensors = await Insensors.find({ storeId: order.storeId, customerId: order.customerId, status: "blocked", }).lean(); // โœ… If missing, update work_status to "active" and save in DB if (!order.work_status) { order.work_status = "active"; await order.save(); // This persists the change to MongoDB } return { ...order.toObject(), customer: customer || null, allocated_sensors: allocatedSensors, work_status: order.work_status // Now always persisted }; }) ); return reply.send({ status_code: 200, message: "Orders fetched successfully", data: ordersWithDetails, }); } catch (err) { console.error("Error fetching orders:", err); return reply.status(500).send({ error: "Internal server error" }); } }; exports.getallocatedsensorstouser= async (req, reply) => { try { const { customerId } = req.params; if (!customerId) { return reply.status(400).send({ error: "customerId is required" }); } // Fetch orders with the matching storeId const allocated_iots = await Insensors.find({ customerId }); if (!allocated_iots.length) { return reply.send({ status_code: 200, message: "No sensors found for this store", data: [], }); } return reply.send({ status_code: 200, message: "iots fetched successfully", data: allocated_iots, }); } catch (err) { console.error("Error fetching iots:", err); return reply.status(500).send({ error: "Internal server error" }); } }; const crypto = require("crypto"); exports.replaceAndRepair = async (req, reply) => { try { const { customerId } = req.params; const { items } = req.body; if (!customerId || !Array.isArray(items) || items.length === 0) { return reply.code(400).send({ error: "customerId and items[] are required" }); } const replacements = []; for (const item of items) { const { type, hardwareId } = item; console.log(`๐Ÿ” Processing ${type} with hardwareId: ${hardwareId}`); const existing = await Insensors.findOne({ hardwareId, type, customerId }); if (!existing) { console.warn(`โš ๏ธ No existing ${type} found for hardwareId: ${hardwareId}`); continue; } // Mark existing as repair await Insensors.updateOne( { _id: existing._id }, { $set: { status: "repair", outforrepairdate: new Date().toISOString() } } ); console.log(`๐Ÿ›  Marked old ${type} ${hardwareId} as repair`); // Find replacement const replacement = await Insensors.findOne({ type, status: "available", storeId: existing.storeId }); if (!replacement) { console.warn(`โš ๏ธ No available replacement found for ${type} at store ${existing.storeId}`); continue; } console.log(`โœ… Found replacement ${replacement.hardwareId} for ${type}`); const updateData = { status: "blocked", customerId: existing.customerId, tankName: existing.tankName, tankLocation: existing.tankLocation, storeId: existing.storeId, model: existing.model, tankhardwareId: existing.tankhardwareId, masterId: existing.masterId, masterName: existing.masterName, location: existing.location }; await Insensors.updateOne({ _id: replacement._id }, { $set: updateData }); console.log(`โœ… Updated replacement ${type} ${replacement.hardwareId} with previous config`); // === Cascade updates === if (type === "master") { const connectedSlaves = await Insensors.find({ type: "slave", connected_to: hardwareId, customerId }); for (const slave of connectedSlaves) { await Insensors.updateOne( { _id: slave._id }, { $set: { connected_to: replacement.hardwareId } } ); console.log(`๐Ÿ” Updated slave ${slave.hardwareId} โ†’ connected_to: ${replacement.hardwareId}`); } } if (type === "slave") { await Insensors.updateOne( { _id: replacement._id }, { $set: { connected_to: existing.connected_to } } ); console.log(`๐Ÿ” New slave ${replacement.hardwareId} โ†’ connected_to: ${existing.connected_to}`); const connectedSensors = await Insensors.find({ type: "sensor", connected_to: hardwareId, customerId }); for (const sensor of connectedSensors) { await Insensors.updateOne( { _id: sensor._id }, { $set: { connected_to: replacement.hardwareId } } ); console.log(`๐Ÿ” Updated sensor ${sensor.hardwareId} โ†’ connected_to: ${replacement.hardwareId}`); } } if (type === "sensor") { await Insensors.updateOne( { _id: replacement._id }, { $set: { connected_to: existing.connected_to } } ); console.log(`๐Ÿ” Sensor ${replacement.hardwareId} connected to same slave: ${existing.connected_to}`); } // Log replacement replacements.push({ type, oldHardwareId: hardwareId, newHardwareId: replacement.hardwareId }); console.log(`๐Ÿ“ฆ Logged replacement: ${type} ${hardwareId} โžœ ${replacement.hardwareId}`); } console.log("๐Ÿงพ Final replacements:", replacements); // Create repair log const packageId = "PKG-" + crypto.randomBytes(4).toString("hex").toUpperCase(); const otp = Math.floor(100000 + Math.random() * 900000).toString(); const repairLog = new Repairorder({ customerId, packageId, otp, replacements, createdAt: new Date() }); await repairLog.save(); console.log("โœ… RepairLog saved"); return reply.send({ status_code: 200, message: "Repaired and replaced successfully", data: { packageId, otp, replacements, createdAt: repairLog.createdAt } }); } catch (err) { console.error("โŒ Error during replacement:", err); return reply.code(500).send({ error: "Internal Server Error" }); } };