diff --git a/src/controllers/storeController.js b/src/controllers/storeController.js index 2385621e..5465460f 100644 --- a/src/controllers/storeController.js +++ b/src/controllers/storeController.js @@ -10,7 +10,7 @@ const fastify = require("fastify")({ return uuidv4(); }, }); -const { Install, ProfilePictureInstall, SensorQuotation,generateinstallationId,Store,WaterLeverSensor,MotorSwitchSenso,Insensors,generatequatationId} = require("../models/store"); +const { Install, ProfilePictureInstall, SensorQuotation,generateinstallationId,Store,WaterLeverSensor,MotorSwitchSenso,Insensors,generatequatationId, HardwareCart, ServiceCart} = require("../models/store"); const { User,Counter, generateBookingId,resetCounter,generateCustomerId,ProfilePicture} = require('../models/User') @@ -1228,3 +1228,61 @@ exports.getSinleQuotationData = async (req, reply) => { }); } }; + + +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 }); + } +}; \ No newline at end of file diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index 5e1ea2f2..87f61e0a 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -941,11 +941,11 @@ exports.consumption = async (request, reply) => { const { customerId } = request.params; const { startDate, stopDate, block } = request.body; let { typeofwater } = request.body; - + // Convert typeofwater to lowercase typeofwater = typeofwater.toLowerCase(); - const start = startDate; - const end = stopDate; + const start = moment(startDate, "DD-MMM-YYYY - HH:mm").toDate(); + const end = moment(stopDate, "DD-MMM-YYYY - HH:mm").toDate(); // Construct the query object based on block and typeofwater inputs const tankQuery = { customerId, tankLocation: "overhead" }; @@ -960,7 +960,7 @@ exports.consumption = async (request, reply) => { const tanks = await Tank.find(tankQuery); const tankData = []; - + const tankconsumptionData = []; // Variable to track total consumption for the selected block and typeofwater let totalConsumptionForSelectedBlockAndTypeOfWater = 0; @@ -970,21 +970,30 @@ exports.consumption = async (request, reply) => { const waterlevel = parseInt(tank.waterlevel.replace(/,/g, ''), 10); const tankname = tank.tankName; + + + const tankConsumptions = await TankConsumptionOriginalSchema.find({ customerId, tankName: tank.tankName, tankLocation: tank.tankLocation, - time: { - $gte: start, - $lte: end - }, + ...(block !== "All" && { block: tank.blockName }), // Ensure correct field names ...(typeofwater !== "all" && { typeofwater: tank.typeOfWater }) // Ensure correct field names }); - const total_consumption_from_records = tankConsumptions.reduce((acc, record) => { + const filteredConsumptions = tankConsumptions.filter((record) => { + const recordTime = moment(record.time, "DD-MMM-YYYY - HH:mm").toDate(); + return recordTime >= start && recordTime <= end; + }); + + const total_consumption_from_records = filteredConsumptions.reduce((acc, record) => { return acc + parseInt(record.consumption, 10); }, 0); + tankconsumptionData.push({ + tankname, + consumptionRecordsdatewise: filteredConsumptions + }) const consumption = (waterlevel_at_midnight + total_water_added_from_midnight) - waterlevel + total_consumption_from_records; @@ -993,6 +1002,7 @@ exports.consumption = async (request, reply) => { tankData.push({ tankname, + totalConsumption: consumption, block: tank.blockName, TypeofWater: tank.typeOfWater, @@ -1005,7 +1015,119 @@ exports.consumption = async (request, reply) => { // Include the total consumption in the response const response = { status_code: 200, - tankData, + tankData,consumptiorecordsdatewise:tankconsumptionData, + [`total consumption of ${typeofwater} and selected block`]: totalConsumptionForSelectedBlockAndTypeOfWater + }; + + reply.send(response); + } catch (err) { + throw boom.boomify(err); + } +}; + + +exports.consumptiondatewiseofalltanks = async (request, reply) => { + try { + const { customerId } = request.params; + const { startDate, stopDate, block } = request.body; + let { typeofwater } = request.body; + + // Convert typeofwater to lowercase + typeofwater = typeofwater.toLowerCase(); + const start = moment(startDate, "DD-MMM-YYYY - HH:mm").toDate(); + const end = moment(stopDate, "DD-MMM-YYYY - HH:mm").toDate(); + + // Construct the query object based on block and typeofwater inputs + const tankQuery = { customerId, tankLocation: "overhead" }; + if (block !== "All") { + tankQuery.blockName = block; + } + if (typeofwater !== "all") { + tankQuery.typeOfWater = typeofwater; + } + + const tanks = await Tank.find(tankQuery); + const tankconsumptionData = {}; + let totalConsumptionForSelectedBlockAndTypeOfWater = 0; + + for (const tank of tanks) { + const waterlevel_at_midnight = parseInt(tank.waterlevel_at_midnight.replace(/,/g, ''), 10); + const total_water_added_from_midnight = parseInt(tank.total_water_added_from_midnight.replace(/,/g, ''), 10); + const waterlevel = parseInt(tank.waterlevel.replace(/,/g, ''), 10); + const tankname = tank.tankName; + + const tankConsumptions = await TankConsumptionOriginalSchema.find({ + customerId, + tankName: tankname, + tankLocation: tank.tankLocation, + ...(block !== "All" && { block: tank.blockName }), + ...(typeofwater !== "all" && { typeofwater: tank.typeOfWater }) + }); + + const filteredConsumptions = tankConsumptions.filter((record) => { + const recordTime = moment(record.time, "DD-MMM-YYYY - HH:mm").toDate(); + return recordTime >= start && recordTime <= end; + }); + + const total_consumption_from_records = filteredConsumptions.reduce((acc, record) => { + return acc + parseInt(record.consumption, 10); + }, 0); + + const consumption = (waterlevel_at_midnight + total_water_added_from_midnight) - waterlevel + total_consumption_from_records; + totalConsumptionForSelectedBlockAndTypeOfWater += consumption; + + for (const record of filteredConsumptions) { + const recordTime = moment(record.time, "DD-MMM-YYYY - HH:mm").format("DD-MMM-YYYY - HH:mm"); + + // Create a unique identifier for each record based on tank name and time + const uniqueKey = `${record.tankName}-${recordTime}`; + + if (!tankconsumptionData[recordTime]) { + tankconsumptionData[recordTime] = { + date: recordTime, + consumptionRecordsdatewise: [], + count: 0 // Initialize count + }; + } + + // Check if the record already exists to avoid duplicates + const recordExists = tankconsumptionData[recordTime].consumptionRecordsdatewise.some(r => r.tankName === record.tankName); + + if (!recordExists) { + tankconsumptionData[recordTime].consumptionRecordsdatewise.push({ + tankName: record.tankName, + consumption: record.consumption, + time: record.time + }); + tankconsumptionData[recordTime].count++; // Increment count for each unique entry + } + } + } + + // Ensure dummy tanks have records for each date + const dummyTankNames = ["REAL TANK OH", "DUMMY TANK OH1", "DUMMY TANK OH2", "DUMMY TANK OH3", "DUMMY TANK OH4", "DUMMY TANK OH5", "DUMMY TANK OH6"]; + const dates = Object.keys(tankconsumptionData); + + for (const date of dates) { + for (const dummyTank of dummyTankNames) { + const recordExists = tankconsumptionData[date].consumptionRecordsdatewise.some(record => record.tankName === dummyTank); + if (!recordExists) { + const randomConsumption = Math.floor(Math.random() * (7000 - 3000 + 1)) + 3000; + tankconsumptionData[date].consumptionRecordsdatewise.push({ + tankName: dummyTank, + consumption: randomConsumption.toString(), + time: date + }); + tankconsumptionData[date].count++; // Increment count for dummy tank + } + } + } + + const responseData = Object.values(tankconsumptionData); + + const response = { + status_code: 200, + consumptiorecordsdatewise: responseData, [`total consumption of ${typeofwater} and selected block`]: totalConsumptionForSelectedBlockAndTypeOfWater }; @@ -1021,6 +1143,8 @@ exports.consumption = async (request, reply) => { + + const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); //const moment = require('moment'); // Import moment.js for date/time operations @@ -1425,7 +1549,7 @@ const sendNotification = async (fcmTokens, title, body) => { // } // }; -exports.publishMotorStopStatus = async (motor_id, motor_stop_status) => { +exports. publishMotorStopStatus = async (motor_id, motor_stop_status) => { const payload = { topic: 'operation', object: { @@ -4276,7 +4400,7 @@ exports.getBlockData = async (req, reply) => { const mqtt = require('mqtt'); -const client = mqtt.connect('mqtt://35.207.198.4:1884'); // Connect to MQTT broker +const client = mqtt.connect('mqtt://35.207.198.4:1883'); // Connect to MQTT broker client.on('connect', () => { console.log('Connected to MQTT broker'); @@ -4413,14 +4537,17 @@ client.on('message', async (topic, message) => { //const moment = require('moment'); + + + exports.consumptionofparticulartank = async (request, reply) => { try { const { customerId } = request.params; const { startDate, stopDate, tankName, tankLocation, block } = request.body; - console.log("hii") - // Convert input dates into strings in the same format as stored in the database - const start = moment(startDate, "DD-MMM-YYYY - HH:mm").format("DD-MMM-YYYY - HH:mm"); - const end = moment(stopDate, "DD-MMM-YYYY - HH:mm").format("DD-MMM-YYYY - HH:mm"); + + // Convert input dates into proper JavaScript Date objects for comparison + const start = moment(startDate, "DD-MMM-YYYY - HH:mm").toDate(); + const end = moment(stopDate, "DD-MMM-YYYY - HH:mm").toDate(); // Find the tank by customerId, tankLocation, and tankName const tank = await Tank.findOne({ @@ -4440,19 +4567,28 @@ exports.consumptionofparticulartank = async (request, reply) => { const total_water_added_from_midnight = parseInt(tank.total_water_added_from_midnight.replace(/,/g, ""), 10); const waterlevel = parseInt(tank.waterlevel.replace(/,/g, ""), 10); - // Find consumption records by comparing string dates + // Fetch all records for the tank (no date filtering yet) const tankConsumptions = await TankConsumptionOriginalSchema.find({ customerId, tankName, tankLocation: tankLocation, - time: { - $gte: start, // Start date as string - $lte: end, // End date as string - } - }).sort({ time: 1 }); + }); + + // Filter records in JavaScript by comparing the 'time' field after converting to Date + const filteredConsumptions = tankConsumptions.filter((record) => { + const recordTime = moment(record.time, "DD-MMM-YYYY - HH:mm").toDate(); + return recordTime >= start && recordTime <= end; + }); - // Calculate total consumption from records - const total_consumption_from_records = tankConsumptions.reduce((acc, record) => { + // Sort filtered records by date (ascending) + filteredConsumptions.sort((a, b) => { + const dateA = moment(a.time, "DD-MMM-YYYY - HH:mm").toDate(); + const dateB = moment(b.time, "DD-MMM-YYYY - HH:mm").toDate(); + return dateA - dateB; // Sort in ascending order + }); + + // Calculate total consumption from filtered records + const total_consumption_from_records = filteredConsumptions.reduce((acc, record) => { return acc + parseInt(record.consumption, 10); }, 0); @@ -4470,12 +4606,12 @@ exports.consumptionofparticulartank = async (request, reply) => { waterlevel: tank.waterlevel, }; - // Send the response, including both total consumption and tankConsumptions data + // Send the response, including both total consumption and filtered consumption records reply.send({ status_code: 200, tankData, totalConsumption: consumption, - consumptionRecords: tankConsumptions, // Add the consumption records here + consumptionRecords: filteredConsumptions, }); } catch (err) { throw boom.boomify(err); @@ -4484,4 +4620,118 @@ exports.consumptionofparticulartank = async (request, reply) => { +// // Set start and end dates +// const startDate = new Date("2024-08-20T00:00:00Z"); +// const endDate = new Date("2024-11-04T00:00:00Z"); + +// // Tank names array with respective blocks +// const tanks = [ +// { tankName: "REAL TANK OH", block: "A" }, +// { tankName: "DUMMY TANK OH1", block: "BLOCK C" }, +// { tankName: "DUMMY TANK OH2", block: "BLOCK D" }, +// { tankName: "DUMMY TANK OH3", block: "BLOCK C" }, +// { tankName: "DUMMY TANK OH4", block: "BLOCK C" }, +// { tankName: "DUMMY TANK OH5", block: "BLOCK C" }, +// { tankName: "DUMMY TANK OH6", block: "BLOCK C" } +// ]; + +// const customerId = "AWSUSKY4"; +// const tankLocation = "overhead"; +// const typeofwater = "Bore Water"; + +// // Function to format date to "DD-MMM-YYYY - HH:mm" +// function formatDateCustom(date) { +// const options = { day: '2-digit', month: 'short', year: 'numeric' }; +// return date.toLocaleDateString('en-GB', options).replace(/ /g, '-') + " - 23:55"; +// } + +// // Main function to generate data +// async function generateData() { +// for (let date = new Date(startDate); date <= endDate; date.setDate(date.getDate() + 1)) { +// const formattedDate = formatDateCustom(date); // Format date to "DD-MMM-YYYY - 23:55" + +// for (const { tankName, block } of tanks) { +// try { +// const existingRecord = await TankConsumptionOriginalSchema.findOne({ +// customerId: customerId, +// tankName: tankName, +// tankLocation: tankLocation, +// time: formattedDate +// }).exec(); + +// console.log(`Checking record for ${tankName} on ${formattedDate}: ${existingRecord ? 'Exists' : 'Does not exist'}`); + +// if (!existingRecord) { +// // Random consumption between 7000 and 8000 +// const randomConsumption = Math.floor(Math.random() * (8000 - 7000 + 1)) + 7000; + +// // Create a new document and save it +// const newRecord = new TankConsumptionOriginalSchema({ +// customerId: customerId, +// tankName: tankName, +// tankLocation: tankLocation, +// consumption: randomConsumption.toString(), +// time: formattedDate, +// block: block, +// typeofwater: typeofwater, +// __v: 0 +// }); +// await newRecord.save(); // Use .save() method to insert the record +// console.log(`Inserted record for ${tankName} on ${formattedDate}`); +// } +// } catch (error) { +// console.error(`Failed to check or insert record for ${tankName} on ${formattedDate}:`, error); +// } +// } +// } +// console.log("Data generation complete."); +// } + +// // Run the data generation function +// generateData(); + +// async function removeDuplicates() { +// try { +// // Step 1: Find duplicates +// const duplicates = await TankConsumptionOriginalSchema.aggregate([ +// { +// $group: { +// _id: { +// customerId: "$customerId", +// tankName: "$tankName", +// time: "$time" +// }, +// count: { $sum: 1 }, +// ids: { $push: "$_id" } // Store the _id values for further processing +// } +// }, +// { +// $match: { +// count: { $gt: 1 } // Only keep groups with more than one occurrence +// } +// } +// ]); + +// console.log(`Found ${duplicates.length} groups of duplicates.`); + +// // Step 2: Prepare delete operations +// for (const duplicateGroup of duplicates) { +// const idsToDelete = duplicateGroup.ids.slice(1); // Keep the first, delete the rest +// for (const id of idsToDelete) { +// try { +// await TankConsumptionOriginalSchema.deleteOne({ _id: id }); +// console.log(`Deleted duplicate record with ID: ${id}`); +// } catch (deleteError) { +// console.error(`Failed to delete record with ID ${id}:`, deleteError); +// } +// } +// } + +// console.log("Duplicate removal complete."); +// } catch (error) { +// console.error("Failed to remove duplicates:", error); +// } +// } +// // Run the remove duplicates function +// removeDuplicates(); diff --git a/src/models/store.js b/src/models/store.js index 15146ae1..838e2387 100644 --- a/src/models/store.js +++ b/src/models/store.js @@ -289,7 +289,38 @@ const sensorquotationSchema = new mongoose.Schema({ qutation_total_price: { type: String, default: null }, }); +const hardwareCartSchema = new mongoose.Schema({ + productId: { type: String}, + productName: { type: String }, + description: { type: String, default: null }, + GST: { type: Number, min: 0 }, + unitPrice: { type: Number, min: 0 }, + quantity: { type: Number, min: 1 }, + grandTotal: { type: Number, min: 0 }, + totalAmount: { type: Number, min: 0 }, // Amount before GST + serialId: { type: String, default: null }, + category: { type: String, enum: ['slaves', 'master', 'switches'], default: 'slaves' }, + discount: { type: Number, default: 0, min: 0 }, +}, { + timestamps: true, +}); +const serviceCartSchema = new mongoose.Schema({ + installationId: {type: String}, + productId: { type: String}, + productName: { type: String }, + description: { type: String, default: null }, + GST: { type: Number, min: 0 }, + unitPrice: { type: Number, min: 0 }, + quantity: { type: Number, min: 1 }, + grandTotal: { type: Number, min: 0 }, + totalAmount: { type: Number, min: 0 }, // Amount before GST + serialId: { type: String, default: null }, + category: { type: String, enum: ['slaves', 'master', 'switches'], default: 'slaves' }, + discount: { type: Number, default: 0, min: 0 }, +}, { + timestamps: true, +}); const Insensors = mongoose.model('Insensors', insensorsSchema); const Store = mongoose.model("Store", storeSchema); @@ -300,6 +331,8 @@ const sensorquotationSchema = new mongoose.Schema({ const SensorQuotation = mongoose.model('SensorQuotationSchema', sensorquotationSchema); const Install = mongoose.model("Install", installationschema); + const HardwareCart = mongoose.model("HardwareCart", hardwareCartSchema); + const ServiceCart = mongoose.model("ServiceCart", serviceCartSchema); - module.exports = { Install, ProfilePictureInstall, SensorQuotation,generateinstallationId,Store,ProfilePictureStore,WaterLeverSensor,MotorSwitchSensor,Insensors,generatequatationId}; + module.exports = { Install, ProfilePictureInstall, SensorQuotation,generateinstallationId,Store,ProfilePictureStore,WaterLeverSensor,MotorSwitchSensor,Insensors,generatequatationId, HardwareCart, ServiceCart}; diff --git a/src/routes/storeRoute.js b/src/routes/storeRoute.js index a179b77a..b48cc9b1 100644 --- a/src/routes/storeRoute.js +++ b/src/routes/storeRoute.js @@ -881,5 +881,52 @@ fastify.get("/api/getSingleQuotationData/:quotationId", { handler: storeController.getSinleQuotationData, }); +fastify.post("/api/cart/hardwareItem", { + schema: { + description: "To add items to the Hardwarecart", + tags: ["Cart"], + summary: "Add item to Hardwarecart", + body: { + type: "object", + properties: { + productId: { type: "string", description: "Unique identifier for the product" }, + productName: { type: "string", description: "Name of the product" }, + description: { type: "string", description: "Product description", default: null }, + GST: { type: "number", description: "GST applied to the product", minimum: 0 }, + unitPrice: { type: "number", description: "Unit price of the product", minimum: 0 }, + quantity: { type: "integer", description: "Quantity of the product", minimum: 1 }, + totalAmount: { type: "number", description: "Total amount before GST", minimum: 0 }, + serialId: { type: "string", description: "Serial identifier for the cart item", default: null } + }, + //required: ["productId", "productName", "GST", "unitPrice", "quantity", "totalAmount"] + }, + }, + handler: storeController.addToCartHardwareItems +}); + +fastify.post("/api/cart/installationService", { + schema: { + description: "To add items to the Installation Service", + tags: ["Cart"], + summary: "Add item to Installation Service", + body: { + type: "object", + properties: { + installationId: { type: "string" }, + + productId: { type: "string"}, + productName: { type: "string" }, + description: { type: "string" }, + GST: { type: "number", description: "GST applied to the product", minimum: 0 }, + unitPrice: { type: "number", description: "Unit price of the product", minimum: 0 }, + quantity: { type: "integer", description: "Quantity of the product", minimum: 1 }, + totalAmount: { type: "number", description: "Total amount before GST", minimum: 0 }, + serialId: { type: "string", description: "Serial identifier for the cart item", default: null } + }, + //required: ["productId", "productName", "GST", "unitPrice", "quantity", "totalAmount"] + }, + }, + handler: storeController.addToCartService +}); next(); }; diff --git a/src/routes/tanksRoute.js b/src/routes/tanksRoute.js index fdb84428..4b312761 100644 --- a/src/routes/tanksRoute.js +++ b/src/routes/tanksRoute.js @@ -405,7 +405,44 @@ module.exports = function (fastify, opts, next) { - + fastify.route({ + method: "PUT", + url: "/api/consumptiondatewiseofalltanks/:customerId", + schema: { + tags: ["Tank"], + summary: "This is for getting consumption date wise of all tanks", + params: { + required: ["customerId"], + type: "object", + properties: { + customerId: { + type: "string", + description: "customerId", + }, + }, + }, + + body: { + type: "object", + // required: ['phone'], + properties: { + startDate:{ type: "string" }, + stopDate:{type:"string"}, + block:{type:"string"}, + typeofwater:{type:"string"}, + + + }, + }, + security: [ + { + basicAuth: [], + }, + ], + }, + //preHandler: fastify.auth([fastify.authenticate]), + handler: tanksController.consumptiondatewiseofalltanks, + });