@payware/mcp-server 1.1.1 ā 1.3.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.
- package/.env.example +0 -0
- package/README.md +22 -16
- package/check-keys.js +0 -0
- package/keys/README.md +0 -0
- package/mcp-config.json +0 -0
- package/package.json +69 -66
- package/payware-mcp-config.json +0 -0
- package/src/auth/rsa-keys.js +0 -0
- package/src/auth/sandbox-setup.js +186 -186
- package/src/config/env.js +0 -0
- package/src/config/partner-types.js +0 -0
- package/src/core/auth/jwt-factory.js +4 -4
- package/src/core/auth/jwt-token.js +107 -66
- package/src/core/utils/json-serializer.js +5 -5
- package/src/core/utils/key-utils.js +0 -0
- package/src/index.js +0 -0
- package/src/isv/data/index.js +0 -0
- package/src/isv/deep-links/delete-product-link.js +0 -0
- package/src/isv/deep-links/delete-transaction-link.js +0 -0
- package/src/isv/deep-links/get-product-link.js +0 -0
- package/src/isv/deep-links/get-transaction-link.js +0 -0
- package/src/isv/deep-links/index.js +0 -0
- package/src/isv/index.js +29 -1
- package/src/isv/invitations/index.js +471 -0
- package/src/isv/oauth2/create-token-simple.js +0 -0
- package/src/isv/oauth2/get-token-info.js +0 -0
- package/src/isv/oauth2/obtain-token.js +19 -8
- package/src/isv/oauth2/token-helper.js +5 -2
- package/src/isv/poi/cancel-price.js +2 -10
- package/src/isv/poi/create.js +19 -0
- package/src/isv/poi/get-poi.js +2 -10
- package/src/isv/poi/get-qrcode.js +2 -10
- package/src/isv/poi/get-status.js +2 -10
- package/src/isv/poi/index.js +5 -0
- package/src/isv/poi/list-pois.js +2 -10
- package/src/isv/poi/set-price.js +217 -225
- package/src/isv/products/audios.js +0 -0
- package/src/isv/products/create-product.js +313 -313
- package/src/isv/products/delete-product.js +0 -0
- package/src/isv/products/get-product-image.js +0 -0
- package/src/isv/products/get-product.js +0 -0
- package/src/isv/products/index.js +0 -0
- package/src/isv/products/list-products.js +0 -0
- package/src/isv/products/schedules.js +0 -0
- package/src/isv/products/update-product.js +264 -264
- package/src/isv/reference/index.js +249 -0
- package/src/isv/shops/index.js +22 -0
- package/src/isv/transactions/cancel-transaction.js +43 -12
- package/src/isv/transactions/create-transaction.js +22 -6
- package/src/isv/transactions/get-status.js +18 -11
- package/src/isv/transactions/process-transaction.js +160 -42
- package/src/isv/transactions/simulate-callback.js +128 -109
- package/src/isv/transactions/transaction-history.js +86 -90
- package/src/isv/utils/auth.js +2 -2
- package/src/mcp-proxy.js +0 -0
- package/src/merchant/data/export-report.js +0 -0
- package/src/merchant/data/generate-report.js +19 -1
- package/src/merchant/data/get-export-list.js +0 -0
- package/src/merchant/data/get-report-requests.js +0 -0
- package/src/merchant/data/get-report-status.js +0 -0
- package/src/merchant/data/index.js +0 -0
- package/src/merchant/data/list-reports.js +0 -0
- package/src/merchant/deep-links/delete-product-link.js +0 -0
- package/src/merchant/deep-links/delete-transaction-link.js +0 -0
- package/src/merchant/deep-links/get-product-link.js +0 -0
- package/src/merchant/deep-links/get-transaction-link.js +0 -0
- package/src/merchant/deep-links/index.js +0 -0
- package/src/merchant/index.js +21 -1
- package/src/merchant/logs/index.js +366 -0
- package/src/merchant/products/audios.js +0 -0
- package/src/merchant/products/create-product.js +287 -287
- package/src/merchant/products/delete-product.js +0 -0
- package/src/merchant/products/get-product-image.js +0 -0
- package/src/merchant/products/get-product.js +0 -0
- package/src/merchant/products/index.js +0 -0
- package/src/merchant/products/list-products.js +0 -0
- package/src/merchant/products/schedules.js +0 -0
- package/src/merchant/products/update-product.js +281 -281
- package/src/merchant/shops/index.js +18 -0
- package/src/merchant/transactions/cancel-transaction.js +16 -19
- package/src/merchant/transactions/create-transaction.js +99 -19
- package/src/merchant/transactions/get-status.js +41 -12
- package/src/merchant/transactions/process-transaction.js +8 -16
- package/src/merchant/transactions/simulate-callback.js +68 -9
- package/src/merchant/transactions/transaction-history.js +275 -257
- package/src/payment-institution/data/index.js +0 -0
- package/src/payment-institution/deep-links/delete-transaction-link.js +0 -0
- package/src/payment-institution/deep-links/get-transaction-link.js +0 -0
- package/src/payment-institution/deep-links/index.js +0 -0
- package/src/payment-institution/index.js +0 -0
- package/src/payment-institution/transactions/create-pi-transaction.js +6 -14
- package/src/payment-institution/transactions/finalize-transaction.js +333 -340
- package/src/payment-institution/transactions/get-transaction-history.js +3 -11
- package/src/payment-institution/transactions/get-transaction-status.js +39 -12
- package/src/payment-institution/transactions/process-pi-transaction.js +5 -13
- package/src/payment-institution/transactions/simulate-pi-callback.js +49 -9
- package/src/payment-institution/transactions/soundbite-transaction.js +5 -13
- package/src/proxy-server.js +0 -0
- package/src/shared/api-errors.js +188 -0
- package/src/shared/auth-headers.js +62 -0
- package/src/shared/data/data-api.js +11 -10
- package/src/shared/deep-links/api.js +5 -4
- package/src/shared/index.js +0 -0
- package/src/shared/logs/logs-api.js +242 -0
- package/src/shared/poi/poi-create-api.js +419 -0
- package/src/shared/products/products-api.js +17 -16
- package/src/shared/shops/shops-api.js +155 -0
- package/src/tools/advanced-code-generator.js +2255 -2246
- package/src/utils/code-examples/common/auth-examples.js +1484 -1481
- package/src/utils/code-examples/common/helpers.js +7 -4
- package/src/utils/code-examples/common/utils-examples.js +0 -0
- package/src/utils/code-examples/frameworks/examples.js +4 -4
- package/src/utils/code-examples/index.js +0 -0
- package/src/utils/code-examples/isv/oauth2.js +458 -600
- package/src/utils/code-examples/isv/products.js +8 -8
- package/src/utils/code-examples/isv/transactions.js +815 -812
- package/src/utils/code-examples/merchant/products.js +0 -0
- package/src/utils/code-examples/merchant/transactions.js +9 -9
- package/src/utils/code-examples/payment-institution/transactions.js +0 -0
- package/src/utils/code-examples/shared/data.js +0 -0
- package/src/utils/code-examples/shared/deep-links.js +0 -0
- package/src/utils/code-examples/shared/soundbites.js +0 -0
- package/src/utils/code-examples.js +24 -24
- package/src/utils/format-request.js +3 -3
- package/src/utils/json-formatter.js +20 -20
- package/src/utils/server-info.js +0 -0
- package/MCP-SETUP.md +0 -190
|
@@ -1,813 +1,816 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ISV transaction examples for all operations
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { PythonGenerator, NodeJSGenerator } from '../common/utils-examples.js';
|
|
6
|
-
import { CommonTemplates } from '../common/helpers.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* ISV transaction operations
|
|
10
|
-
*/
|
|
11
|
-
export const ISVTransactionOperations = {
|
|
12
|
-
create_transaction: {
|
|
13
|
-
description: 'Create a transaction on behalf of a merchant (ISV operation)',
|
|
14
|
-
endpoint: '/transactions',
|
|
15
|
-
method: 'POST',
|
|
16
|
-
requiresOAuth: true,
|
|
17
|
-
sampleBody: {
|
|
18
|
-
trData: {
|
|
19
|
-
amount: '50.00',
|
|
20
|
-
currency: 'EUR',
|
|
21
|
-
reasonL1: 'ISV managed transaction',
|
|
22
|
-
reasonL2: 'Created on behalf of merchant'
|
|
23
|
-
},
|
|
24
|
-
trOptions: {
|
|
25
|
-
type: 'QR',
|
|
26
|
-
timeToLive: 600
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
get_transaction_status: {
|
|
32
|
-
description: 'Get transaction status on behalf of merchant',
|
|
33
|
-
endpoint: '/transactions/{id}',
|
|
34
|
-
method: 'GET',
|
|
35
|
-
requiresOAuth: true,
|
|
36
|
-
sampleBody: {}
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
cancel_transaction: {
|
|
40
|
-
description: 'Cancel transaction on behalf of merchant',
|
|
41
|
-
endpoint: '/transactions/{id}',
|
|
42
|
-
method: 'PATCH',
|
|
43
|
-
requiresOAuth: true,
|
|
44
|
-
sampleBody: {
|
|
45
|
-
status: 'CANCELLED',
|
|
46
|
-
statusMessage: 'ISV initiated cancellation'
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
process_transaction: {
|
|
51
|
-
description: 'Process transaction on behalf of merchant',
|
|
52
|
-
endpoint: '/transactions/{id}',
|
|
53
|
-
method: 'POST',
|
|
54
|
-
requiresOAuth: true,
|
|
55
|
-
sampleBody: {
|
|
56
|
-
account: 'MERCHANT_ACCOUNT_123',
|
|
57
|
-
friendlyName: 'Merchant Name via ISV'
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
get_transaction_history: {
|
|
62
|
-
description: 'Get transaction history for merchant',
|
|
63
|
-
endpoint: '/transactions/{id}/history',
|
|
64
|
-
method: 'GET',
|
|
65
|
-
requiresOAuth: true,
|
|
66
|
-
sampleBody: {}
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
simulate_callback: {
|
|
70
|
-
description: 'Simulate callback for merchant transaction',
|
|
71
|
-
endpoint: '/transactions/{id}/callback',
|
|
72
|
-
method: 'POST',
|
|
73
|
-
requiresOAuth: true,
|
|
74
|
-
sampleBody: {
|
|
75
|
-
status: 'PROCESSED',
|
|
76
|
-
timestamp: new Date().toISOString()
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Generate Python examples for ISV transactions
|
|
83
|
-
*/
|
|
84
|
-
export function generateISVTransactionPython(operation, params = {}) {
|
|
85
|
-
const operationConfig = ISVTransactionOperations[operation];
|
|
86
|
-
|
|
87
|
-
if (!operationConfig) {
|
|
88
|
-
throw new Error(`Unknown operation: ${operation}`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const sections = [];
|
|
92
|
-
|
|
93
|
-
// Header and description
|
|
94
|
-
sections.push(`"""
|
|
95
|
-
${operationConfig.description}
|
|
96
|
-
|
|
97
|
-
This example demonstrates ISV operations for managing transactions on behalf of merchants.
|
|
98
|
-
Partner Type: ISV (Independent Software Vendor)
|
|
99
|
-
Operation: ${operation}
|
|
100
|
-
Method: ${operationConfig.method}
|
|
101
|
-
Endpoint: ${operationConfig.endpoint}
|
|
102
|
-
Authentication: ISV JWT + OAuth2 Token
|
|
103
|
-
"""
|
|
104
|
-
|
|
105
|
-
# Required dependencies:
|
|
106
|
-
# pip install requests pyjwt cryptography python-dotenv
|
|
107
|
-
|
|
108
|
-
import requests
|
|
109
|
-
import jwt
|
|
110
|
-
import json
|
|
111
|
-
import hashlib
|
|
112
|
-
import base64
|
|
113
|
-
import os
|
|
114
|
-
from datetime import datetime
|
|
115
|
-
from dotenv import load_dotenv
|
|
116
|
-
|
|
117
|
-
# Load environment variables
|
|
118
|
-
load_dotenv()`);
|
|
119
|
-
|
|
120
|
-
// Environment setup
|
|
121
|
-
sections.push(`# ISV Environment Configuration
|
|
122
|
-
def load_isv_config():
|
|
123
|
-
"""Load ISV configuration from environment"""
|
|
124
|
-
config = {
|
|
125
|
-
'isv_partner_id': os.getenv('PAYWARE_PARTNER_ID'),
|
|
126
|
-
'sandbox_key_path': os.getenv('PAYWARE_SANDBOX_PRIVATE_KEY_PATH'),
|
|
127
|
-
'production_key_path': os.getenv('PAYWARE_PRODUCTION_PRIVATE_KEY_PATH'),
|
|
128
|
-
'oauth_client_id': os.getenv('PAYWARE_OAUTH_CLIENT_ID'),
|
|
129
|
-
'oauth_client_secret': os.getenv('PAYWARE_OAUTH_CLIENT_SECRET'),
|
|
130
|
-
'default_merchant_id': os.getenv('PAYWARE_DEFAULT_MERCHANT_ID'),
|
|
131
|
-
'sandbox_url': os.getenv('PAYWARE_SANDBOX_URL', 'https://sandbox.payware.eu/api'),
|
|
132
|
-
'production_url': os.getenv('PAYWARE_PRODUCTION_URL', 'https://api.payware.eu/api')
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
# Validate required configuration
|
|
136
|
-
required_vars = ['isv_partner_id', 'oauth_client_id', 'oauth_client_secret']
|
|
137
|
-
for var in required_vars:
|
|
138
|
-
if not config[var]:
|
|
139
|
-
env_var = {
|
|
140
|
-
'isv_partner_id': 'PAYWARE_PARTNER_ID',
|
|
141
|
-
'oauth_client_id': 'PAYWARE_OAUTH_CLIENT_ID',
|
|
142
|
-
'oauth_client_secret': 'PAYWARE_OAUTH_CLIENT_SECRET'
|
|
143
|
-
}[var]
|
|
144
|
-
raise ValueError(f"{env_var} environment variable is required for ISV operations")
|
|
145
|
-
|
|
146
|
-
return config`);
|
|
147
|
-
|
|
148
|
-
// OAuth2 functions
|
|
149
|
-
sections.push(`# OAuth2 Authentication for ISV
|
|
150
|
-
def get_oauth2_token(merchant_partner_id, use_sandbox=True):
|
|
151
|
-
"""Get OAuth2 token for accessing merchant resources"""
|
|
152
|
-
config = load_isv_config()
|
|
153
|
-
base_url = config['sandbox_url'] if use_sandbox else config['production_url']
|
|
154
|
-
|
|
155
|
-
#
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
'
|
|
159
|
-
'
|
|
160
|
-
'
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
try:
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
'
|
|
175
|
-
'
|
|
176
|
-
'
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
'
|
|
218
|
-
'
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
return
|
|
232
|
-
|
|
233
|
-
return obj
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
'
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
${
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if
|
|
283
|
-
request_body['trData']['
|
|
284
|
-
if
|
|
285
|
-
request_body['trData']['
|
|
286
|
-
if
|
|
287
|
-
request_body['trData']['
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
token
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
token
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
'
|
|
331
|
-
'
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
'
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
'
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
base_message += "\\n
|
|
386
|
-
base_message += "\\n -
|
|
387
|
-
|
|
388
|
-
base_message += "\\n
|
|
389
|
-
|
|
390
|
-
base_message += "\\n
|
|
391
|
-
base_message += "\\n -
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
print(
|
|
412
|
-
print(f"
|
|
413
|
-
print("
|
|
414
|
-
print(
|
|
415
|
-
|
|
416
|
-
print(
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
print(f"
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
print("
|
|
429
|
-
print("
|
|
430
|
-
print(" -
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
const
|
|
468
|
-
const
|
|
469
|
-
require('
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
{
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
//
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
console.log(
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
${
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
if (
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
)
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
baseMessage += '\\n
|
|
743
|
-
|
|
744
|
-
baseMessage += '\\n
|
|
745
|
-
baseMessage += '\\n -
|
|
746
|
-
|
|
747
|
-
baseMessage += '\\n
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
console.log(
|
|
771
|
-
console.log(
|
|
772
|
-
console.log(
|
|
773
|
-
|
|
774
|
-
console.log('
|
|
775
|
-
console.log(
|
|
776
|
-
|
|
777
|
-
console.log(
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
console.
|
|
790
|
-
console.log('
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1
|
+
/**
|
|
2
|
+
* ISV transaction examples for all operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { PythonGenerator, NodeJSGenerator } from '../common/utils-examples.js';
|
|
6
|
+
import { CommonTemplates } from '../common/helpers.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ISV transaction operations
|
|
10
|
+
*/
|
|
11
|
+
export const ISVTransactionOperations = {
|
|
12
|
+
create_transaction: {
|
|
13
|
+
description: 'Create a transaction on behalf of a merchant (ISV operation)',
|
|
14
|
+
endpoint: '/transactions',
|
|
15
|
+
method: 'POST',
|
|
16
|
+
requiresOAuth: true,
|
|
17
|
+
sampleBody: {
|
|
18
|
+
trData: {
|
|
19
|
+
amount: '50.00',
|
|
20
|
+
currency: 'EUR',
|
|
21
|
+
reasonL1: 'ISV managed transaction',
|
|
22
|
+
reasonL2: 'Created on behalf of merchant'
|
|
23
|
+
},
|
|
24
|
+
trOptions: {
|
|
25
|
+
type: 'QR',
|
|
26
|
+
timeToLive: 600
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
get_transaction_status: {
|
|
32
|
+
description: 'Get transaction status on behalf of merchant',
|
|
33
|
+
endpoint: '/transactions/{id}',
|
|
34
|
+
method: 'GET',
|
|
35
|
+
requiresOAuth: true,
|
|
36
|
+
sampleBody: {}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
cancel_transaction: {
|
|
40
|
+
description: 'Cancel transaction on behalf of merchant',
|
|
41
|
+
endpoint: '/transactions/{id}',
|
|
42
|
+
method: 'PATCH',
|
|
43
|
+
requiresOAuth: true,
|
|
44
|
+
sampleBody: {
|
|
45
|
+
status: 'CANCELLED',
|
|
46
|
+
statusMessage: 'ISV initiated cancellation'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
process_transaction: {
|
|
51
|
+
description: 'Process transaction on behalf of merchant',
|
|
52
|
+
endpoint: '/transactions/{id}',
|
|
53
|
+
method: 'POST',
|
|
54
|
+
requiresOAuth: true,
|
|
55
|
+
sampleBody: {
|
|
56
|
+
account: 'MERCHANT_ACCOUNT_123',
|
|
57
|
+
friendlyName: 'Merchant Name via ISV'
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
get_transaction_history: {
|
|
62
|
+
description: 'Get transaction history for merchant',
|
|
63
|
+
endpoint: '/transactions/{id}/history',
|
|
64
|
+
method: 'GET',
|
|
65
|
+
requiresOAuth: true,
|
|
66
|
+
sampleBody: {}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
simulate_callback: {
|
|
70
|
+
description: 'Simulate callback for merchant transaction',
|
|
71
|
+
endpoint: '/transactions/{id}/callback',
|
|
72
|
+
method: 'POST',
|
|
73
|
+
requiresOAuth: true,
|
|
74
|
+
sampleBody: {
|
|
75
|
+
status: 'PROCESSED',
|
|
76
|
+
timestamp: new Date().toISOString()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Generate Python examples for ISV transactions
|
|
83
|
+
*/
|
|
84
|
+
export function generateISVTransactionPython(operation, params = {}) {
|
|
85
|
+
const operationConfig = ISVTransactionOperations[operation];
|
|
86
|
+
|
|
87
|
+
if (!operationConfig) {
|
|
88
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const sections = [];
|
|
92
|
+
|
|
93
|
+
// Header and description
|
|
94
|
+
sections.push(`"""
|
|
95
|
+
${operationConfig.description}
|
|
96
|
+
|
|
97
|
+
This example demonstrates ISV operations for managing transactions on behalf of merchants.
|
|
98
|
+
Partner Type: ISV (Independent Software Vendor)
|
|
99
|
+
Operation: ${operation}
|
|
100
|
+
Method: ${operationConfig.method}
|
|
101
|
+
Endpoint: ${operationConfig.endpoint}
|
|
102
|
+
Authentication: ISV JWT + OAuth2 Token
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
# Required dependencies:
|
|
106
|
+
# pip install requests pyjwt cryptography python-dotenv
|
|
107
|
+
|
|
108
|
+
import requests
|
|
109
|
+
import jwt
|
|
110
|
+
import json
|
|
111
|
+
import hashlib
|
|
112
|
+
import base64
|
|
113
|
+
import os
|
|
114
|
+
from datetime import datetime
|
|
115
|
+
from dotenv import load_dotenv
|
|
116
|
+
|
|
117
|
+
# Load environment variables
|
|
118
|
+
load_dotenv()`);
|
|
119
|
+
|
|
120
|
+
// Environment setup
|
|
121
|
+
sections.push(`# ISV Environment Configuration
|
|
122
|
+
def load_isv_config():
|
|
123
|
+
"""Load ISV configuration from environment"""
|
|
124
|
+
config = {
|
|
125
|
+
'isv_partner_id': os.getenv('PAYWARE_PARTNER_ID'),
|
|
126
|
+
'sandbox_key_path': os.getenv('PAYWARE_SANDBOX_PRIVATE_KEY_PATH'),
|
|
127
|
+
'production_key_path': os.getenv('PAYWARE_PRODUCTION_PRIVATE_KEY_PATH'),
|
|
128
|
+
'oauth_client_id': os.getenv('PAYWARE_OAUTH_CLIENT_ID'),
|
|
129
|
+
'oauth_client_secret': os.getenv('PAYWARE_OAUTH_CLIENT_SECRET'),
|
|
130
|
+
'default_merchant_id': os.getenv('PAYWARE_DEFAULT_MERCHANT_ID'),
|
|
131
|
+
'sandbox_url': os.getenv('PAYWARE_SANDBOX_URL', 'https://sandbox.payware.eu/api'),
|
|
132
|
+
'production_url': os.getenv('PAYWARE_PRODUCTION_URL', 'https://api.payware.eu/api')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Validate required configuration
|
|
136
|
+
required_vars = ['isv_partner_id', 'oauth_client_id', 'oauth_client_secret']
|
|
137
|
+
for var in required_vars:
|
|
138
|
+
if not config[var]:
|
|
139
|
+
env_var = {
|
|
140
|
+
'isv_partner_id': 'PAYWARE_PARTNER_ID',
|
|
141
|
+
'oauth_client_id': 'PAYWARE_OAUTH_CLIENT_ID',
|
|
142
|
+
'oauth_client_secret': 'PAYWARE_OAUTH_CLIENT_SECRET'
|
|
143
|
+
}[var]
|
|
144
|
+
raise ValueError(f"{env_var} environment variable is required for ISV operations")
|
|
145
|
+
|
|
146
|
+
return config`);
|
|
147
|
+
|
|
148
|
+
// OAuth2 functions
|
|
149
|
+
sections.push(`# OAuth2 Authentication for ISV
|
|
150
|
+
def get_oauth2_token(merchant_partner_id, use_sandbox=True):
|
|
151
|
+
"""Get OAuth2 token for accessing merchant resources"""
|
|
152
|
+
config = load_isv_config()
|
|
153
|
+
base_url = config['sandbox_url'] if use_sandbox else config['production_url']
|
|
154
|
+
|
|
155
|
+
# OAuth2 token request: JSON body, camelCase fields, no scope parameter.
|
|
156
|
+
# clientId is the merchant's partnerId; clientSecret is that merchant's secret, base64-encoded.
|
|
157
|
+
token_data = {
|
|
158
|
+
'grantType': 'client_credentials',
|
|
159
|
+
'clientId': merchant_partner_id,
|
|
160
|
+
'clientSecret': base64.b64encode(config['merchant_secret'].encode()).decode()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
# OAuth2 endpoints are served from the host root, not under /api
|
|
165
|
+
response = requests.post(
|
|
166
|
+
f"{base_url.replace('/api', '')}/oauth2/tokens",
|
|
167
|
+
json=token_data,
|
|
168
|
+
headers={'Content-Type': 'application/json'}
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if response.status_code == 200:
|
|
172
|
+
token_response = response.json()
|
|
173
|
+
return {
|
|
174
|
+
'access_token': token_response['accessToken'],
|
|
175
|
+
'token_type': token_response['tokenType'],
|
|
176
|
+
'status': token_response.get('status'),
|
|
177
|
+
'expires_in': token_response.get('expiresIn'),
|
|
178
|
+
'scope': token_response.get('scope')
|
|
179
|
+
}
|
|
180
|
+
else:
|
|
181
|
+
raise Exception(f"OAuth2 token request failed: {response.status_code} - {response.text}")
|
|
182
|
+
|
|
183
|
+
except Exception as e:
|
|
184
|
+
raise Exception(f"OAuth2 authentication error: {str(e)}")
|
|
185
|
+
|
|
186
|
+
def create_isv_jwt_token(merchant_partner_id, oauth2_token, request_body=None, use_sandbox=True):
|
|
187
|
+
"""Create ISV JWT token with OAuth2 token for merchant access"""
|
|
188
|
+
config = load_isv_config()
|
|
189
|
+
|
|
190
|
+
# Get private key path based on environment
|
|
191
|
+
private_key_path = config['sandbox_key_path'] if use_sandbox else config['production_key_path']
|
|
192
|
+
if not private_key_path:
|
|
193
|
+
env_var = 'PAYWARE_SANDBOX_PRIVATE_KEY_PATH' if use_sandbox else 'PAYWARE_PRODUCTION_PRIVATE_KEY_PATH'
|
|
194
|
+
raise ValueError(f"{env_var} environment variable is required")
|
|
195
|
+
|
|
196
|
+
# Load ISV private key
|
|
197
|
+
with open(private_key_path, 'r') as f:
|
|
198
|
+
private_key = f.read()
|
|
199
|
+
|
|
200
|
+
# Create JWT header
|
|
201
|
+
header = {
|
|
202
|
+
'alg': 'RS256',
|
|
203
|
+
'typ': 'JWT'
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# Add content SHA-256 for requests with body
|
|
207
|
+
body_string = None
|
|
208
|
+
if request_body:
|
|
209
|
+
body_string = create_minimized_json(request_body)
|
|
210
|
+
content_sha256 = base64.b64encode(
|
|
211
|
+
hashlib.sha256(body_string.encode('utf-8')).digest()
|
|
212
|
+
).decode('utf-8')
|
|
213
|
+
header['contentSha256'] = content_sha256
|
|
214
|
+
|
|
215
|
+
# Create ISV JWT payload with OAuth2 token
|
|
216
|
+
payload = {
|
|
217
|
+
'iss': config['isv_partner_id'], # ISV Partner ID
|
|
218
|
+
'aud': merchant_partner_id, # Target Merchant ID
|
|
219
|
+
'sub': oauth2_token, # OAuth2 access token
|
|
220
|
+
'iat': int(datetime.utcnow().timestamp())
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# Create token
|
|
224
|
+
token = jwt.encode(payload, private_key, algorithm='RS256', headers=header)
|
|
225
|
+
return token, body_string
|
|
226
|
+
|
|
227
|
+
def create_minimized_json(data):
|
|
228
|
+
"""Create deterministic minimized JSON for SHA-256 calculation"""
|
|
229
|
+
def sort_dict(obj):
|
|
230
|
+
if isinstance(obj, dict):
|
|
231
|
+
return {k: sort_dict(v) for k, v in sorted(obj.items())}
|
|
232
|
+
elif isinstance(obj, list):
|
|
233
|
+
return [sort_dict(item) for item in obj]
|
|
234
|
+
else:
|
|
235
|
+
return obj
|
|
236
|
+
|
|
237
|
+
sorted_data = sort_dict(data)
|
|
238
|
+
return json.dumps(sorted_data, separators=(',', ':'))
|
|
239
|
+
|
|
240
|
+
def get_api_headers(token):
|
|
241
|
+
"""Get standard API headers"""
|
|
242
|
+
return {
|
|
243
|
+
'Authorization': f'Bearer {token}',
|
|
244
|
+
'Content-Type': 'application/json',
|
|
245
|
+
'Api-Version': '1'
|
|
246
|
+
}`);
|
|
247
|
+
|
|
248
|
+
// Main operation function
|
|
249
|
+
const needsId = operationConfig.endpoint.includes('{id}');
|
|
250
|
+
const hasBody = operationConfig.method !== 'GET' && Object.keys(operationConfig.sampleBody).length > 0;
|
|
251
|
+
|
|
252
|
+
const paramList = ['merchant_partner_id', 'use_sandbox=True'];
|
|
253
|
+
if (needsId) {
|
|
254
|
+
paramList.splice(1, 0, 'transaction_id');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Add custom parameters for specific operations
|
|
258
|
+
if (operation === 'create_transaction') {
|
|
259
|
+
paramList.splice(-1, 0, 'amount="50.00"', 'currency="EUR"', 'reason_l1="ISV transaction"', 'reason_l2=None');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const endpoint = operationConfig.endpoint.replace('{id}', '{transaction_id}');
|
|
263
|
+
|
|
264
|
+
sections.push(`# Main ISV Operation
|
|
265
|
+
def ${operation}(${paramList.join(', ')}):
|
|
266
|
+
"""${operationConfig.description}"""
|
|
267
|
+
|
|
268
|
+
try:
|
|
269
|
+
config = load_isv_config()
|
|
270
|
+
base_url = config['sandbox_url'] if use_sandbox else config['production_url']
|
|
271
|
+
|
|
272
|
+
# Step 1: Get OAuth2 token for merchant access
|
|
273
|
+
print(f"š Getting OAuth2 token for merchant: {merchant_partner_id}")
|
|
274
|
+
oauth2_response = get_oauth2_token(merchant_partner_id, use_sandbox)
|
|
275
|
+
oauth2_token = oauth2_response['access_token']
|
|
276
|
+
print(f"ā
OAuth2 token acquired (expires in: {oauth2_response.get('expires_in', 'unknown')} seconds)")
|
|
277
|
+
|
|
278
|
+
${hasBody ? `# Step 2: Prepare request body
|
|
279
|
+
request_body = ${JSON.stringify(operationConfig.sampleBody, null, 8).replace(/"/g, "'")}
|
|
280
|
+
|
|
281
|
+
${operation === 'create_transaction' ? `# Customize with parameters
|
|
282
|
+
if amount:
|
|
283
|
+
request_body['trData']['amount'] = amount
|
|
284
|
+
if currency:
|
|
285
|
+
request_body['trData']['currency'] = currency
|
|
286
|
+
if reason_l1:
|
|
287
|
+
request_body['trData']['reasonL1'] = reason_l1
|
|
288
|
+
if reason_l2:
|
|
289
|
+
request_body['trData']['reasonL2'] = reason_l2` : ''}
|
|
290
|
+
|
|
291
|
+
# Step 3: Create ISV JWT token with OAuth2 token
|
|
292
|
+
print("š Creating ISV JWT token with OAuth2 authentication")
|
|
293
|
+
token, body_string = create_isv_jwt_token(
|
|
294
|
+
merchant_partner_id,
|
|
295
|
+
oauth2_token,
|
|
296
|
+
request_body,
|
|
297
|
+
use_sandbox
|
|
298
|
+
)
|
|
299
|
+
headers = get_api_headers(token)
|
|
300
|
+
|
|
301
|
+
# Step 4: Make API request
|
|
302
|
+
url = f"{base_url}${endpoint}"${needsId ? `.format(transaction_id=transaction_id)` : ''}
|
|
303
|
+
print(f"š” Making ${operationConfig.method} request to: {url}")
|
|
304
|
+
response = requests.${operationConfig.method.toLowerCase()}(
|
|
305
|
+
url,
|
|
306
|
+
data=body_string,
|
|
307
|
+
headers=headers
|
|
308
|
+
)` : `# Step 2: Create ISV JWT token with OAuth2 token
|
|
309
|
+
print("š Creating ISV JWT token with OAuth2 authentication")
|
|
310
|
+
token, _ = create_isv_jwt_token(
|
|
311
|
+
merchant_partner_id,
|
|
312
|
+
oauth2_token,
|
|
313
|
+
None,
|
|
314
|
+
use_sandbox
|
|
315
|
+
)
|
|
316
|
+
headers = get_api_headers(token)
|
|
317
|
+
|
|
318
|
+
# Step 3: Make API request
|
|
319
|
+
url = f"{base_url}${endpoint}"${needsId ? `.format(transaction_id=transaction_id)` : ''}
|
|
320
|
+
print(f"š” Making ${operationConfig.method} request to: {url}")
|
|
321
|
+
response = requests.${operationConfig.method.toLowerCase()}(
|
|
322
|
+
url,
|
|
323
|
+
headers=headers
|
|
324
|
+
)`}
|
|
325
|
+
|
|
326
|
+
# Step ${hasBody ? '5' : '4'}: Handle response
|
|
327
|
+
if response.status_code in [200, 201]:
|
|
328
|
+
result = response.json()
|
|
329
|
+
return {
|
|
330
|
+
'success': True,
|
|
331
|
+
'data': result,
|
|
332
|
+
'merchant_partner_id': merchant_partner_id,
|
|
333
|
+
'oauth2_info': {
|
|
334
|
+
'token_type': oauth2_response['token_type'],
|
|
335
|
+
'scope': oauth2_response.get('scope'),
|
|
336
|
+
'expires_in': oauth2_response.get('expires_in')
|
|
337
|
+
},
|
|
338
|
+
'request_id': response.headers.get('x-request-id'),
|
|
339
|
+
'timestamp': datetime.utcnow().isoformat()
|
|
340
|
+
}
|
|
341
|
+
else:
|
|
342
|
+
return {
|
|
343
|
+
'success': False,
|
|
344
|
+
'error': {
|
|
345
|
+
'status': response.status_code,
|
|
346
|
+
'message': response.text,
|
|
347
|
+
'details': response.json() if response.headers.get('content-type', '').startswith('application/json') else None
|
|
348
|
+
},
|
|
349
|
+
'merchant_partner_id': merchant_partner_id,
|
|
350
|
+
'timestamp': datetime.utcnow().isoformat()
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
except Exception as e:
|
|
354
|
+
return {
|
|
355
|
+
'success': False,
|
|
356
|
+
'error': {
|
|
357
|
+
'message': str(e),
|
|
358
|
+
'type': type(e).__name__
|
|
359
|
+
},
|
|
360
|
+
'merchant_partner_id': merchant_partner_id,
|
|
361
|
+
'timestamp': datetime.utcnow().isoformat()
|
|
362
|
+
}`);
|
|
363
|
+
|
|
364
|
+
// Error handling
|
|
365
|
+
sections.push(`# ISV Error Handling
|
|
366
|
+
def handle_isv_error(error_response):
|
|
367
|
+
"""Handle ISV-specific API errors"""
|
|
368
|
+
status = error_response.get('status', 0)
|
|
369
|
+
message = error_response.get('message', 'Unknown error')
|
|
370
|
+
|
|
371
|
+
isv_error_messages = {
|
|
372
|
+
400: f"Bad Request: {message}",
|
|
373
|
+
401: "Authentication failed - check ISV credentials and OAuth2 setup",
|
|
374
|
+
403: "Forbidden - ISV may not have permission for this merchant",
|
|
375
|
+
404: "Resource not found",
|
|
376
|
+
409: "Conflict - resource already exists or invalid state",
|
|
377
|
+
429: "Rate limit exceeded - please retry later",
|
|
378
|
+
500: "Internal server error - please try again"
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
base_message = isv_error_messages.get(status, f"API Error {status}: {message}")
|
|
382
|
+
|
|
383
|
+
# Add ISV-specific guidance
|
|
384
|
+
if status == 401:
|
|
385
|
+
base_message += "\\nš” ISV Troubleshooting:"
|
|
386
|
+
base_message += "\\n - Verify PAYWARE_PARTNER_ID is your ISV partner ID"
|
|
387
|
+
base_message += "\\n - Check OAuth2 client credentials"
|
|
388
|
+
base_message += "\\n - Ensure merchant has granted access to your ISV"
|
|
389
|
+
elif status == 403:
|
|
390
|
+
base_message += "\\nš” ISV Authorization:"
|
|
391
|
+
base_message += "\\n - Merchant may need to authorize your ISV application"
|
|
392
|
+
base_message += "\\n - Check OAuth2 scope permissions"
|
|
393
|
+
base_message += "\\n - Verify merchant partner ID is correct"
|
|
394
|
+
|
|
395
|
+
return base_message`);
|
|
396
|
+
|
|
397
|
+
// Example usage
|
|
398
|
+
const exampleParams = needsId ? '"MERCHANT123", "pw12345678"' : '"MERCHANT123"';
|
|
399
|
+
sections.push(`# Example Usage
|
|
400
|
+
if __name__ == "__main__":
|
|
401
|
+
print("=== ISV ${operation.replace('_', ' ').title()} Example ===\\n")
|
|
402
|
+
|
|
403
|
+
# Example merchant partner ID (replace with actual merchant ID)
|
|
404
|
+
merchant_id = "MERCHANT123"
|
|
405
|
+
|
|
406
|
+
try:
|
|
407
|
+
# Execute the ISV operation
|
|
408
|
+
result = ${operation}(${exampleParams})
|
|
409
|
+
|
|
410
|
+
if result['success']:
|
|
411
|
+
print("ā
ISV operation successful!")
|
|
412
|
+
print(f"š¢ Merchant: {result['merchant_partner_id']}")
|
|
413
|
+
print(f"š OAuth2 Scope: {result['oauth2_info']['scope']}")
|
|
414
|
+
print(f"š Request ID: {result.get('request_id', 'N/A')}")
|
|
415
|
+
print("\\nš Response Data:")
|
|
416
|
+
print(json.dumps(result['data'], indent=2))
|
|
417
|
+
else:
|
|
418
|
+
print("ā ISV operation failed!")
|
|
419
|
+
print(f"š¢ Merchant: {result['merchant_partner_id']}")
|
|
420
|
+
error_message = handle_isv_error(result['error'])
|
|
421
|
+
print(f"ā Error: {error_message}")
|
|
422
|
+
|
|
423
|
+
if result['error'].get('details'):
|
|
424
|
+
print("\\nš Error Details:")
|
|
425
|
+
print(json.dumps(result['error']['details'], indent=2))
|
|
426
|
+
|
|
427
|
+
except Exception as e:
|
|
428
|
+
print(f"ā Unexpected error: {e}")
|
|
429
|
+
print("\\nš” Common Issues:")
|
|
430
|
+
print(" - Check all ISV environment variables are set")
|
|
431
|
+
print(" - Verify merchant has authorized your ISV application")
|
|
432
|
+
print(" - Ensure OAuth2 credentials are correct")
|
|
433
|
+
|
|
434
|
+
print(f"\\nTimestamp: {datetime.utcnow().isoformat()}")
|
|
435
|
+
print("\\n" + "="*60)`);
|
|
436
|
+
|
|
437
|
+
return sections.join('\n\n');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Generate Node.js examples for ISV transactions
|
|
442
|
+
*/
|
|
443
|
+
export function generateISVTransactionNodeJS(operation, params = {}) {
|
|
444
|
+
const operationConfig = ISVTransactionOperations[operation];
|
|
445
|
+
|
|
446
|
+
if (!operationConfig) {
|
|
447
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const sections = [];
|
|
451
|
+
|
|
452
|
+
// Header and description
|
|
453
|
+
sections.push(`/**
|
|
454
|
+
* ${operationConfig.description}
|
|
455
|
+
*
|
|
456
|
+
* This example demonstrates ISV operations for managing transactions on behalf of merchants.
|
|
457
|
+
* Partner Type: ISV (Independent Software Vendor)
|
|
458
|
+
* Operation: ${operation}
|
|
459
|
+
* Method: ${operationConfig.method}
|
|
460
|
+
* Endpoint: ${operationConfig.endpoint}
|
|
461
|
+
* Authentication: ISV JWT + OAuth2 Token
|
|
462
|
+
*/
|
|
463
|
+
|
|
464
|
+
// Required dependencies:
|
|
465
|
+
// npm install axios jsonwebtoken crypto fs dotenv
|
|
466
|
+
|
|
467
|
+
const axios = require('axios');
|
|
468
|
+
const jwt = require('jsonwebtoken');
|
|
469
|
+
const crypto = require('crypto');
|
|
470
|
+
const fs = require('fs');
|
|
471
|
+
require('dotenv').config();`);
|
|
472
|
+
|
|
473
|
+
// Configuration
|
|
474
|
+
sections.push(`// ISV Configuration
|
|
475
|
+
function loadISVConfig() {
|
|
476
|
+
const config = {
|
|
477
|
+
isvPartnerId: process.env.PAYWARE_PARTNER_ID,
|
|
478
|
+
sandboxKeyPath: process.env.PAYWARE_SANDBOX_PRIVATE_KEY_PATH,
|
|
479
|
+
productionKeyPath: process.env.PAYWARE_PRODUCTION_PRIVATE_KEY_PATH,
|
|
480
|
+
oauthClientId: process.env.PAYWARE_OAUTH_CLIENT_ID,
|
|
481
|
+
oauthClientSecret: process.env.PAYWARE_OAUTH_CLIENT_SECRET,
|
|
482
|
+
defaultMerchantId: process.env.PAYWARE_DEFAULT_MERCHANT_ID,
|
|
483
|
+
sandboxUrl: process.env.PAYWARE_SANDBOX_URL || 'https://sandbox.payware.eu/api',
|
|
484
|
+
productionUrl: process.env.PAYWARE_PRODUCTION_URL || 'https://api.payware.eu/api'
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// Validate required configuration
|
|
488
|
+
const requiredVars = ['isvPartnerId', 'oauthClientId', 'oauthClientSecret'];
|
|
489
|
+
for (const varName of requiredVars) {
|
|
490
|
+
if (!config[varName]) {
|
|
491
|
+
const envVar = {
|
|
492
|
+
isvPartnerId: 'PAYWARE_PARTNER_ID',
|
|
493
|
+
oauthClientId: 'PAYWARE_OAUTH_CLIENT_ID',
|
|
494
|
+
oauthClientSecret: 'PAYWARE_OAUTH_CLIENT_SECRET'
|
|
495
|
+
}[varName];
|
|
496
|
+
throw new Error(\`\${envVar} environment variable is required for ISV operations\`);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return config;
|
|
501
|
+
}`);
|
|
502
|
+
|
|
503
|
+
// OAuth2 functions
|
|
504
|
+
sections.push(`// OAuth2 Authentication for ISV
|
|
505
|
+
async function getOAuth2Token(merchantPartnerId, useSandbox = true) {
|
|
506
|
+
const config = loadISVConfig();
|
|
507
|
+
const baseUrl = useSandbox ? config.sandboxUrl : config.productionUrl;
|
|
508
|
+
|
|
509
|
+
const tokenData = new URLSearchParams({
|
|
510
|
+
grantType: 'client_credentials',
|
|
511
|
+
clientId: merchantPartnerId,
|
|
512
|
+
clientSecret: Buffer.from(config.merchantSecret).toString('base64')
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
try {
|
|
516
|
+
// JSON body, camelCase fields, no scope - and /oauth2/tokens is served from the host root
|
|
517
|
+
const response = await axios.post(
|
|
518
|
+
\`\${baseUrl.replace('/api', '')}/oauth2/tokens\`,
|
|
519
|
+
tokenData,
|
|
520
|
+
{
|
|
521
|
+
headers: {
|
|
522
|
+
'Content-Type': 'application/json'
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
return {
|
|
528
|
+
accessToken: response.data.accessToken,
|
|
529
|
+
tokenType: response.data.tokenType,
|
|
530
|
+
status: response.data.status,
|
|
531
|
+
expiresIn: response.data.expiresIn,
|
|
532
|
+
scope: response.data.scope
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
} catch (error) {
|
|
536
|
+
throw new Error(\`OAuth2 token request failed: \${error.response?.data?.error || error.message}\`);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function createISVJWTToken(merchantPartnerId, oauth2Token, requestBody = null, useSandbox = true) {
|
|
541
|
+
const config = loadISVConfig();
|
|
542
|
+
|
|
543
|
+
// Get private key path based on environment
|
|
544
|
+
const privateKeyPath = useSandbox ? config.sandboxKeyPath : config.productionKeyPath;
|
|
545
|
+
if (!privateKeyPath) {
|
|
546
|
+
const envVar = useSandbox ? 'PAYWARE_SANDBOX_PRIVATE_KEY_PATH' : 'PAYWARE_PRODUCTION_PRIVATE_KEY_PATH';
|
|
547
|
+
throw new Error(\`\${envVar} environment variable is required\`);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Load ISV private key
|
|
551
|
+
const privateKey = fs.readFileSync(privateKeyPath, 'utf8');
|
|
552
|
+
|
|
553
|
+
// Create JWT header
|
|
554
|
+
const header = {
|
|
555
|
+
alg: 'RS256',
|
|
556
|
+
typ: 'JWT'
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
// Add content SHA-256 for requests with body
|
|
560
|
+
let bodyString = null;
|
|
561
|
+
if (requestBody) {
|
|
562
|
+
bodyString = createMinimizedJSON(requestBody);
|
|
563
|
+
const contentSha256 = crypto
|
|
564
|
+
.createHash('sha256')
|
|
565
|
+
.update(bodyString, 'utf8')
|
|
566
|
+
.digest('base64');
|
|
567
|
+
header.contentSha256 = contentSha256;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Create ISV JWT payload with OAuth2 token
|
|
571
|
+
const payload = {
|
|
572
|
+
iss: config.isvPartnerId, // ISV Partner ID
|
|
573
|
+
aud: merchantPartnerId, // Target Merchant ID
|
|
574
|
+
sub: oauth2Token, // OAuth2 access token
|
|
575
|
+
iat: Math.floor(Date.now() / 1000)
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
// Create token
|
|
579
|
+
const token = jwt.sign(payload, privateKey, {
|
|
580
|
+
algorithm: 'RS256',
|
|
581
|
+
header
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
return { token, bodyString };
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function createMinimizedJSON(data) {
|
|
588
|
+
// Sort object keys recursively for deterministic output
|
|
589
|
+
function sortObject(obj) {
|
|
590
|
+
if (Array.isArray(obj)) {
|
|
591
|
+
return obj.map(item => sortObject(item));
|
|
592
|
+
} else if (obj !== null && typeof obj === 'object') {
|
|
593
|
+
const sorted = {};
|
|
594
|
+
Object.keys(obj).sort().forEach(key => {
|
|
595
|
+
sorted[key] = sortObject(obj[key]);
|
|
596
|
+
});
|
|
597
|
+
return sorted;
|
|
598
|
+
}
|
|
599
|
+
return obj;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const sortedData = sortObject(data);
|
|
603
|
+
return JSON.stringify(sortedData);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
function getAPIHeaders(token) {
|
|
607
|
+
return {
|
|
608
|
+
'Authorization': \`Bearer \${token}\`,
|
|
609
|
+
'Content-Type': 'application/json',
|
|
610
|
+
'Api-Version': '1'
|
|
611
|
+
};
|
|
612
|
+
}`);
|
|
613
|
+
|
|
614
|
+
// Main operation function
|
|
615
|
+
const needsId = operationConfig.endpoint.includes('{id}');
|
|
616
|
+
const hasBody = operationConfig.method !== 'GET' && Object.keys(operationConfig.sampleBody).length > 0;
|
|
617
|
+
|
|
618
|
+
const paramList = ['merchantPartnerId', 'useSandbox = true'];
|
|
619
|
+
if (needsId) {
|
|
620
|
+
paramList.splice(1, 0, 'transactionId');
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Add custom parameters for specific operations
|
|
624
|
+
if (operation === 'create_transaction') {
|
|
625
|
+
paramList.splice(-1, 0, 'amount = "50.00"', 'currency = "EUR"', 'reasonL1 = "ISV transaction"', 'reasonL2 = null');
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const endpoint = operationConfig.endpoint.replace('{id}', '${transactionId}');
|
|
629
|
+
|
|
630
|
+
sections.push(`// Main ISV Operation
|
|
631
|
+
async function ${operation}(${paramList.join(', ')}) {
|
|
632
|
+
/**
|
|
633
|
+
* ${operationConfig.description}
|
|
634
|
+
*/
|
|
635
|
+
|
|
636
|
+
try {
|
|
637
|
+
const config = loadISVConfig();
|
|
638
|
+
const baseUrl = useSandbox ? config.sandboxUrl : config.productionUrl;
|
|
639
|
+
|
|
640
|
+
// Step 1: Get OAuth2 token for merchant access
|
|
641
|
+
console.log(\`š Getting OAuth2 token for merchant: \${merchantPartnerId}\`);
|
|
642
|
+
const oauth2Response = await getOAuth2Token(merchantPartnerId, useSandbox);
|
|
643
|
+
const oauth2Token = oauth2Response.accessToken;
|
|
644
|
+
console.log(\`ā
OAuth2 token acquired (expires in: \${oauth2Response.expiresIn || 'unknown'} seconds)\`);
|
|
645
|
+
|
|
646
|
+
${hasBody ? `// Step 2: Prepare request body
|
|
647
|
+
const requestBody = ${JSON.stringify(operationConfig.sampleBody, null, 4)};
|
|
648
|
+
|
|
649
|
+
${operation === 'create_transaction' ? `// Customize with parameters
|
|
650
|
+
if (amount) requestBody.trData.amount = amount;
|
|
651
|
+
if (currency) requestBody.trData.currency = currency;
|
|
652
|
+
if (reasonL1) requestBody.trData.reasonL1 = reasonL1;
|
|
653
|
+
if (reasonL2) requestBody.trData.reasonL2 = reasonL2;` : ''}
|
|
654
|
+
|
|
655
|
+
// Step 3: Create ISV JWT token with OAuth2 token
|
|
656
|
+
console.log('š Creating ISV JWT token with OAuth2 authentication');
|
|
657
|
+
const { token, bodyString } = createISVJWTToken(
|
|
658
|
+
merchantPartnerId,
|
|
659
|
+
oauth2Token,
|
|
660
|
+
requestBody,
|
|
661
|
+
useSandbox
|
|
662
|
+
);
|
|
663
|
+
const headers = getAPIHeaders(token);
|
|
664
|
+
|
|
665
|
+
// Step 4: Make API request
|
|
666
|
+
const url = \`\${baseUrl}${endpoint}\`;
|
|
667
|
+
console.log(\`š” Making ${operationConfig.method} request to: \${url}\`);
|
|
668
|
+
const response = await axios.${operationConfig.method.toLowerCase()}(
|
|
669
|
+
url,
|
|
670
|
+
bodyString,
|
|
671
|
+
{
|
|
672
|
+
headers,
|
|
673
|
+
transformRequest: [(data) => data]
|
|
674
|
+
}
|
|
675
|
+
);` : `// Step 2: Create ISV JWT token with OAuth2 token
|
|
676
|
+
console.log('š Creating ISV JWT token with OAuth2 authentication');
|
|
677
|
+
const { token } = createISVJWTToken(
|
|
678
|
+
merchantPartnerId,
|
|
679
|
+
oauth2Token,
|
|
680
|
+
null,
|
|
681
|
+
useSandbox
|
|
682
|
+
);
|
|
683
|
+
const headers = getAPIHeaders(token);
|
|
684
|
+
|
|
685
|
+
// Step 3: Make API request
|
|
686
|
+
const url = \`\${baseUrl}${endpoint}\`;
|
|
687
|
+
console.log(\`š” Making ${operationConfig.method} request to: \${url}\`);
|
|
688
|
+
const response = await axios.${operationConfig.method.toLowerCase()}(
|
|
689
|
+
url,
|
|
690
|
+
{ headers }
|
|
691
|
+
);`}
|
|
692
|
+
|
|
693
|
+
// Step ${hasBody ? '5' : '4'}: Handle successful response
|
|
694
|
+
return {
|
|
695
|
+
success: true,
|
|
696
|
+
data: response.data,
|
|
697
|
+
merchantPartnerId,
|
|
698
|
+
oauth2Info: {
|
|
699
|
+
tokenType: oauth2Response.tokenType,
|
|
700
|
+
scope: oauth2Response.scope,
|
|
701
|
+
expiresIn: oauth2Response.expiresIn
|
|
702
|
+
},
|
|
703
|
+
requestId: response.headers['x-request-id'],
|
|
704
|
+
timestamp: new Date().toISOString()
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
} catch (error) {
|
|
708
|
+
// Handle errors
|
|
709
|
+
return {
|
|
710
|
+
success: false,
|
|
711
|
+
error: {
|
|
712
|
+
message: error.response?.data?.message || error.message,
|
|
713
|
+
status: error.response?.status,
|
|
714
|
+
details: error.response?.data
|
|
715
|
+
},
|
|
716
|
+
merchantPartnerId,
|
|
717
|
+
timestamp: new Date().toISOString()
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
}`);
|
|
721
|
+
|
|
722
|
+
// Error handling
|
|
723
|
+
sections.push(`// ISV Error Handling
|
|
724
|
+
function handleISVError(errorResponse) {
|
|
725
|
+
const status = errorResponse.status || 0;
|
|
726
|
+
const message = errorResponse.message || 'Unknown error';
|
|
727
|
+
|
|
728
|
+
const isvErrorMessages = {
|
|
729
|
+
400: \`Bad Request: \${message}\`,
|
|
730
|
+
401: 'Authentication failed - check ISV credentials and OAuth2 setup',
|
|
731
|
+
403: 'Forbidden - ISV may not have permission for this merchant',
|
|
732
|
+
404: 'Resource not found',
|
|
733
|
+
409: 'Conflict - resource already exists or invalid state',
|
|
734
|
+
429: 'Rate limit exceeded - please retry later',
|
|
735
|
+
500: 'Internal server error - please try again'
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
let baseMessage = isvErrorMessages[status] || \`API Error \${status}: \${message}\`;
|
|
739
|
+
|
|
740
|
+
// Add ISV-specific guidance
|
|
741
|
+
if (status === 401) {
|
|
742
|
+
baseMessage += '\\nš” ISV Troubleshooting:';
|
|
743
|
+
baseMessage += '\\n - Verify PAYWARE_PARTNER_ID is your ISV partner ID';
|
|
744
|
+
baseMessage += '\\n - Check OAuth2 client credentials';
|
|
745
|
+
baseMessage += '\\n - Ensure merchant has granted access to your ISV';
|
|
746
|
+
} else if (status === 403) {
|
|
747
|
+
baseMessage += '\\nš” ISV Authorization:';
|
|
748
|
+
baseMessage += '\\n - Merchant may need to authorize your ISV application';
|
|
749
|
+
baseMessage += '\\n - Check OAuth2 scope permissions';
|
|
750
|
+
baseMessage += '\\n - Verify merchant partner ID is correct';
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
return baseMessage;
|
|
754
|
+
}`);
|
|
755
|
+
|
|
756
|
+
// Example usage
|
|
757
|
+
const exampleParams = needsId ? "'MERCHANT123', 'pw12345678'" : "'MERCHANT123'";
|
|
758
|
+
sections.push(`// Example Usage
|
|
759
|
+
async function main() {
|
|
760
|
+
console.log('=== ISV ${operation.replace(/_/g, ' ').replace(/\\b\\w/g, l => l.toUpperCase())} Example ===\\n');
|
|
761
|
+
|
|
762
|
+
// Example merchant partner ID (replace with actual merchant ID)
|
|
763
|
+
const merchantId = 'MERCHANT123';
|
|
764
|
+
|
|
765
|
+
try {
|
|
766
|
+
// Execute the ISV operation
|
|
767
|
+
const result = await ${operation}(${exampleParams});
|
|
768
|
+
|
|
769
|
+
if (result.success) {
|
|
770
|
+
console.log('ā
ISV operation successful!');
|
|
771
|
+
console.log(\`š¢ Merchant: \${result.merchantPartnerId}\`);
|
|
772
|
+
console.log(\`š OAuth2 Scope: \${result.oauth2Info.scope}\`);
|
|
773
|
+
console.log(\`š Request ID: \${result.requestId || 'N/A'}\`);
|
|
774
|
+
console.log('\\nš Response Data:');
|
|
775
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
776
|
+
} else {
|
|
777
|
+
console.log('ā ISV operation failed!');
|
|
778
|
+
console.log(\`š¢ Merchant: \${result.merchantPartnerId}\`);
|
|
779
|
+
const errorMessage = handleISVError(result.error);
|
|
780
|
+
console.log(\`ā Error: \${errorMessage}\`);
|
|
781
|
+
|
|
782
|
+
if (result.error.details) {
|
|
783
|
+
console.log('\\nš Error Details:');
|
|
784
|
+
console.log(JSON.stringify(result.error.details, null, 2));
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
} catch (error) {
|
|
789
|
+
console.error(\`ā Unexpected error: \${error.message}\`);
|
|
790
|
+
console.log('\\nš” Common Issues:');
|
|
791
|
+
console.log(' - Check all ISV environment variables are set');
|
|
792
|
+
console.log(' - Verify merchant has authorized your ISV application');
|
|
793
|
+
console.log(' - Ensure OAuth2 credentials are correct');
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
console.log(\`\\nTimestamp: \${new Date().toISOString()}\`);
|
|
797
|
+
console.log('\\n' + '='.repeat(60));
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Run the example
|
|
801
|
+
main();`);
|
|
802
|
+
|
|
803
|
+
return sections.join('\n\n');
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Export all ISV transaction examples
|
|
808
|
+
*/
|
|
809
|
+
export const ISVTransactionExamples = {
|
|
810
|
+
operations: ISVTransactionOperations,
|
|
811
|
+
generators: {
|
|
812
|
+
python: generateISVTransactionPython,
|
|
813
|
+
nodejs: generateISVTransactionNodeJS,
|
|
814
|
+
javascript: generateISVTransactionNodeJS
|
|
815
|
+
}
|
|
813
816
|
};
|