@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,361 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
|
|
3
|
+
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Create a transaction via payware API on behalf of a merchant (ISV)
|
|
7
|
+
* @param {Object} params - Transaction parameters including ISV authentication
|
|
8
|
+
* @returns {Object} Transaction response
|
|
9
|
+
*/
|
|
10
|
+
export async function createTransaction({
|
|
11
|
+
// ISV Authentication
|
|
12
|
+
merchantPartnerId,
|
|
13
|
+
oauth2Token,
|
|
14
|
+
// Transaction parameters
|
|
15
|
+
type = 'PLAIN',
|
|
16
|
+
amount,
|
|
17
|
+
currency = 'EUR',
|
|
18
|
+
reasonL1,
|
|
19
|
+
reasonL2,
|
|
20
|
+
callbackUrl,
|
|
21
|
+
account,
|
|
22
|
+
friendlyName,
|
|
23
|
+
shop,
|
|
24
|
+
timeToLive = 120,
|
|
25
|
+
passbackParams,
|
|
26
|
+
// QR Options
|
|
27
|
+
qrFormat,
|
|
28
|
+
qrBorder,
|
|
29
|
+
qrErrorCorrection,
|
|
30
|
+
qrScale,
|
|
31
|
+
qrVersion,
|
|
32
|
+
// Barcode Options
|
|
33
|
+
barFormat,
|
|
34
|
+
barModuleWidth,
|
|
35
|
+
barBarHeight,
|
|
36
|
+
barFontSize,
|
|
37
|
+
barHumanReadableLocation,
|
|
38
|
+
useSandbox = true
|
|
39
|
+
}) {
|
|
40
|
+
// ISV-specific validation
|
|
41
|
+
if (!merchantPartnerId) {
|
|
42
|
+
throw new Error('Merchant Partner ID is required for ISV operations');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!oauth2Token) {
|
|
46
|
+
throw new Error('OAuth2 token is required for ISV operations');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Standard validation
|
|
50
|
+
if (!reasonL1) {
|
|
51
|
+
throw new Error('reasonL1 is required (transaction grounds description)');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (amount !== undefined && (typeof amount !== 'string' && typeof amount !== 'number')) {
|
|
55
|
+
throw new Error('Amount must be a string or number representing currency value (e.g., "25.50" or 25.50)');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (amount !== undefined && parseFloat(amount) < 0) {
|
|
59
|
+
throw new Error('Amount must be non-negative');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!['PLAIN', 'QR', 'BARCODE'].includes(type)) {
|
|
63
|
+
throw new Error('Transaction type must be PLAIN, QR, or BARCODE');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Build QR options if applicable
|
|
67
|
+
const qrOptions = {};
|
|
68
|
+
if (type === 'QR') {
|
|
69
|
+
if (qrFormat) qrOptions.qrFormat = qrFormat;
|
|
70
|
+
if (qrBorder !== undefined) qrOptions.qrBorder = qrBorder;
|
|
71
|
+
if (qrErrorCorrection) qrOptions.qrErrorCorrection = qrErrorCorrection;
|
|
72
|
+
if (qrScale) qrOptions.qrScale = qrScale;
|
|
73
|
+
if (qrVersion) qrOptions.qrVersion = qrVersion;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Build barcode options if applicable
|
|
77
|
+
const barOptions = {};
|
|
78
|
+
if (type === 'BARCODE') {
|
|
79
|
+
if (barFormat) barOptions.barFormat = barFormat;
|
|
80
|
+
if (barModuleWidth) barOptions.barModuleWidth = barModuleWidth;
|
|
81
|
+
if (barBarHeight) barOptions.barBarHeight = barBarHeight;
|
|
82
|
+
if (barFontSize) barOptions.barFontSize = barFontSize;
|
|
83
|
+
if (barHumanReadableLocation) barOptions.barHumanReadableLocation = barHumanReadableLocation;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Build request body according to documentation structure
|
|
87
|
+
const requestBody = {
|
|
88
|
+
...(account && { account }),
|
|
89
|
+
...(friendlyName && { friendlyName }),
|
|
90
|
+
...(shop && { shop }),
|
|
91
|
+
...(callbackUrl && { callbackUrl }),
|
|
92
|
+
...(passbackParams && {
|
|
93
|
+
passbackParams: typeof passbackParams === 'string' ? passbackParams : JSON.stringify(passbackParams)
|
|
94
|
+
}),
|
|
95
|
+
trData: {
|
|
96
|
+
amount: amount !== undefined ? amount.toString() : '0.00',
|
|
97
|
+
currency,
|
|
98
|
+
reasonL1,
|
|
99
|
+
...(reasonL2 && { reasonL2 })
|
|
100
|
+
},
|
|
101
|
+
trOptions: {
|
|
102
|
+
type,
|
|
103
|
+
timeToLive
|
|
104
|
+
},
|
|
105
|
+
...(type === 'QR' && Object.keys(qrOptions).length > 0 && { qrOptions }),
|
|
106
|
+
...(type === 'BARCODE' && Object.keys(barOptions).length > 0 && { barOptions })
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Get ISV credentials
|
|
110
|
+
const isvPartnerId = getPartnerIdSafe();
|
|
111
|
+
const privateKey = getPrivateKeySafe(useSandbox);
|
|
112
|
+
|
|
113
|
+
// Create ISV JWT token
|
|
114
|
+
const jwtData = await createJWTForPartner({
|
|
115
|
+
partnerId: isvPartnerId,
|
|
116
|
+
privateKey,
|
|
117
|
+
requestBody,
|
|
118
|
+
merchantId: merchantPartnerId,
|
|
119
|
+
oauth2Token
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Use the same JSON serialization method as the JWT factory for MD5 calculation
|
|
123
|
+
const { createMinimizedJSON } = await import('../../core/utils/json-serializer.js');
|
|
124
|
+
const minimizedBodyString = createMinimizedJSON(requestBody);
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
128
|
+
// Send the exact minimized JSON string that was used for MD5 calculation
|
|
129
|
+
const response = await axios.post(`${baseUrl}/transactions`, minimizedBodyString, {
|
|
130
|
+
headers: {
|
|
131
|
+
'Authorization': `Bearer ${jwtData.token}`,
|
|
132
|
+
'Content-Type': 'application/json',
|
|
133
|
+
'Api-Version': '1'
|
|
134
|
+
},
|
|
135
|
+
// Tell axios to send the string as-is, don't serialize it again
|
|
136
|
+
transformRequest: [(data) => data]
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return response.data;
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (error.response) {
|
|
142
|
+
throw new Error(`payware API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
143
|
+
}
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export const createTransactionTool = {
|
|
149
|
+
name: 'payware_operations_create_transaction',
|
|
150
|
+
description: `Create a new transaction through payware as an ISV on behalf of a merchant.
|
|
151
|
+
|
|
152
|
+
ISV partners can create transactions for merchants they have authorization for via OAuth2.
|
|
153
|
+
Requires valid OAuth2 token obtained from the merchant.
|
|
154
|
+
|
|
155
|
+
**Authentication**: Uses ISV JWT with merchant partner ID in 'aud' claim and OAuth2 token in 'sub' claim.
|
|
156
|
+
|
|
157
|
+
**Transaction Types:**
|
|
158
|
+
- PLAIN: Basic transaction without visual codes
|
|
159
|
+
- QR: Transaction with QR code for mobile payments
|
|
160
|
+
- BARCODE: Transaction with barcode for scanning
|
|
161
|
+
|
|
162
|
+
**Required for all transactions:**
|
|
163
|
+
- Merchant Partner ID and OAuth2 token (ISV authentication)
|
|
164
|
+
- reasonL1 (transaction description)
|
|
165
|
+
- amount (transaction value)
|
|
166
|
+
|
|
167
|
+
**QR Code Options** (when type='QR'):
|
|
168
|
+
- qrFormat: PNG, SVG (default: PNG)
|
|
169
|
+
- qrBorder: Border width in modules (0-10, default: 4)
|
|
170
|
+
- qrErrorCorrection: L, M, Q, H (default: M)
|
|
171
|
+
- qrScale: Scale factor (1-10, default: 4)
|
|
172
|
+
- qrVersion: QR version (1-40, auto if not specified)
|
|
173
|
+
|
|
174
|
+
**Barcode Options** (when type='BARCODE'):
|
|
175
|
+
- barFormat: CODE128, EAN13, etc.
|
|
176
|
+
- barModuleWidth: Width of bars in pixels
|
|
177
|
+
- barBarHeight: Height of bars in pixels
|
|
178
|
+
- barFontSize: Font size for human readable text
|
|
179
|
+
- barHumanReadableLocation: TOP, BOTTOM, NONE`,
|
|
180
|
+
|
|
181
|
+
inputSchema: {
|
|
182
|
+
type: 'object',
|
|
183
|
+
required: ['merchantPartnerId', 'oauth2Token', 'reasonL1'],
|
|
184
|
+
properties: {
|
|
185
|
+
// ISV Authentication
|
|
186
|
+
merchantPartnerId: {
|
|
187
|
+
type: 'string',
|
|
188
|
+
description: 'Partner ID of the target merchant (8 alphanumeric characters, e.g., "PZAYNMVE")'
|
|
189
|
+
},
|
|
190
|
+
oauth2Token: {
|
|
191
|
+
type: 'string',
|
|
192
|
+
description: 'OAuth2 access token obtained from the merchant'
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
// Core transaction data
|
|
196
|
+
type: {
|
|
197
|
+
type: 'string',
|
|
198
|
+
enum: ['PLAIN', 'QR', 'BARCODE'],
|
|
199
|
+
default: 'PLAIN',
|
|
200
|
+
description: 'Transaction type'
|
|
201
|
+
},
|
|
202
|
+
amount: {
|
|
203
|
+
type: ['string', 'number'],
|
|
204
|
+
description: 'Transaction amount (e.g., "25.50" or 25.50)'
|
|
205
|
+
},
|
|
206
|
+
currency: {
|
|
207
|
+
type: 'string',
|
|
208
|
+
default: 'EUR',
|
|
209
|
+
description: 'Currency code (ISO 4217, e.g., EUR, USD, GBP)'
|
|
210
|
+
},
|
|
211
|
+
reasonL1: {
|
|
212
|
+
type: 'string',
|
|
213
|
+
description: 'Primary transaction reason/description (required)'
|
|
214
|
+
},
|
|
215
|
+
reasonL2: {
|
|
216
|
+
type: 'string',
|
|
217
|
+
description: 'Secondary transaction reason/description (optional)'
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
// Optional transaction metadata
|
|
221
|
+
callbackUrl: {
|
|
222
|
+
type: 'string',
|
|
223
|
+
description: 'URL to receive transaction status updates'
|
|
224
|
+
},
|
|
225
|
+
account: {
|
|
226
|
+
type: 'string',
|
|
227
|
+
description: 'Account identifier'
|
|
228
|
+
},
|
|
229
|
+
friendlyName: {
|
|
230
|
+
type: 'string',
|
|
231
|
+
description: 'Human-readable transaction identifier'
|
|
232
|
+
},
|
|
233
|
+
shop: {
|
|
234
|
+
type: 'string',
|
|
235
|
+
description: 'Shop/location identifier'
|
|
236
|
+
},
|
|
237
|
+
timeToLive: {
|
|
238
|
+
type: 'number',
|
|
239
|
+
default: 120,
|
|
240
|
+
description: 'Transaction validity in minutes'
|
|
241
|
+
},
|
|
242
|
+
passbackParams: {
|
|
243
|
+
type: ['string', 'object'],
|
|
244
|
+
description: 'Additional parameters to pass back in callbacks'
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
// QR Code options (when type='QR')
|
|
248
|
+
qrFormat: {
|
|
249
|
+
type: 'string',
|
|
250
|
+
enum: ['PNG', 'SVG'],
|
|
251
|
+
description: 'QR code image format'
|
|
252
|
+
},
|
|
253
|
+
qrBorder: {
|
|
254
|
+
type: 'number',
|
|
255
|
+
minimum: 0,
|
|
256
|
+
maximum: 10,
|
|
257
|
+
description: 'QR code border width in modules'
|
|
258
|
+
},
|
|
259
|
+
qrErrorCorrection: {
|
|
260
|
+
type: 'string',
|
|
261
|
+
enum: ['L', 'M', 'Q', 'H'],
|
|
262
|
+
description: 'QR error correction level'
|
|
263
|
+
},
|
|
264
|
+
qrScale: {
|
|
265
|
+
type: 'number',
|
|
266
|
+
minimum: 1,
|
|
267
|
+
maximum: 10,
|
|
268
|
+
description: 'QR code scale factor'
|
|
269
|
+
},
|
|
270
|
+
qrVersion: {
|
|
271
|
+
type: 'number',
|
|
272
|
+
minimum: 1,
|
|
273
|
+
maximum: 40,
|
|
274
|
+
description: 'QR code version (size)'
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
// Barcode options (when type='BARCODE')
|
|
278
|
+
barFormat: {
|
|
279
|
+
type: 'string',
|
|
280
|
+
description: 'Barcode format (e.g., CODE128, EAN13)'
|
|
281
|
+
},
|
|
282
|
+
barModuleWidth: {
|
|
283
|
+
type: 'number',
|
|
284
|
+
description: 'Barcode module width in pixels'
|
|
285
|
+
},
|
|
286
|
+
barBarHeight: {
|
|
287
|
+
type: 'number',
|
|
288
|
+
description: 'Barcode height in pixels'
|
|
289
|
+
},
|
|
290
|
+
barFontSize: {
|
|
291
|
+
type: 'number',
|
|
292
|
+
description: 'Font size for human readable text'
|
|
293
|
+
},
|
|
294
|
+
barHumanReadableLocation: {
|
|
295
|
+
type: 'string',
|
|
296
|
+
enum: ['TOP', 'BOTTOM', 'NONE'],
|
|
297
|
+
description: 'Location of human readable text'
|
|
298
|
+
},
|
|
299
|
+
useSandbox: {
|
|
300
|
+
type: 'boolean',
|
|
301
|
+
description: 'Use sandbox environment for testing',
|
|
302
|
+
default: true
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
async handler(params) {
|
|
308
|
+
try {
|
|
309
|
+
const result = await createTransaction(params);
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
content: [{
|
|
313
|
+
type: 'text',
|
|
314
|
+
text: `✅ Transaction Created Successfully (ISV -> Merchant: ${params.merchantPartnerId})
|
|
315
|
+
|
|
316
|
+
📋 **Transaction Details:**
|
|
317
|
+
- **Transaction ID**: ${result.transactionId || 'N/A'}
|
|
318
|
+
- **Status**: ${result.status || 'CREATED'}
|
|
319
|
+
- **Type**: ${params.type}
|
|
320
|
+
- **Amount**: ${params.amount || 'N/A'} ${params.currency || 'EUR'}
|
|
321
|
+
- **Reason**: ${params.reasonL1}
|
|
322
|
+
- **TTL**: ${params.timeToLive || 120} minutes
|
|
323
|
+
|
|
324
|
+
🔗 **Integration Details:**
|
|
325
|
+
- **ISV Partner**: ${getPartnerIdSafe()}
|
|
326
|
+
- **Target Merchant**: ${params.merchantPartnerId}
|
|
327
|
+
- **OAuth2 Token**: ${params.oauth2Token.substring(0, 8)}...
|
|
328
|
+
|
|
329
|
+
${result.qrCodeUrl ? `🔲 **QR Code**: ${result.qrCodeUrl}` : ''}
|
|
330
|
+
${result.barcodeUrl ? `📊 **Barcode**: ${result.barcodeUrl}` : ''}
|
|
331
|
+
${result.paymentUrl ? `💳 **Payment URL**: ${result.paymentUrl}` : ''}
|
|
332
|
+
|
|
333
|
+
**Raw Response:**
|
|
334
|
+
\`\`\`json
|
|
335
|
+
${JSON.stringify(result, null, 2)}
|
|
336
|
+
\`\`\``
|
|
337
|
+
}]
|
|
338
|
+
};
|
|
339
|
+
} catch (error) {
|
|
340
|
+
return {
|
|
341
|
+
content: [{
|
|
342
|
+
type: 'text',
|
|
343
|
+
text: `❌ Transaction Creation Failed
|
|
344
|
+
|
|
345
|
+
**Error**: ${error.message}
|
|
346
|
+
|
|
347
|
+
**ISV Authentication Check:**
|
|
348
|
+
- Merchant Partner ID: ${params.merchantPartnerId || 'Missing'}
|
|
349
|
+
- OAuth2 Token: ${params.oauth2Token ? 'Provided' : 'Missing'}
|
|
350
|
+
- ISV Partner ID: ${getPartnerIdSafe()}
|
|
351
|
+
|
|
352
|
+
**Troubleshooting:**
|
|
353
|
+
- Verify OAuth2 token is valid and granted
|
|
354
|
+
- Ensure merchant partner ID is correct (8 characters)
|
|
355
|
+
- Check transaction parameters meet payware requirements
|
|
356
|
+
- Confirm ISV has authorization to act on behalf of merchant`
|
|
357
|
+
}]
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
|
|
3
|
+
import { getSandboxUrl, getProductionUrl, getPartnerIdSafe, getPrivateKeySafe } from '../../config/env.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get transaction status from payware API as an ISV
|
|
7
|
+
* @param {Object} params - Parameters for status request
|
|
8
|
+
* @returns {Object} Transaction status response
|
|
9
|
+
*/
|
|
10
|
+
export async function getTransactionStatus({ transactionId, merchantPartnerId, oauth2Token, useSandbox = true }) {
|
|
11
|
+
if (!transactionId) {
|
|
12
|
+
throw new Error('Transaction ID is required');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!merchantPartnerId) {
|
|
16
|
+
throw new Error('Merchant Partner ID is required for ISV operations');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!oauth2Token) {
|
|
20
|
+
throw new Error('OAuth2 token is required for ISV operations');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Get ISV credentials
|
|
24
|
+
const isvPartnerId = getPartnerIdSafe();
|
|
25
|
+
const privateKey = getPrivateKeySafe(useSandbox);
|
|
26
|
+
|
|
27
|
+
// Create ISV JWT token (GET request - no body)
|
|
28
|
+
const jwtData = await createJWTForPartner({
|
|
29
|
+
partnerId: isvPartnerId,
|
|
30
|
+
privateKey,
|
|
31
|
+
requestBody: null,
|
|
32
|
+
merchantId: merchantPartnerId,
|
|
33
|
+
oauth2Token
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Required headers as per payware API documentation
|
|
37
|
+
const headers = {
|
|
38
|
+
'Authorization': `Bearer ${jwtData.token}`,
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
'Api-Version': '1' // Required: current API version
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
45
|
+
const response = await axios.get(`${baseUrl}/transactions/${transactionId}`, { headers });
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
success: true,
|
|
49
|
+
transaction: response.data,
|
|
50
|
+
requestId: response.headers['x-request-id'],
|
|
51
|
+
timestamp: new Date().toISOString()
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: {
|
|
57
|
+
message: error.response?.data?.message || error.message,
|
|
58
|
+
status: error.response?.status,
|
|
59
|
+
code: error.response?.data?.code,
|
|
60
|
+
details: error.response?.data
|
|
61
|
+
},
|
|
62
|
+
timestamp: new Date().toISOString()
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Format transaction status for display
|
|
69
|
+
*/
|
|
70
|
+
function formatTransactionStatus(transaction) {
|
|
71
|
+
const statusEmojis = {
|
|
72
|
+
'ACTIVE': '⏳'
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// If a transaction is returned from GET /transactions/{id}, it's always ACTIVE
|
|
76
|
+
// (transactions with final statuses are only available via /transactions-history)
|
|
77
|
+
const status = transaction.status || 'ACTIVE';
|
|
78
|
+
const emoji = statusEmojis[status] || '⏳';
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
emoji,
|
|
82
|
+
status,
|
|
83
|
+
formatted: `${emoji} ${status}`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get transaction status tool implementation for ISV
|
|
89
|
+
*/
|
|
90
|
+
export const getTransactionStatusTool = {
|
|
91
|
+
name: "payware_operations_get_transaction_status",
|
|
92
|
+
description: `Get status of an ACTIVE transaction by ID as an ISV on behalf of a merchant.
|
|
93
|
+
|
|
94
|
+
**ISV Authentication:** Uses ISV JWT with merchant partner ID in 'aud' claim and OAuth2 token in 'sub' claim.
|
|
95
|
+
**Endpoint:** GET /transactions/{transactionId}
|
|
96
|
+
**Use Case:** Check status of ACTIVE transactions only. This endpoint only returns transactions with ACTIVE status.
|
|
97
|
+
**Note:** For transactions with final statuses (CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED), use 'payware_transactions_get_history' instead.
|
|
98
|
+
|
|
99
|
+
**Required:** Merchant Partner ID and OAuth2 token for ISV authentication.`,
|
|
100
|
+
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
required: ["transactionId", "merchantPartnerId", "oauth2Token"],
|
|
104
|
+
properties: {
|
|
105
|
+
transactionId: {
|
|
106
|
+
type: "string",
|
|
107
|
+
description: "Transaction ID to check status for"
|
|
108
|
+
},
|
|
109
|
+
merchantPartnerId: {
|
|
110
|
+
type: "string",
|
|
111
|
+
description: "Partner ID of the target merchant (8 alphanumeric characters, e.g., 'PZAYNMVE')"
|
|
112
|
+
},
|
|
113
|
+
oauth2Token: {
|
|
114
|
+
type: "string",
|
|
115
|
+
description: "OAuth2 access token obtained from the merchant"
|
|
116
|
+
},
|
|
117
|
+
useSandbox: {
|
|
118
|
+
type: "boolean",
|
|
119
|
+
description: "Use sandbox environment for testing",
|
|
120
|
+
default: true
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
async handler(args) {
|
|
126
|
+
const { transactionId, merchantPartnerId, oauth2Token, useSandbox = true } = args;
|
|
127
|
+
|
|
128
|
+
if (!transactionId) {
|
|
129
|
+
throw new Error("Transaction ID is required");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!merchantPartnerId) {
|
|
133
|
+
throw new Error("Merchant Partner ID is required for ISV operations");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!oauth2Token) {
|
|
137
|
+
throw new Error("OAuth2 token is required for ISV operations");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const result = await getTransactionStatus({ transactionId, merchantPartnerId, oauth2Token, useSandbox });
|
|
141
|
+
|
|
142
|
+
if (result.success) {
|
|
143
|
+
const statusInfo = formatTransactionStatus(result.transaction);
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
content: [{
|
|
147
|
+
type: "text",
|
|
148
|
+
text: `📊 **Transaction Status Retrieved (ISV -> Merchant: ${merchantPartnerId})**
|
|
149
|
+
|
|
150
|
+
**Transaction:** ${transactionId}
|
|
151
|
+
**Status:** ${statusInfo.formatted}
|
|
152
|
+
|
|
153
|
+
**ISV Integration:**
|
|
154
|
+
- ISV Partner: ${getPartnerIdSafe()}
|
|
155
|
+
- Target Merchant: ${merchantPartnerId}
|
|
156
|
+
- OAuth2 Token: ${oauth2Token.substring(0, 8)}...
|
|
157
|
+
|
|
158
|
+
**Transaction Details:**
|
|
159
|
+
- ID: ${result.transaction.id || 'N/A'}
|
|
160
|
+
- Type: ${result.transaction.type || 'N/A'}
|
|
161
|
+
- Amount: ${result.transaction.trData ? `${result.transaction.trData.amount} ${result.transaction.trData.currency}` : 'N/A'}
|
|
162
|
+
- Description: ${result.transaction.description || 'N/A'}
|
|
163
|
+
- Created: ${result.transaction.createdAt || 'N/A'}
|
|
164
|
+
- Updated: ${result.transaction.updatedAt || 'N/A'}
|
|
165
|
+
|
|
166
|
+
**Full Response:**
|
|
167
|
+
\`\`\`json
|
|
168
|
+
${JSON.stringify(result.transaction, null, 2)}
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
**Request ID:** ${result.requestId || 'N/A'}
|
|
172
|
+
**Timestamp:** ${result.timestamp}
|
|
173
|
+
|
|
174
|
+
**Status Meanings:**
|
|
175
|
+
- ⏳ ACTIVE: Active transaction pending processing or finalizing
|
|
176
|
+
|
|
177
|
+
**Note:** Only ACTIVE transactions are returned by this endpoint. For final statuses (CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED), use the transaction history tool.`
|
|
178
|
+
}]
|
|
179
|
+
};
|
|
180
|
+
} else {
|
|
181
|
+
return {
|
|
182
|
+
content: [{
|
|
183
|
+
type: "text",
|
|
184
|
+
text: `❌ **Failed to Get Transaction Status**
|
|
185
|
+
|
|
186
|
+
**Transaction ID:** ${transactionId}
|
|
187
|
+
**ISV -> Merchant:** ${getPartnerIdSafe()} -> ${merchantPartnerId}
|
|
188
|
+
|
|
189
|
+
**Error Details:**
|
|
190
|
+
- Message: ${result.error.message}
|
|
191
|
+
- Status: ${result.error.status || 'N/A'}
|
|
192
|
+
- Code: ${result.error.code || 'N/A'}
|
|
193
|
+
|
|
194
|
+
**Full Error Response:**
|
|
195
|
+
\`\`\`json
|
|
196
|
+
${JSON.stringify(result.error.details || result.error, null, 2)}
|
|
197
|
+
\`\`\`
|
|
198
|
+
|
|
199
|
+
**Timestamp:** ${result.timestamp}
|
|
200
|
+
|
|
201
|
+
**ISV-Specific Troubleshooting:**
|
|
202
|
+
1. Verify OAuth2 token is valid and granted for merchant
|
|
203
|
+
2. Ensure merchant partner ID is correct (8 characters)
|
|
204
|
+
3. Check if ISV has authorization to access merchant transactions
|
|
205
|
+
4. Verify transaction belongs to the specified merchant
|
|
206
|
+
5. Confirm JWT token is properly signed for ISV requests
|
|
207
|
+
|
|
208
|
+
**General Troubleshooting:**
|
|
209
|
+
1. Verify the transaction ID is correct
|
|
210
|
+
2. Check if transaction exists and is accessible
|
|
211
|
+
3. Ensure transaction is still ACTIVE (not finalized)
|
|
212
|
+
4. Try using transaction history tool for completed transactions`
|
|
213
|
+
}]
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|