From ddaadce053fbcbc8e772d1761607f5d2b66f33f8 Mon Sep 17 00:00:00 2001 From: Sibunnayak Date: Wed, 30 Oct 2024 19:17:13 +0530 Subject: [PATCH] stock reports --- resources/Reports/OpeningInventoryReports.js | 109 ++++++++++++++++++- resources/Reports/ReportRoute.js | 13 ++- 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/resources/Reports/OpeningInventoryReports.js b/resources/Reports/OpeningInventoryReports.js index 44e89e2..8ae5746 100644 --- a/resources/Reports/OpeningInventoryReports.js +++ b/resources/Reports/OpeningInventoryReports.js @@ -3,6 +3,105 @@ import { Product } from "../Products/ProductModel.js"; import { PDStock } from "../Stock/PdStockModel.js"; import { RDStock } from "../Stock/RdStockModel.js"; +export const getProductsWithOpenInventoryInfo = async (req, res) => { + try { + const { page = 1, show = 10, name, category, brand } = req.query; + + // Pagination setup + const limit = parseInt(show, 10); + const skip = (parseInt(page, 10) - 1) * limit; + + // Search filters + const searchCriteria = {}; + if (name) searchCriteria.name = { $regex: name, $options: "i" }; + if (category) searchCriteria.category = mongoose.Types.ObjectId(category); + if (brand) searchCriteria.brand = mongoose.Types.ObjectId(brand); + + // Step 1: Fetch filtered products with population + const products = await Product.find(searchCriteria) + .skip(skip) + .limit(limit) + .populate("brand", "brandName") // Populate brandName + .populate("category", "categoryName") // Populate categoryName + .exec(); + + // Step 2: Collect all product SKUs to find corresponding PDs and RDs with stock + const productSKUs = products.map((product) => product.SKU); + + // Step 3: Fetch all PDs with non-zero opening inventory for these products using SKU + const pdOIs = await PDStock.aggregate([ + { $unwind: "$products" }, + { + $match: { + "products.openingInventory": { $gt: 0 }, + "products.SKU": { $in: productSKUs }, + }, + }, + { + $group: { + _id: "$products.SKU", + pdCount: { $sum: 1 }, + }, + }, + ]); + + // Step 4: Fetch all RDs with non-zero opening inventory for these products using SKU + const rdOIs = await RDStock.aggregate([ + { $unwind: "$products" }, + { + $match: { + "products.openingInventory": { $gt: 0 }, + "products.SKU": { $in: productSKUs }, + }, + }, + { + $group: { + _id: "$products.SKU", + rdCount: { $sum: 1 }, + }, + }, + ]); + + // Step 5: Prepare a mapping of PD and RD counts by SKU + const pdMap = {}; + pdOIs.forEach((pd) => { + pdMap[pd._id] = pd.pdCount; + }); + + const rdMap = {}; + rdOIs.forEach((rd) => { + rdMap[rd._id] = rd.rdCount; + }); + + // Step 6: Combine product info with PD/RD counts using SKU + const productData = products.map((product) => ({ + SKU: product.SKU, + name: product.name, + brand: product.brand?.brandName || "N/A", // Access brandName here + category: product.category?.categoryName || "N/A", // Access categoryName here + allPDs: pdMap[product.SKU] || 0, + allRDs: rdMap[product.SKU] || 0, + allPdAndRd: (pdMap[product.SKU] || 0) + (rdMap[product.SKU] || 0), + })); + + // Step 7: Get total count for pagination + const totalCount = await Product.countDocuments(searchCriteria); + + // Step 8: Respond with paginated results and total count + res.status(200).json({ + success: true, + data: productData, + pagination: { + total: totalCount, + page: parseInt(page, 10), + pages: Math.ceil(totalCount / limit), + }, + }); + } catch (error) { + res.status(500).json({ success: false, message: error.message }); + } +}; + export const getProductsWithStockInfo = async (req, res) => { try { const { page = 1, show = 10, name, category, brand } = req.query; @@ -28,12 +127,12 @@ export const getProductsWithStockInfo = async (req, res) => { // Step 2: Collect all product SKUs to find corresponding PDs and RDs with stock const productSKUs = products.map((product) => product.SKU); - // Step 3: Fetch all PDs with non-zero opening inventory for these products using SKU + // Step 3: Fetch all PDs with non-zero Stock for these products using SKU const pdStocks = await PDStock.aggregate([ { $unwind: "$products" }, { $match: { - "products.openingInventory": { $gt: 0 }, + "products.Stock": { $gt: 0 }, "products.SKU": { $in: productSKUs }, }, }, @@ -45,12 +144,12 @@ export const getProductsWithStockInfo = async (req, res) => { }, ]); - // Step 4: Fetch all RDs with non-zero opening inventory for these products using SKU + // Step 4: Fetch all RDs with non-zero Stock for these products using SKU const rdStocks = await RDStock.aggregate([ { $unwind: "$products" }, { $match: { - "products.openingInventory": { $gt: 0 }, + "products.Stock": { $gt: 0 }, "products.SKU": { $in: productSKUs }, }, }, @@ -100,4 +199,4 @@ export const getProductsWithStockInfo = async (req, res) => { } catch (error) { res.status(500).json({ success: false, message: error.message }); } -}; +}; \ No newline at end of file diff --git a/resources/Reports/ReportRoute.js b/resources/Reports/ReportRoute.js index 979740a..07b1f4d 100644 --- a/resources/Reports/ReportRoute.js +++ b/resources/Reports/ReportRoute.js @@ -1,5 +1,8 @@ import express from "express"; -import { getProductsWithStockInfo } from "./OpeningInventoryReports.js"; +import { + getProductsWithStockInfo, + getProductsWithOpenInventoryInfo, +} from "./OpeningInventoryReports.js"; import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; @@ -7,6 +10,14 @@ const router = express.Router(); router .route("/opening-inventory") + .get( + isAuthenticatedUser, + authorizeRoles("admin"), + getProductsWithOpenInventoryInfo + ); + +router + .route("/stock") .get(isAuthenticatedUser, authorizeRoles("admin"), getProductsWithStockInfo); export default router;