@payware/mcp-server 1.3.2 → 1.4.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 +4 -0
- package/README.md +18 -0
- package/package.json +7 -9
- package/src/auth/rsa-keys.js +12 -6
- package/src/auth/sandbox-setup.js +2 -0
- package/src/config/toolsets.js +104 -0
- package/src/core/auth/jwt-factory.js +4 -1
- package/src/core/auth/jwt-token.js +4 -0
- package/src/index.js +10 -6
- package/src/isv/data/index.js +15 -14
- package/src/isv/deep-links/delete-product-link.js +3 -2
- package/src/isv/deep-links/delete-transaction-link.js +3 -2
- package/src/isv/deep-links/get-product-link.js +8 -6
- package/src/isv/deep-links/get-transaction-link.js +8 -6
- package/src/isv/index.js +6 -0
- package/src/isv/invitations/index.js +5 -0
- package/src/isv/oauth2/get-token-info.js +10 -5
- package/src/isv/oauth2/obtain-token.js +9 -4
- package/src/isv/oauth2/token-helper.js +28 -26
- package/src/isv/poi/cancel-price.js +9 -2
- package/src/isv/poi/get-poi.js +4 -3
- package/src/isv/poi/get-qrcode.js +40 -9
- package/src/isv/poi/get-status.js +196 -168
- package/src/isv/poi/list-pois.js +6 -6
- package/src/isv/poi/set-price.js +40 -53
- package/src/isv/products/audios.js +8 -2
- package/src/isv/products/create-product.js +2 -0
- package/src/isv/products/delete-product.js +2 -0
- package/src/isv/products/get-product-image.js +2 -0
- package/src/isv/products/get-product.js +2 -0
- package/src/isv/products/list-products.js +2 -0
- package/src/isv/products/schedules.js +6 -0
- package/src/isv/products/update-product.js +2 -0
- package/src/isv/reference/index.js +2 -0
- package/src/isv/transactions/cancel-transaction.js +2 -0
- package/src/isv/transactions/create-transaction.js +2 -0
- package/src/isv/transactions/get-status.js +3 -1
- package/src/isv/transactions/process-transaction.js +2 -0
- package/src/isv/transactions/simulate-callback.js +21 -10
- package/src/isv/transactions/transaction-history.js +2 -0
- package/src/merchant/data/export-report.js +2 -0
- package/src/merchant/data/generate-report.js +2 -0
- package/src/merchant/data/get-export-list.js +2 -0
- package/src/merchant/data/get-report-requests.js +2 -0
- package/src/merchant/data/get-report-status.js +2 -0
- package/src/merchant/data/index.js +15 -10
- package/src/merchant/data/list-reports.js +2 -0
- package/src/merchant/deep-links/delete-product-link.js +3 -2
- package/src/merchant/deep-links/delete-transaction-link.js +3 -2
- package/src/merchant/deep-links/get-product-link.js +8 -6
- package/src/merchant/deep-links/get-transaction-link.js +8 -6
- package/src/merchant/index.js +7 -1
- package/src/merchant/logs/index.js +4 -0
- package/src/merchant/products/audios.js +15 -14
- package/src/merchant/products/create-product.js +3 -2
- package/src/merchant/products/delete-product.js +3 -2
- package/src/merchant/products/get-product-image.js +3 -2
- package/src/merchant/products/get-product.js +3 -2
- package/src/merchant/products/list-products.js +3 -2
- package/src/merchant/products/schedules.js +11 -10
- package/src/merchant/products/update-product.js +3 -2
- package/src/merchant/transactions/cancel-transaction.js +3 -2
- package/src/merchant/transactions/create-transaction.js +3 -1
- package/src/merchant/transactions/get-status.js +4 -3
- package/src/merchant/transactions/process-transaction.js +5 -4
- package/src/merchant/transactions/simulate-callback.js +325 -313
- package/src/merchant/transactions/transaction-history.js +7 -6
- package/src/payment-institution/data/index.js +15 -14
- package/src/payment-institution/deep-links/delete-transaction-link.js +3 -2
- package/src/payment-institution/deep-links/get-transaction-link.js +8 -6
- package/src/payment-institution/transactions/create-pi-transaction.js +4 -3
- package/src/payment-institution/transactions/finalize-transaction.js +6 -3
- package/src/payment-institution/transactions/get-transaction-history.js +8 -5
- package/src/payment-institution/transactions/get-transaction-status.js +16 -13
- package/src/payment-institution/transactions/process-pi-transaction.js +7 -6
- package/src/payment-institution/transactions/simulate-pi-callback.js +388 -375
- package/src/payment-institution/transactions/soundbite-transaction.js +6 -5
- package/src/proxy-server.js +25 -0
- package/src/shared/placements/api.js +51 -0
- package/src/shared/placements/tools.js +519 -0
- package/src/shared/poi/poi-create-api.js +4 -1
- package/src/shared/products/products-api.js +36 -25
- package/src/shared/shops/shops-api.js +2 -0
- package/src/shared/tool-annotations.js +53 -0
- package/src/tools/advanced-code-generator.js +17 -265
- package/src/utils/code-examples/common/auth-examples.js +1 -1
- package/src/utils/code-examples/isv/products.js +1 -1
- package/src/utils/code-examples/isv/transactions.js +1 -1
- package/src/utils/code-examples/merchant/transactions.js +1 -1
- package/src/utils/format-request.js +2 -0
- package/src/utils/json-formatter.js +2 -0
- package/src/utils/server-info.js +2 -0
- package/src/utils/code-examples.js +0 -646
|
@@ -1,314 +1,326 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simulate callback scenarios for testing
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Generate mock callback payload
|
|
7
|
-
* @param {string} transactionId - Transaction ID
|
|
8
|
-
* @param {string} status - Transaction status (CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED)
|
|
9
|
-
* @param {Object} options - Additional options
|
|
10
|
-
* @returns {Object} Mock callback payload
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
...(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
...(
|
|
59
|
-
...(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
**
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
\`
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
},
|
|
176
|
-
|
|
177
|
-
type: "string",
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
description: "Transaction
|
|
190
|
-
default: "
|
|
191
|
-
},
|
|
192
|
-
|
|
193
|
-
type: "string",
|
|
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
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
**
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
**
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Simulate callback scenarios for testing
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate mock callback payload
|
|
7
|
+
* @param {string} transactionId - Transaction ID
|
|
8
|
+
* @param {string} status - Transaction status (CONFIRMED, DECLINED, FAILED, EXPIRED, CANCELLED)
|
|
9
|
+
* @param {Object} options - Additional options
|
|
10
|
+
* @returns {Object} Mock callback payload
|
|
11
|
+
*/
|
|
12
|
+
import { LOCAL } from '../../shared/tool-annotations.js';
|
|
13
|
+
|
|
14
|
+
export function generateMockCallback(transactionId, status = 'CONFIRMED', options = {}) {
|
|
15
|
+
const {
|
|
16
|
+
amount = '57.60',
|
|
17
|
+
currency = 'EUR',
|
|
18
|
+
payerAmount = null,
|
|
19
|
+
payeeAmount = null,
|
|
20
|
+
paymentMethod = null,
|
|
21
|
+
statusMessage = null,
|
|
22
|
+
passbackParams = null,
|
|
23
|
+
// The POI that created the transaction, on a POI sale's callbacks only (server S8, 2026-09-28).
|
|
24
|
+
poiId = null,
|
|
25
|
+
// The fee breakdown the server attaches whenever the transaction has a fee configuration.
|
|
26
|
+
// Before 2026-08-21 a merchant's FINALIZED callback carried the total fee but not the two
|
|
27
|
+
// numbers that produced it, so reconciling a charge meant asking payware. It carries both now.
|
|
28
|
+
feeFixed = '0.1000',
|
|
29
|
+
feeRate = '0.0150',
|
|
30
|
+
// Pass fee: null to model the anomaly the server reports by OMITTING the field - a transaction
|
|
31
|
+
// with no recorded fee. That is deliberately distinguishable from a genuine "0.00".
|
|
32
|
+
fee: feeOverride = undefined
|
|
33
|
+
} = options;
|
|
34
|
+
|
|
35
|
+
// Calculate fee like the server: |payerAmount - amount| or |payeeAmount - amount|.
|
|
36
|
+
const transactionAmount = parseFloat(amount);
|
|
37
|
+
let fee = '0.00';
|
|
38
|
+
if (payerAmount !== null) {
|
|
39
|
+
fee = Math.abs(parseFloat(payerAmount) - transactionAmount).toFixed(2);
|
|
40
|
+
} else if (payeeAmount !== null) {
|
|
41
|
+
fee = Math.abs(parseFloat(payeeAmount) - transactionAmount).toFixed(2);
|
|
42
|
+
}
|
|
43
|
+
if (feeOverride !== undefined) {
|
|
44
|
+
fee = feeOverride;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const currentTime = Date.now();
|
|
48
|
+
// Built with the same omission rule the server applies. TransactionCallbackPayload is
|
|
49
|
+
// @JsonInclude(NON_NULL), so a property with no value is ABSENT from the JSON rather than sent as
|
|
50
|
+
// null or 0 - and a consumer is entitled to tell those apart. Emitting "passbackParams": null or
|
|
51
|
+
// "fee": "0.0000" here would have taught an integrator to expect a shape the server never sends.
|
|
52
|
+
const basePayload = {
|
|
53
|
+
callbackType: 'TRANSACTION_FINALIZED',
|
|
54
|
+
transactionId,
|
|
55
|
+
...(poiId && { poiId }),
|
|
56
|
+
...(passbackParams !== null && passbackParams !== undefined && { passbackParams }),
|
|
57
|
+
amount,
|
|
58
|
+
...(fee !== null && fee !== undefined && { fee }),
|
|
59
|
+
...(feeFixed !== null && feeFixed !== undefined && { feeFixed }),
|
|
60
|
+
...(feeRate !== null && feeRate !== undefined && { feeRate }),
|
|
61
|
+
currency,
|
|
62
|
+
status,
|
|
63
|
+
...(statusMessage !== null && statusMessage !== undefined && { statusMessage }),
|
|
64
|
+
...(paymentMethod && { paymentMethod }),
|
|
65
|
+
created: currentTime - 300000, // Created 5 minutes ago (milliseconds)
|
|
66
|
+
// Absent on EXPIRED: the expiry sweep transitions status in bulk and sets no finalized moment.
|
|
67
|
+
...(status !== 'EXPIRED' && { finalized: currentTime })
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Add status-specific statusMessage
|
|
71
|
+
switch (status) {
|
|
72
|
+
case 'CONFIRMED':
|
|
73
|
+
return {
|
|
74
|
+
...basePayload,
|
|
75
|
+
statusMessage: statusMessage || 'Transaction confirmed'
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
case 'DECLINED':
|
|
79
|
+
return {
|
|
80
|
+
...basePayload,
|
|
81
|
+
statusMessage: statusMessage || 'Insufficient funds'
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
case 'FAILED':
|
|
85
|
+
return {
|
|
86
|
+
...basePayload,
|
|
87
|
+
statusMessage: statusMessage || 'Payment processing failed'
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
case 'EXPIRED':
|
|
91
|
+
return {
|
|
92
|
+
...basePayload,
|
|
93
|
+
statusMessage: statusMessage || 'Transaction expired',
|
|
94
|
+
finalized: undefined // Remove finalized for expired transactions
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
case 'CANCELLED':
|
|
98
|
+
return {
|
|
99
|
+
...basePayload,
|
|
100
|
+
statusMessage: statusMessage || 'Transaction cancelled'
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
default:
|
|
104
|
+
return basePayload;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Simulate callback delivery
|
|
110
|
+
* @param {string} callbackUrl - URL to send callback to
|
|
111
|
+
* @param {Object} payload - Callback payload
|
|
112
|
+
* @returns {Object} Simulation result
|
|
113
|
+
*/
|
|
114
|
+
export async function simulateCallbackDelivery(callbackUrl, payload) {
|
|
115
|
+
if (!callbackUrl || !callbackUrl.startsWith('http')) {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
error: 'Invalid callback URL provided'
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// In a real implementation, this would actually send HTTP POST
|
|
123
|
+
// For simulation, we just return what would be sent
|
|
124
|
+
return {
|
|
125
|
+
success: true,
|
|
126
|
+
url: callbackUrl,
|
|
127
|
+
payload,
|
|
128
|
+
headers: {
|
|
129
|
+
'Content-Type': 'application/json',
|
|
130
|
+
'Authorization': 'Bearer mock-jwt-token-' + Date.now()
|
|
131
|
+
},
|
|
132
|
+
simulatedAt: new Date().toISOString(),
|
|
133
|
+
note: 'This is a simulation - no actual HTTP request was made. Real payware callbacks use JWT tokens in Authorization header.'
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Simulate callback tool implementation
|
|
139
|
+
*/
|
|
140
|
+
export const simulateCallbackTool = {
|
|
141
|
+
name: "payware_operations_simulate_callback",
|
|
142
|
+
annotations: LOCAL,
|
|
143
|
+
description: `Simulate callback scenarios for testing webhook handling.
|
|
144
|
+
|
|
145
|
+
Generates the payload a merchant's \`callbackUrl\` actually receives, so a handler can be built and
|
|
146
|
+
tested against the real shape. Four properties of that shape are easy to get wrong:
|
|
147
|
+
|
|
148
|
+
**1. Absent means absent, not zero.** The payload omits properties with no value rather than sending
|
|
149
|
+
\`null\` or \`0\`. \`statusMessage\`, \`passbackParams\`, \`fee\`, \`feeFixed\` and \`feeRate\` are all simply
|
|
150
|
+
missing when they do not apply. A missing \`fee\` means the fee is *unknown* for that transaction - it
|
|
151
|
+
does not mean the transaction was free. Do not write a handler that reads \`payload.fee\` as a number
|
|
152
|
+
without checking it is there.
|
|
153
|
+
|
|
154
|
+
**2. \`finalized\` is absent on EXPIRED.** An expired transaction is closed by the platform's expiry
|
|
155
|
+
sweep, which sets no finalization moment. Every other status carries one.
|
|
156
|
+
|
|
157
|
+
**3. \`EXPIRED\` is a non-payment, not a failure.** The payer never paid within \`timeToLive\`. Release
|
|
158
|
+
the order or the stock, as you would for a cancellation - do not treat it as an error to retry.
|
|
159
|
+
|
|
160
|
+
**4. Deduplicate on \`(transactionId, callbackType)\`.** payware retries a callback up to 15 times,
|
|
161
|
+
backing off from about a second to at most 5 minutes between attempts, until the endpoint answers any
|
|
162
|
+
2xx. That pair is stable across every retry of the same event, and it is the key payware guarantees.
|
|
163
|
+
A handler that does not deduplicate will eventually process one payment twice.
|
|
164
|
+
|
|
165
|
+
**Not on this payload:** \`deliveryAddress\` (removed 2026-08-07 - fetch it from
|
|
166
|
+
\`payware_operations_get_transaction_history\`, which is authenticated and tenant-scoped),
|
|
167
|
+
\`producerPartnerId\`, \`transactionType\` and \`initiatedBy\` (the last two are carried on
|
|
168
|
+
TRANSACTION_PROCESSED, which merchants do not receive).`,
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: "object",
|
|
171
|
+
properties: {
|
|
172
|
+
transactionId: {
|
|
173
|
+
type: "string",
|
|
174
|
+
description: "Transaction ID to simulate callback for"
|
|
175
|
+
},
|
|
176
|
+
status: {
|
|
177
|
+
type: "string",
|
|
178
|
+
enum: ["CONFIRMED", "DECLINED", "FAILED", "EXPIRED", "CANCELLED"],
|
|
179
|
+
description: "Transaction status to simulate",
|
|
180
|
+
default: "CONFIRMED"
|
|
181
|
+
},
|
|
182
|
+
callbackUrl: {
|
|
183
|
+
type: "string",
|
|
184
|
+
description: "URL where callback would be sent (for simulation only)",
|
|
185
|
+
format: "uri"
|
|
186
|
+
},
|
|
187
|
+
amount: {
|
|
188
|
+
type: "string",
|
|
189
|
+
description: "Transaction amount (e.g., '57.60')",
|
|
190
|
+
default: "57.60"
|
|
191
|
+
},
|
|
192
|
+
currency: {
|
|
193
|
+
type: "string",
|
|
194
|
+
enum: ["EUR", "USD", "GBP"],
|
|
195
|
+
description: "Transaction currency",
|
|
196
|
+
default: "EUR"
|
|
197
|
+
},
|
|
198
|
+
fee: {
|
|
199
|
+
type: "string",
|
|
200
|
+
description: "The payware fee on this transaction, at the currency's smallest payable unit (e.g. '0.29'). Not always two decimals - it follows the currency. Pass null to model the anomaly case, where a transaction has no recorded fee and the server OMITS the property entirely; that is deliberately distinguishable from a genuine '0.00'."
|
|
201
|
+
},
|
|
202
|
+
feeFixed: {
|
|
203
|
+
type: "string",
|
|
204
|
+
description: "Fixed fee component of the applicable fee configuration, e.g. '0.1000'. Informational, for reconciliation. Present on FINALIZED callbacks since 2026-08-21 - before that a merchant got the total fee but not the breakdown that produced it. Pass null to model a transaction with no fee configuration, where it is omitted.",
|
|
205
|
+
default: "0.1000"
|
|
206
|
+
},
|
|
207
|
+
feeRate: {
|
|
208
|
+
type: "string",
|
|
209
|
+
description: "Variable rate of the applicable fee configuration, e.g. '0.0150' = 1.5%. Informational, same as feeFixed. Pass null to model a transaction with no fee configuration.",
|
|
210
|
+
default: "0.0150"
|
|
211
|
+
},
|
|
212
|
+
statusMessage: {
|
|
213
|
+
type: "string",
|
|
214
|
+
description: "Custom status message for the transaction callback"
|
|
215
|
+
},
|
|
216
|
+
paymentMethod: {
|
|
217
|
+
type: "string",
|
|
218
|
+
enum: ["A2A", "CARD_FUNDED", "BNPL", "INSTANT_CREDIT"],
|
|
219
|
+
description: "Payment method chosen by customer. A2A = direct transfer. CARD_FUNDED = card-linked account. BNPL = buy now pay later. INSTANT_CREDIT = credit line."
|
|
220
|
+
},
|
|
221
|
+
poiId: {
|
|
222
|
+
type: "string",
|
|
223
|
+
description: "Set to simulate a POI sale: the callback then carries the poiId of the POI that created the transaction"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
required: ["transactionId"],
|
|
227
|
+
additionalProperties: false
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
async handler(args) {
|
|
231
|
+
const {
|
|
232
|
+
transactionId,
|
|
233
|
+
status = 'CONFIRMED',
|
|
234
|
+
callbackUrl,
|
|
235
|
+
amount = '57.60',
|
|
236
|
+
currency = 'EUR',
|
|
237
|
+
// No default: an omitted fee falls through to generateMockCallback's own derivation.
|
|
238
|
+
// Defaulting it to '0.00' here made every simulated callback assert a zero fee, which is the
|
|
239
|
+
// one value the real payload never sends for "no fee" - it omits the property instead.
|
|
240
|
+
fee,
|
|
241
|
+
feeFixed = '0.1000',
|
|
242
|
+
feeRate = '0.0150',
|
|
243
|
+
statusMessage,
|
|
244
|
+
paymentMethod,
|
|
245
|
+
poiId
|
|
246
|
+
} = args;
|
|
247
|
+
|
|
248
|
+
if (!transactionId) {
|
|
249
|
+
throw new Error("Transaction ID is required");
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Generate mock callback payload
|
|
253
|
+
const payload = generateMockCallback(transactionId, status, {
|
|
254
|
+
amount,
|
|
255
|
+
currency,
|
|
256
|
+
fee,
|
|
257
|
+
feeFixed,
|
|
258
|
+
feeRate,
|
|
259
|
+
statusMessage,
|
|
260
|
+
paymentMethod,
|
|
261
|
+
poiId
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Simulate callback delivery if URL provided
|
|
265
|
+
let deliveryResult = null;
|
|
266
|
+
if (callbackUrl) {
|
|
267
|
+
deliveryResult = await simulateCallbackDelivery(callbackUrl, payload);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const statusEmojis = {
|
|
271
|
+
'CONFIRMED': '✅',
|
|
272
|
+
'DECLINED': '❌',
|
|
273
|
+
'FAILED': '💥',
|
|
274
|
+
'EXPIRED': '⏰',
|
|
275
|
+
'CANCELLED': '🚫'
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const statusEmoji = statusEmojis[status] || '❓';
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
content: [{
|
|
282
|
+
type: "text",
|
|
283
|
+
text: `🔄 **Callback Simulation Complete**
|
|
284
|
+
|
|
285
|
+
**Transaction:** ${transactionId}
|
|
286
|
+
**Simulated Status:** ${statusEmoji} ${status}
|
|
287
|
+
|
|
288
|
+
**Mock Callback Payload:**
|
|
289
|
+
\`\`\`json
|
|
290
|
+
${JSON.stringify(payload, null, 2)}
|
|
291
|
+
\`\`\`
|
|
292
|
+
|
|
293
|
+
${deliveryResult ? `
|
|
294
|
+
**Callback Delivery Simulation:**
|
|
295
|
+
${deliveryResult.success ? '✅ Callback would be delivered successfully' : '❌ Callback delivery would fail'}
|
|
296
|
+
|
|
297
|
+
**Delivery Details:**
|
|
298
|
+
- URL: ${deliveryResult.url || 'N/A'}
|
|
299
|
+
- Headers: ${JSON.stringify(deliveryResult.headers || {}, null, 2)}
|
|
300
|
+
- Simulated At: ${deliveryResult.simulatedAt || 'N/A'}
|
|
301
|
+
|
|
302
|
+
**Note:** ${deliveryResult.note || 'No actual HTTP request was made'}
|
|
303
|
+
` : '**No callback URL provided** - only payload generated'}
|
|
304
|
+
|
|
305
|
+
**Status Explanations:**
|
|
306
|
+
- ✅ **CONFIRMED**: Successfully finalized
|
|
307
|
+
- ❌ **DECLINED**: Declined by the user, processing or finalizing payment institutions
|
|
308
|
+
- 💥 **FAILED**: Failed due to technical reasons or other
|
|
309
|
+
- ⏰ **EXPIRED**: Time to live of the transaction has passed
|
|
310
|
+
- 🚫 **CANCELLED**: Transaction canceled by the originator
|
|
311
|
+
|
|
312
|
+
**Integration Testing:**
|
|
313
|
+
1. Use this payload to test your callback handler
|
|
314
|
+
2. Verify your system processes each status correctly
|
|
315
|
+
3. Check error handling for DECLINED/FAILED statuses
|
|
316
|
+
4. Ensure proper logging and monitoring
|
|
317
|
+
|
|
318
|
+
**Next Steps:**
|
|
319
|
+
1. Implement callback endpoint to receive this payload
|
|
320
|
+
2. Test with different status scenarios
|
|
321
|
+
3. Add signature verification in production
|
|
322
|
+
4. Set up proper error handling and retry logic`
|
|
323
|
+
}]
|
|
324
|
+
};
|
|
325
|
+
}
|
|
314
326
|
};
|