EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
route.ts
Go to the documentation of this file.
1import { NextRequest, NextResponse } from 'next/server';
2import { fieldpineServerApi } from '@/lib/server/fieldpineApi';
3import { getStoredAuth } from '@/lib/server/auth';
4
5/**
6 * Pareto Analysis (80/20 Rule)
7 * BUCK: retailmax.elink.product.paretolist
8 * Returns top performing products by various metrics
9 */
10export async function GET(request: NextRequest) {
11 try {
12 const authData = await getStoredAuth();
13 if (!authData || !authData.authenticated) {
14 return NextResponse.json(
15 { error: 'Authentication required' },
16 { status: 401 }
17 );
18 }
19
20 const { searchParams } = new URL(request.url);
21
22 // Date filters
23 const startDate = searchParams.get('startDate');
24 const endDate = searchParams.get('endDate');
25 const limit = searchParams.get('limit') || '50';
26
27 // Analysis type: basketrate, grossmargin, returns, volume, revenue
28 const type = searchParams.get('type') || 'revenue';
29
30 // Build BUCK parameters
31 const params: string[] = [
32 '3=retailmax.elink.product.paretolist',
33 `8=${limit}`
34 ];
35
36 // Add date filters
37 if (startDate) {
38 params.push(`9=f102,4,${startDate}`);
39 }
40 if (endDate) {
41 params.push(`9=f102,1,${endDate}`);
42 }
43
44 // Set analysis type
45 switch (type) {
46 case 'basketrate':
47 params.push('100=1'); // Sort by basket rate
48 break;
49 case 'grossmargin':
50 params.push('100=2'); // Sort by gross margin
51 break;
52 case 'returns':
53 params.push('100=3'); // Sort by return rate
54 break;
55 case 'volume':
56 params.push('100=4'); // Sort by units sold
57 break;
58 case 'revenue':
59 default:
60 params.push('100=5'); // Sort by revenue (default)
61 break;
62 }
63
64 const query = params.join('&');
65 const url = `/GNAP/j/buck?${query}`;
66
67 console.log('[Pareto Analysis] BUCK query:', url);
68
69 const result = await fieldpineServerApi.apiCall(url, {
70 cookie: authData.apiKey,
71 useOpenApi: false
72 });
73
74 // Process BUCK response
75 if (result && result.DATS && Array.isArray(result.DATS)) {
76 const products = result.DATS.map((item: any, index: number) => ({
77 rank: index + 1,
78 productId: item.f200,
79 productName: item.f201,
80 barcode: item.f202,
81 unitsSold: item.f210,
82 revenue: item.f211,
83 cost: item.f212,
84 grossProfit: item.f213,
85 grossMargin: item.f214,
86 basketRate: item.f220, // % of transactions containing this item
87 returnRate: item.f221,
88 averagePrice: item.f222,
89 supplierId: item.f230,
90 supplierName: item.f231,
91 departmentId: item.f240,
92 departmentName: item.f241,
93 percentOfTotal: item.f250 // Cumulative % contribution
94 }));
95
96 // Calculate 80/20 breakpoint
97 const breakpoint = products.findIndex((p: any) => p.percentOfTotal >= 80);
98
99 return NextResponse.json({
100 success: true,
101 data: products,
102 count: products.length,
103 type,
104 analysis: {
105 top20PercentCount: Math.ceil(products.length * 0.2),
106 eightyPercentBreakpoint: breakpoint > 0 ? breakpoint : products.length,
107 top20PercentRevenue: products.slice(0, Math.ceil(products.length * 0.2))
108 .reduce((sum: number, p: any) => sum + (p.revenue || 0), 0)
109 },
110 source: 'buck'
111 });
112 }
113
114 return NextResponse.json({
115 success: true,
116 data: [],
117 count: 0,
118 type,
119 source: 'buck'
120 });
121
122 } catch (error) {
123 console.error('[Pareto Analysis] Error:', error);
124 return NextResponse.json(
125 { error: 'Failed to fetch pareto analysis' },
126 { status: 500 }
127 );
128 }
129}