strapi-plugin-payone-provider 1.1.2 → 1.2.4
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 +1045 -330
- package/admin/src/index.js +4 -1
- package/admin/src/pages/App/components/AppHeader.js +37 -0
- package/admin/src/pages/App/components/AppTabs.js +126 -0
- package/admin/src/pages/App/components/ConfigurationPanel.js +34 -35
- package/admin/src/pages/App/components/GooglePaybutton.js +300 -0
- package/admin/src/pages/App/components/HistoryPanel.js +25 -38
- package/admin/src/pages/App/components/PaymentActionsPanel.js +95 -280
- package/admin/src/pages/App/components/TransactionHistoryItem.js +4 -1
- package/admin/src/pages/App/components/paymentActions/AuthorizationForm.js +93 -0
- package/admin/src/pages/App/components/paymentActions/CaptureForm.js +64 -0
- package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.js +52 -0
- package/admin/src/pages/App/components/paymentActions/PaymentResult.js +85 -0
- package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.js +93 -0
- package/admin/src/pages/App/components/paymentActions/RefundForm.js +89 -0
- package/admin/src/pages/App/index.js +41 -465
- package/admin/src/pages/App/styles.css +294 -0
- package/admin/src/pages/constants/paymentConstants.js +37 -0
- package/admin/src/pages/hooks/usePaymentActions.js +271 -0
- package/admin/src/pages/hooks/useSettings.js +111 -0
- package/admin/src/pages/hooks/useTransactionHistory.js +87 -0
- package/admin/src/pages/utils/api.js +10 -0
- package/admin/src/pages/utils/injectGooglePayScript.js +31 -0
- package/admin/src/pages/utils/paymentUtils.js +113 -13
- package/package.json +1 -1
- package/server/controllers/payone.js +71 -64
- package/server/routes/index.js +17 -0
- package/server/services/paymentService.js +214 -0
- package/server/services/payone.js +25 -648
- package/server/services/settingsService.js +59 -0
- package/server/services/testConnectionService.js +190 -0
- package/server/services/transactionService.js +114 -0
- package/server/utils/normalize.js +51 -0
- package/server/utils/paymentMethodParams.js +126 -0
- package/server/utils/requestBuilder.js +110 -0
- package/server/utils/responseParser.js +80 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/* Payment System UI - Minimalistic & Professional Styles */
|
|
2
|
+
|
|
3
|
+
/* ===== Global Animations ===== */
|
|
4
|
+
@keyframes fadeIn {
|
|
5
|
+
from {
|
|
6
|
+
opacity: 0;
|
|
7
|
+
transform: translateY(8px);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
to {
|
|
11
|
+
opacity: 1;
|
|
12
|
+
transform: translateY(0);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@keyframes slideIn {
|
|
17
|
+
from {
|
|
18
|
+
opacity: 0;
|
|
19
|
+
transform: translateX(-12px);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
to {
|
|
23
|
+
opacity: 1;
|
|
24
|
+
transform: translateX(0);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@keyframes pulse {
|
|
29
|
+
|
|
30
|
+
0%,
|
|
31
|
+
100% {
|
|
32
|
+
opacity: 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
50% {
|
|
36
|
+
opacity: 0.7;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@keyframes shimmer {
|
|
41
|
+
0% {
|
|
42
|
+
background-position: -1000px 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
100% {
|
|
46
|
+
background-position: 1000px 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* ===== Container Styles ===== */
|
|
51
|
+
|
|
52
|
+
/* ===== Card Styles ===== */
|
|
53
|
+
.payment-card {
|
|
54
|
+
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
/* ===== Button Styles ===== */
|
|
59
|
+
.payment-button {
|
|
60
|
+
border-radius: 8px;
|
|
61
|
+
font-weight: 500;
|
|
62
|
+
letter-spacing: 0.01em;
|
|
63
|
+
border: none !important;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.payment-button-primary {
|
|
67
|
+
background: linear-gradient(135deg, #4945ff 0%, #7b3af4 100%);
|
|
68
|
+
color: white;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
.payment-button-success {
|
|
73
|
+
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
|
74
|
+
color: white;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.payment-button-primary:hover {
|
|
78
|
+
background: linear-gradient(135deg, #4945ff 0%, #7b3af4 100%);
|
|
79
|
+
color: white;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
.payment-button-success:hover {
|
|
84
|
+
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
|
85
|
+
color: white;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
/* ===== Input Styles ===== */
|
|
90
|
+
.payment-input {
|
|
91
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
92
|
+
border-radius: 8px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.payment-input:focus-within {
|
|
96
|
+
border-color: #4945ff;
|
|
97
|
+
box-shadow: 0 0 0 3px rgba(73, 69, 255, 0.1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* ===== Tab Styles ===== */
|
|
101
|
+
.payment-tab {
|
|
102
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
103
|
+
position: relative;
|
|
104
|
+
padding: 12px 20px;
|
|
105
|
+
font-weight: 500;
|
|
106
|
+
color: #6b7280;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.payment-tab:hover {
|
|
110
|
+
color: #4945ff;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.payment-tab-active {
|
|
114
|
+
color: #4945ff;
|
|
115
|
+
font-weight: 600;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.payment-tab-active::after {
|
|
119
|
+
content: '';
|
|
120
|
+
position: absolute;
|
|
121
|
+
bottom: -2px;
|
|
122
|
+
left: 0;
|
|
123
|
+
right: 0;
|
|
124
|
+
height: 2px;
|
|
125
|
+
background: linear-gradient(90deg, #4945ff 0%, #7b3af4 100%);
|
|
126
|
+
animation: slideIn 0.3s ease-out;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* ===== Form Section Styles ===== */
|
|
130
|
+
.payment-form-section {
|
|
131
|
+
animation: fadeIn 0.5s ease-out;
|
|
132
|
+
padding: 24px;
|
|
133
|
+
margin-bottom: 20px;
|
|
134
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.payment-form-section:hover {
|
|
138
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.payment-form-title {
|
|
142
|
+
font-size: 14px;
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
margin-bottom: 8px;
|
|
145
|
+
letter-spacing: -0.01em;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.payment-form-description {
|
|
149
|
+
font-size: 13px;
|
|
150
|
+
line-height: 1.5;
|
|
151
|
+
margin-top: 8px;
|
|
152
|
+
margin-bottom: 20px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* ===== Divider Styles ===== */
|
|
156
|
+
.payment-divider {
|
|
157
|
+
border: none;
|
|
158
|
+
height: 1px;
|
|
159
|
+
background: linear-gradient(90deg, transparent 0%, #e8e8ea 20%, #e8e8ea 80%, transparent 100%);
|
|
160
|
+
margin: 32px 0;
|
|
161
|
+
animation: fadeIn 0.4s ease-out;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* ===== Status Badge Styles ===== */
|
|
165
|
+
.payment-status-badge {
|
|
166
|
+
display: inline-flex;
|
|
167
|
+
align-items: center;
|
|
168
|
+
padding: 6px 12px;
|
|
169
|
+
border-radius: 6px;
|
|
170
|
+
font-size: 12px;
|
|
171
|
+
font-weight: 500;
|
|
172
|
+
letter-spacing: 0.02em;
|
|
173
|
+
animation: fadeIn 0.3s ease-out;
|
|
174
|
+
transition: all 0.2s ease;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.payment-status-badge:hover {
|
|
178
|
+
transform: scale(1.05);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* ===== Loading States ===== */
|
|
182
|
+
.payment-loading {
|
|
183
|
+
position: relative;
|
|
184
|
+
overflow: hidden;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.payment-loading::after {
|
|
188
|
+
content: '';
|
|
189
|
+
position: absolute;
|
|
190
|
+
top: 0;
|
|
191
|
+
left: -100%;
|
|
192
|
+
width: 100%;
|
|
193
|
+
height: 100%;
|
|
194
|
+
background: linear-gradient(90deg,
|
|
195
|
+
transparent,
|
|
196
|
+
rgba(255, 255, 255, 0.4),
|
|
197
|
+
transparent);
|
|
198
|
+
animation: shimmer 1.5s infinite;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* ===== Alert/Notification Styles ===== */
|
|
202
|
+
.payment-alert {
|
|
203
|
+
animation: slideIn 0.3s ease-out;
|
|
204
|
+
transition: all 0.2s ease;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.payment-alert:hover {
|
|
208
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* ===== Result Card Styles ===== */
|
|
212
|
+
.payment-result-card {
|
|
213
|
+
animation: fadeIn 0.5s ease-out;
|
|
214
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.payment-result-card:hover {
|
|
218
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
219
|
+
transform: translateY(-2px);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* ===== Transaction Item Styles ===== */
|
|
223
|
+
.payment-transaction-item {
|
|
224
|
+
margin-bottom: 12px;
|
|
225
|
+
animation: fadeIn 0.4s ease-out;
|
|
226
|
+
cursor: pointer;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.payment-transaction-item:hover {
|
|
230
|
+
box-shadow: 0 4px 12px rgba(73, 69, 255, 0.1);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* ===== Typography Styles ===== */
|
|
234
|
+
.payment-title {
|
|
235
|
+
font-size: 24px;
|
|
236
|
+
font-weight: 700;
|
|
237
|
+
letter-spacing: -0.02em;
|
|
238
|
+
margin-bottom: 8px;
|
|
239
|
+
animation: fadeIn 0.4s ease-out;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.payment-subtitle {
|
|
243
|
+
font-size: 15px;
|
|
244
|
+
line-height: 1.6;
|
|
245
|
+
animation: fadeIn 0.5s ease-out;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.payment-section-title {
|
|
249
|
+
font-size: 16px;
|
|
250
|
+
font-weight: 600;
|
|
251
|
+
margin-bottom: 4px;
|
|
252
|
+
letter-spacing: -0.01em;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* ===== Grid & Layout ===== */
|
|
256
|
+
.payment-grid {
|
|
257
|
+
display: grid;
|
|
258
|
+
gap: 20px;
|
|
259
|
+
animation: fadeIn 0.5s ease-out;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.payment-grid-2 {
|
|
263
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.payment-grid-3 {
|
|
267
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* ===== Smooth Transitions ===== */
|
|
271
|
+
|
|
272
|
+
/* ===== Focus States ===== */
|
|
273
|
+
.payment-focus:focus-visible {
|
|
274
|
+
outline: 2px solid #4945ff;
|
|
275
|
+
outline-offset: 2px;
|
|
276
|
+
border-radius: 6px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* ===== Responsive ===== */
|
|
280
|
+
@media (max-width: 768px) {
|
|
281
|
+
.payment-container {
|
|
282
|
+
border-radius: 12px;
|
|
283
|
+
padding: 16px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.payment-form-section {
|
|
287
|
+
padding: 16px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.payment-grid-2,
|
|
291
|
+
.payment-grid-3 {
|
|
292
|
+
grid-template-columns: 1fr;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default payment data for testing
|
|
3
|
+
* Used across all payment operations
|
|
4
|
+
*
|
|
5
|
+
* Note: successurl, errorurl, and backurl are only required for:
|
|
6
|
+
* - 3D Secure enabled credit card payments
|
|
7
|
+
* - Redirect-based payment methods (PayPal, Google Pay, Apple Pay, Sofort)
|
|
8
|
+
*
|
|
9
|
+
* For non-redirect payments (3DS disabled credit card, SEPA), these URLs are optional
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_PAYMENT_DATA = {
|
|
12
|
+
firstname: "John",
|
|
13
|
+
lastname: "Doe",
|
|
14
|
+
street: "Test Street 123",
|
|
15
|
+
zip: "12345",
|
|
16
|
+
city: "Test City",
|
|
17
|
+
country: "DE",
|
|
18
|
+
email: "test@example.com",
|
|
19
|
+
salutation: "Herr",
|
|
20
|
+
gender: "m",
|
|
21
|
+
telephonenumber: "01752345678",
|
|
22
|
+
ip: "127.0.0.1",
|
|
23
|
+
customer_is_present: "yes",
|
|
24
|
+
language: "de"
|
|
25
|
+
// Note: successurl, errorurl, backurl are added conditionally based on 3DS setting
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Default currency
|
|
30
|
+
*/
|
|
31
|
+
export const DEFAULT_CURRENCY = "EUR";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Default page size for pagination
|
|
35
|
+
*/
|
|
36
|
+
export const DEFAULT_PAGE_SIZE = 10;
|
|
37
|
+
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
import { useNotification } from "@strapi/helper-plugin";
|
|
3
|
+
import payoneRequests from "../utils/api";
|
|
4
|
+
import {
|
|
5
|
+
getPreauthorizationParams,
|
|
6
|
+
getAuthorizationParams,
|
|
7
|
+
getCaptureParams,
|
|
8
|
+
getRefundParams
|
|
9
|
+
} from "../utils/paymentUtils";
|
|
10
|
+
import { DEFAULT_PAYMENT_DATA } from "../constants/paymentConstants";
|
|
11
|
+
|
|
12
|
+
const usePaymentActions = () => {
|
|
13
|
+
const toggleNotification = useNotification();
|
|
14
|
+
|
|
15
|
+
// Load settings to get enable3DSecure value
|
|
16
|
+
const [settings, setSettings] = useState({ enable3DSecure: false });
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const loadSettings = async () => {
|
|
20
|
+
try {
|
|
21
|
+
const response = await payoneRequests.getSettings();
|
|
22
|
+
if (response?.data) {
|
|
23
|
+
setSettings(response.data);
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
// Silent fail
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
loadSettings();
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
// Payment form state
|
|
33
|
+
const [paymentAmount, setPaymentAmount] = useState("1000");
|
|
34
|
+
const [preauthReference, setPreauthReference] = useState("");
|
|
35
|
+
const [authReference, setAuthReference] = useState("");
|
|
36
|
+
const [captureTxid, setCaptureTxid] = useState("");
|
|
37
|
+
const [refundTxid, setRefundTxid] = useState("");
|
|
38
|
+
const [refundSequenceNumber, setRefundSequenceNumber] = useState("2");
|
|
39
|
+
const [refundReference, setRefundReference] = useState("");
|
|
40
|
+
const [paymentMethod, setPaymentMethod] = useState("cc");
|
|
41
|
+
const [captureMode, setCaptureMode] = useState("full");
|
|
42
|
+
const [googlePayToken, setGooglePayToken] = useState(null);
|
|
43
|
+
|
|
44
|
+
// Payment processing state
|
|
45
|
+
const [isProcessingPayment, setIsProcessingPayment] = useState(false);
|
|
46
|
+
const [paymentResult, setPaymentResult] = useState(null);
|
|
47
|
+
const [paymentError, setPaymentError] = useState(null);
|
|
48
|
+
|
|
49
|
+
const handlePaymentError = (error, defaultMessage) => {
|
|
50
|
+
const errorMessage =
|
|
51
|
+
error.response?.data?.data?.Error?.ErrorMessage ||
|
|
52
|
+
error.message ||
|
|
53
|
+
defaultMessage;
|
|
54
|
+
setPaymentError(errorMessage);
|
|
55
|
+
toggleNotification({
|
|
56
|
+
type: "warning",
|
|
57
|
+
message: defaultMessage
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const handlePaymentSuccess = (message) => {
|
|
62
|
+
toggleNotification({
|
|
63
|
+
type: "success",
|
|
64
|
+
message
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const handlePreauthorization = async (tokenParam = null) => {
|
|
69
|
+
setIsProcessingPayment(true);
|
|
70
|
+
setPaymentError(null);
|
|
71
|
+
setPaymentResult(null);
|
|
72
|
+
try {
|
|
73
|
+
const baseParams = {
|
|
74
|
+
amount: parseInt(paymentAmount),
|
|
75
|
+
currency: "EUR",
|
|
76
|
+
reference: preauthReference || `PREAUTH-${Date.now()}`,
|
|
77
|
+
enable3DSecure: settings.enable3DSecure !== false,
|
|
78
|
+
...DEFAULT_PAYMENT_DATA
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const needsRedirectUrls =
|
|
82
|
+
(paymentMethod === "cc" && settings.enable3DSecure !== false) ||
|
|
83
|
+
["wlt", "gpp", "apl", "sb"].includes(paymentMethod);
|
|
84
|
+
|
|
85
|
+
if (needsRedirectUrls) {
|
|
86
|
+
const baseUrl = window.location.origin;
|
|
87
|
+
baseParams.successurl = `${baseUrl}/admin/plugins/strapi-plugin-payone-provider/payment/success`;
|
|
88
|
+
baseParams.errorurl = `${baseUrl}/admin/plugins/strapi-plugin-payone-provider/payment/error`;
|
|
89
|
+
baseParams.backurl = `${baseUrl}/admin/plugins/strapi-plugin-payone-provider/payment/back`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const tokenToUse = tokenParam || googlePayToken;
|
|
93
|
+
if (paymentMethod === "gpp" && tokenToUse) {
|
|
94
|
+
baseParams.googlePayToken = tokenToUse;
|
|
95
|
+
baseParams.settings = settings;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const params = getPreauthorizationParams(paymentMethod, baseParams);
|
|
99
|
+
|
|
100
|
+
const result = await payoneRequests.preauthorization(params);
|
|
101
|
+
const responseData = result?.data || result;
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
const redirectUrl = responseData.redirectUrl || responseData.redirecturl || responseData.RedirectUrl;
|
|
105
|
+
const needsRedirect = responseData.requires3DSRedirect ||
|
|
106
|
+
(responseData.status === "REDIRECT" && redirectUrl) ||
|
|
107
|
+
(responseData.Status === "REDIRECT" && redirectUrl);
|
|
108
|
+
|
|
109
|
+
if (needsRedirect && redirectUrl) {
|
|
110
|
+
window.location.href = redirectUrl;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
setPaymentResult(responseData);
|
|
115
|
+
handlePaymentSuccess("Preauthorization completed successfully");
|
|
116
|
+
} catch (error) {
|
|
117
|
+
handlePaymentError(error, "Preauthorization failed");
|
|
118
|
+
} finally {
|
|
119
|
+
setIsProcessingPayment(false);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const handleAuthorization = async (tokenParam = null) => {
|
|
124
|
+
setIsProcessingPayment(true);
|
|
125
|
+
setPaymentError(null);
|
|
126
|
+
setPaymentResult(null);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const baseParams = {
|
|
130
|
+
amount: parseInt(paymentAmount),
|
|
131
|
+
currency: "EUR",
|
|
132
|
+
reference: authReference || `AUTH-${Date.now()}`,
|
|
133
|
+
enable3DSecure: settings.enable3DSecure !== false,
|
|
134
|
+
...DEFAULT_PAYMENT_DATA
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const needsRedirectUrls =
|
|
138
|
+
(paymentMethod === "cc" && settings.enable3DSecure !== false) ||
|
|
139
|
+
["wlt", "gpp", "apl", "sb"].includes(paymentMethod);
|
|
140
|
+
|
|
141
|
+
if (needsRedirectUrls) {
|
|
142
|
+
const baseUrl = window.location.origin;
|
|
143
|
+
baseParams.successurl = `${baseUrl}/admin/plugins/strapi-plugin-payone-provider/payment/success`;
|
|
144
|
+
baseParams.errorurl = `${baseUrl}/admin/plugins/strapi-plugin-payone-provider/payment/error`;
|
|
145
|
+
baseParams.backurl = `${baseUrl}/admin/plugins/strapi-plugin-payone-provider/payment/back`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const tokenToUse = tokenParam || googlePayToken;
|
|
149
|
+
if (paymentMethod === "gpp" && tokenToUse) {
|
|
150
|
+
baseParams.googlePayToken = tokenToUse;
|
|
151
|
+
baseParams.settings = settings;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const params = getAuthorizationParams(paymentMethod, baseParams);
|
|
155
|
+
|
|
156
|
+
const result = await payoneRequests.authorization(params);
|
|
157
|
+
const responseData = result?.data || result;
|
|
158
|
+
|
|
159
|
+
const redirectUrl = responseData.redirectUrl || responseData.redirecturl || responseData.RedirectUrl;
|
|
160
|
+
const needsRedirect = responseData.requires3DSRedirect ||
|
|
161
|
+
(responseData.status === "REDIRECT" && redirectUrl) ||
|
|
162
|
+
(responseData.Status === "REDIRECT" && redirectUrl);
|
|
163
|
+
|
|
164
|
+
if (needsRedirect && redirectUrl) {
|
|
165
|
+
window.location.href = redirectUrl;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setPaymentResult(responseData);
|
|
170
|
+
handlePaymentSuccess("Authorization completed successfully");
|
|
171
|
+
} catch (error) {
|
|
172
|
+
handlePaymentError(error, "Authorization failed");
|
|
173
|
+
} finally {
|
|
174
|
+
setIsProcessingPayment(false);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const handleCapture = async () => {
|
|
179
|
+
if (!captureTxid.trim()) {
|
|
180
|
+
setPaymentError("Transaction ID is required for capture");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
setIsProcessingPayment(true);
|
|
184
|
+
setPaymentError(null);
|
|
185
|
+
setPaymentResult(null);
|
|
186
|
+
try {
|
|
187
|
+
const params = getCaptureParams(paymentMethod, {
|
|
188
|
+
txid: captureTxid,
|
|
189
|
+
amount: parseInt(paymentAmount),
|
|
190
|
+
currency: "EUR",
|
|
191
|
+
captureMode: captureMode,
|
|
192
|
+
sequencenumber: 1
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const result = await payoneRequests.capture(params);
|
|
196
|
+
setPaymentResult(result);
|
|
197
|
+
handlePaymentSuccess("Capture completed successfully");
|
|
198
|
+
} catch (error) {
|
|
199
|
+
handlePaymentError(error, "Capture failed");
|
|
200
|
+
} finally {
|
|
201
|
+
setIsProcessingPayment(false);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const handleRefund = async () => {
|
|
206
|
+
if (!refundTxid.trim()) {
|
|
207
|
+
setPaymentError("Transaction ID is required for refund");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
setIsProcessingPayment(true);
|
|
211
|
+
setPaymentError(null);
|
|
212
|
+
setPaymentResult(null);
|
|
213
|
+
try {
|
|
214
|
+
const params = getRefundParams(paymentMethod, {
|
|
215
|
+
txid: refundTxid,
|
|
216
|
+
sequencenumber: parseInt(refundSequenceNumber),
|
|
217
|
+
amount: parseInt(paymentAmount),
|
|
218
|
+
currency: "EUR",
|
|
219
|
+
reference: refundReference || `REFUND-${Date.now()}`
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const result = await payoneRequests.refund(params);
|
|
223
|
+
setPaymentResult(result);
|
|
224
|
+
handlePaymentSuccess("Refund completed successfully");
|
|
225
|
+
} catch (error) {
|
|
226
|
+
handlePaymentError(error, "Refund failed");
|
|
227
|
+
} finally {
|
|
228
|
+
setIsProcessingPayment(false);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
// Form state
|
|
234
|
+
paymentAmount,
|
|
235
|
+
setPaymentAmount,
|
|
236
|
+
preauthReference,
|
|
237
|
+
setPreauthReference,
|
|
238
|
+
authReference,
|
|
239
|
+
setAuthReference,
|
|
240
|
+
captureTxid,
|
|
241
|
+
setCaptureTxid,
|
|
242
|
+
refundTxid,
|
|
243
|
+
setRefundTxid,
|
|
244
|
+
refundSequenceNumber,
|
|
245
|
+
setRefundSequenceNumber,
|
|
246
|
+
refundReference,
|
|
247
|
+
setRefundReference,
|
|
248
|
+
paymentMethod,
|
|
249
|
+
setPaymentMethod,
|
|
250
|
+
captureMode,
|
|
251
|
+
setCaptureMode,
|
|
252
|
+
|
|
253
|
+
// Processing state
|
|
254
|
+
isProcessingPayment,
|
|
255
|
+
paymentResult,
|
|
256
|
+
paymentError,
|
|
257
|
+
|
|
258
|
+
// Handlers
|
|
259
|
+
handlePreauthorization,
|
|
260
|
+
handleAuthorization,
|
|
261
|
+
handleCapture,
|
|
262
|
+
handleRefund,
|
|
263
|
+
|
|
264
|
+
// Google Pay
|
|
265
|
+
googlePayToken,
|
|
266
|
+
setGooglePayToken
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export default usePaymentActions;
|
|
271
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
import { useNotification } from "@strapi/helper-plugin";
|
|
3
|
+
import payoneRequests from "../utils/api";
|
|
4
|
+
|
|
5
|
+
const useSettings = () => {
|
|
6
|
+
const toggleNotification = useNotification();
|
|
7
|
+
const [settings, setSettings] = useState({
|
|
8
|
+
aid: "",
|
|
9
|
+
portalid: "",
|
|
10
|
+
mid: "",
|
|
11
|
+
key: "",
|
|
12
|
+
mode: "test",
|
|
13
|
+
api_version: "3.10",
|
|
14
|
+
enable3DSecure: false
|
|
15
|
+
});
|
|
16
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
17
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
18
|
+
const [isTesting, setIsTesting] = useState(false);
|
|
19
|
+
const [testResult, setTestResult] = useState(null);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
loadSettings();
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
const loadSettings = async () => {
|
|
26
|
+
setIsLoading(true);
|
|
27
|
+
try {
|
|
28
|
+
const response = await payoneRequests.getSettings();
|
|
29
|
+
if (response?.data) setSettings(response.data);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
toggleNotification({
|
|
32
|
+
type: "warning",
|
|
33
|
+
message: "Failed to load settings"
|
|
34
|
+
});
|
|
35
|
+
} finally {
|
|
36
|
+
setIsLoading(false);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const handleInputChange = (field, value) => {
|
|
41
|
+
setSettings((prev) => ({ ...prev, [field]: value }));
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleSave = async () => {
|
|
45
|
+
setIsSaving(true);
|
|
46
|
+
try {
|
|
47
|
+
await payoneRequests.updateSettings(settings);
|
|
48
|
+
toggleNotification({
|
|
49
|
+
type: "success",
|
|
50
|
+
message: "Settings saved successfully"
|
|
51
|
+
});
|
|
52
|
+
} catch (error) {
|
|
53
|
+
toggleNotification({
|
|
54
|
+
type: "warning",
|
|
55
|
+
message: "Failed to save settings"
|
|
56
|
+
});
|
|
57
|
+
} finally {
|
|
58
|
+
setIsSaving(false);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleTestConnection = async () => {
|
|
63
|
+
setIsTesting(true);
|
|
64
|
+
setTestResult(null);
|
|
65
|
+
try {
|
|
66
|
+
const response = await payoneRequests.testConnection();
|
|
67
|
+
if (response.data) {
|
|
68
|
+
const result = response.data;
|
|
69
|
+
setTestResult(result);
|
|
70
|
+
if (result.success !== undefined) {
|
|
71
|
+
toggleNotification({
|
|
72
|
+
type: Boolean(result.success) ? "success" : "warning",
|
|
73
|
+
message: result.message || "Test completed"
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
throw new Error("Invalid response format from server");
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
toggleNotification({
|
|
81
|
+
type: "warning",
|
|
82
|
+
message: "Failed to test connection"
|
|
83
|
+
});
|
|
84
|
+
setTestResult({
|
|
85
|
+
success: false,
|
|
86
|
+
message:
|
|
87
|
+
"Failed to test connection. Please check your network and server logs for details.",
|
|
88
|
+
details: {
|
|
89
|
+
errorCode: "NETWORK",
|
|
90
|
+
rawResponse: error.message || "Network error"
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
} finally {
|
|
94
|
+
setIsTesting(false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
settings,
|
|
100
|
+
isLoading,
|
|
101
|
+
isSaving,
|
|
102
|
+
isTesting,
|
|
103
|
+
testResult,
|
|
104
|
+
handleInputChange,
|
|
105
|
+
handleSave,
|
|
106
|
+
handleTestConnection
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export default useSettings;
|
|
111
|
+
|