From 38a882975271577ec1187a12962173ada669f875 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 26 Dec 2024 15:56:43 -0500 Subject: [PATCH] Fix order range chart --- .../klaviyo-server/services/events.service.js | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/dashboard-server/klaviyo-server/services/events.service.js b/dashboard-server/klaviyo-server/services/events.service.js index 844fd73..551f805 100644 --- a/dashboard-server/klaviyo-server/services/events.service.js +++ b/dashboard-server/klaviyo-server/services/events.service.js @@ -1537,6 +1537,104 @@ export class EventsService { prevPeriodEnd = prevRange.end; } + // For order range, we need to process all orders with their value distribution + if (metric === 'order_range') { + const [currentEvents] = await Promise.all([ + this.getEvents({ + ...params, + startDate: periodStart.toISO(), + endDate: periodEnd.toISO(), + metricId: METRIC_IDS.PLACED_ORDER + }) + ]); + + // Transform events + const transformedEvents = this._transformEvents(currentEvents.data || []); + console.log(`[EventsService] Processing ${transformedEvents.length} orders for order range`); + + // Initialize daily stats map with all dates in range + const dailyStats = new Map(); + let currentDate = periodStart; + while (currentDate <= periodEnd) { + const dateKey = currentDate.toFormat('yyyy-MM-dd'); + dailyStats.set(dateKey, { + date: currentDate.toISO(), + timestamp: dateKey, + orders: 0, + averageOrderValue: 0, + orderValueRange: { + largest: 0, + smallest: 0, + largestOrderId: null, + smallestOrderId: null + }, + orderValueDistribution: [ + { min: 0, max: 25, count: 0, total: 0 }, + { min: 25, max: 50, count: 0, total: 0 }, + { min: 50, max: 100, count: 0, total: 0 }, + { min: 100, max: 200, count: 0, total: 0 }, + { min: 200, max: 'Infinity', count: 0, total: 0 } + ] + }); + currentDate = currentDate.plus({ days: 1 }); + } + + // Process events + for (const event of transformedEvents) { + const datetime = this.timeManager.toDateTime(event.attributes?.datetime); + if (!datetime) continue; + + const props = event.event_properties || {}; + const totalAmount = Number(props.TotalAmount || 0); + const orderId = props.OrderId; + + const dayStart = this.timeManager.getDayStart(datetime); + const dateKey = dayStart.toFormat('yyyy-MM-dd'); + + if (dailyStats.has(dateKey)) { + const dayStats = dailyStats.get(dateKey); + dayStats.orders++; + + // Update order value range + if (totalAmount > dayStats.orderValueRange.largest) { + dayStats.orderValueRange.largest = totalAmount; + dayStats.orderValueRange.largestOrderId = orderId; + } + if (totalAmount > 0 && (dayStats.orderValueRange.smallest === 0 || totalAmount < dayStats.orderValueRange.smallest)) { + dayStats.orderValueRange.smallest = totalAmount; + dayStats.orderValueRange.smallestOrderId = orderId; + } + + // Update distribution + if (totalAmount < 25) { + dayStats.orderValueDistribution[0].count++; + dayStats.orderValueDistribution[0].total += totalAmount; + } else if (totalAmount < 50) { + dayStats.orderValueDistribution[1].count++; + dayStats.orderValueDistribution[1].total += totalAmount; + } else if (totalAmount < 100) { + dayStats.orderValueDistribution[2].count++; + dayStats.orderValueDistribution[2].total += totalAmount; + } else if (totalAmount < 200) { + dayStats.orderValueDistribution[3].count++; + dayStats.orderValueDistribution[3].total += totalAmount; + } else { + dayStats.orderValueDistribution[4].count++; + dayStats.orderValueDistribution[4].total += totalAmount; + } + + dayStats.averageOrderValue = dayStats.orderValueDistribution.reduce((sum, range) => sum + range.total, 0) / dayStats.orders; + dailyStats.set(dateKey, dayStats); + } + } + + // Convert to array and sort by date + const stats = Array.from(dailyStats.values()) + .sort((a, b) => a.date.localeCompare(b.date)); + + return stats; + } + // For refunds and cancellations, we need to fetch those specific events if (metric === 'refunds' || metric === 'cancellations') { const [currentEvents] = await Promise.all([