@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.
- package/.env.example +92 -0
- package/MCP-SETUP.md +190 -0
- package/README.md +483 -0
- package/check-keys.js +52 -0
- package/keys/README.md +112 -0
- package/mcp-config.json +9 -0
- package/package.json +66 -0
- package/payware-mcp-config.json +12 -0
- package/src/auth/rsa-keys.js +82 -0
- package/src/auth/sandbox-setup.js +187 -0
- package/src/config/env.js +229 -0
- package/src/config/partner-types.js +143 -0
- package/src/core/auth/jwt-factory.js +182 -0
- package/src/core/auth/jwt-token.js +735 -0
- package/src/core/utils/json-serializer.js +100 -0
- package/src/core/utils/key-utils.js +133 -0
- package/src/index.js +237 -0
- package/src/isv/data/index.js +291 -0
- package/src/isv/deep-links/delete-product-link.js +154 -0
- package/src/isv/deep-links/delete-transaction-link.js +154 -0
- package/src/isv/deep-links/get-product-link.js +167 -0
- package/src/isv/deep-links/get-transaction-link.js +167 -0
- package/src/isv/deep-links/index.js +23 -0
- package/src/isv/index.js +103 -0
- package/src/isv/oauth2/create-token-simple.js +46 -0
- package/src/isv/oauth2/get-token-info.js +157 -0
- package/src/isv/oauth2/obtain-token.js +189 -0
- package/src/isv/oauth2/token-helper.js +151 -0
- package/src/isv/products/audios.js +470 -0
- package/src/isv/products/create-product.js +314 -0
- package/src/isv/products/delete-product.js +119 -0
- package/src/isv/products/get-product-image.js +247 -0
- package/src/isv/products/get-product.js +168 -0
- package/src/isv/products/index.js +65 -0
- package/src/isv/products/list-products.js +136 -0
- package/src/isv/products/schedules.js +522 -0
- package/src/isv/products/update-product.js +265 -0
- package/src/isv/transactions/cancel-transaction.js +129 -0
- package/src/isv/transactions/create-transaction.js +361 -0
- package/src/isv/transactions/get-status.js +217 -0
- package/src/isv/transactions/process-transaction.js +145 -0
- package/src/isv/transactions/simulate-callback.js +146 -0
- package/src/isv/transactions/transaction-history.js +186 -0
- package/src/isv/utils/auth.js +159 -0
- package/src/mcp-proxy.js +150 -0
- package/src/merchant/data/export-report.js +108 -0
- package/src/merchant/data/generate-report.js +151 -0
- package/src/merchant/data/get-report-status.js +120 -0
- package/src/merchant/data/index.js +351 -0
- package/src/merchant/deep-links/delete-product-link.js +121 -0
- package/src/merchant/deep-links/delete-transaction-link.js +121 -0
- package/src/merchant/deep-links/get-product-link.js +134 -0
- package/src/merchant/deep-links/get-transaction-link.js +134 -0
- package/src/merchant/deep-links/index.js +23 -0
- package/src/merchant/index.js +92 -0
- package/src/merchant/products/audios.js +606 -0
- package/src/merchant/products/create-product.js +288 -0
- package/src/merchant/products/delete-product.js +111 -0
- package/src/merchant/products/get-product-image.js +252 -0
- package/src/merchant/products/get-product.js +144 -0
- package/src/merchant/products/index.js +65 -0
- package/src/merchant/products/list-products.js +112 -0
- package/src/merchant/products/schedules.js +646 -0
- package/src/merchant/products/update-product.js +282 -0
- package/src/merchant/transactions/cancel-transaction.js +241 -0
- package/src/merchant/transactions/create-transaction.js +482 -0
- package/src/merchant/transactions/get-status.js +196 -0
- package/src/merchant/transactions/process-transaction.js +349 -0
- package/src/merchant/transactions/simulate-callback.js +246 -0
- package/src/merchant/transactions/transaction-history.js +258 -0
- package/src/payment-institution/data/index.js +280 -0
- package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
- package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
- package/src/payment-institution/deep-links/index.js +17 -0
- package/src/payment-institution/index.js +92 -0
- package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
- package/src/payment-institution/transactions/finalize-transaction.js +340 -0
- package/src/payment-institution/transactions/get-transaction-history.js +269 -0
- package/src/payment-institution/transactions/get-transaction-status.js +234 -0
- package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
- package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
- package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
- package/src/proxy-server.js +205 -0
- package/src/shared/data/data-api.js +372 -0
- package/src/shared/deep-links/api.js +214 -0
- package/src/shared/index.js +44 -0
- package/src/shared/products/products-api.js +872 -0
- package/src/tools/advanced-code-generator.js +2247 -0
- package/src/utils/code-examples/common/auth-examples.js +1482 -0
- package/src/utils/code-examples/common/helpers.js +416 -0
- package/src/utils/code-examples/common/utils-examples.js +591 -0
- package/src/utils/code-examples/frameworks/examples.js +859 -0
- package/src/utils/code-examples/index.js +441 -0
- package/src/utils/code-examples/isv/oauth2.js +600 -0
- package/src/utils/code-examples/isv/products.js +666 -0
- package/src/utils/code-examples/isv/transactions.js +813 -0
- package/src/utils/code-examples/merchant/products.js +497 -0
- package/src/utils/code-examples/merchant/transactions.js +623 -0
- package/src/utils/code-examples/payment-institution/transactions.js +388 -0
- package/src/utils/code-examples/shared/data.js +607 -0
- package/src/utils/code-examples/shared/deep-links.js +662 -0
- package/src/utils/code-examples/shared/soundbites.js +808 -0
- package/src/utils/code-examples.js +646 -0
- package/src/utils/format-request.js +363 -0
- package/src/utils/json-formatter.js +249 -0
- package/src/utils/server-info.js +132 -0
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ISV product management examples with OAuth2 authentication
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ExampleGenerator, CommonTemplates } from '../common/helpers.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ISV product operations (same endpoints as merchant but with OAuth2 auth)
|
|
9
|
+
*/
|
|
10
|
+
export const ISVProductOperations = {
|
|
11
|
+
create_product: {
|
|
12
|
+
description: 'Create a product for merchant via ISV',
|
|
13
|
+
endpoint: '/products',
|
|
14
|
+
method: 'POST',
|
|
15
|
+
requiresOAuth: true,
|
|
16
|
+
sampleBody: {
|
|
17
|
+
name: 'ISV Managed Product',
|
|
18
|
+
shortDescription: 'Product created and managed via ISV integration',
|
|
19
|
+
prData: {
|
|
20
|
+
type: 'ITEM',
|
|
21
|
+
regularPrice: '39.99',
|
|
22
|
+
currency: 'EUR',
|
|
23
|
+
timeToLive: 86400
|
|
24
|
+
},
|
|
25
|
+
prOptions: {
|
|
26
|
+
imageUrl: 'https://isv-cdn.example.com/product-image.jpg',
|
|
27
|
+
category: 'digital',
|
|
28
|
+
tags: ['isv-managed', 'digital', 'premium'],
|
|
29
|
+
isvMetadata: {
|
|
30
|
+
sourceSystem: 'ISV_PLATFORM',
|
|
31
|
+
externalId: 'ext_prod_123'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
get_product: {
|
|
38
|
+
description: 'Get merchant product details via ISV',
|
|
39
|
+
endpoint: '/products/{id}',
|
|
40
|
+
method: 'GET',
|
|
41
|
+
requiresOAuth: true,
|
|
42
|
+
sampleBody: null
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
update_product: {
|
|
46
|
+
description: 'Update merchant product via ISV',
|
|
47
|
+
endpoint: '/products/{id}',
|
|
48
|
+
method: 'PATCH',
|
|
49
|
+
requiresOAuth: true,
|
|
50
|
+
sampleBody: {
|
|
51
|
+
name: 'ISV Managed Product - Updated',
|
|
52
|
+
prData: {
|
|
53
|
+
regularPrice: '34.99'
|
|
54
|
+
},
|
|
55
|
+
prOptions: {
|
|
56
|
+
isvMetadata: {
|
|
57
|
+
lastUpdated: new Date().toISOString(),
|
|
58
|
+
updateSource: 'ISV_BULK_UPDATE'
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
delete_product: {
|
|
65
|
+
description: 'Delete merchant product via ISV',
|
|
66
|
+
endpoint: '/products/{id}',
|
|
67
|
+
method: 'DELETE',
|
|
68
|
+
requiresOAuth: true,
|
|
69
|
+
sampleBody: null
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
list_products: {
|
|
73
|
+
description: 'List merchant products via ISV',
|
|
74
|
+
endpoint: '/products',
|
|
75
|
+
method: 'GET',
|
|
76
|
+
requiresOAuth: true,
|
|
77
|
+
sampleBody: null,
|
|
78
|
+
queryParams: {
|
|
79
|
+
limit: 50,
|
|
80
|
+
offset: 0,
|
|
81
|
+
isvManaged: true,
|
|
82
|
+
status: 'active'
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
bulk_create_products: {
|
|
87
|
+
description: 'Bulk create products for merchant via ISV',
|
|
88
|
+
endpoint: '/products/bulk',
|
|
89
|
+
method: 'POST',
|
|
90
|
+
requiresOAuth: true,
|
|
91
|
+
sampleBody: {
|
|
92
|
+
products: [
|
|
93
|
+
{
|
|
94
|
+
name: 'Bulk Product 1',
|
|
95
|
+
shortDescription: 'First bulk product',
|
|
96
|
+
prData: { type: 'ITEM', regularPrice: '19.99', currency: 'EUR' },
|
|
97
|
+
prOptions: { category: 'bulk-import' }
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'Bulk Product 2',
|
|
101
|
+
shortDescription: 'Second bulk product',
|
|
102
|
+
prData: { type: 'ITEM', regularPrice: '29.99', currency: 'EUR' },
|
|
103
|
+
prOptions: { category: 'bulk-import' }
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
bulkOptions: {
|
|
107
|
+
batchId: 'batch_001',
|
|
108
|
+
validateOnly: false,
|
|
109
|
+
continueOnError: true
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
sync_products: {
|
|
115
|
+
description: 'Synchronize products between ISV and merchant',
|
|
116
|
+
endpoint: '/products/sync',
|
|
117
|
+
method: 'POST',
|
|
118
|
+
requiresOAuth: true,
|
|
119
|
+
sampleBody: {
|
|
120
|
+
syncOptions: {
|
|
121
|
+
direction: 'ISV_TO_MERCHANT',
|
|
122
|
+
conflictResolution: 'ISV_WINS',
|
|
123
|
+
includeDeleted: false
|
|
124
|
+
},
|
|
125
|
+
filters: {
|
|
126
|
+
lastModified: '2024-01-01T00:00:00Z',
|
|
127
|
+
categories: ['digital', 'premium']
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
get_product_analytics: {
|
|
133
|
+
description: 'Get product analytics via ISV',
|
|
134
|
+
endpoint: '/products/{id}/analytics',
|
|
135
|
+
method: 'GET',
|
|
136
|
+
requiresOAuth: true,
|
|
137
|
+
sampleBody: null,
|
|
138
|
+
queryParams: {
|
|
139
|
+
startDate: '2024-01-01',
|
|
140
|
+
endDate: '2024-12-31',
|
|
141
|
+
metrics: 'sales,views,conversions'
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
// Audio/Soundbite Operations
|
|
146
|
+
register_audio: {
|
|
147
|
+
description: 'Register audio file for merchant product via ISV',
|
|
148
|
+
endpoint: '/products/{id}/audios/upload',
|
|
149
|
+
method: 'POST',
|
|
150
|
+
requiresOAuth: true,
|
|
151
|
+
contentType: 'multipart/form-data',
|
|
152
|
+
sampleBody: {
|
|
153
|
+
file: '@/path/to/audio.mp3'
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
get_audios: {
|
|
158
|
+
description: 'Get all audio files for merchant product via ISV',
|
|
159
|
+
endpoint: '/products/{id}/audios',
|
|
160
|
+
method: 'GET',
|
|
161
|
+
requiresOAuth: true,
|
|
162
|
+
sampleBody: null
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
get_audio: {
|
|
166
|
+
description: 'Get specific audio file details via ISV',
|
|
167
|
+
endpoint: '/products/{id}/audios/{audioId}',
|
|
168
|
+
method: 'GET',
|
|
169
|
+
requiresOAuth: true,
|
|
170
|
+
sampleBody: null
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
update_audio: {
|
|
174
|
+
description: 'Update audio file information via ISV',
|
|
175
|
+
endpoint: '/products/{id}/audios/{audioId}',
|
|
176
|
+
method: 'PATCH',
|
|
177
|
+
requiresOAuth: true,
|
|
178
|
+
sampleBody: {
|
|
179
|
+
title: 'Updated Audio Title',
|
|
180
|
+
productId: 'pr_new_product_789'
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
delete_audio: {
|
|
185
|
+
description: 'Delete audio file via ISV',
|
|
186
|
+
endpoint: '/products/{id}/audios/{audioId}',
|
|
187
|
+
method: 'DELETE',
|
|
188
|
+
requiresOAuth: true,
|
|
189
|
+
sampleBody: null
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Python ISV Product Generator
|
|
195
|
+
*/
|
|
196
|
+
export class PythonISVProductGenerator extends ExampleGenerator {
|
|
197
|
+
constructor() {
|
|
198
|
+
super('python');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
getOperationTemplate(operation, partnerType, params = {}) {
|
|
202
|
+
const opConfig = ISVProductOperations[operation];
|
|
203
|
+
if (!opConfig) {
|
|
204
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const {
|
|
208
|
+
productId = 'pr_example_123',
|
|
209
|
+
merchantPartnerId = 'merchant_456',
|
|
210
|
+
audioId = 'aud_example_789',
|
|
211
|
+
...otherParams
|
|
212
|
+
} = params;
|
|
213
|
+
|
|
214
|
+
let endpoint = opConfig.endpoint.replace('{id}', productId);
|
|
215
|
+
if (endpoint.includes('{audioId}')) {
|
|
216
|
+
endpoint = endpoint.replace('{audioId}', audioId);
|
|
217
|
+
}
|
|
218
|
+
const functionName = `${operation}_example`;
|
|
219
|
+
|
|
220
|
+
return `def ${functionName}(product_id='${productId}', merchant_partner_id='${merchantPartnerId}'${audioId && operation.includes('audio') && !operation.includes('get_audios') && !operation.includes('register') ? `, audio_id='${audioId}'` : ''}, use_sandbox=True):
|
|
221
|
+
"""${opConfig.description}"""
|
|
222
|
+
|
|
223
|
+
try:
|
|
224
|
+
# Step 1: Get OAuth2 token for merchant access
|
|
225
|
+
oauth2_token = get_oauth2_token(merchant_partner_id)
|
|
226
|
+
if not oauth2_token:
|
|
227
|
+
print("Failed to obtain OAuth2 token")
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
# Step 2: Get API configuration
|
|
231
|
+
base_url = get_api_base_url(use_sandbox)
|
|
232
|
+
endpoint = '${endpoint}'
|
|
233
|
+
url = f"{base_url}{endpoint}"
|
|
234
|
+
|
|
235
|
+
${this.getQueryParamsSection(operation, opConfig)}
|
|
236
|
+
${this.getRequestBodySection(operation, opConfig)}
|
|
237
|
+
|
|
238
|
+
# Step 3: Create ISV JWT token with OAuth2 token
|
|
239
|
+
token, body_string = create_isv_jwt_token(merchant_partner_id, oauth2_token, request_body, use_sandbox)
|
|
240
|
+
headers = get_api_headers(token)
|
|
241
|
+
|
|
242
|
+
# Step 4: Make API request
|
|
243
|
+
${this.getRequestSection(opConfig.method)}
|
|
244
|
+
|
|
245
|
+
if response.status_code == 200:
|
|
246
|
+
result = response.json()
|
|
247
|
+
print(f"${opConfig.description} successful:")
|
|
248
|
+
print(json.dumps(result, indent=2))
|
|
249
|
+
|
|
250
|
+
${this.getResultProcessingSection(operation)}
|
|
251
|
+
return result
|
|
252
|
+
else:
|
|
253
|
+
error_msg = f"Request failed with status {response.status_code}: {response.text}"
|
|
254
|
+
print(error_msg)
|
|
255
|
+
return None
|
|
256
|
+
|
|
257
|
+
except Exception as e:
|
|
258
|
+
print(f"Error in ${operation}: {str(e)}")
|
|
259
|
+
return None
|
|
260
|
+
|
|
261
|
+
def create_isv_jwt_token(merchant_partner_id, oauth2_token, request_body=None, use_sandbox=True):
|
|
262
|
+
"""Create ISV JWT token with OAuth2 authentication"""
|
|
263
|
+
|
|
264
|
+
# Get ISV configuration
|
|
265
|
+
isv_partner_id = os.getenv('PAYWARE_ISV_PARTNER_ID')
|
|
266
|
+
if use_sandbox:
|
|
267
|
+
private_key_path = os.getenv('PAYWARE_SANDBOX_ISV_PRIVATE_KEY_PATH')
|
|
268
|
+
else:
|
|
269
|
+
private_key_path = os.getenv('PAYWARE_PRODUCTION_ISV_PRIVATE_KEY_PATH')
|
|
270
|
+
|
|
271
|
+
if not isv_partner_id or not private_key_path:
|
|
272
|
+
raise ValueError("Missing ISV configuration")
|
|
273
|
+
|
|
274
|
+
# Load private key
|
|
275
|
+
with open(private_key_path, 'r') as f:
|
|
276
|
+
private_key = f.read()
|
|
277
|
+
|
|
278
|
+
# Create JWT header
|
|
279
|
+
header = {
|
|
280
|
+
'alg': 'RS256',
|
|
281
|
+
'typ': 'JWT'
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
# Add content MD5 for requests with body
|
|
285
|
+
body_string = None
|
|
286
|
+
if request_body:
|
|
287
|
+
body_string = create_minimized_json(request_body)
|
|
288
|
+
content_md5 = base64.b64encode(
|
|
289
|
+
hashlib.md5(body_string.encode('utf-8')).digest()
|
|
290
|
+
).decode('utf-8')
|
|
291
|
+
header['contentMd5'] = content_md5
|
|
292
|
+
|
|
293
|
+
# Create JWT payload for ISV
|
|
294
|
+
payload = {
|
|
295
|
+
'iss': isv_partner_id, # ISV Partner ID
|
|
296
|
+
'aud': merchant_partner_id, # Target Merchant ID
|
|
297
|
+
'sub': oauth2_token, # OAuth2 access token
|
|
298
|
+
'iat': int(datetime.utcnow().timestamp())
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
# Create and return token
|
|
302
|
+
token = jwt.encode(payload, private_key, algorithm='RS256', headers=header)
|
|
303
|
+
return token, body_string
|
|
304
|
+
|
|
305
|
+
# Example usage
|
|
306
|
+
if __name__ == "__main__":
|
|
307
|
+
# Set target merchant
|
|
308
|
+
target_merchant = os.getenv('PAYWARE_TARGET_MERCHANT_ID', 'merchant_example')
|
|
309
|
+
|
|
310
|
+
# ${opConfig.description}
|
|
311
|
+
result = ${functionName}(merchant_partner_id=target_merchant)
|
|
312
|
+
|
|
313
|
+
if result:
|
|
314
|
+
print("ISV operation completed successfully")
|
|
315
|
+
${this.getISVResultProcessingSection(operation)}
|
|
316
|
+
else:
|
|
317
|
+
print("ISV operation failed")`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
getQueryParamsSection(operation, opConfig) {
|
|
321
|
+
if (!opConfig.queryParams) {
|
|
322
|
+
return '';
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const paramsStr = Object.entries(opConfig.queryParams)
|
|
326
|
+
.map(([key, value]) => ` '${key}': ${typeof value === 'string' ? `'${value}'` : value}`)
|
|
327
|
+
.join(',\n');
|
|
328
|
+
|
|
329
|
+
return `# Add query parameters
|
|
330
|
+
params = {
|
|
331
|
+
${paramsStr}
|
|
332
|
+
}
|
|
333
|
+
if params:
|
|
334
|
+
url += '?' + '&'.join([f"{k}={v}" for k, v in params.items()])`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
getRequestBodySection(operation, opConfig) {
|
|
338
|
+
if (!opConfig.sampleBody) {
|
|
339
|
+
return '# No request body needed for this operation\n request_body = None';
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const bodyStr = JSON.stringify(opConfig.sampleBody, null, 8).replace(/^/gm, ' ');
|
|
343
|
+
return `# Prepare request body
|
|
344
|
+
request_body = ${bodyStr}`;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
getRequestSection(method) {
|
|
348
|
+
if (method === 'GET') {
|
|
349
|
+
return 'response = requests.get(url, headers=headers)';
|
|
350
|
+
} else if (method === 'DELETE') {
|
|
351
|
+
return 'response = requests.delete(url, headers=headers)';
|
|
352
|
+
} else {
|
|
353
|
+
return `response = requests.${method.toLowerCase()}(
|
|
354
|
+
url,
|
|
355
|
+
headers=headers,
|
|
356
|
+
data=body_string if request_body else None
|
|
357
|
+
)`;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
getResultProcessingSection(operation) {
|
|
362
|
+
const processing = {
|
|
363
|
+
create_product: `# Store product ID and ISV metadata
|
|
364
|
+
product_id = result.get('productId')
|
|
365
|
+
isv_metadata = result.get('prOptions', {}).get('isvMetadata', {})
|
|
366
|
+
print(f"Product created with ID: {product_id}")
|
|
367
|
+
print(f"ISV metadata: {isv_metadata}")`,
|
|
368
|
+
|
|
369
|
+
bulk_create_products: `# Process bulk creation results
|
|
370
|
+
created_products = result.get('createdProducts', [])
|
|
371
|
+
failed_products = result.get('failedProducts', [])
|
|
372
|
+
print(f"Successfully created: {len(created_products)} products")
|
|
373
|
+
print(f"Failed to create: {len(failed_products)} products")`,
|
|
374
|
+
|
|
375
|
+
sync_products: `# Display sync results
|
|
376
|
+
sync_stats = result.get('syncStats', {})
|
|
377
|
+
print(f"Sync completed:")
|
|
378
|
+
print(f"- Created: {sync_stats.get('created', 0)}")
|
|
379
|
+
print(f"- Updated: {sync_stats.get('updated', 0)}")
|
|
380
|
+
print(f"- Deleted: {sync_stats.get('deleted', 0)}")`,
|
|
381
|
+
|
|
382
|
+
get_product_analytics: `# Display analytics data
|
|
383
|
+
analytics = result.get('analytics', {})
|
|
384
|
+
metrics = analytics.get('metrics', {})
|
|
385
|
+
print("Product Analytics:")
|
|
386
|
+
for metric, value in metrics.items():
|
|
387
|
+
print(f"- {metric}: {value}")`
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
return processing[operation] || '# Process ISV result as needed';
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
getISVResultProcessingSection(operation) {
|
|
394
|
+
const processing = {
|
|
395
|
+
create_product: `# Log ISV operation for audit
|
|
396
|
+
print("ISV Product Creation completed - check merchant dashboard")`,
|
|
397
|
+
|
|
398
|
+
bulk_create_products: `# Generate ISV report
|
|
399
|
+
print("Bulk creation completed - generating ISV summary report")`,
|
|
400
|
+
|
|
401
|
+
sync_products: `# Update ISV sync status
|
|
402
|
+
print("Product synchronization completed - updating ISV tracking")`
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
return processing[operation] || '# Log ISV operation completion';
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Node.js ISV Product Generator
|
|
411
|
+
*/
|
|
412
|
+
export class NodeJSISVProductGenerator extends ExampleGenerator {
|
|
413
|
+
constructor() {
|
|
414
|
+
super('nodejs');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
getOperationTemplate(operation, partnerType, params = {}) {
|
|
418
|
+
const opConfig = ISVProductOperations[operation];
|
|
419
|
+
if (!opConfig) {
|
|
420
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const {
|
|
424
|
+
productId = 'pr_example_123',
|
|
425
|
+
merchantPartnerId = 'merchant_456',
|
|
426
|
+
audioId = 'aud_example_789',
|
|
427
|
+
...otherParams
|
|
428
|
+
} = params;
|
|
429
|
+
|
|
430
|
+
let endpoint = opConfig.endpoint.replace('{id}', productId);
|
|
431
|
+
if (endpoint.includes('{audioId}')) {
|
|
432
|
+
endpoint = endpoint.replace('{audioId}', audioId);
|
|
433
|
+
}
|
|
434
|
+
const functionName = `${operation}Example`;
|
|
435
|
+
|
|
436
|
+
return `async function ${functionName}(productId = '${productId}', merchantPartnerId = '${merchantPartnerId}'${audioId && operation.includes('audio') && !operation.includes('get_audios') && !operation.includes('register') ? `, audioId = '${audioId}'` : ''}, useSandbox = true) {
|
|
437
|
+
/**
|
|
438
|
+
* ${opConfig.description}
|
|
439
|
+
*/
|
|
440
|
+
|
|
441
|
+
try {
|
|
442
|
+
// Step 1: Get OAuth2 token for merchant access
|
|
443
|
+
const oauth2Token = await getOAuth2Token(merchantPartnerId);
|
|
444
|
+
if (!oauth2Token) {
|
|
445
|
+
console.error('Failed to obtain OAuth2 token');
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Step 2: Get API configuration
|
|
450
|
+
const baseUrl = getAPIBaseURL(useSandbox);
|
|
451
|
+
const endpoint = '${endpoint}';
|
|
452
|
+
let url = \`\${baseUrl}\${endpoint}\`;
|
|
453
|
+
|
|
454
|
+
${this.getQueryParamsSection(operation, opConfig)}
|
|
455
|
+
${this.getRequestBodySection(operation, opConfig)}
|
|
456
|
+
|
|
457
|
+
// Step 3: Create ISV JWT token with OAuth2 token
|
|
458
|
+
const { token, bodyString } = createISVJWTToken(merchantPartnerId, oauth2Token, requestBody, useSandbox);
|
|
459
|
+
const headers = getAPIHeaders(token);
|
|
460
|
+
|
|
461
|
+
// Step 4: Make API request
|
|
462
|
+
${this.getRequestSection(opConfig.method)}
|
|
463
|
+
|
|
464
|
+
if (response.status === 200) {
|
|
465
|
+
const result = response.data;
|
|
466
|
+
console.log('${opConfig.description} successful:');
|
|
467
|
+
console.log(JSON.stringify(result, null, 2));
|
|
468
|
+
|
|
469
|
+
${this.getResultProcessingSection(operation)}
|
|
470
|
+
|
|
471
|
+
return result;
|
|
472
|
+
} else {
|
|
473
|
+
console.error(\`Request failed with status \${response.status}: \${response.statusText}\`);
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
} catch (error) {
|
|
478
|
+
console.error(\`Error in ${operation}:\`, error.message);
|
|
479
|
+
if (error.response) {
|
|
480
|
+
console.error('API Error:', error.response.data);
|
|
481
|
+
}
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function createISVJWTToken(merchantPartnerId, oauth2Token, requestBody = null, useSandbox = true) {
|
|
487
|
+
/**
|
|
488
|
+
* Create ISV JWT token with OAuth2 authentication
|
|
489
|
+
*/
|
|
490
|
+
|
|
491
|
+
// Get ISV configuration
|
|
492
|
+
const isvPartnerId = process.env.PAYWARE_ISV_PARTNER_ID;
|
|
493
|
+
const privateKeyPath = useSandbox ?
|
|
494
|
+
process.env.PAYWARE_SANDBOX_ISV_PRIVATE_KEY_PATH :
|
|
495
|
+
process.env.PAYWARE_PRODUCTION_ISV_PRIVATE_KEY_PATH;
|
|
496
|
+
|
|
497
|
+
if (!isvPartnerId || !privateKeyPath) {
|
|
498
|
+
throw new Error('Missing ISV configuration');
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Load private key
|
|
502
|
+
const privateKey = fs.readFileSync(privateKeyPath, 'utf8');
|
|
503
|
+
|
|
504
|
+
// Create JWT header
|
|
505
|
+
const header = {
|
|
506
|
+
alg: 'RS256',
|
|
507
|
+
typ: 'JWT'
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
// Add content MD5 for requests with body
|
|
511
|
+
let bodyString = null;
|
|
512
|
+
if (requestBody) {
|
|
513
|
+
bodyString = createMinimizedJSON(requestBody);
|
|
514
|
+
const contentMd5 = crypto
|
|
515
|
+
.createHash('md5')
|
|
516
|
+
.update(bodyString, 'utf8')
|
|
517
|
+
.digest('base64');
|
|
518
|
+
header.contentMd5 = contentMd5;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Create JWT payload for ISV
|
|
522
|
+
const payload = {
|
|
523
|
+
iss: isvPartnerId, // ISV Partner ID
|
|
524
|
+
aud: merchantPartnerId, // Target Merchant ID
|
|
525
|
+
sub: oauth2Token, // OAuth2 access token
|
|
526
|
+
iat: Math.floor(Date.now() / 1000)
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
// Create and return token
|
|
530
|
+
const token = jwt.sign(payload, privateKey, {
|
|
531
|
+
algorithm: 'RS256',
|
|
532
|
+
header
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
return { token, bodyString };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Example usage
|
|
539
|
+
async function main() {
|
|
540
|
+
console.log('ISV Product Management Example');
|
|
541
|
+
|
|
542
|
+
// Set target merchant
|
|
543
|
+
const targetMerchant = process.env.PAYWARE_TARGET_MERCHANT_ID || 'merchant_example';
|
|
544
|
+
|
|
545
|
+
const result = await ${functionName}(undefined, targetMerchant);
|
|
546
|
+
|
|
547
|
+
if (result) {
|
|
548
|
+
console.log('ISV operation completed successfully');
|
|
549
|
+
${this.getISVResultProcessingSection(operation)}
|
|
550
|
+
} else {
|
|
551
|
+
console.log('ISV operation failed');
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Run example if this file is executed directly
|
|
556
|
+
if (require.main === module) {
|
|
557
|
+
main().catch(console.error);
|
|
558
|
+
}`;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
getQueryParamsSection(operation, opConfig) {
|
|
562
|
+
if (!opConfig.queryParams) {
|
|
563
|
+
return '';
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const paramsStr = JSON.stringify(opConfig.queryParams, null, 4).replace(/^/gm, ' ');
|
|
567
|
+
return `// Add query parameters
|
|
568
|
+
const queryParams = ${paramsStr};
|
|
569
|
+
const searchParams = new URLSearchParams(queryParams);
|
|
570
|
+
url += \`?\${searchParams.toString()}\`;`;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
getRequestBodySection(operation, opConfig) {
|
|
574
|
+
if (!opConfig.sampleBody) {
|
|
575
|
+
return '// No request body needed for this operation\n const requestBody = null;';
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const bodyStr = JSON.stringify(opConfig.sampleBody, null, 4).replace(/^/gm, ' ');
|
|
579
|
+
return `// Prepare request body
|
|
580
|
+
const requestBody = ${bodyStr};`;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
getRequestSection(method) {
|
|
584
|
+
if (method === 'GET') {
|
|
585
|
+
return 'const response = await axios.get(url, { headers });';
|
|
586
|
+
} else if (method === 'DELETE') {
|
|
587
|
+
return 'const response = await axios.delete(url, { headers });';
|
|
588
|
+
} else {
|
|
589
|
+
return `const response = await axios.${method.toLowerCase()}(
|
|
590
|
+
url,
|
|
591
|
+
bodyString || undefined,
|
|
592
|
+
{ headers }
|
|
593
|
+
);`;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
getResultProcessingSection(operation) {
|
|
598
|
+
const processing = {
|
|
599
|
+
create_product: `// Store product ID and ISV metadata
|
|
600
|
+
const productId = result.productId;
|
|
601
|
+
const isvMetadata = result.prOptions?.isvMetadata || {};
|
|
602
|
+
console.log(\`Product created with ID: \${productId}\`);
|
|
603
|
+
console.log('ISV metadata:', isvMetadata);`,
|
|
604
|
+
|
|
605
|
+
bulk_create_products: `// Process bulk creation results
|
|
606
|
+
const createdProducts = result.createdProducts || [];
|
|
607
|
+
const failedProducts = result.failedProducts || [];
|
|
608
|
+
console.log(\`Successfully created: \${createdProducts.length} products\`);
|
|
609
|
+
console.log(\`Failed to create: \${failedProducts.length} products\`);`,
|
|
610
|
+
|
|
611
|
+
sync_products: `// Display sync results
|
|
612
|
+
const syncStats = result.syncStats || {};
|
|
613
|
+
console.log('Sync completed:');
|
|
614
|
+
console.log(\`- Created: \${syncStats.created || 0}\`);
|
|
615
|
+
console.log(\`- Updated: \${syncStats.updated || 0}\`);
|
|
616
|
+
console.log(\`- Deleted: \${syncStats.deleted || 0}\`);`,
|
|
617
|
+
|
|
618
|
+
get_product_analytics: `// Display analytics data
|
|
619
|
+
const analytics = result.analytics || {};
|
|
620
|
+
const metrics = analytics.metrics || {};
|
|
621
|
+
console.log('Product Analytics:');
|
|
622
|
+
Object.entries(metrics).forEach(([metric, value]) => {
|
|
623
|
+
console.log(\`- \${metric}: \${value}\`);
|
|
624
|
+
});`
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
return processing[operation] || '// Process ISV result as needed';
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
getISVResultProcessingSection(operation) {
|
|
631
|
+
const processing = {
|
|
632
|
+
create_product: `// Log ISV operation for audit
|
|
633
|
+
console.log('ISV Product Creation completed - check merchant dashboard');`,
|
|
634
|
+
|
|
635
|
+
bulk_create_products: `// Generate ISV report
|
|
636
|
+
console.log('Bulk creation completed - generating ISV summary report');`,
|
|
637
|
+
|
|
638
|
+
sync_products: `// Update ISV sync status
|
|
639
|
+
console.log('Product synchronization completed - updating ISV tracking');`
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
return processing[operation] || '// Log ISV operation completion';
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Export all generators
|
|
648
|
+
*/
|
|
649
|
+
export const ISVProductGenerators = {
|
|
650
|
+
python: PythonISVProductGenerator,
|
|
651
|
+
nodejs: NodeJSISVProductGenerator,
|
|
652
|
+
javascript: NodeJSISVProductGenerator
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Generate ISV product example
|
|
657
|
+
*/
|
|
658
|
+
export function generateISVProductExample(operation, language = 'python', options = {}) {
|
|
659
|
+
const GeneratorClass = ISVProductGenerators[language];
|
|
660
|
+
if (!GeneratorClass) {
|
|
661
|
+
throw new Error(`Unsupported language: ${language}`);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const generator = new GeneratorClass();
|
|
665
|
+
return generator.generateExample(operation, 'isv', options);
|
|
666
|
+
}
|