fix sales issue
This commit is contained in:
@@ -1,58 +1,139 @@
|
||||
import type {
|
||||
BusinessAlert,
|
||||
CommerceFilterState,
|
||||
ForecastDataPoint,
|
||||
FunnelStage,
|
||||
HeatmapCell,
|
||||
MetricCardData,
|
||||
PaymentBreakdownItem,
|
||||
TopProductRow,
|
||||
} from '../types/commerce';
|
||||
|
||||
export const COMMERCE_KPIS: Record<string, MetricCardData> = {
|
||||
revenue: {title: 'Total Revenue', value: '₹3,40,000', change: '+14.2% vs prev', trendDirection: 'up', subtitle: 'Net revenue across active stores'},
|
||||
orders: {title: 'Total Orders', value: '1,284', change: '+8.5%', trendDirection: 'up', subtitle: 'Completed order volume'},
|
||||
aov: {title: 'Average Order Value', value: '₹1,420', change: '+5.1%', trendDirection: 'up', subtitle: 'Average spend per cart'},
|
||||
netSales: {title: 'Net Sales', value: '₹3,18,000', change: '+13.9%', trendDirection: 'up', subtitle: 'Revenue after discounts'},
|
||||
refunds: {title: 'Refunds & Returns', value: '₹22,000', change: '-2.4%', trendDirection: 'down', subtitle: '6.4% total return rate'},
|
||||
conversion: {title: 'Store Conversion', value: '23.8%', change: '+1.4%', trendDirection: 'up', subtitle: 'Visits to purchase ratio'},
|
||||
topStore: {title: 'Top Performing Store', value: 'Indiranagar Flagship', change: '+18.4%', trendDirection: 'up', subtitle: '₹9.1L Revenue (23.8% Conv)'},
|
||||
const STORE_MULTIPLIERS: Record<string, number> = {
|
||||
all: 1.0,
|
||||
'blr-indiranagar': 0.42,
|
||||
'blr-koramangala': 0.28,
|
||||
'blr-whitefield': 0.18,
|
||||
'che-anna-nagar': 0.12,
|
||||
'hyd-jubilee': 0.1,
|
||||
};
|
||||
|
||||
export const REVENUE_TREND_DATA = [
|
||||
{time: '08:00', Revenue: 18000, Target: 15000},
|
||||
{time: '10:00', Revenue: 35000, Target: 30000},
|
||||
{time: '12:00', Revenue: 72000, Target: 60000},
|
||||
{time: '14:00', Revenue: 95000, Target: 80000},
|
||||
{time: '16:00', Revenue: 82000, Target: 75000},
|
||||
{time: '18:00', Revenue: 110000, Target: 90000},
|
||||
{time: '20:00', Revenue: 68000, Target: 60000},
|
||||
];
|
||||
const RANGE_MULTIPLIERS: Record<string, number> = {
|
||||
'7d': 1.0,
|
||||
'30d': 3.8,
|
||||
'90d': 11.2,
|
||||
mtd: 2.1,
|
||||
ytd: 24.5,
|
||||
custom: 1.5,
|
||||
};
|
||||
|
||||
export const ORDERS_TREND_DATA = [
|
||||
{time: '08:00', Orders: 42},
|
||||
{time: '10:00', Orders: 88},
|
||||
{time: '12:00', Orders: 165},
|
||||
{time: '14:00', Orders: 210},
|
||||
{time: '16:00', Orders: 184},
|
||||
{time: '18:00', Orders: 245},
|
||||
{time: '20:00', Orders: 135},
|
||||
];
|
||||
function getMult(storeId: string, range: string): {storeMult: number; rangeMult: number; totalMult: number} {
|
||||
const storeMult = STORE_MULTIPLIERS[storeId] ?? 1.0;
|
||||
const rangeMult = RANGE_MULTIPLIERS[range] ?? 1.0;
|
||||
return {storeMult, rangeMult, totalMult: storeMult * rangeMult};
|
||||
}
|
||||
|
||||
export const SALES_FUNNEL_STAGES: FunnelStage[] = [
|
||||
{stage: 'Visitors', count: 12400, label: 'Store & Web Visitors', conversionRate: '100%', color: '#3b82f6'},
|
||||
{stage: 'Product Views', count: 8680, label: 'Browsed Items', conversionRate: '70%', color: '#6366f1'},
|
||||
{stage: 'Add to Cart', count: 4340, label: 'Cart Created', conversionRate: '50%', color: '#8b5cf6'},
|
||||
{stage: 'Checkout Initiated', count: 3100, label: 'Entered Checkout', conversionRate: '71.4%', color: '#ec4899'},
|
||||
{stage: 'Purchased', count: 2951, label: 'Order Completed', conversionRate: '95.2%', color: '#10b981'},
|
||||
];
|
||||
export function getCommerceKpis(storeId = 'all', range = '7d') {
|
||||
const {totalMult, storeMult} = getMult(storeId, range);
|
||||
|
||||
export const PAYMENT_BREAKDOWN_DATA: PaymentBreakdownItem[] = [
|
||||
{method: 'UPI', amount: '₹1,97,200', percentage: 58, color: '#10b981'},
|
||||
{method: 'Credit & Debit Cards', amount: '₹95,200', percentage: 28, color: '#3b82f6'},
|
||||
{method: 'Store Credit / LYT', amount: '₹34,000', percentage: 10, color: '#f59e0b'},
|
||||
{method: 'Cash & POS', amount: '₹13,600', percentage: 4, color: '#8b5cf6'},
|
||||
];
|
||||
const baseRevenue = 340000 * totalMult;
|
||||
const baseOrders = Math.round(1284 * totalMult);
|
||||
const baseAov = Math.round(1420 * (0.9 + storeMult * 0.25));
|
||||
const baseNetSales = 318000 * totalMult;
|
||||
const baseRefunds = 22000 * totalMult;
|
||||
const baseConversion = Number((23.8 * (0.85 + storeMult * 0.3)).toFixed(1));
|
||||
|
||||
return {
|
||||
revenue: {
|
||||
title: 'Total Revenue',
|
||||
rawValue: baseRevenue,
|
||||
change: '+14.2% vs prev',
|
||||
trendDirection: 'up' as const,
|
||||
subtitle: 'Net revenue across selected store',
|
||||
},
|
||||
orders: {
|
||||
title: 'Total Orders',
|
||||
rawValue: baseOrders,
|
||||
change: '+8.5%',
|
||||
trendDirection: 'up' as const,
|
||||
subtitle: 'Completed order volume',
|
||||
},
|
||||
aov: {
|
||||
title: 'Avg Order Value',
|
||||
rawValue: baseAov,
|
||||
change: '+5.1%',
|
||||
trendDirection: 'up' as const,
|
||||
subtitle: 'Average spend per cart',
|
||||
},
|
||||
netSales: {
|
||||
title: 'Net Sales',
|
||||
rawValue: baseNetSales,
|
||||
change: '+13.9%',
|
||||
trendDirection: 'up' as const,
|
||||
subtitle: 'Revenue after discounts',
|
||||
},
|
||||
refunds: {
|
||||
title: 'Refunds',
|
||||
rawValue: baseRefunds,
|
||||
change: '-2.4%',
|
||||
trendDirection: 'down' as const,
|
||||
subtitle: 'Total returns rate',
|
||||
},
|
||||
conversion: {
|
||||
title: 'Conversion',
|
||||
rawValue: baseConversion,
|
||||
change: '+1.4%',
|
||||
trendDirection: 'up' as const,
|
||||
subtitle: 'Visits to purchase ratio',
|
||||
},
|
||||
grossSales: {
|
||||
title: 'Gross Sales',
|
||||
rawValue: baseRevenue * 1.065,
|
||||
change: '+12.8%',
|
||||
trendDirection: 'up' as const,
|
||||
},
|
||||
discounts: {
|
||||
title: 'Discounts & Promos',
|
||||
rawValue: baseRefunds,
|
||||
change: '-4.1%',
|
||||
trendDirection: 'down' as const,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getRevenueTrendData(storeId = 'all', range = '7d') {
|
||||
const {totalMult} = getMult(storeId, range);
|
||||
return [
|
||||
{time: '08:00', Revenue: Math.round(18000 * totalMult), Target: Math.round(15000 * totalMult)},
|
||||
{time: '10:00', Revenue: Math.round(35000 * totalMult), Target: Math.round(30000 * totalMult)},
|
||||
{time: '12:00', Revenue: Math.round(72000 * totalMult), Target: Math.round(60000 * totalMult)},
|
||||
{time: '14:00', Revenue: Math.round(95000 * totalMult), Target: Math.round(80000 * totalMult)},
|
||||
{time: '16:00', Revenue: Math.round(82000 * totalMult), Target: Math.round(75000 * totalMult)},
|
||||
{time: '18:00', Revenue: Math.round(110000 * totalMult), Target: Math.round(90000 * totalMult)},
|
||||
{time: '20:00', Revenue: Math.round(68000 * totalMult), Target: Math.round(60000 * totalMult)},
|
||||
];
|
||||
}
|
||||
|
||||
export function getOrdersTrendData(storeId = 'all', range = '7d') {
|
||||
const {totalMult} = getMult(storeId, range);
|
||||
return [
|
||||
{time: '08:00', Orders: Math.max(1, Math.round(42 * totalMult))},
|
||||
{time: '10:00', Orders: Math.max(1, Math.round(88 * totalMult))},
|
||||
{time: '12:00', Orders: Math.max(1, Math.round(165 * totalMult))},
|
||||
{time: '14:00', Orders: Math.max(1, Math.round(210 * totalMult))},
|
||||
{time: '16:00', Orders: Math.max(1, Math.round(184 * totalMult))},
|
||||
{time: '18:00', Orders: Math.max(1, Math.round(245 * totalMult))},
|
||||
{time: '20:00', Orders: Math.max(1, Math.round(135 * totalMult))},
|
||||
];
|
||||
}
|
||||
|
||||
export function getPaymentBreakdownData(storeId = 'all', range = '7d'): PaymentBreakdownItem[] {
|
||||
const {totalMult} = getMult(storeId, range);
|
||||
const totalInr = 340000 * totalMult;
|
||||
|
||||
return [
|
||||
{method: 'UPI', amount: `₹${(totalInr * 0.58).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, percentage: 58, color: '#10b981'},
|
||||
{method: 'Credit & Debit Cards', amount: `₹${(totalInr * 0.28).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, percentage: 28, color: '#3b82f6'},
|
||||
{method: 'Store Credit / LYT', amount: `₹${(totalInr * 0.10).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, percentage: 10, color: '#f59e0b'},
|
||||
{method: 'Cash & POS', amount: `₹${(totalInr * 0.04).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, percentage: 4, color: '#8b5cf6'},
|
||||
];
|
||||
}
|
||||
|
||||
export const STORE_PERFORMANCE_DATA = [
|
||||
{store: 'Indiranagar Flagship', Revenue: 910000},
|
||||
@@ -61,36 +142,16 @@ export const STORE_PERFORMANCE_DATA = [
|
||||
{store: 'Whitefield Main', Revenue: 330000},
|
||||
];
|
||||
|
||||
export const TOP_PRODUCTS_DATA: TopProductRow[] = [
|
||||
{id: 'tp1', name: 'Signature Espresso Blend (1kg)', category: 'Beverage & Beans', unitsSold: 482, revenue: '₹1,44,600', growth: '+18.4%', growthDirection: 'up', stockCount: 142, stockStatus: 'in_stock'},
|
||||
{id: 'tp2', name: 'Artisanal Cold Brew Pack (6x)', category: 'Ready to Drink', unitsSold: 310, revenue: '₹93,000', growth: '+12.1%', growthDirection: 'up', stockCount: 18, stockStatus: 'low_stock'},
|
||||
{id: 'tp3', name: 'Ceramic Barista Mug (Matte Black)', category: 'Merchandise', unitsSold: 215, revenue: '₹75,250', growth: '+8.9%', growthDirection: 'up', stockCount: 8, stockStatus: 'low_stock'},
|
||||
{id: 'tp4', name: 'Vanilla Bean Syrup (750ml)', category: 'Syrups', unitsSold: 184, revenue: '₹46,000', growth: '+5.4%', growthDirection: 'up', stockCount: 85, stockStatus: 'in_stock'},
|
||||
{id: 'tp5', name: 'French Press Brewer (8-Cup)', category: 'Equipment', unitsSold: 94, revenue: '₹37,600', growth: '-2.1%', growthDirection: 'down', stockCount: 0, stockStatus: 'out_of_stock'},
|
||||
];
|
||||
|
||||
export const HEATMAP_HOURS = ['08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00'];
|
||||
export const HEATMAP_DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
||||
|
||||
export const HEATMAP_DATA: HeatmapCell[] = [
|
||||
{day: 'Mon', hour: '12:00', value: 65},
|
||||
{day: 'Mon', hour: '18:00', value: 85},
|
||||
{day: 'Fri', hour: '18:00', value: 98},
|
||||
{day: 'Sat', hour: '14:00', value: 92},
|
||||
{day: 'Sat', hour: '18:00', value: 100},
|
||||
{day: 'Sun', hour: '12:00', value: 78},
|
||||
{day: 'Sun', hour: '18:00', value: 95},
|
||||
];
|
||||
|
||||
export const FORECAST_TREND_DATA: ForecastDataPoint[] = [
|
||||
{date: 'Mon', actual: 280000, forecast: 275000, lowerBound: 260000, upperBound: 290000},
|
||||
{date: 'Tue', actual: 310000, forecast: 300000, lowerBound: 285000, upperBound: 315000},
|
||||
{date: 'Wed', actual: 295000, forecast: 290000, lowerBound: 275000, upperBound: 305000},
|
||||
{date: 'Thu', actual: 340000, forecast: 330000, lowerBound: 310000, upperBound: 350000},
|
||||
{date: 'Fri (Est)', forecast: 380000, lowerBound: 355000, upperBound: 405000},
|
||||
{date: 'Sat (Est)', forecast: 420000, lowerBound: 390000, upperBound: 450000},
|
||||
{date: 'Sun (Est)', forecast: 390000, lowerBound: 360000, upperBound: 420000},
|
||||
];
|
||||
export function getTopProductsData(storeId = 'all', range = '7d'): TopProductRow[] {
|
||||
const {totalMult} = getMult(storeId, range);
|
||||
return [
|
||||
{id: 'tp1', name: 'Signature Espresso Blend (1kg)', category: 'Beverage & Beans', unitsSold: Math.round(482 * totalMult), revenue: `₹${(144600 * totalMult).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, growth: '+18.4%', growthDirection: 'up', stockCount: 142, stockStatus: 'in_stock'},
|
||||
{id: 'tp2', name: 'Artisanal Cold Brew Pack (6x)', category: 'Ready to Drink', unitsSold: Math.round(310 * totalMult), revenue: `₹${(93000 * totalMult).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, growth: '+12.1%', growthDirection: 'up', stockCount: 18, stockStatus: 'low_stock'},
|
||||
{id: 'tp3', name: 'Ceramic Barista Mug (Matte Black)', category: 'Merchandise', unitsSold: Math.round(215 * totalMult), revenue: `₹${(75250 * totalMult).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, growth: '+8.9%', growthDirection: 'up', stockCount: 8, stockStatus: 'low_stock'},
|
||||
{id: 'tp4', name: 'Vanilla Bean Syrup (750ml)', category: 'Syrups', unitsSold: Math.round(184 * totalMult), revenue: `₹${(46000 * totalMult).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, growth: '+5.4%', growthDirection: 'up', stockCount: 85, stockStatus: 'in_stock'},
|
||||
{id: 'tp5', name: 'French Press Brewer (8-Cup)', category: 'Equipment', unitsSold: Math.round(94 * totalMult), revenue: `₹${(37600 * totalMult).toLocaleString('en-IN', {maximumFractionDigits: 0})}`, growth: '-2.1%', growthDirection: 'down', stockCount: 0, stockStatus: 'out_of_stock'},
|
||||
];
|
||||
}
|
||||
|
||||
export const BUSINESS_ALERTS: BusinessAlert[] = [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user