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 { getRequestContext, validateApiAccess } from '@/lib/server/sessionUtils';
4
5/**
6 * Goods Movement Report
7 * BUCK: retailmax.elink.goodsmovement.codedetail
8 * Returns stock transfers, adjustments, write-offs
9 */
10export async function GET(request: NextRequest) {
11 console.log('[Goods Movement] START - Route handler called');
12 try {
13 // 1. Get and validate session
14 const context = await getRequestContext(request);
15 const validation = validateApiAccess(context, 'elink');
16 if (!validation.valid || !context) {
17 return NextResponse.json(
18 { error: validation.error || 'Access denied', errorCode: validation.errorCode },
19 { status: 403 }
20 );
21 }
22
23 const { searchParams } = new URL(request.url);
24
25 // Date filters
26 const startDate = searchParams.get('startDate');
27 const endDate = searchParams.get('endDate');
28 const limit = searchParams.get('limit') || '200';
29
30 // Movement type: transfer, adjustment, writeoff, stocktake
31 const movementType = searchParams.get('type');
32
33 // Location filter
34 const locationId = searchParams.get('locationId');
35
36 // Product filter
37 const productId = searchParams.get('productId');
38
39 // Build BUCK parameters
40 const buckParams: Record<string, string | string[]> = {
41 '3': 'retailmax.elink.goodsmovement.codedetail',
42 '8': limit,
43 '99': Math.random().toString() // Cache buster
44 };
45
46 // Build filters array
47 const filters: string[] = [];
48
49 // Add date filters
50 if (startDate) {
51 filters.push(`f102,4,${startDate}`); // Movement date >=
52 }
53 if (endDate) {
54 filters.push(`f102,1,${endDate}`); // Movement date <
55 }
56
57 // Add location filter
58 if (locationId) {
59 filters.push(`f131,2,${locationId}`);
60 }
61
62 // Add product filter
63 if (productId) {
64 filters.push(`f200,2,${productId}`);
65 }
66
67 // Add movement type filter
68 if (movementType) {
69 let typeCode = '0';
70 switch (movementType) {
71 case 'transfer':
72 typeCode = '1';
73 break;
74 case 'adjustment':
75 typeCode = '2';
76 break;
77 case 'writeoff':
78 typeCode = '3';
79 break;
80 case 'stocktake':
81 typeCode = '4';
82 break;
83 case 'return':
84 typeCode = '5';
85 break;
86 }
87 filters.push(`f110,2,${typeCode}`);
88 }
89
90 // Add filters to BUCK params
91 if (filters.length > 0) {
92 buckParams['9'] = filters;
93 }
94
95 // Use store-specific URL for API calls
96 const result = await fieldpineServerApi.buckApiCall(buckParams, context.session.apiKey, context.store.url);
97
98 console.log('[Goods Movement] BUCK response:', { hasResult: !!result, resultType: typeof result });
99
100 // Process BUCK response
101 if (result?.DATS && Array.isArray(result.DATS)) {
102 const movements = result.DATS.map((item: any) => ({
103 movementId: item?.f100,
104 movementDate: item?.f102,
105 movementType: item?.f110,
106 movementTypeName: item?.f111,
107 productId: item?.f200,
108 productName: item?.f201,
109 barcode: item?.f202,
110 quantity: item?.f210,
111 unitCost: item?.f211,
112 totalCost: item?.f212,
113 fromLocationId: item?.f131,
114 fromLocationName: item?.f132,
115 toLocationId: item?.f133,
116 toLocationName: item?.f134,
117 reasonCode: item?.f120,
118 reasonDescription: item?.f121,
119 userId: item?.f140,
120 userName: item?.f141,
121 notes: item?.f150,
122 referenceNumber: item?.f160
123 }));
124
125 // Calculate summary by type
126 const summary = movements.reduce((acc: Record<string, any>, m: any) => {
127 const type = m.movementTypeName || 'Unknown';
128 if (!acc[type]) {
129 acc[type] = { count: 0, totalUnits: 0, totalValue: 0 };
130 }
131 acc[type].count++;
132 acc[type].totalUnits += Math.abs(m.quantity || 0);
133 acc[type].totalValue += Math.abs(m.totalCost || 0);
134 return acc;
135 }, {} as Record<string, any>);
136
137 return NextResponse.json({
138 success: true,
139 data: movements,
140 count: movements.length,
141 summary,
142 source: 'buck'
143 });
144 }
145
146 return NextResponse.json({
147 success: true,
148 data: [],
149 count: 0,
150 source: 'buck'
151 });
152
153 } catch (error) {
154 console.error('[Goods Movement] Error:', error);
155 return NextResponse.json(
156 { error: 'Failed to fetch goods movements' },
157 { status: 500 }
158 );
159 }
160}