2 * CWA Fieldpine GNAP API Integration
3 * Based on real API analysis from iig.cwanz.online
6export interface CWAApiResponse<T = any> {
12export interface LocationData {
20export interface StatsData {
22 transactions_today?: number;
23 last_updated?: string;
26export interface SalesTotalsData {
32export class CWAGnapApi {
33 private baseUrl: string;
34 private apiKey?: string;
36 constructor(baseUrl?: string) {
37 this.baseUrl = baseUrl || process.env.NEXT_PUBLIC_FIELDPINE_GNAP_API_URL || 'https://iig.cwanz.online/GNAP/j';
41 * Set the API key for authenticated requests
43 setApiKey(apiKey: string) {
48 * Make a BUCK request to the GNAP API
50 private async buckRequest(service: string, params: Record<string, string | number> = {}): Promise<CWAApiResponse> {
51 const url = new URL(`${this.baseUrl}/BUCK`);
53 // Add the service parameter
54 url.searchParams.set('3', service);
56 // Add additional parameters
57 Object.entries(params).forEach(([key, value]) => {
58 url.searchParams.set(key, String(value));
61 const headers: HeadersInit = {
63 'Cache-Control': 'no-cache',
66 // Add authentication if available
68 headers['Cookie'] = `FieldpineApiKey=${this.apiKey}`;
72 const response = await fetch(url.toString(), {
79 error: `HTTP ${response.status}: ${response.statusText}`,
84 const data = await response.json();
91 error: error instanceof Error ? error.message : 'Unknown error',
98 * Make a simple GET request to non-BUCK endpoints
100 private async simpleRequest(endpoint: string, params: Record<string, string | number> = {}): Promise<CWAApiResponse> {
101 const baseUrl = this.baseUrl.replace('/GNAP/j', ''); // Use base domain for simple requests
102 const url = new URL(`${baseUrl}/${endpoint}`);
104 Object.entries(params).forEach(([key, value]) => {
105 url.searchParams.set(key, String(value));
108 const headers: HeadersInit = {
110 'Cache-Control': 'no-cache',
114 headers['Cookie'] = `FieldpineApiKey=${this.apiKey}`;
118 const response = await fetch(url.toString(), {
125 error: `HTTP ${response.status}: ${response.statusText}`,
130 const data = await response.text(); // Some endpoints return text, not JSON
133 const jsonData = JSON.parse(data);
134 return { data: jsonData, status: 'success' };
136 return { data, status: 'success' };
140 error: error instanceof Error ? error.message : 'Unknown error',
146 // Specific API methods based on discovered endpoints
150 * BUCK?3=retailmax.elink.locations&101=1
152 async getLocations(includeAll = true): Promise<CWAApiResponse<LocationData[]>> {
153 return this.buckRequest('retailmax.elink.locations', includeAll ? { '101': 1 } : undefined);
157 * Get specific locations by range
158 * buck?3=retailmax.elink.locations&10=100-160,164,185,186
160 async getLocationsByRange(range: string): Promise<CWAApiResponse<LocationData[]>> {
161 return this.buckRequest('retailmax.elink.locations', { '10': range });
165 * Get today's statistics
166 * buck?3=retailmax.elink.stats.today
168 async getStatsToday(): Promise<CWAApiResponse<StatsData>> {
169 return this.buckRequest('retailmax.elink.stats.today');
173 * Get today's statistics with specific fields
174 * buck?3=retailmax.elink.stats.today&9=f112,0,1
176 async getStatsTodayWithFields(fields: string): Promise<CWAApiResponse<StatsData>> {
177 return this.buckRequest('retailmax.elink.stats.today', { '9': fields });
182 * buck?3=retailmax.elink.sale.totals&13=120&7=101&9=f110,4,month-0
184 async getSalesTotals(params: {
188 } = {}): Promise<CWAApiResponse<SalesTotalsData>> {
189 const requestParams: Record<string, string | number> = {};
190 if (params.field13) requestParams['13'] = params.field13;
191 if (params.field7) requestParams['7'] = params.field7;
192 if (params.field9) requestParams['9'] = params.field9;
194 return this.buckRequest('retailmax.elink.sale.totals', requestParams);
198 * Get user interface components
199 * buck?3=retailmax.elink.userinterface&100=sshome
201 async getUserInterface(component: string): Promise<CWAApiResponse> {
202 return this.buckRequest('retailmax.elink.userinterface', { '100': component });
206 * Get printing pending list
207 * buck?3=retailmax.elink.printingpending.list
209 async getPrintingPending(): Promise<CWAApiResponse> {
210 return this.buckRequest('retailmax.elink.printingpending.list');
214 * Get contact log list
215 * buck?3=retailmax.elink.contactlog.list&500=quicksummary
217 async getContactLog(filter?: string): Promise<CWAApiResponse> {
218 const params = filter ? { '500': filter } : undefined;
219 return this.buckRequest('retailmax.elink.contactlog.list', params);
224 * buck?3=gds.server.status
226 async getServerStatus(): Promise<CWAApiResponse> {
227 return this.buckRequest('gds.server.status');
231 * Get configuration settings
232 * buck?3=retailmax.elink.config.setting&9=f100,0,RmSystem
234 async getConfigSetting(setting: string): Promise<CWAApiResponse> {
235 return this.buckRequest('retailmax.elink.config.setting', { '9': setting });
239 * Get base configuration
240 * BUCK?3=retailmax.elink.config.basesetting&112=1&112=999&9=f100,0,SaleSendRandomHost.1.Address
242 async getBaseSetting(setting: string, field112Values: number[] = [1, 999]): Promise<CWAApiResponse> {
243 const params: Record<string, string | number> = { '9': setting };
244 field112Values.forEach((value, index) => {
245 params[`112`] = value; // Note: This will overwrite, but that's how the original API works
247 return this.buckRequest('retailmax.elink.config.basesetting', params);
251 * Get advisor event list
252 * buck?3=retailmax.elink.advisor.eventlist&110=accou…other,products,staff,reference,security,technical
254 async getAdvisorEventList(categories: string): Promise<CWAApiResponse> {
255 return this.buckRequest('retailmax.elink.advisor.eventlist', { '110': categories });
258 // Simple endpoint methods
261 * Get membership information
262 * membership?id=cartridgeworld
264 async getMembership(id: string): Promise<CWAApiResponse> {
265 return this.simpleRequest('membership', { id });
272 async getProducts(filter?: number): Promise<CWAApiResponse> {
273 const params = filter ? { '99': filter } : undefined;
274 return this.simpleRequest('products', params);
278 * Get locations (simple endpoint)
281 async getLocationsSimple(): Promise<CWAApiResponse> {
282 return this.simpleRequest('locations');
286 * Get retail configuration
289 async getRetailConfig(): Promise<CWAApiResponse> {
290 return this.simpleRequest('RetailConfig');
297 async getEcho(): Promise<CWAApiResponse> {
298 return this.simpleRequest('echo.js');
302// Create singleton instance
303export const cwaApi = new CWAGnapApi();
305// Helper function to set API key globally
306export function setCWAApiKey(apiKey: string) {
307 cwaApi.setApiKey(apiKey);