@payware/mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/.env.example +92 -0
  2. package/MCP-SETUP.md +190 -0
  3. package/README.md +483 -0
  4. package/check-keys.js +52 -0
  5. package/keys/README.md +112 -0
  6. package/mcp-config.json +9 -0
  7. package/package.json +66 -0
  8. package/payware-mcp-config.json +12 -0
  9. package/src/auth/rsa-keys.js +82 -0
  10. package/src/auth/sandbox-setup.js +187 -0
  11. package/src/config/env.js +229 -0
  12. package/src/config/partner-types.js +143 -0
  13. package/src/core/auth/jwt-factory.js +182 -0
  14. package/src/core/auth/jwt-token.js +735 -0
  15. package/src/core/utils/json-serializer.js +100 -0
  16. package/src/core/utils/key-utils.js +133 -0
  17. package/src/index.js +237 -0
  18. package/src/isv/data/index.js +291 -0
  19. package/src/isv/deep-links/delete-product-link.js +154 -0
  20. package/src/isv/deep-links/delete-transaction-link.js +154 -0
  21. package/src/isv/deep-links/get-product-link.js +167 -0
  22. package/src/isv/deep-links/get-transaction-link.js +167 -0
  23. package/src/isv/deep-links/index.js +23 -0
  24. package/src/isv/index.js +103 -0
  25. package/src/isv/oauth2/create-token-simple.js +46 -0
  26. package/src/isv/oauth2/get-token-info.js +157 -0
  27. package/src/isv/oauth2/obtain-token.js +189 -0
  28. package/src/isv/oauth2/token-helper.js +151 -0
  29. package/src/isv/products/audios.js +470 -0
  30. package/src/isv/products/create-product.js +314 -0
  31. package/src/isv/products/delete-product.js +119 -0
  32. package/src/isv/products/get-product-image.js +247 -0
  33. package/src/isv/products/get-product.js +168 -0
  34. package/src/isv/products/index.js +65 -0
  35. package/src/isv/products/list-products.js +136 -0
  36. package/src/isv/products/schedules.js +522 -0
  37. package/src/isv/products/update-product.js +265 -0
  38. package/src/isv/transactions/cancel-transaction.js +129 -0
  39. package/src/isv/transactions/create-transaction.js +361 -0
  40. package/src/isv/transactions/get-status.js +217 -0
  41. package/src/isv/transactions/process-transaction.js +145 -0
  42. package/src/isv/transactions/simulate-callback.js +146 -0
  43. package/src/isv/transactions/transaction-history.js +186 -0
  44. package/src/isv/utils/auth.js +159 -0
  45. package/src/mcp-proxy.js +150 -0
  46. package/src/merchant/data/export-report.js +108 -0
  47. package/src/merchant/data/generate-report.js +151 -0
  48. package/src/merchant/data/get-report-status.js +120 -0
  49. package/src/merchant/data/index.js +351 -0
  50. package/src/merchant/deep-links/delete-product-link.js +121 -0
  51. package/src/merchant/deep-links/delete-transaction-link.js +121 -0
  52. package/src/merchant/deep-links/get-product-link.js +134 -0
  53. package/src/merchant/deep-links/get-transaction-link.js +134 -0
  54. package/src/merchant/deep-links/index.js +23 -0
  55. package/src/merchant/index.js +92 -0
  56. package/src/merchant/products/audios.js +606 -0
  57. package/src/merchant/products/create-product.js +288 -0
  58. package/src/merchant/products/delete-product.js +111 -0
  59. package/src/merchant/products/get-product-image.js +252 -0
  60. package/src/merchant/products/get-product.js +144 -0
  61. package/src/merchant/products/index.js +65 -0
  62. package/src/merchant/products/list-products.js +112 -0
  63. package/src/merchant/products/schedules.js +646 -0
  64. package/src/merchant/products/update-product.js +282 -0
  65. package/src/merchant/transactions/cancel-transaction.js +241 -0
  66. package/src/merchant/transactions/create-transaction.js +482 -0
  67. package/src/merchant/transactions/get-status.js +196 -0
  68. package/src/merchant/transactions/process-transaction.js +349 -0
  69. package/src/merchant/transactions/simulate-callback.js +246 -0
  70. package/src/merchant/transactions/transaction-history.js +258 -0
  71. package/src/payment-institution/data/index.js +280 -0
  72. package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
  73. package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
  74. package/src/payment-institution/deep-links/index.js +17 -0
  75. package/src/payment-institution/index.js +92 -0
  76. package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
  77. package/src/payment-institution/transactions/finalize-transaction.js +340 -0
  78. package/src/payment-institution/transactions/get-transaction-history.js +269 -0
  79. package/src/payment-institution/transactions/get-transaction-status.js +234 -0
  80. package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
  81. package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
  82. package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
  83. package/src/proxy-server.js +205 -0
  84. package/src/shared/data/data-api.js +372 -0
  85. package/src/shared/deep-links/api.js +214 -0
  86. package/src/shared/index.js +44 -0
  87. package/src/shared/products/products-api.js +872 -0
  88. package/src/tools/advanced-code-generator.js +2247 -0
  89. package/src/utils/code-examples/common/auth-examples.js +1482 -0
  90. package/src/utils/code-examples/common/helpers.js +416 -0
  91. package/src/utils/code-examples/common/utils-examples.js +591 -0
  92. package/src/utils/code-examples/frameworks/examples.js +859 -0
  93. package/src/utils/code-examples/index.js +441 -0
  94. package/src/utils/code-examples/isv/oauth2.js +600 -0
  95. package/src/utils/code-examples/isv/products.js +666 -0
  96. package/src/utils/code-examples/isv/transactions.js +813 -0
  97. package/src/utils/code-examples/merchant/products.js +497 -0
  98. package/src/utils/code-examples/merchant/transactions.js +623 -0
  99. package/src/utils/code-examples/payment-institution/transactions.js +388 -0
  100. package/src/utils/code-examples/shared/data.js +607 -0
  101. package/src/utils/code-examples/shared/deep-links.js +662 -0
  102. package/src/utils/code-examples/shared/soundbites.js +808 -0
  103. package/src/utils/code-examples.js +646 -0
  104. package/src/utils/format-request.js +363 -0
  105. package/src/utils/json-formatter.js +249 -0
  106. package/src/utils/server-info.js +132 -0
@@ -0,0 +1,591 @@
1
+ /**
2
+ * Utility examples and language-specific generators
3
+ */
4
+
5
+ import { ExampleGenerator, CommonTemplates, CodeUtils } from './helpers.js';
6
+
7
+ /**
8
+ * Python code generator
9
+ */
10
+ export class PythonGenerator extends ExampleGenerator {
11
+ constructor(framework = 'none') {
12
+ super('python', framework);
13
+ }
14
+
15
+ getEnvironmentTemplate(partnerType) {
16
+ const envVars = CommonTemplates.getEnvironmentVariables(partnerType);
17
+ const envString = Object.entries(envVars)
18
+ .map(([key, value]) => `${key}=${value}`)
19
+ .join('\n');
20
+
21
+ return `# .env file configuration
22
+ ${envString}
23
+
24
+ # Load environment variables
25
+ import os
26
+ from dotenv import load_dotenv
27
+ load_dotenv()`;
28
+ }
29
+
30
+ getDependenciesTemplate(operation) {
31
+ const baseDeps = 'requests pyjwt cryptography python-dotenv';
32
+
33
+ if (this.framework === 'django') {
34
+ return `# Install dependencies:
35
+ # pip install ${baseDeps} django
36
+
37
+ import requests
38
+ import jwt
39
+ import json
40
+ import hashlib
41
+ import base64
42
+ import os
43
+ from datetime import datetime
44
+ from django.conf import settings
45
+ from django.http import JsonResponse
46
+ from django.views.decorators.csrf import csrf_exempt`;
47
+ }
48
+
49
+ if (this.framework === 'fastapi') {
50
+ return `# Install dependencies:
51
+ # pip install ${baseDeps} fastapi uvicorn
52
+
53
+ import requests
54
+ import jwt
55
+ import json
56
+ import hashlib
57
+ import base64
58
+ import os
59
+ from datetime import datetime
60
+ from fastapi import FastAPI, HTTPException
61
+ from pydantic import BaseModel`;
62
+ }
63
+
64
+ return `# Install dependencies:
65
+ # pip install ${baseDeps}
66
+
67
+ import requests
68
+ import jwt
69
+ import json
70
+ import hashlib
71
+ import base64
72
+ import os
73
+ from datetime import datetime`;
74
+ }
75
+
76
+ getOperationTemplate(operation, partnerType, params) {
77
+ const endpoint = CommonTemplates.getApiEndpoint(operation, partnerType);
78
+ const method = CommonTemplates.getHttpMethod(operation);
79
+ const sampleBody = CommonTemplates.getSampleRequestBody(operation, partnerType, params);
80
+ const functionName = CodeUtils.formatFunctionName(operation, 'python');
81
+
82
+ const hasBody = method !== 'GET' && Object.keys(sampleBody).length > 0;
83
+
84
+ if (this.framework === 'django') {
85
+ return this.getDjangoTemplate(operation, endpoint, method, sampleBody, functionName);
86
+ }
87
+
88
+ if (this.framework === 'fastapi') {
89
+ return this.getFastAPITemplate(operation, endpoint, method, sampleBody, functionName);
90
+ }
91
+
92
+ return `def ${functionName}(${this.getParameterList(operation, params)}):
93
+ """${this.getOperationDescription(operation)}"""
94
+
95
+ # Get API configuration
96
+ base_url = get_api_base_url(use_sandbox)
97
+
98
+ ${hasBody ? `# Prepare request body
99
+ request_body = ${JSON.stringify(sampleBody, null, 4).replace(/"/g, "'")}
100
+
101
+ # Create JWT token with body hash
102
+ token, body_string = create_jwt_token(request_body, use_sandbox)
103
+ headers = get_api_headers(token)
104
+
105
+ # Make API request
106
+ response = requests.${method.toLowerCase()}(
107
+ f"{base_url}${endpoint}",
108
+ data=body_string,
109
+ headers=headers
110
+ )` : `# Create JWT token for GET request
111
+ token, _ = create_jwt_token(None, use_sandbox)
112
+ headers = get_api_headers(token)
113
+
114
+ # Make API request
115
+ response = requests.${method.toLowerCase()}(
116
+ f"{base_url}${endpoint}",
117
+ headers=headers
118
+ )`}
119
+
120
+ # Handle response
121
+ if response.status_code == 200:
122
+ return response.json()
123
+ else:
124
+ raise Exception(f"API request failed: {response.status_code} - {response.text}")
125
+
126
+ # Example usage
127
+ if __name__ == "__main__":
128
+ try:
129
+ result = ${functionName}(${this.getExampleParameters(operation, params)})
130
+ print("Success:", json.dumps(result, indent=2))
131
+ except Exception as e:
132
+ print(f"Error: {e}")`;
133
+ }
134
+
135
+ getDjangoTemplate(operation, endpoint, method, sampleBody, functionName) {
136
+ return `# Django view implementation
137
+ @csrf_exempt
138
+ def ${functionName}_view(request):
139
+ """Django view for ${operation}"""
140
+ if request.method == '${method}':
141
+ try:
142
+ ${method !== 'GET' ? `# Parse request data
143
+ data = json.loads(request.body)
144
+
145
+ # Call payware API
146
+ result = ${functionName}(**data)` : `# Call payware API
147
+ result = ${functionName}()`}
148
+
149
+ return JsonResponse({
150
+ 'success': True,
151
+ 'data': result
152
+ })
153
+ except Exception as e:
154
+ return JsonResponse({
155
+ 'success': False,
156
+ 'error': str(e)
157
+ }, status=400)
158
+
159
+ return JsonResponse({'error': 'Method not allowed'}, status=405)`;
160
+ }
161
+
162
+ getFastAPITemplate(operation, endpoint, method, sampleBody, functionName) {
163
+ const hasBody = method !== 'GET' && Object.keys(sampleBody).length > 0;
164
+
165
+ return `# FastAPI implementation
166
+ app = FastAPI()
167
+
168
+ ${hasBody ? `class ${operation.charAt(0).toUpperCase() + operation.slice(1)}Request(BaseModel):
169
+ ${Object.keys(sampleBody).map(key => `${key}: str`).join('\n ')}
170
+
171
+ @app.${method.toLowerCase()}("/${operation}")
172
+ async def ${functionName}(request: ${operation.charAt(0).toUpperCase() + operation.slice(1)}Request):` : `@app.${method.toLowerCase()}("/${operation}")
173
+ async def ${functionName}():`}
174
+ """FastAPI endpoint for ${operation}"""
175
+ try:
176
+ ${hasBody ? `# Convert request to dict
177
+ data = request.dict()
178
+
179
+ # Call payware API
180
+ result = ${functionName}(**data)` : `# Call payware API
181
+ result = ${functionName}()`}
182
+
183
+ return {"success": True, "data": result}
184
+ except Exception as e:
185
+ raise HTTPException(status_code=400, detail=str(e))`;
186
+ }
187
+
188
+ getParameterList(operation, params) {
189
+ const baseParams = ['use_sandbox=True'];
190
+
191
+ if (operation.includes('_transaction') && !operation.includes('list')) {
192
+ baseParams.unshift('transaction_id');
193
+ }
194
+ if (operation.includes('product') && !operation.includes('create')) {
195
+ baseParams.unshift('product_id');
196
+ }
197
+
198
+ return baseParams.join(', ');
199
+ }
200
+
201
+ getExampleParameters(operation, params) {
202
+ if (operation.includes('_transaction') && !operation.includes('list')) {
203
+ return '"pw12345678"';
204
+ }
205
+ if (operation.includes('product') && !operation.includes('create')) {
206
+ return '"pr12345678"';
207
+ }
208
+ return '';
209
+ }
210
+
211
+ getOperationDescription(operation) {
212
+ const descriptions = {
213
+ create_transaction: 'Create a new payment transaction',
214
+ get_transaction_status: 'Get the status of a transaction',
215
+ cancel_transaction: 'Cancel an active transaction',
216
+ process_transaction: 'Process a transaction',
217
+ create_product: 'Create a new product',
218
+ get_product: 'Get product details',
219
+ update_product: 'Update product information',
220
+ delete_product: 'Delete a product'
221
+ };
222
+
223
+ return descriptions[operation] || `Execute ${operation} operation`;
224
+ }
225
+
226
+ getErrorHandlingTemplate() {
227
+ return `def handle_payware_error(response):
228
+ """Handle payware API errors consistently"""
229
+ if response.status_code == 401:
230
+ return "Authentication failed - check your credentials"
231
+ elif response.status_code == 400:
232
+ return f"Bad request - {response.json().get('message', 'Invalid data')}"
233
+ elif response.status_code == 404:
234
+ return "Resource not found"
235
+ elif response.status_code == 429:
236
+ return "Rate limit exceeded - please retry later"
237
+ else:
238
+ return f"API error: {response.status_code} - {response.text}"`;
239
+ }
240
+
241
+ getTestTemplate(operation, partnerType) {
242
+ return `import unittest
243
+ from unittest.mock import patch, Mock
244
+
245
+ class Test${operation.charAt(0).toUpperCase() + operation.slice(1)}(unittest.TestCase):
246
+
247
+ def setUp(self):
248
+ """Set up test environment"""
249
+ os.environ['PAYWARE_PARTNER_ID'] = 'test_partner'
250
+ os.environ['PAYWARE_SANDBOX_PRIVATE_KEY_PATH'] = 'test_key.pem'
251
+
252
+ @patch('requests.${CommonTemplates.getHttpMethod(operation).toLowerCase()}')
253
+ def test_${operation}_success(self, mock_request):
254
+ """Test successful ${operation}"""
255
+ # Mock successful response
256
+ mock_response = Mock()
257
+ mock_response.status_code = 200
258
+ mock_response.json.return_value = {'transactionId': 'pw12345678'}
259
+ mock_request.return_value = mock_response
260
+
261
+ # Test the function
262
+ result = ${CodeUtils.formatFunctionName(operation, 'python')}()
263
+
264
+ # Assertions
265
+ self.assertEqual(result['transactionId'], 'pw12345678')
266
+ mock_request.assert_called_once()
267
+
268
+ @patch('requests.${CommonTemplates.getHttpMethod(operation).toLowerCase()}')
269
+ def test_${operation}_error(self, mock_request):
270
+ """Test error handling for ${operation}"""
271
+ # Mock error response
272
+ mock_response = Mock()
273
+ mock_response.status_code = 400
274
+ mock_response.text = 'Bad Request'
275
+ mock_request.return_value = mock_response
276
+
277
+ # Test error handling
278
+ with self.assertRaises(Exception):
279
+ ${CodeUtils.formatFunctionName(operation, 'python')}()
280
+
281
+ if __name__ == '__main__':
282
+ unittest.main()`;
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Node.js/JavaScript code generator
288
+ */
289
+ export class NodeJSGenerator extends ExampleGenerator {
290
+ constructor(framework = 'none') {
291
+ super('nodejs', framework);
292
+ }
293
+
294
+ getEnvironmentTemplate(partnerType) {
295
+ const envVars = CommonTemplates.getEnvironmentVariables(partnerType);
296
+ const envString = Object.entries(envVars)
297
+ .map(([key, value]) => `${key}=${value}`)
298
+ .join('\n');
299
+
300
+ return `// .env file configuration
301
+ ${envString}
302
+
303
+ // Load environment variables
304
+ require('dotenv').config();`;
305
+ }
306
+
307
+ getDependenciesTemplate(operation) {
308
+ if (this.framework === 'express') {
309
+ return `// Install dependencies:
310
+ // npm install axios jsonwebtoken crypto fs dotenv express
311
+
312
+ const express = require('express');
313
+ const axios = require('axios');
314
+ const jwt = require('jsonwebtoken');
315
+ const crypto = require('crypto');
316
+ const fs = require('fs');
317
+ require('dotenv').config();
318
+
319
+ const app = express();
320
+ app.use(express.json());`;
321
+ }
322
+
323
+ return `// Install dependencies:
324
+ // npm install axios jsonwebtoken crypto fs dotenv
325
+
326
+ const axios = require('axios');
327
+ const jwt = require('jsonwebtoken');
328
+ const crypto = require('crypto');
329
+ const fs = require('fs');
330
+ require('dotenv').config();`;
331
+ }
332
+
333
+ getOperationTemplate(operation, partnerType, params) {
334
+ const endpoint = CommonTemplates.getApiEndpoint(operation, partnerType);
335
+ const method = CommonTemplates.getHttpMethod(operation);
336
+ const sampleBody = CommonTemplates.getSampleRequestBody(operation, partnerType, params);
337
+ const functionName = CodeUtils.formatFunctionName(operation, 'nodejs');
338
+
339
+ const hasBody = method !== 'GET' && Object.keys(sampleBody).length > 0;
340
+
341
+ if (this.framework === 'express') {
342
+ return this.getExpressTemplate(operation, endpoint, method, sampleBody, functionName);
343
+ }
344
+
345
+ return `async function ${functionName}(${this.getParameterList(operation, params)}) {
346
+ /**
347
+ * ${this.getOperationDescription(operation)}
348
+ */
349
+
350
+ try {
351
+ // Get API configuration
352
+ const baseURL = getAPIBaseURL(useSandbox);
353
+
354
+ ${hasBody ? `// Prepare request body
355
+ const requestBody = ${JSON.stringify(sampleBody, null, 2)};
356
+
357
+ // Create JWT token with body hash
358
+ const { token, bodyString } = createJWTToken(requestBody, useSandbox);
359
+ const headers = getAPIHeaders(token);
360
+
361
+ // Make API request
362
+ const response = await axios.${method.toLowerCase()}(
363
+ \`\${baseURL}${endpoint}\`,
364
+ bodyString,
365
+ {
366
+ headers,
367
+ transformRequest: [(data) => data]
368
+ }
369
+ );` : `// Create JWT token for GET request
370
+ const { token } = createJWTToken(null, useSandbox);
371
+ const headers = getAPIHeaders(token);
372
+
373
+ // Make API request
374
+ const response = await axios.${method.toLowerCase()}(
375
+ \`\${baseURL}${endpoint}\`,
376
+ { headers }
377
+ );`}
378
+
379
+ return {
380
+ success: true,
381
+ data: response.data,
382
+ requestId: response.headers['x-request-id']
383
+ };
384
+
385
+ } catch (error) {
386
+ return {
387
+ success: false,
388
+ error: {
389
+ message: error.response?.data?.message || error.message,
390
+ status: error.response?.status,
391
+ details: error.response?.data
392
+ }
393
+ };
394
+ }
395
+ }
396
+
397
+ // Example usage
398
+ async function main() {
399
+ try {
400
+ const result = await ${functionName}(${this.getExampleParameters(operation, params)});
401
+ if (result.success) {
402
+ console.log('Success:', JSON.stringify(result.data, null, 2));
403
+ } else {
404
+ console.error('Error:', result.error);
405
+ }
406
+ } catch (error) {
407
+ console.error('Unexpected error:', error.message);
408
+ }
409
+ }
410
+
411
+ main();`;
412
+ }
413
+
414
+ getExpressTemplate(operation, endpoint, method, sampleBody, functionName) {
415
+ const hasBody = method !== 'GET' && Object.keys(sampleBody).length > 0;
416
+
417
+ return `// Express.js route implementation
418
+ app.${method.toLowerCase()}('/${operation}', async (req, res) => {
419
+ try {
420
+ ${hasBody ? `// Get data from request body
421
+ const requestData = req.body;
422
+
423
+ // Call payware API
424
+ const result = await ${functionName}(requestData);` : `// Call payware API
425
+ const result = await ${functionName}();`}
426
+
427
+ if (result.success) {
428
+ res.json({
429
+ success: true,
430
+ data: result.data,
431
+ requestId: result.requestId
432
+ });
433
+ } else {
434
+ res.status(400).json({
435
+ success: false,
436
+ error: result.error
437
+ });
438
+ }
439
+ } catch (error) {
440
+ res.status(500).json({
441
+ success: false,
442
+ error: {
443
+ message: error.message
444
+ }
445
+ });
446
+ }
447
+ });
448
+
449
+ // Start server
450
+ const PORT = process.env.PORT || 3000;
451
+ app.listen(PORT, () => {
452
+ console.log(\`Server running on port \${PORT}\`);
453
+ });`;
454
+ }
455
+
456
+ getParameterList(operation, params) {
457
+ const baseParams = ['useSandbox = true'];
458
+
459
+ if (operation.includes('_transaction') && !operation.includes('list')) {
460
+ baseParams.unshift('transactionId');
461
+ }
462
+ if (operation.includes('product') && !operation.includes('create')) {
463
+ baseParams.unshift('productId');
464
+ }
465
+
466
+ return baseParams.join(', ');
467
+ }
468
+
469
+ getExampleParameters(operation, params) {
470
+ if (operation.includes('_transaction') && !operation.includes('list')) {
471
+ return "'pw12345678'";
472
+ }
473
+ if (operation.includes('product') && !operation.includes('create')) {
474
+ return "'pr12345678'";
475
+ }
476
+ return '';
477
+ }
478
+
479
+ getOperationDescription(operation) {
480
+ const descriptions = {
481
+ create_transaction: 'Create a new payment transaction',
482
+ get_transaction_status: 'Get the status of a transaction',
483
+ cancel_transaction: 'Cancel an active transaction',
484
+ process_transaction: 'Process a transaction',
485
+ create_product: 'Create a new product',
486
+ get_product: 'Get product details',
487
+ update_product: 'Update product information',
488
+ delete_product: 'Delete a product'
489
+ };
490
+
491
+ return descriptions[operation] || `Execute ${operation} operation`;
492
+ }
493
+
494
+ getErrorHandlingTemplate() {
495
+ return `function handlePaywareError(error) {
496
+ if (error.response) {
497
+ // Server responded with error status
498
+ const status = error.response.status;
499
+ const data = error.response.data;
500
+
501
+ switch (status) {
502
+ case 401:
503
+ return 'Authentication failed - check your credentials';
504
+ case 400:
505
+ return \`Bad request - \${data.message || 'Invalid data'}\`;
506
+ case 404:
507
+ return 'Resource not found';
508
+ case 429:
509
+ return 'Rate limit exceeded - please retry later';
510
+ default:
511
+ return \`API error: \${status} - \${data.message || error.message}\`;
512
+ }
513
+ } else if (error.request) {
514
+ // Network error
515
+ return 'Network error - please check your connection';
516
+ } else {
517
+ // Other error
518
+ return \`Error: \${error.message}\`;
519
+ }
520
+ }`;
521
+ }
522
+
523
+ getTestTemplate(operation, partnerType) {
524
+ return `// Jest test example
525
+ const { ${CodeUtils.formatFunctionName(operation, 'nodejs')} } = require('./payware-client');
526
+ const axios = require('axios');
527
+
528
+ // Mock axios
529
+ jest.mock('axios');
530
+ const mockedAxios = axios;
531
+
532
+ describe('${operation}', () => {
533
+ beforeEach(() => {
534
+ // Set up environment variables
535
+ process.env.PAYWARE_PARTNER_ID = 'test_partner';
536
+ process.env.PAYWARE_SANDBOX_PRIVATE_KEY_PATH = 'test_key.pem';
537
+
538
+ // Clear all mocks
539
+ jest.clearAllMocks();
540
+ });
541
+
542
+ test('should handle successful response', async () => {
543
+ // Mock successful response
544
+ const mockResponse = {
545
+ data: { transactionId: 'pw12345678' },
546
+ headers: { 'x-request-id': 'req-123' },
547
+ status: 200
548
+ };
549
+
550
+ mockedAxios.${CommonTemplates.getHttpMethod(operation).toLowerCase()}.mockResolvedValue(mockResponse);
551
+
552
+ // Test the function
553
+ const result = await ${CodeUtils.formatFunctionName(operation, 'nodejs')}();
554
+
555
+ // Assertions
556
+ expect(result.success).toBe(true);
557
+ expect(result.data.transactionId).toBe('pw12345678');
558
+ expect(mockedAxios.${CommonTemplates.getHttpMethod(operation).toLowerCase()}).toHaveBeenCalledTimes(1);
559
+ });
560
+
561
+ test('should handle API errors', async () => {
562
+ // Mock error response
563
+ const mockError = {
564
+ response: {
565
+ status: 400,
566
+ data: { message: 'Bad Request' }
567
+ }
568
+ };
569
+
570
+ mockedAxios.${CommonTemplates.getHttpMethod(operation).toLowerCase()}.mockRejectedValue(mockError);
571
+
572
+ // Test error handling
573
+ const result = await ${CodeUtils.formatFunctionName(operation, 'nodejs')}();
574
+
575
+ // Assertions
576
+ expect(result.success).toBe(false);
577
+ expect(result.error.status).toBe(400);
578
+ expect(result.error.message).toBe('Bad Request');
579
+ });
580
+ });`;
581
+ }
582
+ }
583
+
584
+ /**
585
+ * Export all utility generators
586
+ */
587
+ export const UtilityGenerators = {
588
+ python: PythonGenerator,
589
+ nodejs: NodeJSGenerator,
590
+ javascript: NodeJSGenerator
591
+ };