From d85d387c1a33b70e37fc0332a483d955a2b3706b Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 17 Jan 2025 21:41:43 -0500 Subject: [PATCH] Fix and restyle replenishmentmetrics component --- inventory-server/src/routes/dashboard.js | 68 ++++++++++--------- .../components/dashboard/PurchaseMetrics.tsx | 2 +- .../dashboard/ReplenishmentMetrics.tsx | 41 +++++++---- .../src/components/dashboard/StockMetrics.tsx | 2 +- 4 files changed, 67 insertions(+), 46 deletions(-) diff --git a/inventory-server/src/routes/dashboard.js b/inventory-server/src/routes/dashboard.js index d8e3f24..237d345 100644 --- a/inventory-server/src/routes/dashboard.js +++ b/inventory-server/src/routes/dashboard.js @@ -173,28 +173,25 @@ router.get('/replenishment/metrics', async (req, res) => { // Get summary metrics const [metrics] = await executeQuery(` SELECT - COUNT(DISTINCT CASE - WHEN pm.stock_status IN ('Critical', 'Reorder') - THEN p.product_id - END) as products_to_replenish, - SUM(CASE - WHEN pm.stock_status IN ('Critical', 'Reorder') - THEN pm.reorder_qty - ELSE 0 - END) as total_units_needed, - SUM(CASE - WHEN pm.stock_status IN ('Critical', 'Reorder') - THEN pm.reorder_qty * p.cost_price - ELSE 0 - END) as total_cost, - SUM(CASE - WHEN pm.stock_status IN ('Critical', 'Reorder') - THEN pm.reorder_qty * p.price - ELSE 0 - END) as total_retail + COUNT(DISTINCT p.product_id) as products_to_replenish, + COALESCE(SUM(CASE + WHEN p.stock_quantity < 0 THEN ABS(p.stock_quantity) + pm.reorder_qty + ELSE pm.reorder_qty + END), 0) as total_units_needed, + COALESCE(SUM(CASE + WHEN p.stock_quantity < 0 THEN (ABS(p.stock_quantity) + pm.reorder_qty) * p.cost_price + ELSE pm.reorder_qty * p.cost_price + END), 0) as total_cost, + COALESCE(SUM(CASE + WHEN p.stock_quantity < 0 THEN (ABS(p.stock_quantity) + pm.reorder_qty) * p.price + ELSE pm.reorder_qty * p.price + END), 0) as total_retail FROM products p JOIN product_metrics pm ON p.product_id = pm.product_id WHERE p.replenishable = true + AND (pm.stock_status IN ('Critical', 'Reorder') + OR p.stock_quantity < 0) + AND pm.reorder_qty > 0 `); // Get top variants to replenish @@ -203,15 +200,25 @@ router.get('/replenishment/metrics', async (req, res) => { p.product_id, p.title, p.stock_quantity as current_stock, - pm.reorder_qty as replenish_qty, - (pm.reorder_qty * p.cost_price) as replenish_cost, - (pm.reorder_qty * p.price) as replenish_retail, - pm.stock_status, - DATE_FORMAT(pm.planning_period_end, '%b %d, %Y') as planning_period + CASE + WHEN p.stock_quantity < 0 THEN ABS(p.stock_quantity) + pm.reorder_qty + ELSE pm.reorder_qty + END as replenish_qty, + CASE + WHEN p.stock_quantity < 0 THEN (ABS(p.stock_quantity) + pm.reorder_qty) * p.cost_price + ELSE pm.reorder_qty * p.cost_price + END as replenish_cost, + CASE + WHEN p.stock_quantity < 0 THEN (ABS(p.stock_quantity) + pm.reorder_qty) * p.price + ELSE pm.reorder_qty * p.price + END as replenish_retail, + pm.stock_status FROM products p JOIN product_metrics pm ON p.product_id = pm.product_id WHERE p.replenishable = true - AND pm.stock_status IN ('Critical', 'Reorder') + AND (pm.stock_status IN ('Critical', 'Reorder') + OR p.stock_quantity < 0) + AND pm.reorder_qty > 0 ORDER BY CASE pm.stock_status WHEN 'Critical' THEN 1 @@ -223,10 +230,10 @@ router.get('/replenishment/metrics', async (req, res) => { // Format response const response = { - productsToReplenish: parseInt(metrics.products_to_replenish) || 0, - unitsToReplenish: parseInt(metrics.total_units_needed) || 0, - replenishmentCost: parseFloat(metrics.total_cost) || 0, - replenishmentRetail: parseFloat(metrics.total_retail) || 0, + productsToReplenish: parseInt(metrics[0].products_to_replenish) || 0, + unitsToReplenish: parseInt(metrics[0].total_units_needed) || 0, + replenishmentCost: parseFloat(metrics[0].total_cost) || 0, + replenishmentRetail: parseFloat(metrics[0].total_retail) || 0, topVariants: variants.map(v => ({ id: v.product_id, title: v.title, @@ -234,8 +241,7 @@ router.get('/replenishment/metrics', async (req, res) => { replenishQty: parseInt(v.replenish_qty) || 0, replenishCost: parseFloat(v.replenish_cost) || 0, replenishRetail: parseFloat(v.replenish_retail) || 0, - status: v.stock_status, - planningPeriod: v.planning_period + status: v.stock_status })) }; diff --git a/inventory/src/components/dashboard/PurchaseMetrics.tsx b/inventory/src/components/dashboard/PurchaseMetrics.tsx index 6a015da..71ebe4d 100644 --- a/inventory/src/components/dashboard/PurchaseMetrics.tsx +++ b/inventory/src/components/dashboard/PurchaseMetrics.tsx @@ -1,6 +1,6 @@ import { useQuery } from "@tanstack/react-query" import { CardHeader, CardTitle, CardContent } from "@/components/ui/card" -import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip, Sector } from "recharts" +import { PieChart, Pie, ResponsiveContainer, Cell, Sector } from "recharts" import config from "@/config" import { formatCurrency } from "@/lib/utils" import { ClipboardList, AlertCircle, Layers, DollarSign, ShoppingCart } from "lucide-react" // Importing icons diff --git a/inventory/src/components/dashboard/ReplenishmentMetrics.tsx b/inventory/src/components/dashboard/ReplenishmentMetrics.tsx index 80502b6..f94487f 100644 --- a/inventory/src/components/dashboard/ReplenishmentMetrics.tsx +++ b/inventory/src/components/dashboard/ReplenishmentMetrics.tsx @@ -5,28 +5,43 @@ import { formatCurrency } from "@/lib/utils" import { Package, DollarSign, ShoppingCart } from "lucide-react" // Importing icons interface ReplenishmentMetricsData { - totalUnitsToReplenish: number - totalReplenishmentCost: number - totalReplenishmentRetail: number - replenishmentByCategory: { - category: string - units: number - cost: number + productsToReplenish: number + unitsToReplenish: number + replenishmentCost: number + replenishmentRetail: number + topVariants: { + id: number + title: string + currentStock: number + replenishQty: number + replenishCost: number + replenishRetail: number + status: string + planningPeriod: string }[] } export function ReplenishmentMetrics() { - const { data } = useQuery({ + const { data, error, isLoading } = useQuery({ queryKey: ["replenishment-metrics"], queryFn: async () => { + console.log('Fetching from:', `${config.apiUrl}/dashboard/replenishment/metrics`); const response = await fetch(`${config.apiUrl}/dashboard/replenishment/metrics`) if (!response.ok) { - throw new Error("Failed to fetch replenishment metrics") + const text = await response.text(); + console.error('API Error:', text); + throw new Error(`Failed to fetch replenishment metrics: ${response.status} ${response.statusText} - ${text}`) } - return response.json() + const data = await response.json(); + console.log('API Response:', data); + return data; }, }) + if (isLoading) return
Loading replenishment metrics...
; + if (error) return
Error: {error.message}
; + if (!data) return
No replenishment data available
; + return ( <> @@ -39,21 +54,21 @@ export function ReplenishmentMetrics() {

Units to Replenish

-

{data?.totalUnitsToReplenish.toLocaleString() || 0}

+

{data.unitsToReplenish.toLocaleString() || 0}

Replenishment Cost

-

{formatCurrency(data?.totalReplenishmentCost || 0)}

+

{formatCurrency(data.replenishmentCost || 0)}

Replenishment Retail

-

{formatCurrency(data?.totalReplenishmentRetail || 0)}

+

{formatCurrency(data.replenishmentRetail || 0)}

diff --git a/inventory/src/components/dashboard/StockMetrics.tsx b/inventory/src/components/dashboard/StockMetrics.tsx index 62c53e3..a9f13c2 100644 --- a/inventory/src/components/dashboard/StockMetrics.tsx +++ b/inventory/src/components/dashboard/StockMetrics.tsx @@ -1,6 +1,6 @@ import { useQuery } from "@tanstack/react-query" import { CardHeader, CardTitle, CardContent } from "@/components/ui/card" -import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip, Sector } from "recharts" +import { PieChart, Pie, ResponsiveContainer, Cell, Sector } from "recharts" import config from "@/config" import { formatCurrency } from "@/lib/utils" import { Package, Layers, DollarSign, ShoppingCart } from "lucide-react"