strapi-plugin-payone-provider 1.6.3 → 1.6.5
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/admin/src/pages/App/components/AppHeader.jsx +14 -8
- package/admin/src/pages/App/components/ApplePayBtn.jsx +327 -306
- package/admin/src/pages/App/components/ApplePayConfigPanel.jsx +8 -19
- package/admin/src/pages/App/components/ConfigurationPanel.jsx +74 -16
- package/admin/src/pages/App/components/DocsPanel.jsx +0 -1
- package/admin/src/pages/App/components/GooglePayConfig.jsx +80 -43
- package/admin/src/pages/App/components/PaymentActionsPanel.jsx +40 -55
- package/admin/src/pages/App/components/paymentActions/ApplePayPanel.jsx +51 -0
- package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.jsx +2 -9
- package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.jsx +1 -1
- package/admin/src/pages/hooks/usePaymentActions.js +4 -14
- package/admin/src/pages/utils/paymentUtils.js +46 -25
- package/package.json +1 -1
- package/server/bootstrap.js +19 -35
- package/server/controllers/payone.js +67 -15
- package/server/services/applePayService.js +218 -47
- package/server/services/paymentService.js +0 -13
- package/server/services/testConnectionService.js +3 -2
- package/server/utils/paymentMethodParams.js +46 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import {
|
|
3
3
|
Box,
|
|
4
4
|
Flex,
|
|
@@ -24,13 +24,6 @@ const PaymentMethodSelector = ({
|
|
|
24
24
|
onNavigateToConfig,
|
|
25
25
|
isLiveMode,
|
|
26
26
|
}) => {
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
if (isLiveMode && paymentMethod !== "apl") {
|
|
29
|
-
setPaymentMethod("apl");
|
|
30
|
-
}
|
|
31
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32
|
-
}, [isLiveMode]);
|
|
33
|
-
|
|
34
27
|
return (
|
|
35
28
|
<Box>
|
|
36
29
|
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
@@ -290,7 +283,7 @@ const PaymentMethodSelector = ({
|
|
|
290
283
|
</Box>
|
|
291
284
|
</>
|
|
292
285
|
)}
|
|
293
|
-
{supportsCaptureMode(paymentMethod) && (
|
|
286
|
+
{paymentMethod !== "apl" && supportsCaptureMode(paymentMethod) && (
|
|
294
287
|
<Select
|
|
295
288
|
label="Capture Mode"
|
|
296
289
|
name="captureMode"
|
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
getAuthorizationParams,
|
|
7
7
|
getCaptureParams,
|
|
8
8
|
getRefundParams,
|
|
9
|
-
generateLagOrderNumber
|
|
9
|
+
generateLagOrderNumber,
|
|
10
|
+
getValidCardExpiryDate,
|
|
10
11
|
} from "../utils/paymentUtils";
|
|
11
12
|
import { DEFAULT_PAYMENT_DATA } from "../constants/paymentConstants";
|
|
12
13
|
|
|
@@ -75,11 +76,6 @@ const usePaymentActions = () => {
|
|
|
75
76
|
};
|
|
76
77
|
|
|
77
78
|
const handlePreauthorization = async (tokenParam = null) => {
|
|
78
|
-
console.log("[Payment] handlePreauthorization called", {
|
|
79
|
-
hasToken: !!tokenParam,
|
|
80
|
-
paymentMethod,
|
|
81
|
-
amount: paymentAmount
|
|
82
|
-
});
|
|
83
79
|
setIsProcessingPayment(true);
|
|
84
80
|
setPaymentError(null);
|
|
85
81
|
setPaymentResult(null);
|
|
@@ -102,7 +98,7 @@ const usePaymentActions = () => {
|
|
|
102
98
|
if (paymentMethod === "cc" && settings.enable3DSecure !== false) {
|
|
103
99
|
if (cardtype) baseParams.cardtype = cardtype;
|
|
104
100
|
if (cardpan) baseParams.cardpan = cardpan;
|
|
105
|
-
|
|
101
|
+
baseParams.cardexpiredate = getValidCardExpiryDate(cardexpiredate);
|
|
106
102
|
if (cardcvc2) baseParams.cardcvc2 = cardcvc2;
|
|
107
103
|
}
|
|
108
104
|
|
|
@@ -152,8 +148,6 @@ const usePaymentActions = () => {
|
|
|
152
148
|
null;
|
|
153
149
|
|
|
154
150
|
if (is3DSRequiredError && !redirectUrl) {
|
|
155
|
-
console.warn("3DS authentication required (Error 4219) but no redirect URL found in response");
|
|
156
|
-
console.log("Full response:", JSON.stringify(responseData, null, 2));
|
|
157
151
|
setPaymentError(
|
|
158
152
|
"3D Secure authentication required. Please check Payone configuration and ensure redirect URLs are properly set. Error: " +
|
|
159
153
|
(errorMessage || `Error code: ${errorCode}`)
|
|
@@ -177,7 +171,6 @@ const usePaymentActions = () => {
|
|
|
177
171
|
(is3DSRequiredError && redirectUrl);
|
|
178
172
|
|
|
179
173
|
if (needsRedirect && redirectUrl) {
|
|
180
|
-
console.log("Redirecting to 3DS:", redirectUrl);
|
|
181
174
|
window.location.href = redirectUrl;
|
|
182
175
|
return;
|
|
183
176
|
}
|
|
@@ -228,7 +221,7 @@ const usePaymentActions = () => {
|
|
|
228
221
|
if (paymentMethod === "cc" && settings.enable3DSecure !== false) {
|
|
229
222
|
if (cardtype) baseParams.cardtype = cardtype;
|
|
230
223
|
if (cardpan) baseParams.cardpan = cardpan;
|
|
231
|
-
|
|
224
|
+
baseParams.cardexpiredate = getValidCardExpiryDate(cardexpiredate);
|
|
232
225
|
if (cardcvc2) baseParams.cardcvc2 = cardcvc2;
|
|
233
226
|
}
|
|
234
227
|
|
|
@@ -278,8 +271,6 @@ const usePaymentActions = () => {
|
|
|
278
271
|
null;
|
|
279
272
|
|
|
280
273
|
if (is3DSRequiredError && !redirectUrl) {
|
|
281
|
-
console.warn("3DS authentication required (Error 4219) but no redirect URL found in response");
|
|
282
|
-
console.log("Full response:", JSON.stringify(responseData, null, 2));
|
|
283
274
|
setPaymentError(
|
|
284
275
|
"3D Secure authentication required. Please check Payone configuration and ensure redirect URLs are properly set. Error: " +
|
|
285
276
|
(errorMessage || `Error code: ${errorCode}`)
|
|
@@ -303,7 +294,6 @@ const usePaymentActions = () => {
|
|
|
303
294
|
(is3DSRequiredError && redirectUrl);
|
|
304
295
|
|
|
305
296
|
if (needsRedirect && redirectUrl) {
|
|
306
|
-
console.log("Redirecting to 3DS:", redirectUrl);
|
|
307
297
|
window.location.href = redirectUrl;
|
|
308
298
|
return;
|
|
309
299
|
}
|
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
export function getValidCardExpiryDate(cardexpiredate) {
|
|
2
|
+
const now = new Date();
|
|
3
|
+
const currentYear = now.getFullYear() % 100;
|
|
4
|
+
const currentMonth = now.getMonth() + 1;
|
|
5
|
+
|
|
6
|
+
if (!cardexpiredate || cardexpiredate.trim() === "") {
|
|
7
|
+
const nextYear = currentYear + 1;
|
|
8
|
+
const monthStr = String(currentMonth).padStart(2, '0');
|
|
9
|
+
return `${nextYear}${monthStr}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Validate format (must be 4 digits)
|
|
13
|
+
if (!/^\d{4}$/.test(cardexpiredate)) {
|
|
14
|
+
const nextYear = currentYear + 1;
|
|
15
|
+
const monthStr = String(currentMonth).padStart(2, '0');
|
|
16
|
+
return `${nextYear}${monthStr}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Parse YYMM format
|
|
20
|
+
const year = parseInt(cardexpiredate.substring(0, 2), 10);
|
|
21
|
+
const month = parseInt(cardexpiredate.substring(2, 4), 10);
|
|
22
|
+
|
|
23
|
+
// Validate month (1-12)
|
|
24
|
+
if (month < 1 || month > 12) {
|
|
25
|
+
const nextYear = currentYear + 1;
|
|
26
|
+
const monthStr = String(currentMonth).padStart(2, '0');
|
|
27
|
+
return `${nextYear}${monthStr}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const currentDate = new Date(2000 + currentYear, currentMonth - 1);
|
|
31
|
+
const expiryDate = new Date(2000 + year, month - 1);
|
|
32
|
+
|
|
33
|
+
if (expiryDate < currentDate) {
|
|
34
|
+
const nextYear = currentYear + 1;
|
|
35
|
+
const monthStr = String(currentMonth).padStart(2, '0');
|
|
36
|
+
return `${nextYear}${monthStr}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return cardexpiredate;
|
|
40
|
+
}
|
|
1
41
|
|
|
2
42
|
export function generateLagOrderNumber(sequence = 1000) {
|
|
3
43
|
const paddedSequence = sequence.toString().padStart(5, '0');
|
|
@@ -125,7 +165,7 @@ export const getPaymentMethodParams = (paymentMethod, options = {}) => {
|
|
|
125
165
|
clearingtype: "cc",
|
|
126
166
|
cardtype: finalCardType, // V = Visa, M = Mastercard, A = Amex
|
|
127
167
|
cardpan: cardpan || "4111111111111111", // Test Visa card
|
|
128
|
-
cardexpiredate: cardexpiredate
|
|
168
|
+
cardexpiredate: getValidCardExpiryDate(cardexpiredate),
|
|
129
169
|
cardcvc2: cardcvc2 || "123" // 3-digit security code
|
|
130
170
|
};
|
|
131
171
|
|
|
@@ -374,24 +414,16 @@ export const getPaymentMethodOptions = (isLiveMode = false) => {
|
|
|
374
414
|
{ value: "wlt", label: "PayPal" },
|
|
375
415
|
{ value: "gpp", label: "Google Pay" },
|
|
376
416
|
{ value: "apl", label: "Apple Pay" },
|
|
377
|
-
{ value: "sb", label: "Sofort Banking" },
|
|
378
417
|
{ value: "elv", label: "SEPA Direct Debit" }
|
|
379
418
|
];
|
|
380
419
|
};
|
|
381
420
|
|
|
382
|
-
|
|
383
|
-
* Check if payment method supports capture mode
|
|
384
|
-
* @param {string} paymentMethod - Payment method
|
|
385
|
-
* @returns {boolean} True if supports capture mode
|
|
386
|
-
*/
|
|
421
|
+
|
|
387
422
|
export const supportsCaptureMode = (paymentMethod) => {
|
|
388
|
-
return paymentMethod === "wlt" || paymentMethod === "gpp" || paymentMethod === "apl";
|
|
423
|
+
return paymentMethod === "wlt" || paymentMethod === "gpp" || paymentMethod === "apl";
|
|
389
424
|
};
|
|
390
425
|
|
|
391
|
-
|
|
392
|
-
* Get capture mode options
|
|
393
|
-
* @returns {Array} Array of capture mode options
|
|
394
|
-
*/
|
|
426
|
+
|
|
395
427
|
export const getCaptureModeOptions = () => {
|
|
396
428
|
return [
|
|
397
429
|
{ value: "full", label: "Full Capture" },
|
|
@@ -399,14 +431,6 @@ export const getCaptureModeOptions = () => {
|
|
|
399
431
|
];
|
|
400
432
|
};
|
|
401
433
|
|
|
402
|
-
/**
|
|
403
|
-
* Validate payment parameters based on Payone v1 documentation
|
|
404
|
-
* Comprehensive validation for all operations and payment methods
|
|
405
|
-
* @param {string} operation - Operation type (preauthorization, authorization, capture, refund)
|
|
406
|
-
* @param {string} paymentMethod - Payment method
|
|
407
|
-
* @param {Object} params - Parameters to validate
|
|
408
|
-
* @returns {Object} Validation result with detailed error messages
|
|
409
|
-
*/
|
|
410
434
|
export const validatePaymentParams = (operation, paymentMethod, params) => {
|
|
411
435
|
const errors = [];
|
|
412
436
|
|
|
@@ -419,12 +443,10 @@ export const validatePaymentParams = (operation, paymentMethod, params) => {
|
|
|
419
443
|
errors.push("Currency is required");
|
|
420
444
|
}
|
|
421
445
|
|
|
422
|
-
// Validate currency format (ISO 4217)
|
|
423
446
|
if (params.currency && !/^[A-Z]{3}$/.test(params.currency)) {
|
|
424
447
|
errors.push("Currency must be in ISO 4217 format (e.g., EUR, USD)");
|
|
425
448
|
}
|
|
426
449
|
|
|
427
|
-
// Operation specific validations (Payone v1 documentation)
|
|
428
450
|
switch (operation) {
|
|
429
451
|
case "preauthorization":
|
|
430
452
|
if (!params.reference) {
|
|
@@ -504,7 +526,6 @@ export const validatePaymentParams = (operation, paymentMethod, params) => {
|
|
|
504
526
|
break;
|
|
505
527
|
}
|
|
506
528
|
|
|
507
|
-
// Payment method specific validations (Payone v1 documentation)
|
|
508
529
|
switch (paymentMethod) {
|
|
509
530
|
case "cc":
|
|
510
531
|
if (!params.cardpan || !params.cardexpiredate || !params.cardcvc2) {
|
|
@@ -517,9 +538,9 @@ export const validatePaymentParams = (operation, paymentMethod, params) => {
|
|
|
517
538
|
if (params.cardpan && !/^\d{13,19}$/.test(params.cardpan.replace(/\s/g, ''))) {
|
|
518
539
|
errors.push("Card number must be 13-19 digits");
|
|
519
540
|
}
|
|
520
|
-
// Validate expiry date format (
|
|
541
|
+
// Validate expiry date format (YYMM)
|
|
521
542
|
if (params.cardexpiredate && !/^\d{4}$/.test(params.cardexpiredate)) {
|
|
522
|
-
errors.push("Card expiry date must be in
|
|
543
|
+
errors.push("Card expiry date must be in YYMM format (e.g., 2512 = December 2025)");
|
|
523
544
|
}
|
|
524
545
|
// Validate CVC format (3-4 digits)
|
|
525
546
|
if (params.cardcvc2 && !/^\d{3,4}$/.test(params.cardcvc2)) {
|
package/package.json
CHANGED
package/server/bootstrap.js
CHANGED
|
@@ -58,53 +58,37 @@ module.exports = async ({ strapi }) => {
|
|
|
58
58
|
try {
|
|
59
59
|
const publicPath = path.join(process.cwd(), 'public');
|
|
60
60
|
const wellKnownPath = path.join(publicPath, '.well-known');
|
|
61
|
-
const
|
|
62
|
-
|
|
61
|
+
const possiblePaths = [
|
|
62
|
+
path.join(wellKnownPath, 'apple-developer-merchantid-domain-association'),
|
|
63
|
+
path.join(wellKnownPath, 'apple-developer-merchantid-domain-association.txt'),
|
|
64
|
+
path.join(wellKnownPath, 'apple-developer-merchant-id-domain-association.txt'),
|
|
65
|
+
];
|
|
63
66
|
|
|
64
67
|
let fileContent = null;
|
|
65
68
|
let filePathFound = null;
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
fileContent = fs.readFileSync(filePathTxt, 'utf8');
|
|
70
|
+
for (const filePath of possiblePaths) {
|
|
71
|
+
if (fs.existsSync(filePath)) {
|
|
72
|
+
filePathFound = filePath;
|
|
73
|
+
fileContent = fs.readFileSync(filePath, 'utf8');
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
if (fileContent) {
|
|
77
79
|
ctx.type = 'text/plain';
|
|
78
|
-
ctx.
|
|
79
|
-
|
|
80
|
+
ctx.set('Content-Type', 'text/plain');
|
|
81
|
+
ctx.set('Cache-Control', 'public, max-age=31536000');
|
|
82
|
+
ctx.body = fileContent.trim();
|
|
80
83
|
} else {
|
|
81
|
-
strapi.log.warn(`[Apple Pay] Well-known file not found. Tried: ${filePath} and ${filePathTxt}`);
|
|
82
84
|
ctx.status = 404;
|
|
83
|
-
ctx.
|
|
84
|
-
|
|
85
|
-
status: 404,
|
|
86
|
-
name: "NotFoundError",
|
|
87
|
-
message: "Apple Pay domain verification file not found",
|
|
88
|
-
details: {
|
|
89
|
-
expectedPaths: [
|
|
90
|
-
filePath,
|
|
91
|
-
filePathTxt
|
|
92
|
-
]
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
};
|
|
85
|
+
ctx.type = 'text/plain';
|
|
86
|
+
ctx.body = 'File not found';
|
|
96
87
|
}
|
|
97
88
|
} catch (error) {
|
|
98
|
-
strapi.log.error("[Apple Pay] Serve well-known file error:", error);
|
|
99
89
|
ctx.status = 500;
|
|
100
|
-
ctx.
|
|
101
|
-
|
|
102
|
-
status: 500,
|
|
103
|
-
name: "InternalServerError",
|
|
104
|
-
message: error.message || "Failed to serve well-known file",
|
|
105
|
-
details: error.stack
|
|
106
|
-
}
|
|
107
|
-
};
|
|
90
|
+
ctx.type = 'text/plain';
|
|
91
|
+
ctx.body = 'Internal server error';
|
|
108
92
|
}
|
|
109
93
|
});
|
|
110
94
|
|
|
@@ -113,6 +97,6 @@ module.exports = async ({ strapi }) => {
|
|
|
113
97
|
strapi.server.app.use(router.allowedMethods());
|
|
114
98
|
}
|
|
115
99
|
} catch (error) {
|
|
116
|
-
|
|
100
|
+
// Silent fail
|
|
117
101
|
}
|
|
118
102
|
};
|
|
@@ -7,7 +7,12 @@ const getPayoneService = (strapi) => {
|
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
const handleError = (ctx, error) => {
|
|
10
|
-
|
|
10
|
+
if (error.response || error.status >= 400) {
|
|
11
|
+
ctx.strapi.log.error("Payone controller error:", {
|
|
12
|
+
status: error.status || error.response?.status,
|
|
13
|
+
message: error.message
|
|
14
|
+
});
|
|
15
|
+
}
|
|
11
16
|
ctx.throw(500, error);
|
|
12
17
|
};
|
|
13
18
|
|
|
@@ -71,11 +76,9 @@ module.exports = ({ strapi }) => ({
|
|
|
71
76
|
async authorization(ctx) {
|
|
72
77
|
try {
|
|
73
78
|
const params = ctx.request.body;
|
|
74
|
-
strapi.log.info("Payone authorization controller called with:", params);
|
|
75
79
|
const result = await getPayoneService(strapi).authorization(params);
|
|
76
80
|
ctx.body = { data: result };
|
|
77
81
|
} catch (error) {
|
|
78
|
-
strapi.log.error("Payone authorization error:", error);
|
|
79
82
|
handleError(ctx, error);
|
|
80
83
|
}
|
|
81
84
|
},
|
|
@@ -134,7 +137,6 @@ module.exports = ({ strapi }) => ({
|
|
|
134
137
|
}
|
|
135
138
|
|
|
136
139
|
const callbackData = isGetRequest ? ctx.query : ctx.request.body;
|
|
137
|
-
strapi.log.info(`3DS ${resultType} received (${ctx.request.method}):`, callbackData);
|
|
138
140
|
const result = await getPayoneService(strapi).handle3DSCallback(callbackData, resultType);
|
|
139
141
|
|
|
140
142
|
if (isGetRequest) {
|
|
@@ -153,31 +155,81 @@ module.exports = ({ strapi }) => ({
|
|
|
153
155
|
|
|
154
156
|
ctx.body = { data: result };
|
|
155
157
|
} catch (error) {
|
|
156
|
-
strapi.log.error("3DS callback error:", error);
|
|
157
158
|
handleError(ctx, error);
|
|
158
159
|
}
|
|
159
160
|
},
|
|
160
161
|
|
|
161
162
|
async validateApplePayMerchant(ctx) {
|
|
162
163
|
try {
|
|
163
|
-
|
|
164
|
+
const settings = await getPayoneService(strapi).getSettings();
|
|
165
|
+
const applePayConfig = settings?.applePayConfig || {};
|
|
164
166
|
|
|
165
167
|
const params = ctx.request.body;
|
|
168
|
+
|
|
169
|
+
if (!params) {
|
|
170
|
+
throw new Error("Request body is missing");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Ensure domain is set
|
|
174
|
+
if (!params.domain && !params.domainName) {
|
|
175
|
+
params.domain = ctx.request.hostname || ctx.request.host || 'localhost';
|
|
176
|
+
params.domainName = params.domain;
|
|
177
|
+
} else if (params.domain && !params.domainName) {
|
|
178
|
+
params.domainName = params.domain;
|
|
179
|
+
} else if (params.domainName && !params.domain) {
|
|
180
|
+
params.domain = params.domainName;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (!params.displayName) {
|
|
184
|
+
params.displayName = settings?.merchantName || "Store";
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!params.currency) {
|
|
188
|
+
params.currency = applePayConfig.currencyCode || "EUR";
|
|
189
|
+
}
|
|
190
|
+
if (!params.countryCode) {
|
|
191
|
+
params.countryCode = applePayConfig.countryCode || "DE";
|
|
192
|
+
}
|
|
193
|
+
|
|
166
194
|
let result = await getPayoneService(strapi).validateApplePayMerchant(params);
|
|
167
|
-
|
|
195
|
+
|
|
196
|
+
if (!result) {
|
|
197
|
+
throw new Error("Merchant validation returned null. Please check your Payone Apple Pay configuration.");
|
|
198
|
+
}
|
|
199
|
+
|
|
168
200
|
ctx.body = { data: result };
|
|
169
201
|
} catch (error) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
202
|
+
const errorStatus = error.status || (error.message?.includes('403') ? 403 : 500);
|
|
203
|
+
|
|
204
|
+
// Only log if it's a response error
|
|
205
|
+
if (error.response || errorStatus === 403 || errorStatus === 401 || errorStatus >= 500) {
|
|
206
|
+
strapi.log.error("[Apple Pay] Controller error:", {
|
|
207
|
+
status: errorStatus,
|
|
208
|
+
message: error.message
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Extract detailed error message if available
|
|
213
|
+
let errorMessage = error.message || "Apple Pay merchant validation failed";
|
|
214
|
+
let errorDetails = "Please check your Payone Apple Pay configuration in PMI (CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay). Ensure that Merchant ID (mid) is correctly configured and Apple Pay is enabled for your portal.";
|
|
215
|
+
|
|
216
|
+
// If it's a 403 error, provide more specific guidance
|
|
217
|
+
if (errorStatus === 403 || error.message?.includes('403')) {
|
|
218
|
+
errorDetails = "403 Forbidden: Authentication failed with Payone. " +
|
|
219
|
+
"Please check: 1) Your Payone credentials (aid, portalid, mid, key) in plugin settings, " +
|
|
220
|
+
"2) Mode is set to 'live' (Apple Pay only works in live mode), " +
|
|
221
|
+
"3) Your domain is registered with Payone Merchant Services, " +
|
|
222
|
+
"4) Merchant ID (mid) matches your merchantIdentifier in PMI, " +
|
|
223
|
+
"5) Apple Pay is enabled for your portal in PMI.";
|
|
224
|
+
}
|
|
175
225
|
|
|
176
|
-
ctx.status =
|
|
226
|
+
ctx.status = errorStatus;
|
|
177
227
|
ctx.body = {
|
|
178
228
|
error: {
|
|
179
|
-
|
|
180
|
-
|
|
229
|
+
status: errorStatus,
|
|
230
|
+
name: error.name || "Error",
|
|
231
|
+
message: errorMessage,
|
|
232
|
+
details: errorDetails
|
|
181
233
|
}
|
|
182
234
|
};
|
|
183
235
|
}
|