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 { getRequestContext, validateApiAccess } from '@/lib/server/sessionUtils';
3
4/**
5 * Store Stock Levels API
6 * GET /api/v1/inventory/stock-levels
7 *
8 * Returns current stock levels across all locations (or filtered by location)
9 * Uses Fieldpine's SQL3 endpoint
10 */
11export async function GET(request: NextRequest) {
12 try {
13 // 1. Get session and store context
14 const context = await getRequestContext(request);
15
16 if (!context || !context.isAuthenticated) {
17 return NextResponse.json(
18 { error: 'Authentication required' },
19 { status: 401 }
20 );
21 }
22
23 // 2. SECURITY: Validate API access
24 const apiAccessValidation = validateApiAccess(context, 'elink');
25 if (!apiAccessValidation.valid) {
26 console.warn(`[Stock Levels API] Access denied: ${apiAccessValidation.error}`);
27 return NextResponse.json(
28 {
29 error: apiAccessValidation.error,
30 code: apiAccessValidation.errorCode
31 },
32 { status: 403 }
33 );
34 }
35
36 // 3. Parse query parameters
37 const { searchParams } = new URL(request.url);
38 const locationId = searchParams.get('locationId');
39 const minQty = searchParams.get('minQty') || '0';
40 const includeZero = searchParams.get('includeZero') === 'true';
41
42 console.log('[Stock Levels API] Request params:', { locationId, minQty, includeZero });
43
44 // 4. Build SQL query
45 let sqlQuery = `
46 select
47 l.name as [locname],
48 i.pid as [pid],
49 i.qoh as [qoh],
50 p.description as [descrip],
51 p.plucode as [sku],
52 p.manupartcode as [partcode]
53 from
54 products_inventory i,
55 products p,
56 locations l
57 where
58 i.pid = p.pid
59 and i.location_id = l.location_id
60 `.trim();
61
62 // Add filters
63 if (!includeZero) {
64 sqlQuery += ' and i.qoh <> 0';
65 }
66
67 if (locationId) {
68 sqlQuery += ` and l.location_id = ${parseInt(locationId)}`;
69 }
70
71 sqlQuery += ' order by i.qoh desc';
72
73 console.log('[Stock Levels API] SQL:', sqlQuery);
74
75 // 5. Make SQL3 API call
76 const encodedQuery = encodeURIComponent(sqlQuery);
77 const url = `${context.store.url}/GNAP/J/SQL3?19=${encodedQuery}`;
78
79 const response = await fetch(url, {
80 method: 'GET',
81 headers: {
82 'Cookie': `FieldpineApiKey=${context.session.apiKey}`,
83 'Accept': 'application/json'
84 }
85 });
86
87 if (!response.ok) {
88 console.error('[Stock Levels API] SQL3 failed:', response.status, response.statusText);
89 throw new Error(`SQL3 API error: ${response.status} ${response.statusText}`);
90 }
91
92 const data = await response.json();
93
94 console.log('[Stock Levels API] Response:', {
95 hasData: !!data.data,
96 rowCount: data.data?.rows?.length || 0
97 });
98
99 // 6. Return formatted response
100 return NextResponse.json({
101 success: true,
102 data: {
103 sql: sqlQuery,
104 rows: data.data?.rows || [],
105 count: data.data?.rows?.length || 0
106 }
107 });
108
109 } catch (error: any) {
110 console.error('[Stock Levels API] Error:', error);
111
112 if (error.message && error.message.includes('403')) {
113 return NextResponse.json(
114 {
115 error: 'Your session has expired. Please refresh the page and log in again.',
116 code: 'SESSION_EXPIRED'
117 },
118 { status: 401 }
119 );
120 }
121
122 return NextResponse.json(
123 { error: error.message || 'Failed to fetch stock levels' },
124 { status: 500 }
125 );
126 }
127}