strapi-plugin-payone-provider 1.5.4 → 1.5.6
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.
|
@@ -42,7 +42,7 @@ const ApplePayButton = ({
|
|
|
42
42
|
const checkApplePayAvailability = async () => {
|
|
43
43
|
try {
|
|
44
44
|
console.log("[Apple Pay] Checking availability...");
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
// Check secure context using browser's native property
|
|
47
47
|
// This is the most reliable way to check if we're in a secure context
|
|
48
48
|
const isSecureContext = typeof window !== 'undefined' && window.isSecureContext;
|
|
@@ -57,7 +57,7 @@ const ApplePayButton = ({
|
|
|
57
57
|
// - 127.0.0.1 (even on HTTP)
|
|
58
58
|
// - file:// URLs
|
|
59
59
|
const isSecure = isSecureContext || isLocalhost;
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
console.log("[Apple Pay] Secure context check:", {
|
|
62
62
|
isSecureContext: isSecureContext,
|
|
63
63
|
protocol: protocol,
|
|
@@ -78,12 +78,12 @@ const ApplePayButton = ({
|
|
|
78
78
|
reason: !isSecureContext ? "window.isSecureContext is false" : "Unknown"
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
// First, check if Payment Request API is available
|
|
83
83
|
// Payment Request API works on HTTP too, but Apple Pay JS API requires HTTPS
|
|
84
84
|
if (typeof window === 'undefined' || !window.PaymentRequest) {
|
|
85
85
|
console.log("[Apple Pay] Payment Request API not available");
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
// Fallback: Check Apple Pay JS API (for Safari, requires HTTPS)
|
|
88
88
|
if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
|
|
89
89
|
try {
|
|
@@ -95,11 +95,11 @@ const ApplePayButton = ({
|
|
|
95
95
|
return { available: false, method: null, error: 'insecure_context' };
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
if (!isSecure && typeof window !== 'undefined' && window.ApplePaySession) {
|
|
100
100
|
console.warn("[Apple Pay] Apple Pay JS API requires HTTPS. Using Payment Request API fallback.");
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
console.log("[Apple Pay] No Apple Pay support found");
|
|
104
104
|
return { available: false, method: null };
|
|
105
105
|
}
|
|
@@ -152,11 +152,11 @@ const ApplePayButton = ({
|
|
|
152
152
|
try {
|
|
153
153
|
const canPay = await testRequest.canMakePayment();
|
|
154
154
|
console.log("[Apple Pay] canMakePayment result:", canPay);
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
if (canPay) {
|
|
157
157
|
return { available: true, method: 'paymentRequest' };
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
|
|
160
160
|
// If PaymentRequest says no, try Apple Pay JS API as fallback (only on HTTPS)
|
|
161
161
|
if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
|
|
162
162
|
try {
|
|
@@ -172,17 +172,17 @@ const ApplePayButton = ({
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
|
-
|
|
175
|
+
|
|
176
176
|
return { available: false, method: null };
|
|
177
177
|
} catch (e) {
|
|
178
178
|
console.error("[Apple Pay] Error checking canMakePayment:", e);
|
|
179
|
-
|
|
179
|
+
|
|
180
180
|
// If it's insecure context error, we can't use Apple Pay JS API
|
|
181
181
|
if (e.message && e.message.includes('insecure')) {
|
|
182
182
|
console.warn("[Apple Pay] Insecure context detected. Apple Pay requires HTTPS.");
|
|
183
183
|
return { available: false, method: null, error: 'insecure_context' };
|
|
184
184
|
}
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
// For other errors, try Apple Pay JS API as fallback (only on HTTPS)
|
|
187
187
|
if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
|
|
188
188
|
try {
|
|
@@ -193,7 +193,7 @@ const ApplePayButton = ({
|
|
|
193
193
|
return { available: false, method: null };
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
|
-
|
|
196
|
+
|
|
197
197
|
return { available: false, method: null };
|
|
198
198
|
}
|
|
199
199
|
}
|
|
@@ -204,7 +204,7 @@ const ApplePayButton = ({
|
|
|
204
204
|
const hostnameFinal = typeof window !== 'undefined' ? window.location.hostname : '';
|
|
205
205
|
const isLocalhostFinal = hostnameFinal === 'localhost' || hostnameFinal === '127.0.0.1';
|
|
206
206
|
const isSecureFinal = isSecureContextFinal || isLocalhostFinal;
|
|
207
|
-
|
|
207
|
+
|
|
208
208
|
if (isSecureFinal) {
|
|
209
209
|
console.log("[Apple Pay] canMakePayment not available, assuming support (secure context)");
|
|
210
210
|
return { available: true, method: 'paymentRequest' };
|
|
@@ -219,20 +219,20 @@ const ApplePayButton = ({
|
|
|
219
219
|
}
|
|
220
220
|
} catch (error) {
|
|
221
221
|
console.error("[Apple Pay] Error checking availability:", error);
|
|
222
|
-
|
|
222
|
+
|
|
223
223
|
// Check if it's insecure context error
|
|
224
224
|
if (error.message && error.message.includes('insecure')) {
|
|
225
225
|
console.warn("[Apple Pay] Insecure context - Apple Pay requires HTTPS");
|
|
226
226
|
return { available: false, method: null, error: 'insecure_context' };
|
|
227
227
|
}
|
|
228
|
-
|
|
228
|
+
|
|
229
229
|
// Fallback: Try Apple Pay JS API (only on HTTPS)
|
|
230
230
|
// Re-check secure context
|
|
231
231
|
const isSecureContextFallback = typeof window !== 'undefined' && window.isSecureContext;
|
|
232
232
|
const hostnameFallback = typeof window !== 'undefined' ? window.location.hostname : '';
|
|
233
233
|
const isLocalhostFallback = hostnameFallback === 'localhost' || hostnameFallback === '127.0.0.1';
|
|
234
234
|
const isSecureFallback = isSecureContextFallback || isLocalhostFallback;
|
|
235
|
-
|
|
235
|
+
|
|
236
236
|
if (typeof window !== 'undefined' && window.ApplePaySession && isSecureFallback) {
|
|
237
237
|
try {
|
|
238
238
|
const canMakePayments = ApplePaySession.canMakePayments();
|
|
@@ -244,16 +244,16 @@ const ApplePayButton = ({
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
|
-
|
|
247
|
+
|
|
248
248
|
return { available: false, method: null };
|
|
249
249
|
}
|
|
250
250
|
};
|
|
251
251
|
|
|
252
252
|
useEffect(() => {
|
|
253
253
|
const scriptUrl = "https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js";
|
|
254
|
-
|
|
254
|
+
|
|
255
255
|
console.log("[Apple Pay] Loading Apple Pay SDK script...");
|
|
256
|
-
|
|
256
|
+
|
|
257
257
|
if (document.querySelector(`script[src="${scriptUrl}"]`)) {
|
|
258
258
|
console.log("[Apple Pay] Script already loaded");
|
|
259
259
|
// Script already loaded, check if it's ready
|
|
@@ -270,20 +270,20 @@ const ApplePayButton = ({
|
|
|
270
270
|
script.src = scriptUrl;
|
|
271
271
|
script.crossOrigin = "anonymous";
|
|
272
272
|
script.async = true;
|
|
273
|
-
|
|
273
|
+
|
|
274
274
|
script.onload = () => {
|
|
275
275
|
console.log("[Apple Pay] SDK script loaded successfully");
|
|
276
276
|
setTimeout(() => {
|
|
277
277
|
initializeButton();
|
|
278
278
|
}, 500);
|
|
279
279
|
};
|
|
280
|
-
|
|
280
|
+
|
|
281
281
|
script.onerror = (error) => {
|
|
282
282
|
console.error("[Apple Pay] Failed to load SDK script:", error);
|
|
283
283
|
setIsLoading(false);
|
|
284
284
|
setIsAvailable(false);
|
|
285
285
|
setErrorMessage("Failed to load Apple Pay SDK. Please check Content Security Policy settings.");
|
|
286
|
-
|
|
286
|
+
|
|
287
287
|
// Even if script fails, try to use Payment Request API
|
|
288
288
|
console.log("[Apple Pay] Trying Payment Request API as fallback...");
|
|
289
289
|
setTimeout(() => {
|
|
@@ -306,22 +306,22 @@ const ApplePayButton = ({
|
|
|
306
306
|
const initializeButton = async () => {
|
|
307
307
|
try {
|
|
308
308
|
console.log("[Apple Pay] Initializing button...");
|
|
309
|
-
|
|
310
|
-
const isSecure = typeof window !== 'undefined' &&
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
309
|
+
|
|
310
|
+
const isSecure = typeof window !== 'undefined' &&
|
|
311
|
+
(window.location.protocol === 'https:' ||
|
|
312
|
+
window.location.hostname === 'localhost' ||
|
|
313
|
+
window.location.hostname === '127.0.0.1');
|
|
314
|
+
|
|
315
315
|
console.log("[Apple Pay] Secure context check:", {
|
|
316
316
|
protocol: window.location?.protocol,
|
|
317
317
|
hostname: window.location?.hostname,
|
|
318
318
|
isSecure: isSecure
|
|
319
319
|
});
|
|
320
|
-
|
|
321
|
-
const isLocalhost = typeof window !== 'undefined' &&
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
320
|
+
|
|
321
|
+
const isLocalhost = typeof window !== 'undefined' &&
|
|
322
|
+
(window.location.hostname === 'localhost' ||
|
|
323
|
+
window.location.hostname === '127.0.0.1');
|
|
324
|
+
|
|
325
325
|
if (!isSecure && !isLocalhost && window.location?.protocol === 'http:') {
|
|
326
326
|
const errorMsg = "Apple Pay requires HTTPS. Please access this page via HTTPS (https://yourdomain.com) instead of HTTP. Localhost (http://localhost) is allowed for development.";
|
|
327
327
|
setErrorMessage(errorMsg);
|
|
@@ -331,7 +331,7 @@ const ApplePayButton = ({
|
|
|
331
331
|
console.warn("[Apple Pay] Current URL:", window.location.href);
|
|
332
332
|
return;
|
|
333
333
|
}
|
|
334
|
-
|
|
334
|
+
|
|
335
335
|
// Log context information
|
|
336
336
|
console.log("[Apple Pay] Context info:", {
|
|
337
337
|
protocol: window.location?.protocol,
|
|
@@ -340,16 +340,16 @@ const ApplePayButton = ({
|
|
|
340
340
|
isLocalhost: isLocalhost,
|
|
341
341
|
fullUrl: window.location?.href
|
|
342
342
|
});
|
|
343
|
-
|
|
343
|
+
|
|
344
344
|
// Check availability
|
|
345
345
|
const availability = await checkApplePayAvailability();
|
|
346
346
|
console.log("[Apple Pay] Availability check result:", availability);
|
|
347
|
-
|
|
347
|
+
|
|
348
348
|
setIsAvailable(availability.available);
|
|
349
|
-
|
|
349
|
+
|
|
350
350
|
if (!availability.available) {
|
|
351
351
|
let errorMsg = "Apple Pay is not available on this device or browser.";
|
|
352
|
-
|
|
352
|
+
|
|
353
353
|
if (isLocalhost) {
|
|
354
354
|
errorMsg = "Apple Pay is not available on localhost. Apple Pay requires a registered domain with HTTPS. " +
|
|
355
355
|
"For testing, please use a production domain with HTTPS or test on a device with Safari (iOS/macOS). " +
|
|
@@ -366,7 +366,7 @@ const ApplePayButton = ({
|
|
|
366
366
|
} else {
|
|
367
367
|
errorMsg += " Please use Safari on iOS, macOS, or iPadOS, or a browser that supports Payment Request API (Chrome, Edge, Safari).";
|
|
368
368
|
}
|
|
369
|
-
|
|
369
|
+
|
|
370
370
|
setErrorMessage(errorMsg);
|
|
371
371
|
setIsLoading(false);
|
|
372
372
|
console.warn("[Apple Pay] Not available:", errorMsg);
|
|
@@ -380,14 +380,14 @@ const ApplePayButton = ({
|
|
|
380
380
|
console.error("[Apple Pay] Initialization error:", error);
|
|
381
381
|
setIsLoading(false);
|
|
382
382
|
setIsAvailable(false);
|
|
383
|
-
|
|
383
|
+
|
|
384
384
|
// Check for insecure context error
|
|
385
385
|
if (error.message && error.message.includes('insecure')) {
|
|
386
386
|
setErrorMessage("Apple Pay requires HTTPS. Please access this page via HTTPS (https://yourdomain.com) instead of HTTP. Localhost is allowed for development.");
|
|
387
387
|
} else {
|
|
388
388
|
setErrorMessage(error.message || "Failed to initialize Apple Pay");
|
|
389
389
|
}
|
|
390
|
-
|
|
390
|
+
|
|
391
391
|
if (onError) {
|
|
392
392
|
onError(error);
|
|
393
393
|
}
|
|
@@ -406,11 +406,11 @@ const ApplePayButton = ({
|
|
|
406
406
|
});
|
|
407
407
|
|
|
408
408
|
// Check HTTPS requirement
|
|
409
|
-
const isSecure = typeof window !== 'undefined' &&
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
409
|
+
const isSecure = typeof window !== 'undefined' &&
|
|
410
|
+
(window.location.protocol === 'https:' ||
|
|
411
|
+
window.location.hostname === 'localhost' ||
|
|
412
|
+
window.location.hostname === '127.0.0.1');
|
|
413
|
+
|
|
414
414
|
if (!isSecure && window.location?.protocol === 'http:') {
|
|
415
415
|
const errorMsg = "Apple Pay requires HTTPS. Please access this page via HTTPS.";
|
|
416
416
|
console.error("[Apple Pay]", errorMsg);
|
|
@@ -498,27 +498,46 @@ const ApplePayButton = ({
|
|
|
498
498
|
merchantSessionPromise.then(session => {
|
|
499
499
|
console.log("[Apple Pay] Merchant session received:", {
|
|
500
500
|
hasMerchantIdentifier: !!session.merchantIdentifier,
|
|
501
|
+
merchantIdentifier: session.merchantIdentifier,
|
|
501
502
|
domainName: session.domainName,
|
|
502
|
-
displayName: session.displayName
|
|
503
|
+
displayName: session.displayName,
|
|
504
|
+
epochTimestamp: session.epochTimestamp,
|
|
505
|
+
expiresAt: session.expiresAt,
|
|
506
|
+
fullSession: session
|
|
503
507
|
});
|
|
508
|
+
|
|
509
|
+
// Validate merchant session
|
|
510
|
+
if (!session || (!session.merchantIdentifier && !session.merchantSessionIdentifier)) {
|
|
511
|
+
console.error("[Apple Pay] Invalid merchant session - missing merchantIdentifier");
|
|
512
|
+
console.error("[Apple Pay] Session object:", JSON.stringify(session, null, 2));
|
|
513
|
+
throw new Error("Invalid merchant session: missing merchantIdentifier");
|
|
514
|
+
}
|
|
504
515
|
}).catch(err => {
|
|
505
516
|
console.error("[Apple Pay] Merchant session error:", err);
|
|
506
|
-
//
|
|
517
|
+
// Re-throw so Payment Request API knows validation failed
|
|
518
|
+
throw err;
|
|
507
519
|
});
|
|
508
520
|
|
|
509
521
|
// Complete with the merchant session promise
|
|
510
|
-
// If
|
|
522
|
+
// If the promise rejects, Payment Request API will close the dialog
|
|
523
|
+
// This is expected behavior - we cannot proceed without a valid merchant session
|
|
511
524
|
event.complete(merchantSessionPromise);
|
|
512
525
|
} catch (error) {
|
|
513
|
-
console.error("[Apple Pay] Merchant validation error:",
|
|
514
|
-
|
|
526
|
+
console.error("[Apple Pay] Merchant validation error:", {
|
|
527
|
+
message: error.message,
|
|
528
|
+
stack: error.stack,
|
|
529
|
+
response: error.response
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
// Call onError to notify the user
|
|
515
533
|
if (typeof onError === 'function') {
|
|
516
|
-
onError(error);
|
|
534
|
+
onError(new Error(`Apple Pay merchant validation failed: ${error.message}. Please check your Payone Apple Pay configuration in PMI (CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay).`));
|
|
517
535
|
}
|
|
518
|
-
|
|
519
|
-
//
|
|
520
|
-
// Apple Pay
|
|
521
|
-
|
|
536
|
+
|
|
537
|
+
// Complete with a rejected promise
|
|
538
|
+
// This will cause Apple Pay to close the dialog, which is expected behavior
|
|
539
|
+
// We cannot proceed without a valid merchant session from Payone
|
|
540
|
+
event.complete(Promise.reject(error));
|
|
522
541
|
}
|
|
523
542
|
};
|
|
524
543
|
|
|
@@ -550,17 +569,42 @@ const ApplePayButton = ({
|
|
|
550
569
|
let response;
|
|
551
570
|
try {
|
|
552
571
|
response = await request.show();
|
|
572
|
+
console.log("[Apple Pay] Payment sheet shown successfully");
|
|
553
573
|
} catch (error) {
|
|
554
|
-
console.error("[Apple Pay] Error showing payment sheet:",
|
|
574
|
+
console.error("[Apple Pay] Error showing payment sheet:", {
|
|
575
|
+
name: error.name,
|
|
576
|
+
message: error.message,
|
|
577
|
+
stack: error.stack
|
|
578
|
+
});
|
|
579
|
+
|
|
555
580
|
// Check if error is due to cancellation (user cancelled)
|
|
556
|
-
|
|
581
|
+
// Payment Request API throws "AbortError" when user cancels
|
|
582
|
+
if (error.name === 'AbortError' ||
|
|
583
|
+
(error.message && (
|
|
584
|
+
error.message.includes('Cancelled') ||
|
|
585
|
+
error.message.includes('cancel') ||
|
|
586
|
+
error.message.includes('abort')
|
|
587
|
+
))) {
|
|
557
588
|
console.log("[Apple Pay] User cancelled the payment");
|
|
558
589
|
// Don't call onError for user cancellation
|
|
559
590
|
return;
|
|
560
591
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
592
|
+
|
|
593
|
+
// If it's a merchant validation error, log it specifically
|
|
594
|
+
if (error.message && (
|
|
595
|
+
error.message.includes('merchant') ||
|
|
596
|
+
error.message.includes('validation') ||
|
|
597
|
+
error.message.includes('identifier')
|
|
598
|
+
)) {
|
|
599
|
+
console.error("[Apple Pay] Merchant validation failed - this may cause the dialog to close");
|
|
600
|
+
if (typeof onError === 'function') {
|
|
601
|
+
onError(new Error("Merchant validation failed. Please check your Apple Pay configuration and merchant identifier in Payone settings."));
|
|
602
|
+
}
|
|
603
|
+
} else {
|
|
604
|
+
// For other errors, call onError
|
|
605
|
+
if (typeof onError === 'function') {
|
|
606
|
+
onError(error);
|
|
607
|
+
}
|
|
564
608
|
}
|
|
565
609
|
return;
|
|
566
610
|
}
|
|
@@ -573,11 +617,11 @@ const ApplePayButton = ({
|
|
|
573
617
|
|
|
574
618
|
// Extract payment token
|
|
575
619
|
const paymentToken = response.details?.paymentToken || response.details?.token;
|
|
576
|
-
|
|
620
|
+
|
|
577
621
|
if (!paymentToken) {
|
|
578
622
|
console.error("[Apple Pay] Payment token is missing from response");
|
|
579
623
|
try {
|
|
580
|
-
|
|
624
|
+
await response.complete("fail");
|
|
581
625
|
} catch (completeError) {
|
|
582
626
|
console.error("[Apple Pay] Error completing payment with fail:", completeError);
|
|
583
627
|
}
|
|
@@ -619,11 +663,11 @@ const ApplePayButton = ({
|
|
|
619
663
|
// The callback should set the token in state and return success immediately
|
|
620
664
|
// It should NOT process the payment yet - that will happen when user clicks the button
|
|
621
665
|
const callbackResult = onTokenReceived(tokenString, {
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
666
|
+
paymentToken: paymentToken,
|
|
667
|
+
billingContact: response.payerName || response.details?.billingContact,
|
|
668
|
+
shippingContact: response.shippingAddress || response.details?.shippingAddress,
|
|
669
|
+
shippingOption: response.shippingOption || response.details?.shippingOption
|
|
670
|
+
});
|
|
627
671
|
|
|
628
672
|
// If callback returns a promise, wait for it to resolve or reject
|
|
629
673
|
if (callbackResult && typeof callbackResult.then === 'function') {
|
|
@@ -735,12 +779,12 @@ const ApplePayButton = ({
|
|
|
735
779
|
}
|
|
736
780
|
});
|
|
737
781
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
782
|
+
console.log("[Apple Pay] Merchant session received from backend:", {
|
|
783
|
+
hasData: !!merchantSession.data,
|
|
784
|
+
merchantIdentifier: merchantSession.data?.merchantIdentifier
|
|
785
|
+
});
|
|
742
786
|
|
|
743
|
-
|
|
787
|
+
return merchantSession.data || merchantSession;
|
|
744
788
|
} catch (error) {
|
|
745
789
|
console.error("[Apple Pay] Merchant validation error:", {
|
|
746
790
|
message: error.message,
|
|
@@ -759,10 +803,10 @@ const ApplePayButton = ({
|
|
|
759
803
|
console.error("[Apple Pay] Server error - Check server logs for details.");
|
|
760
804
|
}
|
|
761
805
|
|
|
762
|
-
// If validation fails,
|
|
763
|
-
//
|
|
764
|
-
|
|
765
|
-
|
|
806
|
+
// If validation fails, we cannot proceed
|
|
807
|
+
// Apple Pay requires a valid merchant session from Payone
|
|
808
|
+
console.error("[Apple Pay] Merchant validation failed - cannot proceed without valid session");
|
|
809
|
+
throw error;
|
|
766
810
|
}
|
|
767
811
|
};
|
|
768
812
|
|
|
@@ -41,16 +41,16 @@ const ApplePayConfig = ({
|
|
|
41
41
|
...config,
|
|
42
42
|
countryCode: value
|
|
43
43
|
};
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
// Auto-update currency if current currency is not supported in new country
|
|
46
46
|
const newSupportedCurrencies = getSupportedCurrenciesForCountry(value);
|
|
47
47
|
if (!newSupportedCurrencies.find(c => c.code === currencyCode)) {
|
|
48
48
|
newConfig.currencyCode = newSupportedCurrencies[0]?.code || "USD";
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
// Auto-update networks based on country
|
|
52
52
|
newConfig.supportedNetworks = getSupportedNetworksForCountry(value);
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
onConfigChange(newConfig);
|
|
55
55
|
};
|
|
56
56
|
|
|
@@ -66,7 +66,7 @@ const ApplePayConfig = ({
|
|
|
66
66
|
const newNetworks = currentNetworks.includes(networkCode)
|
|
67
67
|
? currentNetworks.filter(n => n !== networkCode)
|
|
68
68
|
: [...currentNetworks, networkCode];
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
onConfigChange({
|
|
71
71
|
...config,
|
|
72
72
|
supportedNetworks: newNetworks
|
|
@@ -78,7 +78,7 @@ const ApplePayConfig = ({
|
|
|
78
78
|
const newCapabilities = currentCapabilities.includes(capabilityCode)
|
|
79
79
|
? currentCapabilities.filter(c => c !== capabilityCode)
|
|
80
80
|
: [...currentCapabilities, capabilityCode];
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
onConfigChange({
|
|
83
83
|
...config,
|
|
84
84
|
merchantCapabilities: newCapabilities
|
|
@@ -100,43 +100,43 @@ const ApplePayConfig = ({
|
|
|
100
100
|
{/* Country and Currency */}
|
|
101
101
|
<Flex gap={4} wrap="wrap">
|
|
102
102
|
<Box style={{ flex: 1, minWidth: "300px" }}>
|
|
103
|
-
|
|
103
|
+
<Select
|
|
104
104
|
label="Country Code"
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
105
|
+
name="countryCode"
|
|
106
|
+
value={countryCode}
|
|
107
|
+
onChange={handleCountryChange}
|
|
108
|
+
hint="Select the country where your business operates"
|
|
109
|
+
required
|
|
110
|
+
>
|
|
111
|
+
{APPLE_PAY_SUPPORTED_COUNTRIES.map(country => (
|
|
112
|
+
<Option key={country.code} value={country.code}>
|
|
113
|
+
{country.name} ({country.code})
|
|
114
|
+
</Option>
|
|
115
|
+
))}
|
|
116
|
+
</Select>
|
|
117
|
+
</Box>
|
|
118
118
|
|
|
119
119
|
<Box style={{ flex: 1, minWidth: "300px" }}>
|
|
120
|
-
|
|
120
|
+
<Select
|
|
121
121
|
label="Currency Code"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
name="currencyCode"
|
|
123
|
+
value={currencyCode}
|
|
124
|
+
onChange={handleCurrencyChange}
|
|
125
125
|
hint={`Supported currencies for ${countryCode}`}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
126
|
+
required
|
|
127
|
+
>
|
|
128
|
+
{supportedCurrencies.map(currency => (
|
|
129
|
+
<Option key={currency.code} value={currency.code}>
|
|
130
|
+
{currency.name} ({currency.code}) {currency.symbol}
|
|
131
|
+
</Option>
|
|
132
|
+
))}
|
|
133
|
+
</Select>
|
|
134
|
+
{supportedCurrencies.length === 0 && (
|
|
135
|
+
<Typography variant="pi" textColor="danger600" style={{ marginTop: "4px" }}>
|
|
136
|
+
No supported currencies for this country. Please select a different country.
|
|
137
|
+
</Typography>
|
|
138
|
+
)}
|
|
139
|
+
</Box>
|
|
140
140
|
</Flex>
|
|
141
141
|
|
|
142
142
|
{/* Button Style and Type */}
|
|
@@ -186,23 +186,23 @@ const ApplePayConfig = ({
|
|
|
186
186
|
{APPLE_PAY_SUPPORTED_NETWORKS.map(network => {
|
|
187
187
|
const isSupported = supportedNetworksForCountry.includes(network.code);
|
|
188
188
|
const isSelected = supportedNetworks?.includes(network.code);
|
|
189
|
-
|
|
189
|
+
|
|
190
190
|
return (
|
|
191
191
|
<Box key={network.code} style={{ flex: "0 0 calc(50% - 8px)", minWidth: "250px" }}>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
192
|
+
<Checkbox
|
|
193
|
+
name={`network-${network.code}`}
|
|
194
|
+
checked={isSelected}
|
|
195
|
+
onChange={() => handleNetworkToggle(network.code)}
|
|
196
|
+
disabled={!isSupported}
|
|
197
|
+
hint={!isSupported ? `Not supported in ${countryCode}` : undefined}
|
|
198
|
+
>
|
|
199
|
+
{network.name} ({network.code})
|
|
200
|
+
{!isSupported && (
|
|
201
|
+
<Typography variant="sigma" textColor="neutral500" style={{ marginLeft: "8px" }}>
|
|
202
202
|
(Not available)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
</Typography>
|
|
204
|
+
)}
|
|
205
|
+
</Checkbox>
|
|
206
206
|
</Box>
|
|
207
207
|
);
|
|
208
208
|
})}
|
|
@@ -225,16 +225,16 @@ const ApplePayConfig = ({
|
|
|
225
225
|
<Flex wrap="wrap" gap={4} style={{ marginTop: "12px" }}>
|
|
226
226
|
{APPLE_PAY_MERCHANT_CAPABILITIES.map(capability => {
|
|
227
227
|
const isSelected = merchantCapabilities?.includes(capability.code);
|
|
228
|
-
|
|
228
|
+
|
|
229
229
|
return (
|
|
230
230
|
<Box key={capability.code} style={{ flex: "0 0 calc(50% - 8px)", minWidth: "250px" }}>
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
231
|
+
<Checkbox
|
|
232
|
+
name={`capability-${capability.code}`}
|
|
233
|
+
checked={isSelected}
|
|
234
|
+
onChange={() => handleCapabilityToggle(capability.code)}
|
|
235
|
+
>
|
|
236
|
+
{capability.name} - {capability.description}
|
|
237
|
+
</Checkbox>
|
|
238
238
|
</Box>
|
|
239
239
|
);
|
|
240
240
|
})}
|
|
@@ -256,49 +256,49 @@ const ApplePayConfig = ({
|
|
|
256
256
|
</Typography>
|
|
257
257
|
<Flex wrap="wrap" gap={4} style={{ marginTop: "12px" }}>
|
|
258
258
|
<Box style={{ flex: "0 0 calc(33.333% - 11px)", minWidth: "200px" }}>
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
259
|
+
<Checkbox
|
|
260
|
+
name="requestPayerName"
|
|
261
|
+
checked={requestPayerName}
|
|
262
|
+
onChange={(checked) => onConfigChange({ ...config, requestPayerName: checked })}
|
|
263
|
+
>
|
|
264
|
+
Request Payer Name
|
|
265
|
+
</Checkbox>
|
|
266
266
|
</Box>
|
|
267
267
|
<Box style={{ flex: "0 0 calc(33.333% - 11px)", minWidth: "200px" }}>
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
268
|
+
<Checkbox
|
|
269
|
+
name="requestBillingAddress"
|
|
270
|
+
checked={requestBillingAddress}
|
|
271
|
+
onChange={(checked) => onConfigChange({ ...config, requestBillingAddress: checked })}
|
|
272
|
+
>
|
|
273
|
+
Request Billing Address
|
|
274
|
+
</Checkbox>
|
|
275
275
|
</Box>
|
|
276
276
|
<Box style={{ flex: "0 0 calc(33.333% - 11px)", minWidth: "200px" }}>
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
277
|
+
<Checkbox
|
|
278
|
+
name="requestPayerEmail"
|
|
279
|
+
checked={requestPayerEmail}
|
|
280
|
+
onChange={(checked) => onConfigChange({ ...config, requestPayerEmail: checked })}
|
|
281
|
+
>
|
|
282
|
+
Request Payer Email
|
|
283
|
+
</Checkbox>
|
|
284
284
|
</Box>
|
|
285
285
|
<Box style={{ flex: "0 0 calc(33.333% - 11px)", minWidth: "200px" }}>
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
286
|
+
<Checkbox
|
|
287
|
+
name="requestPayerPhone"
|
|
288
|
+
checked={requestPayerPhone}
|
|
289
|
+
onChange={(checked) => onConfigChange({ ...config, requestPayerPhone: checked })}
|
|
290
|
+
>
|
|
291
|
+
Request Payer Phone
|
|
292
|
+
</Checkbox>
|
|
293
293
|
</Box>
|
|
294
294
|
<Box style={{ flex: "0 0 calc(33.333% - 11px)", minWidth: "200px" }}>
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
295
|
+
<Checkbox
|
|
296
|
+
name="requestShipping"
|
|
297
|
+
checked={requestShipping}
|
|
298
|
+
onChange={(checked) => onConfigChange({ ...config, requestShipping: checked })}
|
|
299
|
+
>
|
|
300
|
+
Request Shipping Address
|
|
301
|
+
</Checkbox>
|
|
302
302
|
</Box>
|
|
303
303
|
</Flex>
|
|
304
304
|
</Box> */}
|
|
@@ -309,7 +309,7 @@ const ApplePayConfig = ({
|
|
|
309
309
|
Merchant Identifier
|
|
310
310
|
</Typography>
|
|
311
311
|
<Typography variant="pi" textColor="neutral600">
|
|
312
|
-
{settings?.mid || settings?.portalid
|
|
312
|
+
{settings?.mid || settings?.portalid
|
|
313
313
|
? `Using: ${settings.mid || settings.portalid}`
|
|
314
314
|
: "Merchant identifier will be obtained from Payone after domain verification. See documentation for setup instructions."
|
|
315
315
|
}
|
package/package.json
CHANGED
|
@@ -214,57 +214,202 @@ const validateApplePayMerchant = async (strapi, params) => {
|
|
|
214
214
|
strapi.log.info("[Apple Pay] Session initialization result:", {
|
|
215
215
|
status: sessionResponse.status || sessionResponse.Status,
|
|
216
216
|
hasMerchantIdentifier: !!(sessionResponse.merchantIdentifier || sessionResponse.merchantSessionIdentifier),
|
|
217
|
+
hasApplePaySession: !!(sessionResponse["add_paydata[applepay_payment_session]"] ||
|
|
218
|
+
sessionResponse["add_paydata[applepay_payment_session]"] ||
|
|
219
|
+
sessionResponse.add_paydata?.applepay_payment_session),
|
|
217
220
|
fullResponse: JSON.stringify(sessionResponse, null, 2)
|
|
218
221
|
});
|
|
219
222
|
|
|
220
|
-
// If session initialization is successful,
|
|
221
|
-
// Payone
|
|
223
|
+
// If session initialization is successful, extract merchant session from Payone response
|
|
224
|
+
// Payone returns: add_paydata[applepay_payment_session] = BASE64 encoded merchant session
|
|
222
225
|
// Check for both uppercase and lowercase status
|
|
223
226
|
const responseStatus = sessionResponse.status || sessionResponse.Status;
|
|
224
|
-
if (responseStatus === "APPROVED" || responseStatus === "
|
|
225
|
-
responseStatus === "approved" || responseStatus === "
|
|
226
|
-
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
strapi.log.info("[Apple Pay] Merchant session created:", {
|
|
248
|
-
merchantIdentifier: merchantSession.merchantIdentifier,
|
|
249
|
-
domainName: merchantSession.domainName,
|
|
250
|
-
expiresAt: new Date(merchantSession.expiresAt).toISOString()
|
|
227
|
+
if (responseStatus === "APPROVED" || responseStatus === "OK" ||
|
|
228
|
+
responseStatus === "approved" || responseStatus === "ok") {
|
|
229
|
+
|
|
230
|
+
// Extract BASE64 encoded merchant session from Payone response
|
|
231
|
+
// Payone returns it in: add_paydata[applepay_payment_session]
|
|
232
|
+
// Try all possible variations of the field name
|
|
233
|
+
const applePaySessionBase64 =
|
|
234
|
+
sessionResponse["add_paydata[applepay_payment_session]"] ||
|
|
235
|
+
sessionResponse["add_paydata[applepay_payment_session]"] ||
|
|
236
|
+
sessionResponse["add_paydata_applepay_payment_session"] ||
|
|
237
|
+
sessionResponse.add_paydata?.applepay_payment_session ||
|
|
238
|
+
sessionResponse.add_paydata?.["applepay_payment_session"] ||
|
|
239
|
+
sessionResponse["addPaydata[applepay_payment_session]"] ||
|
|
240
|
+
sessionResponse["addPaydata_applepay_payment_session"] ||
|
|
241
|
+
null;
|
|
242
|
+
|
|
243
|
+
strapi.log.info("[Apple Pay] Checking for merchant session in response:", {
|
|
244
|
+
hasWorkorderid: !!sessionResponse.workorderid,
|
|
245
|
+
workorderid: sessionResponse.workorderid,
|
|
246
|
+
allKeys: Object.keys(sessionResponse).filter(k => k.includes('applepay') || k.includes('session') || k.includes('paydata')),
|
|
247
|
+
responseKeys: Object.keys(sessionResponse)
|
|
251
248
|
});
|
|
252
249
|
|
|
253
|
-
|
|
250
|
+
strapi.log.info("[Apple Pay] Extracted Apple Pay session data:", {
|
|
251
|
+
hasBase64Session: !!applePaySessionBase64,
|
|
252
|
+
sessionLength: applePaySessionBase64?.length,
|
|
253
|
+
workorderid: sessionResponse.workorderid,
|
|
254
|
+
allResponseKeys: Object.keys(sessionResponse),
|
|
255
|
+
responseSample: JSON.stringify(sessionResponse).substring(0, 500)
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
if (applePaySessionBase64 && applePaySessionBase64.length > 0) {
|
|
259
|
+
try {
|
|
260
|
+
// Decode BASE64 merchant session
|
|
261
|
+
const merchantSessionJson = Buffer.from(applePaySessionBase64, 'base64').toString('utf-8');
|
|
262
|
+
const merchantSession = JSON.parse(merchantSessionJson);
|
|
263
|
+
|
|
264
|
+
strapi.log.info("[Apple Pay] Decoded merchant session:", {
|
|
265
|
+
merchantIdentifier: merchantSession.merchantIdentifier,
|
|
266
|
+
domainName: merchantSession.domainName,
|
|
267
|
+
displayName: merchantSession.displayName,
|
|
268
|
+
hasEpochTimestamp: !!merchantSession.epochTimestamp,
|
|
269
|
+
hasExpiresAt: !!merchantSession.expiresAt,
|
|
270
|
+
fullSession: merchantSession
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Validate decoded merchant session
|
|
274
|
+
if (!merchantSession.merchantIdentifier) {
|
|
275
|
+
strapi.log.warn("[Apple Pay] Decoded merchant session missing merchantIdentifier, using fallback");
|
|
276
|
+
// Use fallback merchant identifier
|
|
277
|
+
merchantSession.merchantIdentifier = settings.merchantIdentifier ||
|
|
278
|
+
settings.mid ||
|
|
279
|
+
settings.portalid ||
|
|
280
|
+
`merchant.${domainName}`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Ensure epochTimestamp and expiresAt are in seconds (not milliseconds)
|
|
284
|
+
if (merchantSession.epochTimestamp && merchantSession.epochTimestamp > 1000000000000) {
|
|
285
|
+
// If timestamp is in milliseconds, convert to seconds
|
|
286
|
+
merchantSession.epochTimestamp = Math.floor(merchantSession.epochTimestamp / 1000);
|
|
287
|
+
}
|
|
288
|
+
if (merchantSession.expiresAt && merchantSession.expiresAt > 1000000000000) {
|
|
289
|
+
// If timestamp is in milliseconds, convert to seconds
|
|
290
|
+
merchantSession.expiresAt = Math.floor(merchantSession.expiresAt / 1000);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Validate final merchant session
|
|
294
|
+
if (!merchantSession.merchantIdentifier || merchantSession.merchantIdentifier === 'undefined' || merchantSession.merchantIdentifier === 'null') {
|
|
295
|
+
throw new Error("Decoded merchant session has invalid merchantIdentifier");
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
strapi.log.info("[Apple Pay] Validated merchant session:", {
|
|
299
|
+
merchantIdentifier: merchantSession.merchantIdentifier,
|
|
300
|
+
domainName: merchantSession.domainName,
|
|
301
|
+
epochTimestamp: merchantSession.epochTimestamp,
|
|
302
|
+
expiresAt: merchantSession.expiresAt
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
return merchantSession;
|
|
306
|
+
} catch (decodeError) {
|
|
307
|
+
strapi.log.error("[Apple Pay] Failed to decode merchant session:", {
|
|
308
|
+
error: decodeError.message,
|
|
309
|
+
base64Length: applePaySessionBase64?.length,
|
|
310
|
+
base64Preview: applePaySessionBase64?.substring(0, 100)
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// If decoding fails, we cannot proceed - merchant session is invalid
|
|
314
|
+
throw new Error(`Failed to decode Apple Pay merchant session: ${decodeError.message}`);
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
// CRITICAL: If Payone doesn't return merchant session, we cannot proceed
|
|
318
|
+
// Apple Pay requires the merchant session to be validated by Apple's servers
|
|
319
|
+
// Payone should return add_paydata[applepay_payment_session] after successful initialization
|
|
320
|
+
strapi.log.error("[Apple Pay] CRITICAL: No Apple Pay session data in Payone response!");
|
|
321
|
+
strapi.log.error("[Apple Pay] This means merchant validation will fail. Possible causes:");
|
|
322
|
+
strapi.log.error("[Apple Pay] 1. Apple Pay not properly configured in Payone PMI");
|
|
323
|
+
strapi.log.error("[Apple Pay] 2. Domain not verified in Payone PMI");
|
|
324
|
+
strapi.log.error("[Apple Pay] 3. Merchant identifier not configured in Payone PMI");
|
|
325
|
+
strapi.log.error("[Apple Pay] 4. Apple Pay onboarding not completed in Payone PMI");
|
|
326
|
+
strapi.log.error("[Apple Pay] Response status:", responseStatus);
|
|
327
|
+
strapi.log.error("[Apple Pay] Full response keys:", Object.keys(sessionResponse));
|
|
328
|
+
strapi.log.error("[Apple Pay] Response sample:", JSON.stringify(sessionResponse).substring(0, 1000));
|
|
329
|
+
|
|
330
|
+
// DO NOT create a fallback session - it will fail validation
|
|
331
|
+
// Instead, throw an error so the frontend knows validation failed
|
|
332
|
+
throw new Error("Payone did not return Apple Pay merchant session. Please ensure Apple Pay is properly configured in Payone Merchant Interface (PMI): CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay configuration. The merchant session must come from Payone after successful Apple Pay onboarding.");
|
|
333
|
+
|
|
334
|
+
// Get merchant identifier from settings
|
|
335
|
+
// According to Payone docs, merchant identifier should be visible in PMI after onboarding
|
|
336
|
+
// Path: CONFIGURATION/PAYMENT PORTALS - choose an onboarded Portal - Payment type configuration tab
|
|
337
|
+
let merchantIdentifier = settings.merchantIdentifier ||
|
|
338
|
+
settings.mid ||
|
|
339
|
+
settings.portalid;
|
|
340
|
+
|
|
341
|
+
// If still no merchant identifier, try to construct one from domain
|
|
342
|
+
// But this is not ideal - merchant identifier should come from Payone PMI
|
|
343
|
+
if (!merchantIdentifier) {
|
|
344
|
+
strapi.log.warn("[Apple Pay] No merchant identifier found in settings, using domain-based fallback");
|
|
345
|
+
merchantIdentifier = `merchant.${domainName}`;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Ensure merchant identifier is a string and not empty
|
|
349
|
+
merchantIdentifier = merchantIdentifier.toString().trim();
|
|
350
|
+
if (!merchantIdentifier || merchantIdentifier === 'undefined' || merchantIdentifier === 'null') {
|
|
351
|
+
strapi.log.error("[Apple Pay] Invalid merchant identifier:", merchantIdentifier);
|
|
352
|
+
throw new Error("Merchant identifier is invalid. Please configure a valid merchant identifier in Payone Merchant Interface (PMI) after Apple Pay onboarding. Path: CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Payment type configuration tab");
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Create a valid merchant session object
|
|
356
|
+
// This format is required by Apple Pay Payment Request API
|
|
357
|
+
// IMPORTANT: epochTimestamp and expiresAt must be in seconds (Unix timestamp), not milliseconds
|
|
358
|
+
const merchantSession = {
|
|
359
|
+
epochTimestamp: Math.floor(Date.now() / 1000), // Unix timestamp in seconds
|
|
360
|
+
expiresAt: Math.floor((Date.now() + (5 * 60 * 1000)) / 1000), // 5 minutes from now, in seconds
|
|
361
|
+
merchantSessionIdentifier: `merchant.${domainName}`,
|
|
362
|
+
nonce: generateNonce(),
|
|
363
|
+
merchantIdentifier: merchantIdentifier, // Already validated and converted to string
|
|
364
|
+
domainName: domainName,
|
|
365
|
+
displayName: merchantName
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// Validate merchant session before returning
|
|
369
|
+
if (!merchantSession.merchantIdentifier || merchantSession.merchantIdentifier === 'undefined' || merchantSession.merchantIdentifier === 'null') {
|
|
370
|
+
strapi.log.error("[Apple Pay] Created merchant session is missing or invalid merchantIdentifier!", {
|
|
371
|
+
merchantIdentifier: merchantSession.merchantIdentifier,
|
|
372
|
+
settings: {
|
|
373
|
+
hasMerchantIdentifier: !!settings.merchantIdentifier,
|
|
374
|
+
hasMid: !!settings.mid,
|
|
375
|
+
hasPortalid: !!settings.portalid,
|
|
376
|
+
mid: settings.mid,
|
|
377
|
+
portalid: settings.portalid
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
throw new Error("Merchant identifier is required but not found in settings. Please configure merchant identifier in Payone Merchant Interface (PMI) after Apple Pay onboarding.");
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
strapi.log.info("[Apple Pay] Created merchant session from settings:", {
|
|
384
|
+
merchantIdentifier: merchantSession.merchantIdentifier,
|
|
385
|
+
domainName: merchantSession.domainName,
|
|
386
|
+
displayName: merchantSession.displayName,
|
|
387
|
+
epochTimestamp: merchantSession.epochTimestamp,
|
|
388
|
+
expiresAt: merchantSession.expiresAt
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
return merchantSession;
|
|
392
|
+
}
|
|
254
393
|
}
|
|
255
394
|
|
|
256
|
-
// If initialization failed,
|
|
257
|
-
// Payment Request API
|
|
258
|
-
strapi.log.
|
|
259
|
-
|
|
395
|
+
// If initialization failed, we cannot proceed
|
|
396
|
+
// Payment Request API requires a valid merchant session
|
|
397
|
+
strapi.log.error("[Apple Pay] Session initialization failed - status:", responseStatus);
|
|
398
|
+
strapi.log.error("[Apple Pay] This means merchant validation will fail.");
|
|
399
|
+
strapi.log.error("[Apple Pay] Please check Payone PMI configuration and ensure Apple Pay is properly set up.");
|
|
400
|
+
throw new Error(`Apple Pay session initialization failed with status: ${responseStatus}. Please check your Payone Apple Pay configuration in PMI.`);
|
|
260
401
|
} catch (error) {
|
|
261
402
|
strapi.log.error("[Apple Pay] Merchant validation error:", {
|
|
262
403
|
message: error.message,
|
|
263
404
|
stack: error.stack,
|
|
264
|
-
response: error.response?.data
|
|
405
|
+
response: error.response?.data,
|
|
406
|
+
status: error.response?.status
|
|
265
407
|
});
|
|
266
|
-
|
|
267
|
-
return
|
|
408
|
+
|
|
409
|
+
// DO NOT return empty object - this causes Apple Pay to close the dialog
|
|
410
|
+
// Instead, re-throw the error so the frontend can handle it properly
|
|
411
|
+
// The error message will help the user understand what went wrong
|
|
412
|
+
throw error;
|
|
268
413
|
}
|
|
269
414
|
};
|
|
270
415
|
|
|
@@ -24,8 +24,20 @@ const parseResponse = (responseText, logger) => {
|
|
|
24
24
|
const params = new URLSearchParams(responseText);
|
|
25
25
|
const response = {};
|
|
26
26
|
for (const [key, value] of params) {
|
|
27
|
+
// Store both lowercase and original case
|
|
27
28
|
response[key.toLowerCase()] = value;
|
|
28
29
|
response[key] = value;
|
|
30
|
+
|
|
31
|
+
// Also handle add_paydata fields with brackets
|
|
32
|
+
// Payone returns: add_paydata[applepay_payment_session]=BASE64_STRING
|
|
33
|
+
// URLSearchParams handles brackets, but we need to ensure we can access it
|
|
34
|
+
if (key.includes('add_paydata') || key.includes('addPaydata')) {
|
|
35
|
+
// Store with original key format
|
|
36
|
+
response[key] = value;
|
|
37
|
+
// Also try normalized versions
|
|
38
|
+
const normalizedKey = key.replace(/\[/g, '_').replace(/\]/g, '');
|
|
39
|
+
response[normalizedKey] = value;
|
|
40
|
+
}
|
|
29
41
|
}
|
|
30
42
|
return response;
|
|
31
43
|
};
|