Update frontend to match part 2
This commit is contained in:
@@ -369,14 +369,16 @@ router.get('/pricing', async (req, res) => {
|
|||||||
// Get price points analysis
|
// Get price points analysis
|
||||||
const [pricePoints] = await pool.query(`
|
const [pricePoints] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
p.price,
|
CAST(p.price AS DECIMAL(15,3)) as price,
|
||||||
SUM(o.quantity) as salesVolume,
|
CAST(SUM(o.quantity) AS DECIMAL(15,3)) as salesVolume,
|
||||||
SUM(o.price * o.quantity) as revenue,
|
CAST(SUM(o.price * o.quantity) AS DECIMAL(15,3)) as revenue,
|
||||||
p.categories as category
|
c.name as category
|
||||||
FROM products p
|
FROM products p
|
||||||
LEFT JOIN orders o ON p.pid = o.pid
|
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)
|
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
||||||
GROUP BY p.price, p.categories
|
GROUP BY p.price, c.name
|
||||||
HAVING salesVolume > 0
|
HAVING salesVolume > 0
|
||||||
ORDER BY revenue DESC
|
ORDER BY revenue DESC
|
||||||
LIMIT 50
|
LIMIT 50
|
||||||
@@ -386,8 +388,8 @@ router.get('/pricing', async (req, res) => {
|
|||||||
const [elasticity] = await pool.query(`
|
const [elasticity] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
DATE_FORMAT(o.date, '%Y-%m-%d') as date,
|
DATE_FORMAT(o.date, '%Y-%m-%d') as date,
|
||||||
AVG(o.price) as price,
|
CAST(AVG(o.price) AS DECIMAL(15,3)) as price,
|
||||||
SUM(o.quantity) as demand
|
CAST(SUM(o.quantity) AS DECIMAL(15,3)) as demand
|
||||||
FROM orders o
|
FROM orders o
|
||||||
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
||||||
GROUP BY DATE_FORMAT(o.date, '%Y-%m-%d')
|
GROUP BY DATE_FORMAT(o.date, '%Y-%m-%d')
|
||||||
@@ -398,21 +400,25 @@ router.get('/pricing', async (req, res) => {
|
|||||||
const [recommendations] = await pool.query(`
|
const [recommendations] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
p.title as product,
|
p.title as product,
|
||||||
p.price as currentPrice,
|
CAST(p.price AS DECIMAL(15,3)) as currentPrice,
|
||||||
ROUND(
|
CAST(
|
||||||
CASE
|
ROUND(
|
||||||
WHEN AVG(o.quantity) > 10 THEN p.price * 1.1
|
CASE
|
||||||
WHEN AVG(o.quantity) < 2 THEN p.price * 0.9
|
WHEN AVG(o.quantity) > 10 THEN p.price * 1.1
|
||||||
ELSE p.price
|
WHEN AVG(o.quantity) < 2 THEN p.price * 0.9
|
||||||
END, 2
|
ELSE p.price
|
||||||
|
END, 2
|
||||||
|
) AS DECIMAL(15,3)
|
||||||
) as recommendedPrice,
|
) as recommendedPrice,
|
||||||
ROUND(
|
CAST(
|
||||||
SUM(o.price * o.quantity) *
|
ROUND(
|
||||||
CASE
|
SUM(o.price * o.quantity) *
|
||||||
WHEN AVG(o.quantity) > 10 THEN 1.15
|
CASE
|
||||||
WHEN AVG(o.quantity) < 2 THEN 0.95
|
WHEN AVG(o.quantity) > 10 THEN 1.15
|
||||||
ELSE 1
|
WHEN AVG(o.quantity) < 2 THEN 0.95
|
||||||
END, 2
|
ELSE 1
|
||||||
|
END, 2
|
||||||
|
) AS DECIMAL(15,3)
|
||||||
) as potentialRevenue,
|
) as potentialRevenue,
|
||||||
CASE
|
CASE
|
||||||
WHEN AVG(o.quantity) > 10 THEN 85
|
WHEN AVG(o.quantity) > 10 THEN 85
|
||||||
@@ -422,9 +428,9 @@ router.get('/pricing', async (req, res) => {
|
|||||||
FROM products p
|
FROM products p
|
||||||
LEFT JOIN orders o ON p.pid = o.pid
|
LEFT JOIN orders o ON p.pid = o.pid
|
||||||
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
WHERE o.date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
|
||||||
GROUP BY p.pid
|
GROUP BY p.pid, p.price
|
||||||
HAVING ABS(recommendedPrice - currentPrice) > 0
|
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
|
LIMIT 10
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -536,14 +542,14 @@ router.get('/forecast', async (req, res) => {
|
|||||||
const [results] = await pool.query(`
|
const [results] = await pool.query(`
|
||||||
WITH category_metrics AS (
|
WITH category_metrics AS (
|
||||||
SELECT
|
SELECT
|
||||||
c.cat_id as category_id,
|
c.cat_id,
|
||||||
c.name as category_name,
|
c.name as category_name,
|
||||||
p.brand,
|
p.brand,
|
||||||
COUNT(DISTINCT p.pid) as num_products,
|
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(SUM(o.quantity), 0) as total_sold,
|
||||||
COALESCE(ROUND(SUM(o.quantity) / COUNT(DISTINCT p.pid), 2), 0) as avgTotalSold,
|
CAST(COALESCE(ROUND(SUM(o.quantity) / COUNT(DISTINCT p.pid), 2), 0) AS DECIMAL(15,3)) as avgTotalSold,
|
||||||
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 categories c
|
FROM categories c
|
||||||
JOIN product_categories pc ON c.cat_id = pc.cat_id
|
JOIN product_categories pc ON c.cat_id = pc.cat_id
|
||||||
JOIN products p ON pc.pid = p.pid
|
JOIN products p ON pc.pid = p.pid
|
||||||
@@ -564,7 +570,7 @@ router.get('/forecast', async (req, res) => {
|
|||||||
pc.cat_id,
|
pc.cat_id,
|
||||||
pm.first_received_date,
|
pm.first_received_date,
|
||||||
COALESCE(SUM(o.quantity), 0) as total_sold,
|
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
|
FROM products p
|
||||||
JOIN product_categories pc ON p.pid = pc.pid
|
JOIN product_categories pc ON p.pid = pc.pid
|
||||||
JOIN product_metrics pm ON p.pid = pm.pid
|
JOIN product_metrics pm ON p.pid = pm.pid
|
||||||
@@ -589,8 +595,8 @@ router.get('/forecast', async (req, res) => {
|
|||||||
)
|
)
|
||||||
) as products
|
) as products
|
||||||
FROM category_metrics cm
|
FROM category_metrics cm
|
||||||
JOIN product_metrics pm ON cm.category_id = pm.cat_id
|
JOIN product_metrics pm ON cm.cat_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
|
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
|
ORDER BY cm.total_sold DESC
|
||||||
`, [startDate, endDate, startDate, endDate, brand, startDate, endDate, startDate, endDate, brand, startDate, endDate]);
|
`, [startDate, endDate, startDate, endDate, brand, startDate, endDate, startDate, endDate, brand, startDate, endDate]);
|
||||||
|
|
||||||
|
|||||||
@@ -11,33 +11,33 @@ interface Product {
|
|||||||
sku: string;
|
sku: string;
|
||||||
title: string;
|
title: string;
|
||||||
units_sold: number;
|
units_sold: number;
|
||||||
revenue: number;
|
revenue: string;
|
||||||
profit: number;
|
profit: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Category {
|
interface Category {
|
||||||
cat_id: number;
|
cat_id: number;
|
||||||
name: string;
|
name: string;
|
||||||
total_revenue: number;
|
total_revenue: string;
|
||||||
total_profit: number;
|
total_profit: string;
|
||||||
total_units: number;
|
total_units: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BestSellerBrand {
|
interface BestSellerBrand {
|
||||||
brand: string
|
brand: string
|
||||||
units_sold: number
|
units_sold: number
|
||||||
revenue: number
|
revenue: string
|
||||||
profit: number
|
profit: string
|
||||||
growth_rate: number
|
growth_rate: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BestSellerCategory {
|
interface BestSellerCategory {
|
||||||
cat_id: number;
|
cat_id: number;
|
||||||
name: string;
|
name: string;
|
||||||
units_sold: number;
|
units_sold: number;
|
||||||
revenue: number;
|
revenue: string;
|
||||||
profit: number;
|
profit: string;
|
||||||
growth_rate: number;
|
growth_rate: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BestSellersData {
|
interface BestSellersData {
|
||||||
@@ -98,8 +98,8 @@ export function BestSellers() {
|
|||||||
<div className="text-sm text-muted-foreground">{product.sku}</div>
|
<div className="text-sm text-muted-foreground">{product.sku}</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-right">{product.units_sold}</TableCell>
|
<TableCell className="text-right">{product.units_sold}</TableCell>
|
||||||
<TableCell className="text-right">{formatCurrency(product.revenue)}</TableCell>
|
<TableCell className="text-right">{formatCurrency(Number(product.revenue))}</TableCell>
|
||||||
<TableCell className="text-right">{formatCurrency(product.profit)}</TableCell>
|
<TableCell className="text-right">{formatCurrency(Number(product.profit))}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
@@ -129,13 +129,13 @@ export function BestSellers() {
|
|||||||
{brand.units_sold.toLocaleString()}
|
{brand.units_sold.toLocaleString()}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="w-[15%] text-right">
|
<TableCell className="w-[15%] text-right">
|
||||||
{formatCurrency(brand.revenue)}
|
{formatCurrency(Number(brand.revenue))}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="w-[15%] text-right">
|
<TableCell className="w-[15%] text-right">
|
||||||
{formatCurrency(brand.profit)}
|
{formatCurrency(Number(brand.profit))}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="w-[15%] text-right">
|
<TableCell className="w-[15%] text-right">
|
||||||
{brand.growth_rate > 0 ? '+' : ''}{brand.growth_rate.toFixed(1)}%
|
{Number(brand.growth_rate) > 0 ? '+' : ''}{Number(brand.growth_rate).toFixed(1)}%
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
@@ -160,8 +160,8 @@ export function BestSellers() {
|
|||||||
<TableRow key={category.cat_id}>
|
<TableRow key={category.cat_id}>
|
||||||
<TableCell>{category.name}</TableCell>
|
<TableCell>{category.name}</TableCell>
|
||||||
<TableCell className="text-right">{category.total_units}</TableCell>
|
<TableCell className="text-right">{category.total_units}</TableCell>
|
||||||
<TableCell className="text-right">{formatCurrency(category.total_revenue)}</TableCell>
|
<TableCell className="text-right">{formatCurrency(Number(category.total_revenue))}</TableCell>
|
||||||
<TableCell className="text-right">{formatCurrency(category.total_profit)}</TableCell>
|
<TableCell className="text-right">{formatCurrency(Number(category.total_profit))}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ import { DateRangePicker } from "@/components/ui/date-range-picker-narrow"
|
|||||||
|
|
||||||
interface ForecastData {
|
interface ForecastData {
|
||||||
forecastSales: number
|
forecastSales: number
|
||||||
forecastRevenue: number
|
forecastRevenue: string
|
||||||
confidenceLevel: number
|
confidenceLevel: number
|
||||||
dailyForecasts: {
|
dailyForecasts: {
|
||||||
date: string
|
date: string
|
||||||
units: number
|
units: number
|
||||||
revenue: number
|
revenue: string
|
||||||
confidence: number
|
confidence: number
|
||||||
}[]
|
}[]
|
||||||
categoryForecasts: {
|
categoryForecasts: {
|
||||||
category: string
|
category: string
|
||||||
units: number
|
units: number
|
||||||
revenue: number
|
revenue: string
|
||||||
confidence: number
|
confidence: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ export function ForecastMetrics() {
|
|||||||
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
||||||
<p className="text-sm font-medium text-muted-foreground">Forecast Revenue</p>
|
<p className="text-sm font-medium text-muted-foreground">Forecast Revenue</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-lg font-bold">{formatCurrency(data?.forecastRevenue || 0)}</p>
|
<p className="text-lg font-bold">{formatCurrency(Number(data?.forecastRevenue) || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ export function ForecastMetrics() {
|
|||||||
tick={false}
|
tick={false}
|
||||||
/>
|
/>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
formatter={(value: number) => [formatCurrency(value), "Revenue"]}
|
formatter={(value: string) => [formatCurrency(Number(value)), "Revenue"]}
|
||||||
labelFormatter={(date) => format(new Date(date), 'MMM d, yyyy')}
|
labelFormatter={(date) => format(new Date(date), 'MMM d, yyyy')}
|
||||||
/>
|
/>
|
||||||
<Area
|
<Area
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ interface InventoryMetrics {
|
|||||||
topVendors: {
|
topVendors: {
|
||||||
vendor: string;
|
vendor: string;
|
||||||
productCount: number;
|
productCount: number;
|
||||||
averageStockLevel: number;
|
averageStockLevel: string;
|
||||||
}[];
|
}[];
|
||||||
stockTurnover: {
|
stockTurnover: {
|
||||||
category: string;
|
category: string;
|
||||||
rate: number;
|
rate: string;
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ export function InventoryStats() {
|
|||||||
<BarChart data={data?.stockTurnover}>
|
<BarChart data={data?.stockTurnover}>
|
||||||
<XAxis dataKey="category" />
|
<XAxis dataKey="category" />
|
||||||
<YAxis />
|
<YAxis />
|
||||||
<Tooltip />
|
<Tooltip formatter={(value: string) => [Number(value).toFixed(2), "Rate"]} />
|
||||||
<Bar dataKey="rate" name="Turnover Rate" fill="#60a5fa" />
|
<Bar dataKey="rate" name="Turnover Rate" fill="#60a5fa" />
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
@@ -93,7 +93,7 @@ export function InventoryStats() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="ml-4 text-right">
|
<div className="ml-4 text-right">
|
||||||
<p className="text-sm font-medium">
|
<p className="text-sm font-medium">
|
||||||
Avg. Stock: {vendor.averageStockLevel.toFixed(0)}
|
Avg. Stock: {Number(vendor.averageStockLevel).toFixed(0)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ interface Product {
|
|||||||
sku: string;
|
sku: string;
|
||||||
title: string;
|
title: string;
|
||||||
stock_quantity: number;
|
stock_quantity: number;
|
||||||
daily_sales_avg: number;
|
daily_sales_avg: string;
|
||||||
days_of_inventory: number;
|
days_of_inventory: string;
|
||||||
reorder_qty: number;
|
reorder_qty: number;
|
||||||
last_purchase_date: string | null;
|
last_purchase_date: string | null;
|
||||||
lead_time_status: string;
|
lead_time_status: string;
|
||||||
@@ -70,8 +70,8 @@ export function LowStockAlerts() {
|
|||||||
<div className="text-sm text-muted-foreground">{product.sku}</div>
|
<div className="text-sm text-muted-foreground">{product.sku}</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-right">{product.stock_quantity}</TableCell>
|
<TableCell className="text-right">{product.stock_quantity}</TableCell>
|
||||||
<TableCell className="text-right">{product.daily_sales_avg.toFixed(1)}</TableCell>
|
<TableCell className="text-right">{Number(product.daily_sales_avg).toFixed(1)}</TableCell>
|
||||||
<TableCell className="text-right">{product.days_of_inventory.toFixed(1)}</TableCell>
|
<TableCell className="text-right">{Number(product.days_of_inventory).toFixed(1)}</TableCell>
|
||||||
<TableCell className="text-right">{product.reorder_qty}</TableCell>
|
<TableCell className="text-right">{product.reorder_qty}</TableCell>
|
||||||
<TableCell>{product.last_purchase_date ? formatDate(product.last_purchase_date) : '-'}</TableCell>
|
<TableCell>{product.last_purchase_date ? formatDate(product.last_purchase_date) : '-'}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ import { DateRangePicker } from "@/components/ui/date-range-picker-narrow"
|
|||||||
interface SalesData {
|
interface SalesData {
|
||||||
totalOrders: number
|
totalOrders: number
|
||||||
totalUnitsSold: number
|
totalUnitsSold: number
|
||||||
totalCogs: number
|
totalCogs: string
|
||||||
totalRevenue: number
|
totalRevenue: string
|
||||||
dailySales: {
|
dailySales: {
|
||||||
date: string
|
date: string
|
||||||
units: number
|
units: number
|
||||||
revenue: number
|
revenue: string
|
||||||
cogs: number
|
cogs: string
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,14 +78,14 @@ export function SalesMetrics() {
|
|||||||
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
||||||
<p className="text-sm font-medium text-muted-foreground">Cost of Goods</p>
|
<p className="text-sm font-medium text-muted-foreground">Cost of Goods</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-lg font-bold">{formatCurrency(data?.totalCogs || 0)}</p>
|
<p className="text-lg font-bold">{formatCurrency(Number(data?.totalCogs) || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-baseline justify-between">
|
<div className="flex items-baseline justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
|
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
|
||||||
<p className="text-sm font-medium text-muted-foreground">Revenue</p>
|
<p className="text-sm font-medium text-muted-foreground">Revenue</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-lg font-bold">{formatCurrency(data?.totalRevenue || 0)}</p>
|
<p className="text-lg font-bold">{formatCurrency(Number(data?.totalRevenue) || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ export function SalesMetrics() {
|
|||||||
tick={false}
|
tick={false}
|
||||||
/>
|
/>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
formatter={(value: number) => [formatCurrency(value), "Revenue"]}
|
formatter={(value: string) => [formatCurrency(Number(value)), "Revenue"]}
|
||||||
labelFormatter={(date) => format(new Date(date), 'MMM d, yyyy')}
|
labelFormatter={(date) => format(new Date(date), 'MMM d, yyyy')}
|
||||||
/>
|
/>
|
||||||
<Area
|
<Area
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ interface StockMetricsData {
|
|||||||
totalProducts: number
|
totalProducts: number
|
||||||
productsInStock: number
|
productsInStock: number
|
||||||
totalStockUnits: number
|
totalStockUnits: number
|
||||||
totalStockCost: number
|
totalStockCost: string
|
||||||
totalStockRetail: number
|
totalStockRetail: string
|
||||||
brandStock: {
|
brandStock: {
|
||||||
brand: string
|
brand: string
|
||||||
variants: number
|
variants: number
|
||||||
units: number
|
units: number
|
||||||
cost: number
|
cost: string
|
||||||
retail: number
|
retail: string
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ const renderActiveShape = (props: any) => {
|
|||||||
fill="#000000"
|
fill="#000000"
|
||||||
className="text-base font-medium"
|
className="text-base font-medium"
|
||||||
>
|
>
|
||||||
{formatCurrency(retail)}
|
{formatCurrency(Number(retail))}
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
@@ -154,14 +154,14 @@ export function StockMetrics() {
|
|||||||
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
||||||
<p className="text-sm font-medium text-muted-foreground">Stock Cost</p>
|
<p className="text-sm font-medium text-muted-foreground">Stock Cost</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-lg font-bold">{formatCurrency(data?.totalStockCost || 0)}</p>
|
<p className="text-lg font-bold">{formatCurrency(Number(data?.totalStockCost) || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-baseline justify-between">
|
<div className="flex items-baseline justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
|
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
|
||||||
<p className="text-sm font-medium text-muted-foreground">Stock Retail</p>
|
<p className="text-sm font-medium text-muted-foreground">Stock Retail</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-lg font-bold">{formatCurrency(data?.totalStockRetail || 0)}</p>
|
<p className="text-lg font-bold">{formatCurrency(Number(data?.totalStockRetail) || 0)}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface Product {
|
|||||||
sku: string;
|
sku: string;
|
||||||
title: string;
|
title: string;
|
||||||
stock_quantity: number;
|
stock_quantity: number;
|
||||||
daily_sales_avg: number;
|
daily_sales_avg: string;
|
||||||
reorder_qty: number;
|
reorder_qty: number;
|
||||||
last_purchase_date: string | null;
|
last_purchase_date: string | null;
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ export function TopReplenishProducts() {
|
|||||||
<div className="text-sm text-muted-foreground">{product.sku}</div>
|
<div className="text-sm text-muted-foreground">{product.sku}</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-right">{product.stock_quantity}</TableCell>
|
<TableCell className="text-right">{product.stock_quantity}</TableCell>
|
||||||
<TableCell className="text-right">{product.daily_sales_avg.toFixed(1)}</TableCell>
|
<TableCell className="text-right">{Number(product.daily_sales_avg).toFixed(1)}</TableCell>
|
||||||
<TableCell className="text-right">{product.reorder_qty}</TableCell>
|
<TableCell className="text-right">{product.reorder_qty}</TableCell>
|
||||||
<TableCell>{product.last_purchase_date ? product.last_purchase_date : '-'}</TableCell>
|
<TableCell>{product.last_purchase_date ? product.last_purchase_date : '-'}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|||||||
Reference in New Issue
Block a user