mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 13:15:24 +02:00
Implement Weeks of Coverage indicator for Vendor Stock
This commit is contained in:
@@ -598,10 +598,35 @@ export const mergeSalesAndAdsData = (
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Calculate 4-Week Average Sales per ASIN
|
||||
const latestYear = Math.max(...salesData.map(r => r.year).filter(y => y > 0));
|
||||
const yearData = salesData.filter(r => r.year === latestYear);
|
||||
const latestWeek = yearData.length > 0 ? Math.max(...yearData.map(r => r.week).filter(w => w !== undefined) as number[]) : 0;
|
||||
|
||||
const last4WeeksKeys = new Set<string>();
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let w = latestWeek - i;
|
||||
let y = latestYear;
|
||||
if (w <= 0) {
|
||||
w = 52 + w;
|
||||
y = latestYear - 1;
|
||||
}
|
||||
last4WeeksKeys.add(`${y}|${w}`);
|
||||
}
|
||||
|
||||
const asin4WeekSales = new Map<string, number>();
|
||||
salesData.forEach(r => {
|
||||
if (r.week === undefined) return;
|
||||
if (last4WeeksKeys.has(`${r.year}|${r.week}`)) {
|
||||
const key = r.asin.trim().toUpperCase();
|
||||
asin4WeekSales.set(key, (asin4WeekSales.get(key) || 0) + r.units);
|
||||
}
|
||||
});
|
||||
|
||||
const mergedData: CombinedKPIs[] = [];
|
||||
const processedKeys = new Set<string>();
|
||||
|
||||
// 4. Create ONE record per ASIN/Customer/Year/Week from sales
|
||||
// 5. Create ONE record per ASIN/Customer/Year/Week from sales
|
||||
salesMap.forEach((sale, key) => {
|
||||
processedKeys.add(key);
|
||||
const ad = adsMap.get(key);
|
||||
@@ -623,6 +648,7 @@ export const mergeSalesAndAdsData = (
|
||||
const ctr = adImpressions > 0 ? (adClicks / adImpressions) * 100 : 0;
|
||||
const cpc = adClicks > 0 ? adCost / adClicks : 0;
|
||||
const cvrUnits = adClicks > 0 ? (adUnits / adClicks) * 100 : 0;
|
||||
const avgWeeklySales = (asin4WeekSales.get(sale.asin.trim().toUpperCase()) || 0) / 4;
|
||||
|
||||
mergedData.push({
|
||||
id: `merged-${key}`,
|
||||
@@ -653,7 +679,8 @@ export const mergeSalesAndAdsData = (
|
||||
ctr,
|
||||
cpc,
|
||||
cvrUnits,
|
||||
glanceViews: trafficMap.get(key) || 0
|
||||
glanceViews: trafficMap.get(key) || 0,
|
||||
avgWeeklySales
|
||||
});
|
||||
});
|
||||
|
||||
@@ -662,6 +689,7 @@ export const mergeSalesAndAdsData = (
|
||||
if (!processedKeys.has(key)) {
|
||||
const asin = ad.asin.trim().toUpperCase();
|
||||
const meta = asinMetadata.get(asin);
|
||||
const avgWeeklySales = (asin4WeekSales.get(asin) || 0) / 4;
|
||||
|
||||
mergedData.push({
|
||||
id: `ads-only-${key}`,
|
||||
@@ -692,7 +720,8 @@ export const mergeSalesAndAdsData = (
|
||||
ctr: ad.impressions > 0 ? (ad.clicks / ad.impressions) * 100 : 0,
|
||||
cpc: ad.clicks > 0 ? ad.cost / ad.clicks : 0,
|
||||
cvrUnits: ad.clicks > 0 ? (ad.attributedUnits30d / ad.clicks) * 100 : 0,
|
||||
glanceViews: trafficMap.get(key) || 0
|
||||
glanceViews: trafficMap.get(key) || 0,
|
||||
avgWeeklySales
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1684,9 +1713,35 @@ export const calculateForecastViewData = (
|
||||
monthMap.set(m, (monthMap.get(m) || 0) + r.units);
|
||||
});
|
||||
|
||||
// 4-Week Average Sales Calculation
|
||||
const latestYear = Math.max(...rawData.map(r => r.year).filter(y => y > 0));
|
||||
const yearData = rawData.filter(r => r.year === latestYear);
|
||||
const latestWeek = yearData.length > 0 ? Math.max(...yearData.map(r => r.week).filter(w => w !== undefined) as number[]) : 0;
|
||||
|
||||
const last4WeeksKeys = new Set<string>();
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let w = latestWeek - i;
|
||||
let y = latestYear;
|
||||
if (w <= 0) {
|
||||
w = 52 + w;
|
||||
y = latestYear - 1;
|
||||
}
|
||||
last4WeeksKeys.add(`${y}|${w}`);
|
||||
}
|
||||
|
||||
const asin4WeekSales = new Map<string, number>();
|
||||
rawData.forEach(r => {
|
||||
if (r.week === undefined) return;
|
||||
if (last4WeeksKeys.has(`${r.year}|${r.week}`)) {
|
||||
const key = r.asin.trim().toUpperCase();
|
||||
asin4WeekSales.set(key, (asin4WeekSales.get(key) || 0) + r.units);
|
||||
}
|
||||
});
|
||||
|
||||
return forecastData.map(fc => {
|
||||
const identifier = fc.asin.toUpperCase();
|
||||
const meta = asinMetadata.get(identifier);
|
||||
const avgWeeklySales = (asin4WeekSales.get(identifier) || 0) / 4;
|
||||
|
||||
// 2. Determine weights for this ASIN
|
||||
const productRecords2025 = dataByAsin2025.get(identifier) || [];
|
||||
@@ -1735,6 +1790,7 @@ export const calculateForecastViewData = (
|
||||
actualUnits: totalActualUnits,
|
||||
forecastUnits: totalForecastUnits,
|
||||
accuracy: Math.max(0, accuracy),
|
||||
avgWeeklySales,
|
||||
monthlyData
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user