Fix and restyle overstockmetrics and topoverstockedproducts, link products to backend
This commit is contained in:
@@ -357,7 +357,7 @@ router.get('/overstock/metrics', async (req, res) => {
|
||||
SUM(total_excess_units) as total_excess_units,
|
||||
SUM(total_excess_cost) as total_excess_cost,
|
||||
SUM(total_excess_retail) as total_excess_retail,
|
||||
CAST(JSON_ARRAYAGG(
|
||||
CONCAT('[', GROUP_CONCAT(
|
||||
JSON_OBJECT(
|
||||
'category', category_name,
|
||||
'products', overstocked_products,
|
||||
@@ -365,7 +365,7 @@ router.get('/overstock/metrics', async (req, res) => {
|
||||
'cost', total_excess_cost,
|
||||
'retail', total_excess_retail
|
||||
)
|
||||
) AS JSON) as category_data
|
||||
), ']') as category_data
|
||||
FROM (
|
||||
SELECT *
|
||||
FROM category_overstock
|
||||
@@ -378,10 +378,17 @@ router.get('/overstock/metrics', async (req, res) => {
|
||||
// Format response with explicit type conversion
|
||||
const response = {
|
||||
overstockedProducts: parseInt(rows[0].total_overstocked) || 0,
|
||||
excessUnits: parseInt(rows[0].total_excess_units) || 0,
|
||||
excessCost: parseFloat(rows[0].total_excess_cost) || 0,
|
||||
excessRetail: parseFloat(rows[0].total_excess_retail) || 0,
|
||||
categoryData: rows[0].category_data ? JSON.parse(rows[0].category_data) : []
|
||||
total_excess_units: parseInt(rows[0].total_excess_units) || 0,
|
||||
total_excess_cost: parseFloat(rows[0].total_excess_cost) || 0,
|
||||
total_excess_retail: parseFloat(rows[0].total_excess_retail) || 0,
|
||||
category_data: rows[0].category_data ?
|
||||
JSON.parse(rows[0].category_data).map(obj => ({
|
||||
category: obj.category,
|
||||
products: parseInt(obj.products) || 0,
|
||||
units: parseInt(obj.units) || 0,
|
||||
cost: parseFloat(obj.cost) || 0,
|
||||
retail: parseFloat(obj.retail) || 0
|
||||
})) : []
|
||||
};
|
||||
|
||||
res.json(response);
|
||||
|
||||
@@ -6,14 +6,15 @@ import { Package, Layers, DollarSign, ShoppingCart } from "lucide-react"
|
||||
|
||||
interface OverstockMetricsData {
|
||||
overstockedProducts: number
|
||||
overstockedUnits: number
|
||||
overstockedCost: number
|
||||
overstockedRetail: number
|
||||
overstockByCategory: {
|
||||
total_excess_units: number
|
||||
total_excess_cost: number
|
||||
total_excess_retail: number
|
||||
category_data: {
|
||||
category: string
|
||||
products: number
|
||||
units: number
|
||||
cost: number
|
||||
retail: number
|
||||
}[]
|
||||
}
|
||||
|
||||
@@ -41,28 +42,28 @@ export function OverstockMetrics() {
|
||||
<Package className="h-4 w-4 text-muted-foreground" />
|
||||
<p className="text-sm font-medium text-muted-foreground">Overstocked Products</p>
|
||||
</div>
|
||||
<p className="text-2xl font-bold">{data?.overstockedProducts.toLocaleString() || 0}</p>
|
||||
<p className="text-lg font-bold">{data?.overstockedProducts.toLocaleString() || 0}</p>
|
||||
</div>
|
||||
<div className="flex items-baseline justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Layers className="h-4 w-4 text-muted-foreground" />
|
||||
<p className="text-sm font-medium text-muted-foreground">Overstocked Units</p>
|
||||
</div>
|
||||
<p className="text-2xl font-bold">{data?.overstockedUnits.toLocaleString() || 0}</p>
|
||||
<p className="text-lg font-bold">{data?.total_excess_units.toLocaleString() || 0}</p>
|
||||
</div>
|
||||
<div className="flex items-baseline justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
||||
<p className="text-sm font-medium text-muted-foreground">Overstocked Cost</p>
|
||||
</div>
|
||||
<p className="text-2xl font-bold">{formatCurrency(data?.overstockedCost || 0)}</p>
|
||||
<p className="text-lg font-bold">{formatCurrency(data?.total_excess_cost || 0)}</p>
|
||||
</div>
|
||||
<div className="flex items-baseline justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
|
||||
<p className="text-sm font-medium text-muted-foreground">Overstocked Retail</p>
|
||||
</div>
|
||||
<p className="text-2xl font-bold">{formatCurrency(data?.overstockedRetail || 0)}</p>
|
||||
<p className="text-lg font-bold">{formatCurrency(data?.total_excess_retail || 0)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@@ -9,10 +9,10 @@ interface OverstockedProduct {
|
||||
product_id: number
|
||||
SKU: string
|
||||
title: string
|
||||
stock_quantity: number
|
||||
overstocked_amt: number
|
||||
excess_cost: number
|
||||
excess_retail: number
|
||||
days_of_inventory: number
|
||||
}
|
||||
|
||||
export function TopOverstockedProducts() {
|
||||
@@ -38,9 +38,10 @@ export function TopOverstockedProducts() {
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Product</TableHead>
|
||||
<TableHead className="text-right">Units</TableHead>
|
||||
<TableHead className="text-right">Cost</TableHead>
|
||||
<TableHead className="text-right">Days</TableHead>
|
||||
<TableHead className="text-right">Current Stock</TableHead>
|
||||
<TableHead className="text-right">Overstock Amt</TableHead>
|
||||
<TableHead className="text-right">Overstock Cost</TableHead>
|
||||
<TableHead className="text-right">Overstock Retail</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -48,10 +49,20 @@ export function TopOverstockedProducts() {
|
||||
<TableRow key={product.product_id}>
|
||||
<TableCell>
|
||||
<div>
|
||||
<p className="font-medium">{product.title}</p>
|
||||
<a
|
||||
href={`https://backend.acherryontop.com/product/${product.product_id}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="font-medium hover:underline"
|
||||
>
|
||||
{product.title}
|
||||
</a>
|
||||
<p className="text-sm text-muted-foreground">{product.SKU}</p>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{product.stock_quantity.toLocaleString()}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{product.overstocked_amt.toLocaleString()}
|
||||
</TableCell>
|
||||
@@ -59,7 +70,7 @@ export function TopOverstockedProducts() {
|
||||
{formatCurrency(product.excess_cost)}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{product.days_of_inventory}
|
||||
{formatCurrency(product.excess_retail)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
|
||||
@@ -49,7 +49,14 @@ export function TopReplenishProducts() {
|
||||
<TableRow key={product.product_id}>
|
||||
<TableCell>
|
||||
<div>
|
||||
<p className="font-medium">{product.title}</p>
|
||||
<a
|
||||
href={`https://backend.acherryontop.com/product/${product.product_id}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="font-medium hover:underline"
|
||||
>
|
||||
{product.title}
|
||||
</a>
|
||||
<p className="text-sm text-muted-foreground">{product.SKU}</p>
|
||||
</div>
|
||||
</TableCell>
|
||||
|
||||
Reference in New Issue
Block a user