strapi-plugin-payone-provider 1.5.0 → 1.5.3
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 +179 -22
- package/admin/src/pages/App/components/AppHeader.js +22 -4
- package/admin/src/pages/App/components/AppTabs.js +23 -1
- package/admin/src/pages/App/components/ApplePayButton.js +93 -13
- package/admin/src/pages/App/components/ApplePayConfig.js +224 -165
- package/admin/src/pages/App/components/ApplePayConfigPanel.js +81 -0
- package/admin/src/pages/App/components/ConfigurationPanel.js +19 -3
- package/admin/src/pages/App/components/DocsPanel.js +1057 -0
- package/admin/src/pages/App/components/GooglePayConfig.js +217 -0
- package/admin/src/pages/App/components/GooglePayConfigPanel.js +82 -0
- package/admin/src/pages/App/components/GooglePaybutton.js +1 -1
- package/admin/src/pages/App/components/PaymentActionsPanel.js +18 -6
- package/admin/src/pages/App/components/paymentActions/AuthorizationForm.js +58 -12
- package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.js +106 -2
- package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.js +55 -20
- package/admin/src/pages/App/index.js +70 -1
- package/admin/src/pages/hooks/usePaymentActions.js +38 -2
- package/admin/src/pages/hooks/useSettings.js +2 -0
- package/admin/src/pages/utils/googlePayConstants.js +79 -0
- package/package.json +1 -1
- package/APPLE_PAY_INTEGRATION.md +0 -472
- package/CSP_SETUP.md +0 -184
- package/HTTPS_REQUIREMENT.md +0 -136
package/README.md
CHANGED
|
@@ -85,6 +85,159 @@ After installation, you need to configure your Payone credentials:
|
|
|
85
85
|
5. Click **"Test Connection"** to verify your credentials
|
|
86
86
|
6. Click **"Save Configuration"** to store your settings
|
|
87
87
|
|
|
88
|
+
### Apple Pay Configuration
|
|
89
|
+
|
|
90
|
+
To configure Apple Pay settings:
|
|
91
|
+
|
|
92
|
+
1. Navigate to **Payone Provider** in the sidebar menu
|
|
93
|
+
2. Go to **Payment Actions** tab
|
|
94
|
+
3. Select **Apple Pay** as the payment method
|
|
95
|
+
4. Click on the Apple Pay configuration link: `/plugins/strapi-plugin-payone-provider/apple-pay-config`
|
|
96
|
+
5. Configure the following settings:
|
|
97
|
+
- **Country Code**: Select the country where your business operates
|
|
98
|
+
- **Currency Code**: Select the currency for transactions
|
|
99
|
+
- **Supported Networks**: Select payment card networks (Visa, Mastercard, Amex, etc.)
|
|
100
|
+
- **Merchant Capabilities**: Select payment capabilities (3D Secure is recommended)
|
|
101
|
+
- **Button Style & Type**: Customize the Apple Pay button appearance
|
|
102
|
+
6. Click **"Save Apple Pay Configuration"** to store your settings
|
|
103
|
+
|
|
104
|
+
> ⚠️ **Important**: Apple Pay requires a registered domain with HTTPS. It does NOT work on localhost. For testing, use a production domain with HTTPS or test on a device with Safari (iOS/macOS).
|
|
105
|
+
|
|
106
|
+
#### Apple Pay Domain Verification File (.well-known)
|
|
107
|
+
|
|
108
|
+
Apple Pay requires a domain verification file to be placed on your server. This file must be accessible at:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
https://yourdomain.com/.well-known/apple-developer-merchantid-domain-association
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Steps to set up the domain verification file:**
|
|
115
|
+
|
|
116
|
+
1. **Download the file from Payone:**
|
|
117
|
+
|
|
118
|
+
- Download the domain verification file from Payone documentation: [https://docs.payone.com/payment-methods/apple-pay/apple-pay-without-dev](https://docs.payone.com/payment-methods/apple-pay/apple-pay-without-dev)
|
|
119
|
+
- Alternatively, log into your Payone Merchant Interface (PMI)
|
|
120
|
+
- Navigate to **Configuration** → **Payment Portals** → **Apple Pay**
|
|
121
|
+
- Download the `apple-developer-merchantid-domain-association` file
|
|
122
|
+
|
|
123
|
+
2. **Place the file in Strapi:**
|
|
124
|
+
|
|
125
|
+
- Create the directory: `public/.well-known/` (if it doesn't exist)
|
|
126
|
+
- Place the file at: `public/.well-known/apple-developer-merchantid-domain-association`
|
|
127
|
+
|
|
128
|
+
3. **Place the file in your Frontend (if separate):**
|
|
129
|
+
|
|
130
|
+
- Create the directory: `public/.well-known/` (if it doesn't exist)
|
|
131
|
+
- Place the file at: `public/.well-known/apple-developer-merchantid-domain-association`
|
|
132
|
+
|
|
133
|
+
4. **Verify accessibility:**
|
|
134
|
+
- The file must be accessible via HTTPS at: `https://yourdomain.com/.well-known/apple-developer-merchantid-domain-association`
|
|
135
|
+
- Test by visiting the URL in your browser - you should see the file content
|
|
136
|
+
|
|
137
|
+
> ⚠️ **Critical**: Without this file, Apple Pay will NOT work on your domain. The file must be accessible via HTTPS and must match exactly what Payone provides.
|
|
138
|
+
|
|
139
|
+
#### Middleware Configuration for Apple Pay
|
|
140
|
+
|
|
141
|
+
Apple Pay requires Content Security Policy (CSP) configuration in `config/middlewares.js` to allow Apple Pay scripts. Without this configuration, Apple Pay will NOT work.
|
|
142
|
+
|
|
143
|
+
**Required CSP directives:**
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
module.exports = [
|
|
147
|
+
"strapi::logger",
|
|
148
|
+
"strapi::errors",
|
|
149
|
+
{
|
|
150
|
+
name: "strapi::security",
|
|
151
|
+
config: {
|
|
152
|
+
contentSecurityPolicy: {
|
|
153
|
+
useDefaults: true,
|
|
154
|
+
directives: {
|
|
155
|
+
"script-src": [
|
|
156
|
+
"'self'",
|
|
157
|
+
"'unsafe-inline'",
|
|
158
|
+
"'unsafe-eval'",
|
|
159
|
+
"https://applepay.cdn-apple.com", // Apple Pay SDK
|
|
160
|
+
"https://www.apple.com", // Apple Pay manifest
|
|
161
|
+
],
|
|
162
|
+
"connect-src": [
|
|
163
|
+
"'self'",
|
|
164
|
+
"https:",
|
|
165
|
+
"https://applepay.cdn-apple.com", // Apple Pay API
|
|
166
|
+
"https://www.apple.com", // Apple Pay manifest
|
|
167
|
+
],
|
|
168
|
+
"frame-src": [
|
|
169
|
+
"'self'",
|
|
170
|
+
"https://applepay.cdn-apple.com", // Apple Pay iframe
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
// ... other middlewares
|
|
177
|
+
];
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
> ⚠️ **Important**: Without this middleware configuration, Apple Pay scripts will be blocked and Apple Pay will NOT work!
|
|
181
|
+
|
|
182
|
+
### Google Pay Configuration
|
|
183
|
+
|
|
184
|
+
To configure Google Pay settings:
|
|
185
|
+
|
|
186
|
+
1. Navigate to **Payone Provider** in the sidebar menu
|
|
187
|
+
2. Go to **Payment Actions** tab
|
|
188
|
+
3. Select **Google Pay** as the payment method
|
|
189
|
+
4. Click on the Google Pay configuration link: `/plugins/strapi-plugin-payone-provider/google-pay-config`
|
|
190
|
+
5. Configure the following settings:
|
|
191
|
+
- **Country Code**: Select the country where your business operates
|
|
192
|
+
- **Currency Code**: Select the currency for transactions
|
|
193
|
+
- **Merchant Name**: Enter your business name as it will appear in Google Pay
|
|
194
|
+
- **Allowed Card Networks**: Select payment card networks (Mastercard, Visa, Amex, etc.)
|
|
195
|
+
- **Allowed Authentication Methods**: Select authentication methods (PAN Only, 3D Secure)
|
|
196
|
+
6. Click **"Save Google Pay Configuration"** to store your settings
|
|
197
|
+
|
|
198
|
+
> ℹ️ **Note**: The Gateway Merchant ID will be automatically obtained from your Payone Merchant ID (MID) or Portal ID configured in the main Configuration tab.
|
|
199
|
+
|
|
200
|
+
#### Middleware Configuration for Google Pay
|
|
201
|
+
|
|
202
|
+
Google Pay requires Content Security Policy (CSP) configuration in `config/middlewares.js` to allow Google Pay scripts. Without this configuration, Google Pay will NOT work.
|
|
203
|
+
|
|
204
|
+
**Required CSP directives:**
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
module.exports = [
|
|
208
|
+
"strapi::logger",
|
|
209
|
+
"strapi::errors",
|
|
210
|
+
{
|
|
211
|
+
name: "strapi::security",
|
|
212
|
+
config: {
|
|
213
|
+
contentSecurityPolicy: {
|
|
214
|
+
useDefaults: true,
|
|
215
|
+
directives: {
|
|
216
|
+
"script-src": [
|
|
217
|
+
"'self'",
|
|
218
|
+
"'unsafe-inline'",
|
|
219
|
+
"'unsafe-eval'",
|
|
220
|
+
"https://pay.google.com", // Google Pay SDK
|
|
221
|
+
],
|
|
222
|
+
"connect-src": [
|
|
223
|
+
"'self'",
|
|
224
|
+
"https:",
|
|
225
|
+
"https://pay.google.com", // Google Pay API
|
|
226
|
+
],
|
|
227
|
+
"frame-src": [
|
|
228
|
+
"'self'",
|
|
229
|
+
"https://pay.google.com", // Google Pay iframe
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
// ... other middlewares
|
|
236
|
+
];
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
> ⚠️ **Important**: Without this middleware configuration, Google Pay scripts will be blocked and Google Pay will NOT work!
|
|
240
|
+
|
|
88
241
|
## 🚀 Getting Started
|
|
89
242
|
|
|
90
243
|
### 1. Test Your Connection
|
|
@@ -590,7 +743,7 @@ Google Pay integration requires obtaining an encrypted payment token from Google
|
|
|
590
743
|
|
|
591
744
|
```javascript
|
|
592
745
|
const paymentsClient = new google.payments.api.PaymentsClient({
|
|
593
|
-
environment:
|
|
746
|
+
environment: "TEST", // or "PRODUCTION" for live
|
|
594
747
|
});
|
|
595
748
|
|
|
596
749
|
const baseRequest = {
|
|
@@ -598,19 +751,19 @@ const baseRequest = {
|
|
|
598
751
|
apiVersionMinor: 0,
|
|
599
752
|
};
|
|
600
753
|
|
|
601
|
-
const allowedCardNetworks = [
|
|
602
|
-
const allowedAuthMethods = [
|
|
754
|
+
const allowedCardNetworks = ["MASTERCARD", "VISA"];
|
|
755
|
+
const allowedAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"];
|
|
603
756
|
|
|
604
757
|
const tokenizationSpecification = {
|
|
605
|
-
type:
|
|
758
|
+
type: "PAYMENT_GATEWAY",
|
|
606
759
|
parameters: {
|
|
607
|
-
gateway:
|
|
608
|
-
gatewayMerchantId:
|
|
760
|
+
gateway: "payonegmbh",
|
|
761
|
+
gatewayMerchantId: "YOUR_PAYONE_MERCHANT_ID", // Use your Payone MID or Portal ID
|
|
609
762
|
},
|
|
610
763
|
};
|
|
611
764
|
|
|
612
765
|
const cardPaymentMethod = {
|
|
613
|
-
type:
|
|
766
|
+
type: "CARD",
|
|
614
767
|
parameters: {
|
|
615
768
|
allowedCardNetworks,
|
|
616
769
|
allowedAuthMethods,
|
|
@@ -634,45 +787,47 @@ paymentsClient.isReadyToPay(isReadyToPayRequest).then(function (response) {
|
|
|
634
787
|
const paymentDataRequest = Object.assign({}, baseRequest);
|
|
635
788
|
paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
|
|
636
789
|
paymentDataRequest.transactionInfo = {
|
|
637
|
-
totalPriceStatus:
|
|
638
|
-
totalPrice:
|
|
639
|
-
currencyCode:
|
|
790
|
+
totalPriceStatus: "FINAL",
|
|
791
|
+
totalPrice: "10.00",
|
|
792
|
+
currencyCode: "EUR",
|
|
640
793
|
};
|
|
641
794
|
paymentDataRequest.merchantInfo = {
|
|
642
|
-
merchantId:
|
|
643
|
-
merchantName:
|
|
795
|
+
merchantId: "YOUR_GOOGLE_MERCHANT_ID", // Optional: from Google Console
|
|
796
|
+
merchantName: "Your Merchant Name",
|
|
644
797
|
};
|
|
645
798
|
|
|
646
799
|
const button = paymentsClient.createButton({
|
|
647
800
|
onClick: async () => {
|
|
648
801
|
try {
|
|
649
|
-
const paymentData = await paymentsClient.loadPaymentData(
|
|
802
|
+
const paymentData = await paymentsClient.loadPaymentData(
|
|
803
|
+
paymentDataRequest
|
|
804
|
+
);
|
|
650
805
|
const token = paymentData.paymentMethodData.tokenizationData.token;
|
|
651
806
|
|
|
652
807
|
// Token is a JSON string, encode it to Base64 for Payone
|
|
653
808
|
const base64Token = btoa(unescape(encodeURIComponent(token)));
|
|
654
809
|
|
|
655
810
|
// Send to your backend
|
|
656
|
-
await fetch(
|
|
657
|
-
method:
|
|
811
|
+
await fetch("/api/strapi-plugin-payone-provider/preauthorization", {
|
|
812
|
+
method: "POST",
|
|
658
813
|
headers: {
|
|
659
|
-
|
|
660
|
-
Authorization:
|
|
814
|
+
"Content-Type": "application/json",
|
|
815
|
+
Authorization: "Bearer YOUR_TOKEN",
|
|
661
816
|
},
|
|
662
817
|
body: JSON.stringify({
|
|
663
818
|
amount: 1000,
|
|
664
|
-
currency:
|
|
665
|
-
reference:
|
|
819
|
+
currency: "EUR",
|
|
820
|
+
reference: "PAY1234567890ABCDEF",
|
|
666
821
|
googlePayToken: base64Token,
|
|
667
822
|
}),
|
|
668
823
|
});
|
|
669
824
|
} catch (error) {
|
|
670
|
-
console.error(
|
|
825
|
+
console.error("Google Pay error:", error);
|
|
671
826
|
}
|
|
672
827
|
},
|
|
673
828
|
});
|
|
674
829
|
|
|
675
|
-
document.getElementById(
|
|
830
|
+
document.getElementById("google-pay-button").appendChild(button);
|
|
676
831
|
```
|
|
677
832
|
|
|
678
833
|
**Token Format**
|
|
@@ -684,7 +839,9 @@ The token from Google Pay is a JSON string with the following structure:
|
|
|
684
839
|
"signature": "MEUCIFr4ETGzv0uLZX3sR+i1ScARXnRBrncyYFDX/TI/VSLCAiEAvC/Q4dqXMQhwcSdg/ZvXj8+up0wXsfHja3V/6z48/vk=",
|
|
685
840
|
"intermediateSigningKey": {
|
|
686
841
|
"signedKey": "{\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7PWUi+e6WPUhNmTSQ2WN006oWlcWy0FtBWizw9sph1wvX9XcXUNRLcfcsmCBfI5IsKQkjAmYxpCSB+L5sIudLw\\u003d\\u003d\",\"keyExpiration\":\"1722393105282\"}",
|
|
687
|
-
"signatures": [
|
|
842
|
+
"signatures": [
|
|
843
|
+
"MEUCIQCpU30A3g2pP93IBE5NxgO9ZcJlGF9YPzCZS7H4/IR1CQIgF6+I5t8olT8YsRDUcj7w3R1bvX4ZCcyFXE2+YXa+3H0="
|
|
844
|
+
]
|
|
688
845
|
},
|
|
689
846
|
"protocolVersion": "ECv2",
|
|
690
847
|
"signedMessage": "{\"encryptedMessage\":\"...\",\"ephemeralPublicKey\":\"...\",\"tag\":\"...\"}"
|
|
@@ -1,22 +1,40 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { HeaderLayout, Box, Typography, Button } from "@strapi/design-system";
|
|
3
|
-
import { Check } from "@strapi/icons";
|
|
3
|
+
import { Check, ArrowLeft } from "@strapi/icons";
|
|
4
|
+
import { useHistory, useLocation } from "react-router-dom";
|
|
5
|
+
import pluginId from "../../../pluginId";
|
|
4
6
|
|
|
5
7
|
const AppHeader = ({ activeTab, isSaving, onSave }) => {
|
|
8
|
+
const history = useHistory();
|
|
9
|
+
const location = useLocation();
|
|
10
|
+
const isApplePayConfigPage = location.pathname.includes('/apple-pay-config');
|
|
11
|
+
|
|
6
12
|
return (
|
|
7
13
|
<HeaderLayout
|
|
8
14
|
title={
|
|
9
15
|
<Box>
|
|
10
16
|
<Typography variant="alpha" as="h1" fontWeight="bold" className="payment-title">
|
|
11
|
-
Payone Provider
|
|
17
|
+
{isApplePayConfigPage ? "Apple Pay Configuration" : "Payone Provider"}
|
|
12
18
|
</Typography>
|
|
13
19
|
<Typography variant="pi" marginTop={2} className="payment-subtitle">
|
|
14
|
-
|
|
20
|
+
{isApplePayConfigPage
|
|
21
|
+
? "Configure Apple Pay settings for your payment gateway"
|
|
22
|
+
: "Configure your Payone integration and manage payment transactions"
|
|
23
|
+
}
|
|
15
24
|
</Typography>
|
|
16
25
|
</Box>
|
|
17
26
|
}
|
|
18
27
|
primaryAction={
|
|
19
|
-
|
|
28
|
+
isApplePayConfigPage ? (
|
|
29
|
+
<Button
|
|
30
|
+
onClick={() => history.push(`/plugins/${pluginId}`)}
|
|
31
|
+
startIcon={<ArrowLeft />}
|
|
32
|
+
size="L"
|
|
33
|
+
variant="secondary"
|
|
34
|
+
>
|
|
35
|
+
Back to Main
|
|
36
|
+
</Button>
|
|
37
|
+
) : activeTab === 0 ? (
|
|
20
38
|
<Button
|
|
21
39
|
loading={isSaving}
|
|
22
40
|
onClick={onSave}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Tabs, Tab, TabGroup, TabPanels, TabPanel } from "@strapi/design-system";
|
|
3
|
+
import pluginId from "../../../pluginId";
|
|
3
4
|
import ConfigurationPanel from "./ConfigurationPanel";
|
|
4
5
|
import HistoryPanel from "./HistoryPanel";
|
|
5
6
|
import PaymentActionsPanel from "./PaymentActionsPanel";
|
|
7
|
+
import DocsPanel from "./DocsPanel";
|
|
6
8
|
|
|
7
9
|
const AppTabs = ({
|
|
8
10
|
activeTab,
|
|
@@ -30,8 +32,18 @@ const AppTabs = ({
|
|
|
30
32
|
selectedTransaction,
|
|
31
33
|
onTransactionSelect,
|
|
32
34
|
// Payment actions props
|
|
33
|
-
paymentActions
|
|
35
|
+
paymentActions,
|
|
36
|
+
history
|
|
34
37
|
}) => {
|
|
38
|
+
const handleNavigateToConfig = (configType = "apple-pay") => {
|
|
39
|
+
if (history) {
|
|
40
|
+
if (configType === "google-pay") {
|
|
41
|
+
history.push(`/plugins/${pluginId}/google-pay-config`);
|
|
42
|
+
} else {
|
|
43
|
+
history.push(`/plugins/${pluginId}/apple-pay-config`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
35
47
|
return (
|
|
36
48
|
<TabGroup
|
|
37
49
|
label="Payone Provider Tabs"
|
|
@@ -53,6 +65,11 @@ const AppTabs = ({
|
|
|
53
65
|
>
|
|
54
66
|
Payment Actions
|
|
55
67
|
</Tab>
|
|
68
|
+
<Tab
|
|
69
|
+
className={`payment-tab ${activeTab === 3 ? 'payment-tab-active' : ''}`}
|
|
70
|
+
>
|
|
71
|
+
Documentation
|
|
72
|
+
</Tab>
|
|
56
73
|
</Tabs>
|
|
57
74
|
<TabPanels>
|
|
58
75
|
<TabPanel>
|
|
@@ -125,8 +142,13 @@ const AppTabs = ({
|
|
|
125
142
|
setCardexpiredate={paymentActions.setCardexpiredate}
|
|
126
143
|
cardcvc2={paymentActions.cardcvc2}
|
|
127
144
|
setCardcvc2={paymentActions.setCardcvc2}
|
|
145
|
+
onNavigateToConfig={handleNavigateToConfig}
|
|
128
146
|
/>
|
|
129
147
|
</TabPanel>
|
|
148
|
+
|
|
149
|
+
<TabPanel>
|
|
150
|
+
<DocsPanel />
|
|
151
|
+
</TabPanel>
|
|
130
152
|
</TabPanels>
|
|
131
153
|
</TabGroup>
|
|
132
154
|
);
|
|
@@ -499,7 +499,16 @@ const ApplePayButton = ({
|
|
|
499
499
|
|
|
500
500
|
// Show payment sheet and get response
|
|
501
501
|
console.log("[Apple Pay] Showing payment sheet...");
|
|
502
|
-
|
|
502
|
+
let response;
|
|
503
|
+
try {
|
|
504
|
+
response = await request.show();
|
|
505
|
+
} catch (error) {
|
|
506
|
+
console.error("[Apple Pay] Error showing payment sheet:", error);
|
|
507
|
+
if (onError) {
|
|
508
|
+
onError(error);
|
|
509
|
+
}
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
503
512
|
|
|
504
513
|
console.log("[Apple Pay] Payment response received:", {
|
|
505
514
|
hasDetails: !!response.details,
|
|
@@ -512,7 +521,11 @@ const ApplePayButton = ({
|
|
|
512
521
|
|
|
513
522
|
if (!paymentToken) {
|
|
514
523
|
console.error("[Apple Pay] Payment token is missing from response");
|
|
515
|
-
|
|
524
|
+
try {
|
|
525
|
+
await response.complete("fail");
|
|
526
|
+
} catch (completeError) {
|
|
527
|
+
console.error("[Apple Pay] Error completing payment with fail:", completeError);
|
|
528
|
+
}
|
|
516
529
|
if (onError) {
|
|
517
530
|
onError(new Error("Apple Pay token is missing"));
|
|
518
531
|
}
|
|
@@ -539,21 +552,88 @@ const ApplePayButton = ({
|
|
|
539
552
|
tokenString = btoa(unescape(encodeURIComponent(JSON.stringify(paymentToken))));
|
|
540
553
|
}
|
|
541
554
|
|
|
542
|
-
// Call the callback with the token
|
|
555
|
+
// Call the callback with the token BEFORE completing payment
|
|
556
|
+
// This ensures the token is saved before the dialog closes
|
|
543
557
|
console.log("[Apple Pay] Sending token to callback");
|
|
558
|
+
let callbackSuccess = true;
|
|
559
|
+
let callbackError = null;
|
|
560
|
+
|
|
544
561
|
if (onTokenReceived) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
562
|
+
try {
|
|
563
|
+
// Call the callback to save the token
|
|
564
|
+
// The callback should set the token in state and return success immediately
|
|
565
|
+
// It should NOT process the payment yet - that will happen when user clicks the button
|
|
566
|
+
const callbackResult = onTokenReceived(tokenString, {
|
|
567
|
+
paymentToken: paymentToken,
|
|
568
|
+
billingContact: response.payerName || response.details?.billingContact,
|
|
569
|
+
shippingContact: response.shippingAddress || response.details?.shippingAddress,
|
|
570
|
+
shippingOption: response.shippingOption || response.details?.shippingOption
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// If callback returns a promise, wait for it to resolve or reject
|
|
574
|
+
if (callbackResult && typeof callbackResult.then === 'function') {
|
|
575
|
+
try {
|
|
576
|
+
const result = await callbackResult;
|
|
577
|
+
console.log("[Apple Pay] Token callback completed successfully:", result);
|
|
578
|
+
// Check if result indicates success
|
|
579
|
+
if (result && result.success === false) {
|
|
580
|
+
callbackSuccess = false;
|
|
581
|
+
callbackError = new Error(result.message || "Token callback returned failure");
|
|
582
|
+
}
|
|
583
|
+
} catch (error) {
|
|
584
|
+
console.error("[Apple Pay] Token callback promise rejected:", error);
|
|
585
|
+
callbackSuccess = false;
|
|
586
|
+
callbackError = error;
|
|
587
|
+
}
|
|
588
|
+
} else if (callbackResult === false) {
|
|
589
|
+
// If callback explicitly returns false, treat as failure
|
|
590
|
+
callbackSuccess = false;
|
|
591
|
+
console.warn("[Apple Pay] Token callback returned false");
|
|
592
|
+
} else {
|
|
593
|
+
// If callback returns a value (not a promise), assume success
|
|
594
|
+
console.log("[Apple Pay] Token callback returned synchronously");
|
|
595
|
+
}
|
|
596
|
+
} catch (error) {
|
|
597
|
+
console.error("[Apple Pay] Error in token callback:", error);
|
|
598
|
+
callbackSuccess = false;
|
|
599
|
+
callbackError = error;
|
|
600
|
+
}
|
|
601
|
+
} else {
|
|
602
|
+
console.warn("[Apple Pay] No onTokenReceived callback provided");
|
|
603
|
+
// If no callback, we should still complete the payment
|
|
604
|
+
// But mark as success since we can't determine the result
|
|
605
|
+
callbackSuccess = true;
|
|
551
606
|
}
|
|
552
607
|
|
|
553
|
-
// Complete payment with success
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
608
|
+
// Complete payment with success or fail based on callback result
|
|
609
|
+
// IMPORTANT: Only call complete() after the callback has fully finished
|
|
610
|
+
console.log("[Apple Pay] Completing payment with status:", callbackSuccess ? "success" : "fail");
|
|
611
|
+
|
|
612
|
+
try {
|
|
613
|
+
// Use a small delay to ensure state updates are complete
|
|
614
|
+
// This prevents the dialog from closing before the token is saved
|
|
615
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
616
|
+
|
|
617
|
+
const completionStatus = callbackSuccess ? "success" : "fail";
|
|
618
|
+
await response.complete(completionStatus);
|
|
619
|
+
console.log("[Apple Pay] Payment completed with status:", completionStatus);
|
|
620
|
+
|
|
621
|
+
// If there was an error, notify the error handler
|
|
622
|
+
if (!callbackSuccess && callbackError && onError) {
|
|
623
|
+
onError(callbackError);
|
|
624
|
+
}
|
|
625
|
+
} catch (completeError) {
|
|
626
|
+
console.error("[Apple Pay] Error completing payment:", completeError);
|
|
627
|
+
// Try to complete with fail status if there's an error
|
|
628
|
+
try {
|
|
629
|
+
await response.complete("fail");
|
|
630
|
+
} catch (finalError) {
|
|
631
|
+
console.error("[Apple Pay] Failed to complete payment even with fail status:", finalError);
|
|
632
|
+
}
|
|
633
|
+
if (onError) {
|
|
634
|
+
onError(completeError);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
557
637
|
|
|
558
638
|
} catch (error) {
|
|
559
639
|
console.error("[Apple Pay] Payment error:", {
|