strapi-plugin-payone-provider 1.0.1
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/README.md +571 -0
- package/admin/src/components/Initializer/index.js +16 -0
- package/admin/src/components/PluginIcon/index.js +6 -0
- package/admin/src/index.js +37 -0
- package/admin/src/pages/App/components/ConfigurationPanel.js +265 -0
- package/admin/src/pages/App/components/HistoryPanel.js +298 -0
- package/admin/src/pages/App/components/PaymentActionsPanel.js +333 -0
- package/admin/src/pages/App/components/StatusBadge.js +22 -0
- package/admin/src/pages/App/components/TransactionHistoryItem.js +374 -0
- package/admin/src/pages/App/components/icons/BankIcon.js +10 -0
- package/admin/src/pages/App/components/icons/ChevronDownIcon.js +9 -0
- package/admin/src/pages/App/components/icons/ChevronUpIcon.js +9 -0
- package/admin/src/pages/App/components/icons/CreditCardIcon.js +9 -0
- package/admin/src/pages/App/components/icons/ErrorIcon.js +10 -0
- package/admin/src/pages/App/components/icons/InfoIcon.js +9 -0
- package/admin/src/pages/App/components/icons/PaymentIcon.js +10 -0
- package/admin/src/pages/App/components/icons/PendingIcon.js +9 -0
- package/admin/src/pages/App/components/icons/PersonIcon.js +9 -0
- package/admin/src/pages/App/components/icons/SuccessIcon.js +9 -0
- package/admin/src/pages/App/components/icons/WalletIcon.js +9 -0
- package/admin/src/pages/App/components/icons/index.js +11 -0
- package/admin/src/pages/App/index.js +483 -0
- package/admin/src/pages/utils/api.js +75 -0
- package/admin/src/pages/utils/formatTransactionData.js +16 -0
- package/admin/src/pages/utils/paymentUtils.js +528 -0
- package/admin/src/pluginId.js +5 -0
- package/package.json +43 -0
- package/server/bootstrap.js +26 -0
- package/server/config/index.js +42 -0
- package/server/controllers/index.js +7 -0
- package/server/controllers/payone.js +134 -0
- package/server/destroy.js +5 -0
- package/server/index.js +21 -0
- package/server/policies/index.js +6 -0
- package/server/policies/isAuth.js +23 -0
- package/server/policies/isSuperAdmin.js +18 -0
- package/server/register.js +5 -0
- package/server/routes/index.js +124 -0
- package/server/services/index.js +7 -0
- package/server/services/payone.js +679 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +3 -0
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const axios = require("axios");
|
|
4
|
+
const crypto = require("crypto");
|
|
5
|
+
|
|
6
|
+
const POST_GATEWAY_URL = "https://api.pay1.de/post-gateway/";
|
|
7
|
+
|
|
8
|
+
const normalizeReference = (input, fallbackPrefix = "REF") => {
|
|
9
|
+
try {
|
|
10
|
+
const raw = (input == null ? "" : String(input));
|
|
11
|
+
// Keep only alphanumeric characters
|
|
12
|
+
let normalized = raw.replace(/[^A-Za-z0-9]/g, "");
|
|
13
|
+
if (!normalized) {
|
|
14
|
+
normalized = `${fallbackPrefix}${Date.now()}`;
|
|
15
|
+
}
|
|
16
|
+
// Limit length to 20 chars (safe for PAYONE)
|
|
17
|
+
if (normalized.length > 20) normalized = normalized.slice(0, 20);
|
|
18
|
+
return normalized;
|
|
19
|
+
} catch (_) {
|
|
20
|
+
const fallback = `${fallbackPrefix}${Date.now()}`;
|
|
21
|
+
return fallback.slice(0, 20);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const buildClientRequestParams = (settings, params) => {
|
|
26
|
+
const requestParams = {
|
|
27
|
+
request: params.request,
|
|
28
|
+
aid: settings.aid,
|
|
29
|
+
mid: settings.mid,
|
|
30
|
+
portalid: settings.portalid,
|
|
31
|
+
mode: settings.mode || "test",
|
|
32
|
+
encoding: "UTF-8",
|
|
33
|
+
...params
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
requestParams.key = crypto
|
|
37
|
+
.createHash("md5")
|
|
38
|
+
.update(settings.portalKey || settings.key)
|
|
39
|
+
.digest("hex");
|
|
40
|
+
|
|
41
|
+
if (!requestParams.salutation) requestParams.salutation = "Herr";
|
|
42
|
+
if (!requestParams.gender) requestParams.gender = "m";
|
|
43
|
+
if (!requestParams.telephonenumber)
|
|
44
|
+
requestParams.telephonenumber = "01752345678";
|
|
45
|
+
if (!requestParams.ip) requestParams.ip = "127.0.0.1";
|
|
46
|
+
if (!requestParams.language) requestParams.language = "de";
|
|
47
|
+
if (!requestParams.customer_is_present)
|
|
48
|
+
requestParams.customer_is_present = "yes";
|
|
49
|
+
|
|
50
|
+
return requestParams;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
const toFormData = (requestParams) => {
|
|
55
|
+
const formData = new URLSearchParams();
|
|
56
|
+
for (const [key, value] of Object.entries(requestParams)) {
|
|
57
|
+
if (value !== undefined && value !== null) {
|
|
58
|
+
formData.append(key, value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return formData;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
module.exports = ({ strapi }) => ({
|
|
65
|
+
async getSettings() {
|
|
66
|
+
const pluginStore = strapi.store({
|
|
67
|
+
environment: "",
|
|
68
|
+
type: "plugin",
|
|
69
|
+
name: "payone-provider"
|
|
70
|
+
});
|
|
71
|
+
return await pluginStore.get({ key: "settings" });
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
async updateSettings(settings) {
|
|
75
|
+
const pluginStore = strapi.store({
|
|
76
|
+
environment: "",
|
|
77
|
+
type: "plugin",
|
|
78
|
+
name: "payone-provider"
|
|
79
|
+
});
|
|
80
|
+
await pluginStore.set({
|
|
81
|
+
key: "settings",
|
|
82
|
+
value: settings
|
|
83
|
+
});
|
|
84
|
+
return settings;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
async sendRequest(params) {
|
|
88
|
+
try {
|
|
89
|
+
strapi.log.info("Payone sendRequest called with params:", params);
|
|
90
|
+
|
|
91
|
+
const settings = await this.getSettings();
|
|
92
|
+
|
|
93
|
+
if (!settings || !settings.aid || !settings.portalid || !settings.key) {
|
|
94
|
+
throw new Error("Payone settings not configured");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const reqType = params.request;
|
|
98
|
+
if (reqType === "authorization" || reqType === "preauthorization" || reqType === "refund") {
|
|
99
|
+
const prefix = reqType === "refund" ? "REF" : reqType === "preauthorization" ? "PRE" : "AUTH";
|
|
100
|
+
params.reference = normalizeReference(params.reference, prefix);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const requestParams = buildClientRequestParams(settings, params);
|
|
104
|
+
const debugParams = { ...requestParams };
|
|
105
|
+
if (debugParams.key) debugParams.key = "***HIDDEN***";
|
|
106
|
+
strapi.log.info("Payone Client API request params:", debugParams);
|
|
107
|
+
const formData = toFormData(requestParams);
|
|
108
|
+
|
|
109
|
+
strapi.log.info("Payone form data being sent:", formData.toString());
|
|
110
|
+
strapi.log.info("Payone form data reference:", formData.get("reference"));
|
|
111
|
+
|
|
112
|
+
const response = await axios.post(POST_GATEWAY_URL, formData, {
|
|
113
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
114
|
+
timeout: 30000
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
let dataSample = "null";
|
|
118
|
+
if (response.data) {
|
|
119
|
+
if (typeof response.data === "string") {
|
|
120
|
+
dataSample = response.data.substring(0, 200);
|
|
121
|
+
} else {
|
|
122
|
+
dataSample = JSON.stringify(response.data).substring(0, 200);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
strapi.log.info("Payone raw response:", {
|
|
126
|
+
status: response.status,
|
|
127
|
+
statusText: response.statusText,
|
|
128
|
+
dataType: typeof response.data,
|
|
129
|
+
dataSample,
|
|
130
|
+
fullData:
|
|
131
|
+
typeof response.data === "string"
|
|
132
|
+
? response.data
|
|
133
|
+
: JSON.stringify(response.data)
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const responseData = this.parseResponse(response.data);
|
|
137
|
+
const extractTxId = (data) => {
|
|
138
|
+
return (
|
|
139
|
+
data.txid ||
|
|
140
|
+
data.TxId ||
|
|
141
|
+
data.tx_id ||
|
|
142
|
+
data.transactionid ||
|
|
143
|
+
data.transaction_id ||
|
|
144
|
+
data.id ||
|
|
145
|
+
null
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
await this.logTransaction({
|
|
150
|
+
txid: extractTxId(responseData) || params.txid || null,
|
|
151
|
+
reference: params.reference || null,
|
|
152
|
+
status: responseData.status || responseData.Status || "unknown",
|
|
153
|
+
request_type: params.request,
|
|
154
|
+
amount: params.amount || null,
|
|
155
|
+
currency: params.currency || "EUR",
|
|
156
|
+
raw_request: requestParams,
|
|
157
|
+
raw_response: responseData,
|
|
158
|
+
error_code: responseData.Error?.ErrorCode || null,
|
|
159
|
+
error_message: responseData.Error?.ErrorMessage || null,
|
|
160
|
+
customer_message: responseData.Error?.CustomerMessage || null
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return responseData;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
strapi.log.error("Payone sendRequest error:", error);
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
parseResponse(responseText) {
|
|
171
|
+
try {
|
|
172
|
+
if (typeof responseText === "object") {
|
|
173
|
+
return responseText;
|
|
174
|
+
}
|
|
175
|
+
if (responseText.trim().startsWith("{")) {
|
|
176
|
+
return JSON.parse(responseText);
|
|
177
|
+
}
|
|
178
|
+
} catch (e) {
|
|
179
|
+
strapi.log.error("Payone parseResponse error:", e);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const params = new URLSearchParams(responseText);
|
|
183
|
+
const response = {};
|
|
184
|
+
for (const [key, value] of params) {
|
|
185
|
+
response[key.toLowerCase()] = value;
|
|
186
|
+
response[key] = value;
|
|
187
|
+
}
|
|
188
|
+
return response;
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
addPaymentMethodParams(params) {
|
|
192
|
+
const updated = { ...params };
|
|
193
|
+
const clearingtype = updated.clearingtype || "cc";
|
|
194
|
+
|
|
195
|
+
switch (clearingtype) {
|
|
196
|
+
case "cc":
|
|
197
|
+
if (!updated.cardpan) updated.cardpan = "4111111111111111";
|
|
198
|
+
if (!updated.cardexpiredate) updated.cardexpiredate = "2512";
|
|
199
|
+
if (!updated.cardcvc2) updated.cardcvc2 = "123";
|
|
200
|
+
if (!updated.cardtype) updated.cardtype = "V";
|
|
201
|
+
break;
|
|
202
|
+
|
|
203
|
+
case "wlt":
|
|
204
|
+
if (!updated.wallettype) updated.wallettype = "PPE";
|
|
205
|
+
break;
|
|
206
|
+
|
|
207
|
+
case "elv":
|
|
208
|
+
if (!updated.bankcountry) updated.bankcountry = "DE";
|
|
209
|
+
if (!updated.iban) updated.iban = "DE89370400440532013000";
|
|
210
|
+
if (!updated.bic) updated.bic = "COBADEFFXXX";
|
|
211
|
+
if (!updated.bankaccountholder)
|
|
212
|
+
updated.bankaccountholder = `${updated.firstname || "Test"} ${updated.lastname || "User"}`;
|
|
213
|
+
break;
|
|
214
|
+
|
|
215
|
+
case "sb":
|
|
216
|
+
if (!updated.bankcountry) updated.bankcountry = "DE";
|
|
217
|
+
if (!updated.onlinebanktransfertype) updated.onlinebanktransfertype = "PNT";
|
|
218
|
+
break;
|
|
219
|
+
|
|
220
|
+
case "gp":
|
|
221
|
+
if (!updated.bankcountry) updated.bankcountry = "DE";
|
|
222
|
+
if (!updated.onlinebanktransfertype) updated.onlinebanktransfertype = "GPY";
|
|
223
|
+
break;
|
|
224
|
+
|
|
225
|
+
case "idl":
|
|
226
|
+
if (!updated.bankcountry) updated.bankcountry = "NL";
|
|
227
|
+
if (!updated.onlinebanktransfertype) updated.onlinebanktransfertype = "IDL";
|
|
228
|
+
break;
|
|
229
|
+
|
|
230
|
+
case "bct":
|
|
231
|
+
if (!updated.bankcountry) updated.bankcountry = "BE";
|
|
232
|
+
if (!updated.onlinebanktransfertype) updated.onlinebanktransfertype = "BCT";
|
|
233
|
+
break;
|
|
234
|
+
|
|
235
|
+
case "rec":
|
|
236
|
+
if (!updated.recurrence) updated.recurrence = "recurring";
|
|
237
|
+
break;
|
|
238
|
+
|
|
239
|
+
case "fnc":
|
|
240
|
+
if (!updated.financingtype) updated.financingtype = "fnc";
|
|
241
|
+
break;
|
|
242
|
+
|
|
243
|
+
case "iv":
|
|
244
|
+
if (!updated.invoicetype) updated.invoicetype = "invoice";
|
|
245
|
+
break;
|
|
246
|
+
|
|
247
|
+
default:
|
|
248
|
+
strapi.log.warn(`Unknown clearingtype: ${clearingtype}, using credit card defaults`);
|
|
249
|
+
if (!updated.cardpan) updated.cardpan = "4111111111111111";
|
|
250
|
+
if (!updated.cardexpiredate) updated.cardexpiredate = "2512";
|
|
251
|
+
if (!updated.cardcvc2) updated.cardcvc2 = "123";
|
|
252
|
+
if (!updated.cardtype) updated.cardtype = "V";
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (!updated.salutation) updated.salutation = "Herr";
|
|
257
|
+
if (!updated.gender) updated.gender = "m";
|
|
258
|
+
if (!updated.telephonenumber) updated.telephonenumber = "01752345678";
|
|
259
|
+
if (!updated.ip) updated.ip = "127.0.0.1";
|
|
260
|
+
if (!updated.language) updated.language = "de";
|
|
261
|
+
if (!updated.customer_is_present) updated.customer_is_present = "yes";
|
|
262
|
+
|
|
263
|
+
return updated;
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
async preauthorization(params) {
|
|
267
|
+
strapi.log.info("Payone preauthorization called with params:", params);
|
|
268
|
+
|
|
269
|
+
const requiredParams = {
|
|
270
|
+
request: "preauthorization",
|
|
271
|
+
clearingtype: params.clearingtype || "cc",
|
|
272
|
+
...params
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
if (!requiredParams.amount) requiredParams.amount = 1000;
|
|
276
|
+
if (!requiredParams.currency) requiredParams.currency = "EUR";
|
|
277
|
+
if (!requiredParams.reference)
|
|
278
|
+
requiredParams.reference = `PREAUTH-${Date.now()}`;
|
|
279
|
+
if (!requiredParams.firstname) requiredParams.firstname = "Test";
|
|
280
|
+
if (!requiredParams.lastname) requiredParams.lastname = "User";
|
|
281
|
+
if (!requiredParams.street) requiredParams.street = "Test Street 1";
|
|
282
|
+
if (!requiredParams.zip) requiredParams.zip = "12345";
|
|
283
|
+
if (!requiredParams.city) requiredParams.city = "Test City";
|
|
284
|
+
if (!requiredParams.country) requiredParams.country = "DE";
|
|
285
|
+
if (!requiredParams.email) requiredParams.email = "test@example.com";
|
|
286
|
+
|
|
287
|
+
const updatedParams = this.addPaymentMethodParams(requiredParams);
|
|
288
|
+
|
|
289
|
+
return await this.sendRequest(updatedParams);
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
async authorization(params) {
|
|
293
|
+
strapi.log.info("Payone authorization called with params:", params);
|
|
294
|
+
|
|
295
|
+
const requiredParams = {
|
|
296
|
+
request: "authorization",
|
|
297
|
+
clearingtype: params.clearingtype || "cc",
|
|
298
|
+
...params
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const updatedParams = this.addPaymentMethodParams(requiredParams);
|
|
302
|
+
|
|
303
|
+
return await this.sendRequest(updatedParams);
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
async capture(params) {
|
|
307
|
+
strapi.log.info("Payone capture called with params:", params);
|
|
308
|
+
|
|
309
|
+
if (!params.txid) {
|
|
310
|
+
throw new Error("Transaction ID (txid) is required for capture");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const requiredParams = {
|
|
314
|
+
request: "capture",
|
|
315
|
+
txid: params.txid,
|
|
316
|
+
amount: params.amount || 1000,
|
|
317
|
+
currency: params.currency || "EUR",
|
|
318
|
+
...params
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
delete requiredParams.reference;
|
|
322
|
+
|
|
323
|
+
strapi.log.info("Payone capture required params:", requiredParams);
|
|
324
|
+
|
|
325
|
+
return await this.sendRequest(requiredParams);
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
async refund(params) {
|
|
329
|
+
strapi.log.info("Payone refund called with params:", params);
|
|
330
|
+
|
|
331
|
+
if (!params.txid) {
|
|
332
|
+
throw new Error("Transaction ID (txid) is required for refund");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const requiredParams = {
|
|
336
|
+
request: "refund",
|
|
337
|
+
txid: params.txid,
|
|
338
|
+
...params
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
if (!requiredParams.amount) requiredParams.amount = 1000; // 10.00 EUR in cents
|
|
342
|
+
if (!requiredParams.currency) requiredParams.currency = "EUR";
|
|
343
|
+
if (!requiredParams.reference)
|
|
344
|
+
requiredParams.reference = `REFUND-${Date.now()}`;
|
|
345
|
+
|
|
346
|
+
return await this.sendRequest(requiredParams);
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
async logTransaction(transactionData) {
|
|
350
|
+
const pluginStore = strapi.store({
|
|
351
|
+
environment: "",
|
|
352
|
+
type: "plugin",
|
|
353
|
+
name: "payone-provider"
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
let transactionHistory =
|
|
357
|
+
(await pluginStore.get({ key: "transactionHistory" })) || [];
|
|
358
|
+
|
|
359
|
+
const logEntry = {
|
|
360
|
+
id: Date.now().toString(),
|
|
361
|
+
timestamp: new Date().toISOString(),
|
|
362
|
+
txid: transactionData.txid || null,
|
|
363
|
+
reference: transactionData.reference || null,
|
|
364
|
+
request_type:
|
|
365
|
+
transactionData.request_type || transactionData.request || "unknown",
|
|
366
|
+
amount: transactionData.amount || null,
|
|
367
|
+
currency: transactionData.currency || "EUR",
|
|
368
|
+
status: transactionData.status || transactionData.Status || "unknown",
|
|
369
|
+
error_code:
|
|
370
|
+
transactionData.error_code || transactionData.Error?.ErrorCode || null,
|
|
371
|
+
error_message:
|
|
372
|
+
transactionData.error_message ||
|
|
373
|
+
transactionData.Error?.ErrorMessage ||
|
|
374
|
+
null,
|
|
375
|
+
customer_message:
|
|
376
|
+
transactionData.customer_message ||
|
|
377
|
+
transactionData.Error?.CustomerMessage ||
|
|
378
|
+
null,
|
|
379
|
+
raw_request: transactionData.raw_request || null,
|
|
380
|
+
raw_response: transactionData.raw_response || transactionData,
|
|
381
|
+
created_at: new Date().toISOString(),
|
|
382
|
+
updated_at: new Date().toISOString()
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
transactionHistory.unshift(logEntry);
|
|
386
|
+
|
|
387
|
+
if (transactionHistory.length > 1000) {
|
|
388
|
+
transactionHistory = transactionHistory.slice(0, 1000);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
await pluginStore.set({
|
|
392
|
+
key: "transactionHistory",
|
|
393
|
+
value: transactionHistory
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
strapi.log.info("Transaction logged:", logEntry);
|
|
397
|
+
},
|
|
398
|
+
|
|
399
|
+
async getTransactionHistory(filters = {}) {
|
|
400
|
+
const pluginStore = strapi.store({
|
|
401
|
+
environment: "",
|
|
402
|
+
type: "plugin",
|
|
403
|
+
name: "payone-provider"
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
let transactionHistory =
|
|
407
|
+
(await pluginStore.get({ key: "transactionHistory" })) || [];
|
|
408
|
+
|
|
409
|
+
if (filters.status) {
|
|
410
|
+
transactionHistory = transactionHistory.filter(
|
|
411
|
+
(transaction) => transaction.status === filters.status
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (filters.request_type) {
|
|
416
|
+
transactionHistory = transactionHistory.filter(
|
|
417
|
+
(transaction) => transaction.request_type === filters.request_type
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (filters.txid) {
|
|
422
|
+
transactionHistory = transactionHistory.filter(
|
|
423
|
+
(transaction) => transaction.txid === filters.txid
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (filters.reference) {
|
|
428
|
+
transactionHistory = transactionHistory.filter(
|
|
429
|
+
(transaction) => transaction.reference === filters.reference
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (filters.date_from) {
|
|
434
|
+
transactionHistory = transactionHistory.filter(
|
|
435
|
+
(transaction) =>
|
|
436
|
+
new Date(transaction.timestamp) >= new Date(filters.date_from)
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (filters.date_to) {
|
|
441
|
+
transactionHistory = transactionHistory.filter(
|
|
442
|
+
(transaction) =>
|
|
443
|
+
new Date(transaction.timestamp) <= new Date(filters.date_to)
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
return transactionHistory;
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
async testConnection() {
|
|
450
|
+
try {
|
|
451
|
+
const settings = await this.getSettings();
|
|
452
|
+
|
|
453
|
+
if (!settings || !settings.aid || !settings.portalid || !settings.key) {
|
|
454
|
+
return {
|
|
455
|
+
success: false,
|
|
456
|
+
message:
|
|
457
|
+
"Payone settings not configured. Please fill in all required fields."
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const timestamp = Date.now();
|
|
462
|
+
const testParams = {
|
|
463
|
+
request: "authorization",
|
|
464
|
+
amount: 100,
|
|
465
|
+
currency: "EUR",
|
|
466
|
+
reference: `TEST-${timestamp}`, // Unique reference for each test
|
|
467
|
+
clearingtype: "cc",
|
|
468
|
+
cardtype: "V",
|
|
469
|
+
cardpan: "4111111111111111",
|
|
470
|
+
cardexpiredate: "2512",
|
|
471
|
+
cardcvc2: "123",
|
|
472
|
+
firstname: "Test",
|
|
473
|
+
lastname: "User",
|
|
474
|
+
street: "Test Street 1",
|
|
475
|
+
zip: "12345",
|
|
476
|
+
city: "Test City",
|
|
477
|
+
country: "DE",
|
|
478
|
+
email: "test@example.com",
|
|
479
|
+
salutation: "Herr",
|
|
480
|
+
gender: "m",
|
|
481
|
+
telephonenumber: "01752345678",
|
|
482
|
+
ip: "127.0.0.1",
|
|
483
|
+
customer_is_present: "yes",
|
|
484
|
+
language: "de"
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
const originalSendRequest = this.sendRequest.bind(this);
|
|
488
|
+
this.sendRequest = async (params) => {
|
|
489
|
+
try {
|
|
490
|
+
const settings = await this.getSettings();
|
|
491
|
+
|
|
492
|
+
if (
|
|
493
|
+
!settings ||
|
|
494
|
+
!settings.aid ||
|
|
495
|
+
!settings.portalid ||
|
|
496
|
+
!settings.key
|
|
497
|
+
) {
|
|
498
|
+
throw new Error("Payone settings not configured");
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const requestParams = buildClientRequestParams(settings, params);
|
|
502
|
+
const formData = toFormData(requestParams);
|
|
503
|
+
|
|
504
|
+
// Send request to Payone
|
|
505
|
+
const response = await axios.post(POST_GATEWAY_URL, formData, {
|
|
506
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
507
|
+
timeout: 30000
|
|
508
|
+
});
|
|
509
|
+
const responseData = this.parseResponse(response.data);
|
|
510
|
+
|
|
511
|
+
return responseData;
|
|
512
|
+
} catch (error) {
|
|
513
|
+
strapi.log.error("Payone API request failed:", error.message);
|
|
514
|
+
|
|
515
|
+
if (error.response) {
|
|
516
|
+
strapi.log.error("Response error:", {
|
|
517
|
+
status: error.response.status,
|
|
518
|
+
data: error.response.data
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
const result = await this.sendRequest(testParams);
|
|
527
|
+
|
|
528
|
+
this.sendRequest = originalSendRequest;
|
|
529
|
+
|
|
530
|
+
const status = result.status || result.Status || result.STATUS;
|
|
531
|
+
const errorMessage =
|
|
532
|
+
result.errormessage ||
|
|
533
|
+
result.Errormessage ||
|
|
534
|
+
result.ERRORMESSAGE ||
|
|
535
|
+
result.error ||
|
|
536
|
+
result.Error ||
|
|
537
|
+
result.ERROR ||
|
|
538
|
+
"";
|
|
539
|
+
const errorCode =
|
|
540
|
+
result.errorcode ||
|
|
541
|
+
result.Errorcode ||
|
|
542
|
+
result.ERRORCODE ||
|
|
543
|
+
(result.Error && result.Error.ErrorCode) ||
|
|
544
|
+
"";
|
|
545
|
+
const customErrorMessage =
|
|
546
|
+
result.customerrormessage ||
|
|
547
|
+
result.Customerrormessage ||
|
|
548
|
+
result.CUSTOMERRORMESSAGE ||
|
|
549
|
+
(result.Error && result.Error.CustomerMessage) ||
|
|
550
|
+
"";
|
|
551
|
+
|
|
552
|
+
strapi.log.info("Payone test connection response:", {
|
|
553
|
+
status,
|
|
554
|
+
errorCode,
|
|
555
|
+
keys: Object.keys(result)
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
if (status === "ERROR" || status === "error") {
|
|
559
|
+
// First check for authentication errors (including "Key incorrect")
|
|
560
|
+
if (
|
|
561
|
+
errorCode === "2006" ||
|
|
562
|
+
errorCode === "920" ||
|
|
563
|
+
errorCode === "921" ||
|
|
564
|
+
errorCode === "922" ||
|
|
565
|
+
errorCode === "401" || // common unauthorized style codes
|
|
566
|
+
errorCode === "403"
|
|
567
|
+
) {
|
|
568
|
+
const errorMsg =
|
|
569
|
+
customErrorMessage ||
|
|
570
|
+
(typeof errorMessage === "string"
|
|
571
|
+
? errorMessage
|
|
572
|
+
: JSON.stringify(errorMessage)) ||
|
|
573
|
+
"Invalid credentials";
|
|
574
|
+
return {
|
|
575
|
+
success: false,
|
|
576
|
+
message: `Authentication failed: ${errorMsg}`,
|
|
577
|
+
errorcode: errorCode
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Additional heuristic for invalid credentials based on message content
|
|
582
|
+
const errorMessageStr =
|
|
583
|
+
typeof errorMessage === "string"
|
|
584
|
+
? errorMessage
|
|
585
|
+
: JSON.stringify(errorMessage);
|
|
586
|
+
const errorMessageLower = (errorMessageStr || "").toLowerCase();
|
|
587
|
+
if (
|
|
588
|
+
errorMessageLower.includes("key incorrect") ||
|
|
589
|
+
errorMessageLower.includes("invalid key") ||
|
|
590
|
+
errorMessageLower.includes("portal key") ||
|
|
591
|
+
errorMessageLower.includes("unauthorized") ||
|
|
592
|
+
errorMessageLower.includes("not authorized") ||
|
|
593
|
+
errorMessageLower.includes("unknown aid") ||
|
|
594
|
+
errorMessageLower.includes("unknown account") ||
|
|
595
|
+
errorMessageLower.includes("unknown portal") ||
|
|
596
|
+
errorMessageLower.includes("unknown merchant") ||
|
|
597
|
+
errorMessageLower.includes("invalid aid") ||
|
|
598
|
+
errorMessageLower.includes("invalid mid") ||
|
|
599
|
+
errorMessageLower.includes("invalid portalid")
|
|
600
|
+
) {
|
|
601
|
+
return {
|
|
602
|
+
success: false,
|
|
603
|
+
message: `Authentication failed: ${errorMessageStr}`,
|
|
604
|
+
errorcode: errorCode || "AUTH"
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Check for reference already exists (911) - this means credentials are working
|
|
609
|
+
if (errorCode === "911") {
|
|
610
|
+
return {
|
|
611
|
+
success: true,
|
|
612
|
+
message:
|
|
613
|
+
"Connection successful! Your Payone credentials are valid.",
|
|
614
|
+
details: {
|
|
615
|
+
mode: settings.mode,
|
|
616
|
+
aid: settings.aid,
|
|
617
|
+
portalid: settings.portalid,
|
|
618
|
+
mid: settings.mid
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Otherwise, for any ERROR status treat as failure
|
|
624
|
+
const errorMsg =
|
|
625
|
+
customErrorMessage ||
|
|
626
|
+
(typeof errorMessage === "string"
|
|
627
|
+
? errorMessage
|
|
628
|
+
: JSON.stringify(errorMessage)) ||
|
|
629
|
+
"Unknown error";
|
|
630
|
+
return {
|
|
631
|
+
success: false,
|
|
632
|
+
message: `Connection failed: ${errorMsg}`,
|
|
633
|
+
errorcode: errorCode,
|
|
634
|
+
details: {
|
|
635
|
+
status,
|
|
636
|
+
errorCode,
|
|
637
|
+
rawResponse: JSON.stringify(result).substring(0, 200) // Include partial raw response for debugging
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// APPROVED status shouldn't happen with dummy txid, but if it does, connection is OK
|
|
643
|
+
if (status === "APPROVED" || status === "approved") {
|
|
644
|
+
return {
|
|
645
|
+
success: true,
|
|
646
|
+
message: "Connection successful! Your Payone credentials are valid.",
|
|
647
|
+
details: {
|
|
648
|
+
mode: settings.mode,
|
|
649
|
+
aid: settings.aid,
|
|
650
|
+
portalid: settings.portalid,
|
|
651
|
+
mid: settings.mid
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return {
|
|
657
|
+
success: false,
|
|
658
|
+
message: "Unexpected response format from Payone API",
|
|
659
|
+
response: result,
|
|
660
|
+
details: {
|
|
661
|
+
status,
|
|
662
|
+
keys: Object.keys(result),
|
|
663
|
+
rawResponse: JSON.stringify(result).substring(0, 200)
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
} catch (error) {
|
|
667
|
+
strapi.log.error("Payone test connection error:", error);
|
|
668
|
+
return {
|
|
669
|
+
success: false,
|
|
670
|
+
message: `Connection error: ${error.message || "Unknown error"}`,
|
|
671
|
+
error: error.toString(),
|
|
672
|
+
details: {
|
|
673
|
+
errorType: error.constructor.name,
|
|
674
|
+
stack: error.stack ? error.stack.substring(0, 200) : "No stack trace"
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
});
|
package/strapi-admin.js
ADDED
package/strapi-server.js
ADDED