Fix previous period data
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { TimeManager } from '../utils/time.utils.js';
|
import { TimeManager } from '../utils/time.utils.js';
|
||||||
import { RedisService } from './redis.service.js';
|
import { RedisService } from './redis.service.js';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
const METRIC_IDS = {
|
const METRIC_IDS = {
|
||||||
PLACED_ORDER: 'Y8cqcF',
|
PLACED_ORDER: 'Y8cqcF',
|
||||||
@@ -225,12 +226,24 @@ export class EventsService {
|
|||||||
metricId: METRIC_IDS.CANCELED_ORDER
|
metricId: METRIC_IDS.CANCELED_ORDER
|
||||||
}),
|
}),
|
||||||
this.getEvents({
|
this.getEvents({
|
||||||
|
// Only pass through non-date related params for previous period
|
||||||
|
..._.omit(params, ['timeRange', 'startDate', 'endDate']),
|
||||||
metricId: METRIC_IDS.PLACED_ORDER,
|
metricId: METRIC_IDS.PLACED_ORDER,
|
||||||
startDate: prevPeriodStart.toISO(),
|
startDate: prevPeriodStart.toISO(),
|
||||||
endDate: prevPeriodEnd.toISO()
|
endDate: prevPeriodEnd.toISO()
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Add debug logging
|
||||||
|
console.log('[EventsService] Previous period request:', {
|
||||||
|
params: _.omit(params, ['timeRange', 'startDate', 'endDate']),
|
||||||
|
dates: {
|
||||||
|
start: prevPeriodStart.toISO(),
|
||||||
|
end: prevPeriodEnd.toISO()
|
||||||
|
},
|
||||||
|
responseLength: prevPeriodData?.data?.length
|
||||||
|
});
|
||||||
|
|
||||||
// Transform all data
|
// Transform all data
|
||||||
const transformedOrders = this._transformEvents(orderData.data);
|
const transformedOrders = this._transformEvents(orderData.data);
|
||||||
const transformedShipped = this._transformEvents(shippedData.data);
|
const transformedShipped = this._transformEvents(shippedData.data);
|
||||||
@@ -1489,15 +1502,51 @@ export class EventsService {
|
|||||||
...params,
|
...params,
|
||||||
startDate: periodStart.toISO(),
|
startDate: periodStart.toISO(),
|
||||||
endDate: periodEnd.toISO(),
|
endDate: periodEnd.toISO(),
|
||||||
metricId: METRIC_IDS.PLACED_ORDER
|
metricId: METRIC_IDS.PLACED_ORDER,
|
||||||
|
customFilters: params.metric === 'pre_orders' ? ['equals(event_properties.HasPreorder,true)'] :
|
||||||
|
params.metric === 'local_pickup' ? ['equals(event_properties.LocalPickup,true)'] :
|
||||||
|
params.metric === 'on_hold' ? ['equals(event_properties.IsOnHold,true)'] : undefined
|
||||||
}),
|
}),
|
||||||
this.getEvents({
|
this.getEvents({
|
||||||
metricId: METRIC_IDS.PLACED_ORDER,
|
..._.omit(params, ['timeRange', 'startDate', 'endDate']),
|
||||||
startDate: prevPeriodStart.toISO(),
|
startDate: prevPeriodStart.toISO(),
|
||||||
endDate: prevPeriodEnd.toISO()
|
endDate: prevPeriodEnd.toISO(),
|
||||||
|
metricId: METRIC_IDS.PLACED_ORDER,
|
||||||
|
timeRange: undefined,
|
||||||
|
isPreviousPeriod: true,
|
||||||
|
cacheKey: `prev_${prevPeriodStart.toISO()}_${prevPeriodEnd.toISO()}`,
|
||||||
|
customFilters: params.metric === 'pre_orders' ? ['equals(event_properties.HasPreorder,true)'] :
|
||||||
|
params.metric === 'local_pickup' ? ['equals(event_properties.LocalPickup,true)'] :
|
||||||
|
params.metric === 'on_hold' ? ['equals(event_properties.IsOnHold,true)'] : undefined
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Add debug logging for request params and filters
|
||||||
|
console.log('[EventsService] Request details with filters:', {
|
||||||
|
current: {
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
startDate: periodStart.toISO(),
|
||||||
|
endDate: periodEnd.toISO(),
|
||||||
|
customFilters: params.metric === 'pre_orders' ? ['equals(event_properties.HasPreorder,true)'] :
|
||||||
|
params.metric === 'local_pickup' ? ['equals(event_properties.LocalPickup,true)'] :
|
||||||
|
params.metric === 'on_hold' ? ['equals(event_properties.IsOnHold,true)'] : undefined
|
||||||
|
},
|
||||||
|
responseLength: currentResponse?.data?.length
|
||||||
|
},
|
||||||
|
previous: {
|
||||||
|
params: {
|
||||||
|
..._.omit(params, ['timeRange', 'startDate', 'endDate']),
|
||||||
|
startDate: prevPeriodStart.toISO(),
|
||||||
|
endDate: prevPeriodEnd.toISO(),
|
||||||
|
customFilters: params.metric === 'pre_orders' ? ['equals(event_properties.HasPreorder,true)'] :
|
||||||
|
params.metric === 'local_pickup' ? ['equals(event_properties.LocalPickup,true)'] :
|
||||||
|
params.metric === 'on_hold' ? ['equals(event_properties.IsOnHold,true)'] : undefined
|
||||||
|
},
|
||||||
|
responseLength: prevResponse?.data?.length
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Transform events
|
// Transform events
|
||||||
const currentEvents = this._transformEvents(currentResponse.data || []);
|
const currentEvents = this._transformEvents(currentResponse.data || []);
|
||||||
const prevEvents = this._transformEvents(prevResponse.data || []);
|
const prevEvents = this._transformEvents(prevResponse.data || []);
|
||||||
@@ -1561,6 +1610,7 @@ export class EventsService {
|
|||||||
const dateKey = prevDate.toFormat('yyyy-MM-dd');
|
const dateKey = prevDate.toFormat('yyyy-MM-dd');
|
||||||
prevDailyStats.set(dateKey, {
|
prevDailyStats.set(dateKey, {
|
||||||
date: prevDate.toISO(),
|
date: prevDate.toISO(),
|
||||||
|
timestamp: dateKey,
|
||||||
revenue: 0,
|
revenue: 0,
|
||||||
orders: 0,
|
orders: 0,
|
||||||
itemCount: 0
|
itemCount: 0
|
||||||
@@ -1584,31 +1634,43 @@ export class EventsService {
|
|||||||
dayStats.revenue += totalAmount;
|
dayStats.revenue += totalAmount;
|
||||||
dayStats.orders++;
|
dayStats.orders++;
|
||||||
dayStats.itemCount += items.length;
|
dayStats.itemCount += items.length;
|
||||||
|
prevDailyStats.set(dateKey, dayStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map previous period data to current period days based on relative position
|
// Map previous period data to current period days
|
||||||
const prevPeriodDays = Array.from(prevDailyStats.values());
|
const prevPeriodDays = Array.from(prevDailyStats.values()).sort((a, b) => a.date.localeCompare(b.date));
|
||||||
const currentPeriodDays = Array.from(dailyStats.values());
|
const currentPeriodDays = Array.from(dailyStats.values()).sort((a, b) => a.date.localeCompare(b.date));
|
||||||
const daysInPeriod = currentPeriodDays.length;
|
|
||||||
|
|
||||||
for (let i = 0; i < daysInPeriod; i++) {
|
// Add debug logging for data before mapping
|
||||||
|
console.log('[EventsService] Data before mapping:', {
|
||||||
|
currentPeriod: currentPeriodDays.slice(0, 3),
|
||||||
|
previousPeriod: prevPeriodDays.slice(0, 3),
|
||||||
|
currentLength: currentPeriodDays.length,
|
||||||
|
prevLength: prevPeriodDays.length
|
||||||
|
});
|
||||||
|
|
||||||
|
// Map the data using array indices
|
||||||
|
for (let i = 0; i < currentPeriodDays.length && i < prevPeriodDays.length; i++) {
|
||||||
const currentDayStats = currentPeriodDays[i];
|
const currentDayStats = currentPeriodDays[i];
|
||||||
const prevDayStats = prevPeriodDays[i];
|
const prevDayStats = prevPeriodDays[i];
|
||||||
|
|
||||||
if (prevDayStats) {
|
if (prevDayStats && currentDayStats) {
|
||||||
const dayStats = dailyStats.get(currentDayStats.timestamp);
|
const dayStats = dailyStats.get(currentDayStats.timestamp);
|
||||||
|
if (dayStats) {
|
||||||
dayStats.prevRevenue = prevDayStats.revenue;
|
dayStats.prevRevenue = prevDayStats.revenue;
|
||||||
dayStats.prevOrders = prevDayStats.orders;
|
dayStats.prevOrders = prevDayStats.orders;
|
||||||
dayStats.prevItemCount = prevDayStats.itemCount;
|
dayStats.prevItemCount = prevDayStats.itemCount;
|
||||||
dayStats.prevAvgOrderValue = prevDayStats.orders > 0 ? prevDayStats.revenue / prevDayStats.orders : 0;
|
dayStats.prevAvgOrderValue = prevDayStats.orders > 0 ? prevDayStats.revenue / prevDayStats.orders : 0;
|
||||||
|
dailyStats.set(currentDayStats.timestamp, dayStats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the final daily stats before returning
|
// Add debug logging for mapped data
|
||||||
console.log('[EventsService] Final daily stats sample:', {
|
console.log('[EventsService] Sample of mapped data:', {
|
||||||
totalDays: dailyStats.size,
|
firstDay: dailyStats.get(currentPeriodDays[0]?.timestamp),
|
||||||
firstDay: Array.from(dailyStats.values())[0],
|
lastDay: dailyStats.get(currentPeriodDays[currentPeriodDays.length - 1]?.timestamp),
|
||||||
lastDay: Array.from(dailyStats.values())[dailyStats.size - 1]
|
totalDays: dailyStats.size
|
||||||
});
|
});
|
||||||
|
|
||||||
// Convert to array and sort by date
|
// Convert to array and sort by date
|
||||||
|
|||||||
@@ -133,22 +133,45 @@ export class RedisService {
|
|||||||
|
|
||||||
// Helper to generate cache keys
|
// Helper to generate cache keys
|
||||||
_getCacheKey(type, params = {}) {
|
_getCacheKey(type, params = {}) {
|
||||||
const { timeRange, startDate, endDate, metricId, metric, daily } = params;
|
const {
|
||||||
|
timeRange,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
metricId,
|
||||||
|
metric,
|
||||||
|
daily,
|
||||||
|
cacheKey,
|
||||||
|
isPreviousPeriod
|
||||||
|
} = params;
|
||||||
|
|
||||||
let key = `klaviyo:${type}`;
|
let key = `klaviyo:${type}`;
|
||||||
|
|
||||||
|
// Handle "stats:details" for daily or metric-based keys
|
||||||
if (type === 'stats:details') {
|
if (type === 'stats:details') {
|
||||||
key += `:${metric}${daily ? ':daily' : ''}`;
|
key += `:${metric}${daily ? ':daily' : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeRange) {
|
// If a specific cache key is provided, use it (highest priority)
|
||||||
|
if (cacheKey) {
|
||||||
|
key += `:${cacheKey}`;
|
||||||
|
}
|
||||||
|
// Otherwise, build a default cache key
|
||||||
|
else if (timeRange) {
|
||||||
key += `:${timeRange}${metricId ? `:${metricId}` : ''}`;
|
key += `:${timeRange}${metricId ? `:${metricId}` : ''}`;
|
||||||
|
if (isPreviousPeriod) {
|
||||||
|
key += ':prev';
|
||||||
|
}
|
||||||
} else if (startDate && endDate) {
|
} else if (startDate && endDate) {
|
||||||
key += `:custom:${startDate}:${endDate}${metricId ? `:${metricId}` : ''}`;
|
key += `:custom:${startDate}:${endDate}${metricId ? `:${metricId}` : ''}`;
|
||||||
|
if (isPreviousPeriod) {
|
||||||
|
key += ':prev';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get TTL based on time range
|
// Get TTL based on time range
|
||||||
_getTTL(timeRange) {
|
_getTTL(timeRange) {
|
||||||
const TTL_MAP = {
|
const TTL_MAP = {
|
||||||
|
|||||||
@@ -523,53 +523,24 @@ const SalesChart = ({
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
// Get previous period params
|
// Fetch data
|
||||||
const prevPeriodParams = calculatePreviousPeriodDates(
|
const response = await axios.get('/api/klaviyo/events/stats/details', {
|
||||||
params.timeRange,
|
|
||||||
params.startDate,
|
|
||||||
params.endDate
|
|
||||||
);
|
|
||||||
|
|
||||||
// Fetch both current and previous period data
|
|
||||||
const [currentResponse, prevResponse] = await Promise.all([
|
|
||||||
axios.get('/api/klaviyo/events/stats/details', {
|
|
||||||
params: {
|
params: {
|
||||||
...params,
|
...params,
|
||||||
metric: 'revenue',
|
metric: 'revenue',
|
||||||
daily: true
|
daily: true
|
||||||
}
|
}
|
||||||
}),
|
});
|
||||||
axios.get('/api/klaviyo/events/stats/details', {
|
|
||||||
params: {
|
|
||||||
metric: 'revenue',
|
|
||||||
daily: true,
|
|
||||||
...(prevPeriodParams || {})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!currentResponse.data) {
|
if (!response.data) {
|
||||||
throw new Error('Invalid response format');
|
throw new Error('Invalid response format');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the data
|
// Process the data
|
||||||
const currentStats = Array.isArray(currentResponse.data) ? currentResponse.data : currentResponse.data.stats || [];
|
const currentStats = Array.isArray(response.data) ? response.data : response.data.stats || [];
|
||||||
const prevStats = Array.isArray(prevResponse.data) ? prevResponse.data : (prevResponse.data?.stats || []);
|
|
||||||
|
|
||||||
// Map previous period data to current period dates
|
// Process the data directly without remapping
|
||||||
const processedStats = currentStats.map((day, index) => {
|
const processedData = processData(currentStats);
|
||||||
// Find the corresponding previous period day
|
|
||||||
const prevDay = prevStats[index] || {};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...day,
|
|
||||||
prevRevenue: Number(prevDay.revenue || 0),
|
|
||||||
prevOrders: Number(prevDay.orders || 0),
|
|
||||||
prevAvgOrderValue: Number(prevDay.averageOrderValue || (prevDay.orders > 0 ? prevDay.revenue / prevDay.orders : 0))
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const processedData = processData(processedStats);
|
|
||||||
const stats = calculateSummaryStats(processedData);
|
const stats = calculateSummaryStats(processedData);
|
||||||
|
|
||||||
setData(processedData);
|
setData(processedData);
|
||||||
|
|||||||
Reference in New Issue
Block a user