From b44985aef4890709809bd6bd6919e8706906f3ac Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 15 Jan 2025 23:52:50 -0500 Subject: [PATCH] Fix forecasting brand list and filter on products received during period selected --- inventory-server/src/routes/analytics.js | 12 +++++++++--- inventory-server/src/routes/products.js | 15 +++++++++------ inventory/src/components/forecasting/columns.tsx | 3 +++ inventory/src/pages/Forecasting.tsx | 8 ++++---- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/inventory-server/src/routes/analytics.js b/inventory-server/src/routes/analytics.js index 6c83f82..e29693e 100644 --- a/inventory-server/src/routes/analytics.js +++ b/inventory-server/src/routes/analytics.js @@ -547,10 +547,12 @@ router.get('/forecast', async (req, res) => { FROM categories c JOIN product_categories pc ON c.id = pc.category_id JOIN products p ON pc.product_id = p.product_id + LEFT JOIN product_metrics pm ON p.product_id = pm.product_id LEFT JOIN orders o ON p.product_id = o.product_id AND o.date BETWEEN ? AND ? AND o.canceled = false WHERE p.brand = ? + AND pm.first_received_date BETWEEN ? AND ? GROUP BY c.id, c.name, p.brand ), product_metrics AS ( @@ -560,15 +562,18 @@ router.get('/forecast', async (req, res) => { p.sku, p.stock_quantity, pc.category_id, + pm.first_received_date, COALESCE(SUM(o.quantity), 0) as total_sold, COALESCE(ROUND(AVG(o.price), 2), 0) as avg_price FROM products p JOIN product_categories pc ON p.product_id = pc.product_id + JOIN product_metrics pm ON p.product_id = pm.product_id LEFT JOIN orders o ON p.product_id = o.product_id AND o.date BETWEEN ? AND ? AND o.canceled = false WHERE p.brand = ? - GROUP BY p.product_id, p.title, p.sku, p.stock_quantity, pc.category_id + AND pm.first_received_date BETWEEN ? AND ? + GROUP BY p.product_id, p.title, p.sku, p.stock_quantity, pc.category_id, pm.first_received_date ) SELECT cm.*, @@ -579,14 +584,15 @@ router.get('/forecast', async (req, res) => { 'sku', pm.sku, 'stock_quantity', pm.stock_quantity, 'total_sold', pm.total_sold, - 'avg_price', pm.avg_price + 'avg_price', pm.avg_price, + 'first_received_date', DATE_FORMAT(pm.first_received_date, '%Y-%m-%d') ) ) as products FROM category_metrics cm JOIN product_metrics pm ON cm.category_id = pm.category_id GROUP BY cm.category_id, cm.category_name, cm.brand, cm.num_products, cm.avg_daily_sales, cm.total_sold, cm.avgTotalSold, cm.avg_price ORDER BY cm.total_sold DESC - `, [startDate, endDate, startDate, endDate, brand, startDate, endDate, brand]); + `, [startDate, endDate, startDate, endDate, brand, startDate, endDate, startDate, endDate, brand, startDate, endDate]); res.json(results); } catch (error) { diff --git a/inventory-server/src/routes/products.js b/inventory-server/src/routes/products.js index ac9b6bd..e333d40 100755 --- a/inventory-server/src/routes/products.js +++ b/inventory-server/src/routes/products.js @@ -20,12 +20,15 @@ router.get('/brands', async (req, res) => { console.log('Fetching brands from database...'); const [results] = await pool.query(` - SELECT DISTINCT brand - FROM products - WHERE brand IS NOT NULL - AND brand != '' - AND visible = true - ORDER BY brand + SELECT DISTINCT p.brand + FROM products p + JOIN purchase_orders po ON p.product_id = po.product_id + WHERE p.brand IS NOT NULL + AND p.brand != '' + AND p.visible = true + GROUP BY p.brand + HAVING SUM(po.cost_price * po.received) >= 500 + ORDER BY p.brand `); console.log(`Found ${results.length} brands:`, results.slice(0, 3)); diff --git a/inventory/src/components/forecasting/columns.tsx b/inventory/src/components/forecasting/columns.tsx index f7e24d8..e3fe4f7 100644 --- a/inventory/src/components/forecasting/columns.tsx +++ b/inventory/src/components/forecasting/columns.tsx @@ -10,6 +10,7 @@ interface ProductDetail { stock_quantity: number; total_sold: number; avg_price: number; + first_received_date: string; } export interface ForecastItem { @@ -148,6 +149,7 @@ export const renderSubComponent = ({ row }: { row: any }) => { Product Name SKU + First Received Stock Quantity Total Sold Average Price @@ -158,6 +160,7 @@ export const renderSubComponent = ({ row }: { row: any }) => { {product.name} {product.sku} + {product.first_received_date} {product.stock_quantity.toLocaleString()} {product.total_sold.toLocaleString()} ${product.avg_price.toFixed(2)} diff --git a/inventory/src/pages/Forecasting.tsx b/inventory/src/pages/Forecasting.tsx index beace91..5430518 100644 --- a/inventory/src/pages/Forecasting.tsx +++ b/inventory/src/pages/Forecasting.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, Fragment } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useQuery } from "@tanstack/react-query"; @@ -72,6 +72,7 @@ export default function Forecasting() { stock_quantity: Number(p.stock_quantity) || 0, total_sold: Number(p.total_sold) || 0, avg_price: Number(p.avg_price) || 0, + first_received_date: p.first_received_date, })) })); }, @@ -145,9 +146,8 @@ export default function Forecasting() { {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row: Row) => ( - <> + {row.getVisibleCells().map((cell) => ( @@ -163,7 +163,7 @@ export default function Forecasting() { )} - + )) ) : (