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() {
{product.sku}
{product.units_sold} - {formatCurrency(product.revenue)} - {formatCurrency(product.profit)} + {formatCurrency(Number(product.revenue))} + {formatCurrency(Number(product.profit))} ))} @@ -129,13 +129,13 @@ export function BestSellers() { {brand.units_sold.toLocaleString()} - {formatCurrency(brand.revenue)} + {formatCurrency(Number(brand.revenue))} - {formatCurrency(brand.profit)} + {formatCurrency(Number(brand.profit))} - {brand.growth_rate > 0 ? '+' : ''}{brand.growth_rate.toFixed(1)}% + {Number(brand.growth_rate) > 0 ? '+' : ''}{Number(brand.growth_rate).toFixed(1)}% ))} @@ -160,8 +160,8 @@ export function BestSellers() { {category.name} {category.total_units} - {formatCurrency(category.total_revenue)} - {formatCurrency(category.total_profit)} + {formatCurrency(Number(category.total_revenue))} + {formatCurrency(Number(category.total_profit))} ))} diff --git a/inventory/src/components/dashboard/ForecastMetrics.tsx b/inventory/src/components/dashboard/ForecastMetrics.tsx index 6eb5ab0..3455230 100644 --- a/inventory/src/components/dashboard/ForecastMetrics.tsx +++ b/inventory/src/components/dashboard/ForecastMetrics.tsx @@ -11,18 +11,18 @@ import { DateRangePicker } from "@/components/ui/date-range-picker-narrow" interface ForecastData { forecastSales: number - forecastRevenue: number + forecastRevenue: string confidenceLevel: number dailyForecasts: { date: string units: number - revenue: number + revenue: string confidence: number }[] categoryForecasts: { category: string units: number - revenue: number + revenue: string confidence: number }[] } @@ -86,7 +86,7 @@ export function ForecastMetrics() {

Forecast Revenue

-

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

+

{formatCurrency(Number(data?.forecastRevenue) || 0)}

@@ -108,7 +108,7 @@ export function ForecastMetrics() { tick={false} /> [formatCurrency(value), "Revenue"]} + formatter={(value: string) => [formatCurrency(Number(value)), "Revenue"]} labelFormatter={(date) => format(new Date(date), 'MMM d, yyyy')} /> - + [Number(value).toFixed(2), "Rate"]} /> @@ -93,7 +93,7 @@ export function InventoryStats() {

- Avg. Stock: {vendor.averageStockLevel.toFixed(0)} + Avg. Stock: {Number(vendor.averageStockLevel).toFixed(0)}

diff --git a/inventory/src/components/dashboard/LowStockAlerts.tsx b/inventory/src/components/dashboard/LowStockAlerts.tsx index 6f995e0..f37aca5 100644 --- a/inventory/src/components/dashboard/LowStockAlerts.tsx +++ b/inventory/src/components/dashboard/LowStockAlerts.tsx @@ -17,8 +17,8 @@ interface Product { sku: string; title: string; stock_quantity: number; - daily_sales_avg: number; - days_of_inventory: number; + daily_sales_avg: string; + days_of_inventory: string; reorder_qty: number; last_purchase_date: string | null; lead_time_status: string; @@ -70,8 +70,8 @@ export function LowStockAlerts() {
{product.sku}
{product.stock_quantity} - {product.daily_sales_avg.toFixed(1)} - {product.days_of_inventory.toFixed(1)} + {Number(product.daily_sales_avg).toFixed(1)} + {Number(product.days_of_inventory).toFixed(1)} {product.reorder_qty} {product.last_purchase_date ? formatDate(product.last_purchase_date) : '-'} diff --git a/inventory/src/components/dashboard/SalesMetrics.tsx b/inventory/src/components/dashboard/SalesMetrics.tsx index ceb41d5..8ccf497 100644 --- a/inventory/src/components/dashboard/SalesMetrics.tsx +++ b/inventory/src/components/dashboard/SalesMetrics.tsx @@ -12,13 +12,13 @@ import { DateRangePicker } from "@/components/ui/date-range-picker-narrow" interface SalesData { totalOrders: number totalUnitsSold: number - totalCogs: number - totalRevenue: number + totalCogs: string + totalRevenue: string dailySales: { date: string units: number - revenue: number - cogs: number + revenue: string + cogs: string }[] } @@ -78,14 +78,14 @@ export function SalesMetrics() {

Cost of Goods

-

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

+

{formatCurrency(Number(data?.totalCogs) || 0)}

Revenue

-

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

+

{formatCurrency(Number(data?.totalRevenue) || 0)}

@@ -107,7 +107,7 @@ export function SalesMetrics() { tick={false} /> [formatCurrency(value), "Revenue"]} + formatter={(value: string) => [formatCurrency(Number(value)), "Revenue"]} labelFormatter={(date) => format(new Date(date), 'MMM d, yyyy')} /> { fill="#000000" className="text-base font-medium" > - {formatCurrency(retail)} + {formatCurrency(Number(retail))} ); @@ -154,14 +154,14 @@ export function StockMetrics() {

Stock Cost

-

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

+

{formatCurrency(Number(data?.totalStockCost) || 0)}

Stock Retail

-

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

+

{formatCurrency(Number(data?.totalStockRetail) || 0)}

diff --git a/inventory/src/components/dashboard/TopReplenishProducts.tsx b/inventory/src/components/dashboard/TopReplenishProducts.tsx index 4701ed5..dc50ab5 100644 --- a/inventory/src/components/dashboard/TopReplenishProducts.tsx +++ b/inventory/src/components/dashboard/TopReplenishProducts.tsx @@ -9,7 +9,7 @@ interface Product { sku: string; title: string; stock_quantity: number; - daily_sales_avg: number; + daily_sales_avg: string; reorder_qty: number; last_purchase_date: string | null; } @@ -58,7 +58,7 @@ export function TopReplenishProducts() {
{product.sku}
{product.stock_quantity} - {product.daily_sales_avg.toFixed(1)} + {Number(product.daily_sales_avg).toFixed(1)} {product.reorder_qty} {product.last_purchase_date ? product.last_purchase_date : '-'}