Fix mini sales chart and sales charts previous period calculations

This commit is contained in:
2025-05-30 09:51:03 -04:00
parent 21185e23cf
commit 1200d26866
3 changed files with 61 additions and 31 deletions

View File

@@ -328,44 +328,74 @@ router.get('/stats/details', async (req, res) => {
const [dailyResults] = await connection.execute(dailyQuery, params); const [dailyResults] = await connection.execute(dailyQuery, params);
// Get all previous year data in a single query // Get previous period data using the same logic as main stats endpoint
const prevYearQuery = ` let prevWhereClause, prevParams;
if (timeRange && timeRange !== 'custom') {
const prevTimeRange = getPreviousTimeRange(timeRange);
const result = getTimeRangeConditions(prevTimeRange);
prevWhereClause = result.whereClause;
prevParams = result.params;
} else {
// Custom date range - go back by the same duration
const start = new Date(startDate);
const end = new Date(endDate);
const duration = end.getTime() - start.getTime();
const prevEnd = new Date(start.getTime() - 1);
const prevStart = new Date(prevEnd.getTime() - duration);
prevWhereClause = 'date_placed >= ? AND date_placed <= ?';
prevParams = [prevStart.toISOString(), prevEnd.toISOString()];
}
// Get previous period daily data
const prevQuery = `
SELECT SELECT
DATE(date_placed) as date, DATE(date_placed) as date,
COUNT(*) as prevOrders, COUNT(*) as prevOrders,
SUM(summary_total) as prevRevenue, SUM(summary_total) as prevRevenue,
AVG(summary_total) as prevAvgOrderValue AVG(summary_total) as prevAvgOrderValue
FROM _order FROM _order
WHERE order_status > 15 AND ${whereClause.replace(/date_placed/g, 'DATE_SUB(date_placed, INTERVAL 1 YEAR)')} WHERE order_status > 15 AND ${prevWhereClause}
GROUP BY DATE(date_placed) GROUP BY DATE(date_placed)
`; `;
const [prevYearResults] = await connection.execute(prevYearQuery, params); const [prevResults] = await connection.execute(prevQuery, prevParams);
// Create a map for quick lookup of previous year data // Create a map for quick lookup of previous period data
const prevYearMap = new Map(); const prevMap = new Map();
prevYearResults.forEach(prev => { prevResults.forEach(prev => {
const currentYearDate = new Date(prev.date); const key = new Date(prev.date).toISOString().split('T')[0];
currentYearDate.setFullYear(currentYearDate.getFullYear() + 1); prevMap.set(key, prev);
const key = currentYearDate.toISOString().split('T')[0];
prevYearMap.set(key, prev);
}); });
// Combine current and previous year data // For period-to-period comparison, we need to map days by relative position
const statsWithComparison = dailyResults.map(day => { // since dates won't match exactly (e.g., current week vs previous week)
const dayKey = new Date(day.date).toISOString().split('T')[0]; const dailyArray = dailyResults.map(day => ({
const prev = prevYearMap.get(dayKey) || { prevOrders: 0, prevRevenue: 0, prevAvgOrderValue: 0 }; timestamp: day.date,
date: day.date,
orders: parseInt(day.orders),
revenue: parseFloat(day.revenue),
averageOrderValue: parseFloat(day.averageOrderValue || 0),
itemCount: parseInt(day.itemCount)
}));
const prevArray = prevResults.map(day => ({
orders: parseInt(day.prevOrders),
revenue: parseFloat(day.prevRevenue),
averageOrderValue: parseFloat(day.prevAvgOrderValue || 0)
}));
// Combine current and previous period data by matching relative positions
const statsWithComparison = dailyArray.map((day, index) => {
const prev = prevArray[index] || { orders: 0, revenue: 0, averageOrderValue: 0 };
return { return {
timestamp: day.date, ...day,
date: day.date, prevOrders: prev.orders,
orders: parseInt(day.orders), prevRevenue: prev.revenue,
revenue: parseFloat(day.revenue), prevAvgOrderValue: prev.averageOrderValue
averageOrderValue: parseFloat(day.averageOrderValue || 0),
itemCount: parseInt(day.itemCount),
prevOrders: parseInt(prev.prevOrders || 0),
prevRevenue: parseFloat(prev.prevRevenue || 0),
prevAvgOrderValue: parseFloat(prev.prevAvgOrderValue || 0)
}; };
}); });

View File

@@ -4058,9 +4058,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001686", "version": "1.0.30001720",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001686.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
"integrity": "sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==", "integrity": "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {

View File

@@ -196,13 +196,13 @@ const MiniSalesChart = ({ className = "" }) => {
daily: true, daily: true,
}); });
if (!response.data) { if (!response.stats) {
throw new Error("Invalid response format"); throw new Error("Invalid response format");
} }
const stats = Array.isArray(response) const stats = Array.isArray(response.stats)
? response ? response.stats
: response.stats || []; : [];
const processedData = processData(stats); const processedData = processData(stats);