diff --git a/inventory-server/src/routes/analytics.js b/inventory-server/src/routes/analytics.js index f367895..8d8cc18 100644 --- a/inventory-server/src/routes/analytics.js +++ b/inventory-server/src/routes/analytics.js @@ -369,14 +369,16 @@ router.get('/pricing', async (req, res) => { // Get price points analysis const [pricePoints] = await pool.query(` SELECT - p.price, - SUM(o.quantity) as salesVolume, - SUM(o.price * o.quantity) as revenue, - p.categories as category + CAST(p.price AS DECIMAL(15,3)) as price, + CAST(SUM(o.quantity) AS DECIMAL(15,3)) as salesVolume, + CAST(SUM(o.price * o.quantity) AS DECIMAL(15,3)) as revenue, + c.name as category FROM products p LEFT JOIN orders o ON p.pid = o.pid + JOIN product_categories pc ON p.pid = pc.pid + JOIN categories c ON pc.cat_id = c.cat_id WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) - GROUP BY p.price, p.categories + GROUP BY p.price, c.name HAVING salesVolume > 0 ORDER BY revenue DESC LIMIT 50 @@ -386,8 +388,8 @@ router.get('/pricing', async (req, res) => { const [elasticity] = await pool.query(` SELECT DATE_FORMAT(o.date, '%Y-%m-%d') as date, - AVG(o.price) as price, - SUM(o.quantity) as demand + CAST(AVG(o.price) AS DECIMAL(15,3)) as price, + CAST(SUM(o.quantity) AS DECIMAL(15,3)) as demand FROM orders o WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY DATE_FORMAT(o.date, '%Y-%m-%d') @@ -398,21 +400,25 @@ router.get('/pricing', async (req, res) => { const [recommendations] = await pool.query(` SELECT p.title as product, - p.price as currentPrice, - ROUND( - CASE - WHEN AVG(o.quantity) > 10 THEN p.price * 1.1 - WHEN AVG(o.quantity) < 2 THEN p.price * 0.9 - ELSE p.price - END, 2 + CAST(p.price AS DECIMAL(15,3)) as currentPrice, + CAST( + ROUND( + CASE + WHEN AVG(o.quantity) > 10 THEN p.price * 1.1 + WHEN AVG(o.quantity) < 2 THEN p.price * 0.9 + ELSE p.price + END, 2 + ) AS DECIMAL(15,3) ) as recommendedPrice, - ROUND( - SUM(o.price * o.quantity) * - CASE - WHEN AVG(o.quantity) > 10 THEN 1.15 - WHEN AVG(o.quantity) < 2 THEN 0.95 - ELSE 1 - END, 2 + CAST( + ROUND( + SUM(o.price * o.quantity) * + CASE + WHEN AVG(o.quantity) > 10 THEN 1.15 + WHEN AVG(o.quantity) < 2 THEN 0.95 + ELSE 1 + END, 2 + ) AS DECIMAL(15,3) ) as potentialRevenue, CASE WHEN AVG(o.quantity) > 10 THEN 85 @@ -422,9 +428,9 @@ router.get('/pricing', async (req, res) => { FROM products p LEFT JOIN orders o ON p.pid = o.pid WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) - GROUP BY p.pid + GROUP BY p.pid, p.price HAVING ABS(recommendedPrice - currentPrice) > 0 - ORDER BY potentialRevenue - SUM(o.price * o.quantity) DESC + ORDER BY potentialRevenue - CAST(SUM(o.price * o.quantity) AS DECIMAL(15,3)) DESC LIMIT 10 `); @@ -536,14 +542,14 @@ router.get('/forecast', async (req, res) => { const [results] = await pool.query(` WITH category_metrics AS ( SELECT - c.cat_id as category_id, + c.cat_id, c.name as category_name, p.brand, COUNT(DISTINCT p.pid) as num_products, - COALESCE(ROUND(SUM(o.quantity) / DATEDIFF(?, ?), 2), 0) as avg_daily_sales, + CAST(COALESCE(ROUND(SUM(o.quantity) / DATEDIFF(?, ?), 2), 0) AS DECIMAL(15,3)) as avg_daily_sales, COALESCE(SUM(o.quantity), 0) as total_sold, - COALESCE(ROUND(SUM(o.quantity) / COUNT(DISTINCT p.pid), 2), 0) as avgTotalSold, - COALESCE(ROUND(AVG(o.price), 2), 0) as avg_price + CAST(COALESCE(ROUND(SUM(o.quantity) / COUNT(DISTINCT p.pid), 2), 0) AS DECIMAL(15,3)) as avgTotalSold, + CAST(COALESCE(ROUND(AVG(o.price), 2), 0) AS DECIMAL(15,3)) as avg_price FROM categories c JOIN product_categories pc ON c.cat_id = pc.cat_id JOIN products p ON pc.pid = p.pid @@ -564,7 +570,7 @@ router.get('/forecast', async (req, res) => { pc.cat_id, pm.first_received_date, COALESCE(SUM(o.quantity), 0) as total_sold, - COALESCE(ROUND(AVG(o.price), 2), 0) as avg_price + CAST(COALESCE(ROUND(AVG(o.price), 2), 0) AS DECIMAL(15,3)) as avg_price FROM products p JOIN product_categories pc ON p.pid = pc.pid JOIN product_metrics pm ON p.pid = pm.pid @@ -589,8 +595,8 @@ router.get('/forecast', async (req, res) => { ) ) as products FROM category_metrics cm - JOIN product_metrics pm ON cm.category_id = pm.cat_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 + JOIN product_metrics pm ON cm.cat_id = pm.cat_id + GROUP BY cm.cat_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, startDate, endDate, brand, startDate, endDate]); diff --git a/inventory/src/components/dashboard/BestSellers.tsx b/inventory/src/components/dashboard/BestSellers.tsx index 0fa55ff..2106ebe 100644 --- a/inventory/src/components/dashboard/BestSellers.tsx +++ b/inventory/src/components/dashboard/BestSellers.tsx @@ -11,33 +11,33 @@ interface Product { sku: string; title: string; units_sold: number; - revenue: number; - profit: number; + revenue: string; + profit: string; } interface Category { cat_id: number; name: string; - total_revenue: number; - total_profit: number; + total_revenue: string; + total_profit: string; total_units: number; } interface BestSellerBrand { brand: string units_sold: number - revenue: number - profit: number - growth_rate: number + revenue: string + profit: string + growth_rate: string } interface BestSellerCategory { cat_id: number; name: string; units_sold: number; - revenue: number; - profit: number; - growth_rate: number; + revenue: string; + profit: string; + growth_rate: string; } interface BestSellersData { @@ -98,8 +98,8 @@ export function BestSellers() {
Forecast Revenue
-{formatCurrency(data?.forecastRevenue || 0)}
+{formatCurrency(Number(data?.forecastRevenue) || 0)}
@@ -108,7 +108,7 @@ export function ForecastMetrics() { tick={false} />- Avg. Stock: {vendor.averageStockLevel.toFixed(0)} + Avg. Stock: {Number(vendor.averageStockLevel).toFixed(0)}
Cost of Goods
-{formatCurrency(data?.totalCogs || 0)}
+{formatCurrency(Number(data?.totalCogs) || 0)}
Revenue
{formatCurrency(data?.totalRevenue || 0)}
+{formatCurrency(Number(data?.totalRevenue) || 0)}
Stock Cost
-{formatCurrency(data?.totalStockCost || 0)}
+{formatCurrency(Number(data?.totalStockCost) || 0)}
Stock Retail
{formatCurrency(data?.totalStockRetail || 0)}
+{formatCurrency(Number(data?.totalStockRetail) || 0)}