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.
Files changed (36) hide show
  1. package/README.md +1045 -330
  2. package/admin/src/index.js +4 -1
  3. package/admin/src/pages/App/components/AppHeader.js +37 -0
  4. package/admin/src/pages/App/components/AppTabs.js +126 -0
  5. package/admin/src/pages/App/components/ConfigurationPanel.js +34 -35
  6. package/admin/src/pages/App/components/GooglePaybutton.js +300 -0
  7. package/admin/src/pages/App/components/HistoryPanel.js +25 -38
  8. package/admin/src/pages/App/components/PaymentActionsPanel.js +95 -280
  9. package/admin/src/pages/App/components/TransactionHistoryItem.js +4 -1
  10. package/admin/src/pages/App/components/paymentActions/AuthorizationForm.js +93 -0
  11. package/admin/src/pages/App/components/paymentActions/CaptureForm.js +64 -0
  12. package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.js +52 -0
  13. package/admin/src/pages/App/components/paymentActions/PaymentResult.js +85 -0
  14. package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.js +93 -0
  15. package/admin/src/pages/App/components/paymentActions/RefundForm.js +89 -0
  16. package/admin/src/pages/App/index.js +41 -465
  17. package/admin/src/pages/App/styles.css +294 -0
  18. package/admin/src/pages/constants/paymentConstants.js +37 -0
  19. package/admin/src/pages/hooks/usePaymentActions.js +271 -0
  20. package/admin/src/pages/hooks/useSettings.js +111 -0
  21. package/admin/src/pages/hooks/useTransactionHistory.js +87 -0
  22. package/admin/src/pages/utils/api.js +10 -0
  23. package/admin/src/pages/utils/injectGooglePayScript.js +31 -0
  24. package/admin/src/pages/utils/paymentUtils.js +113 -13
  25. package/package.json +1 -1
  26. package/server/controllers/payone.js +71 -64
  27. package/server/routes/index.js +17 -0
  28. package/server/services/paymentService.js +214 -0
  29. package/server/services/payone.js +25 -648
  30. package/server/services/settingsService.js +59 -0
  31. package/server/services/testConnectionService.js +190 -0
  32. package/server/services/transactionService.js +114 -0
  33. package/server/utils/normalize.js +51 -0
  34. package/server/utils/paymentMethodParams.js +126 -0
  35. package/server/utils/requestBuilder.js +110 -0
  36. package/server/utils/responseParser.js +80 -0
@@ -1,478 +1,54 @@
1
- import React, { useState, useEffect } from "react";
2
- import { useNotification } from "@strapi/helper-plugin";
3
- import {
4
- Layout,
5
- HeaderLayout,
6
- ContentLayout,
7
- Box,
8
- Button,
9
- Tabs,
10
- Tab,
11
- TabGroup,
12
- TabPanels,
13
- TabPanel,
14
- Typography
15
- } from "@strapi/design-system";
16
- import { Check } from "@strapi/icons";
17
- import payoneRequests from "../utils/api";
18
- import ConfigurationPanel from "./components/ConfigurationPanel";
19
- import HistoryPanel from "./components/HistoryPanel";
20
- import PaymentActionsPanel from "./components/PaymentActionsPanel";
1
+ import React, { useState } from "react";
2
+ import { Layout, ContentLayout, Box } from "@strapi/design-system";
3
+ import useSettings from "../hooks/useSettings";
4
+ import useTransactionHistory from "../hooks/useTransactionHistory";
5
+ import usePaymentActions from "../hooks/usePaymentActions";
6
+ import AppHeader from "./components/AppHeader";
7
+ import AppTabs from "./components/AppTabs";
8
+ import "./styles.css";
21
9
 
22
10
  const App = () => {
23
- const toggleNotification = useNotification();
24
-
25
- const [settings, setSettings] = useState({
26
- aid: "",
27
- portalid: "",
28
- mid: "",
29
- key: "",
30
- mode: "test",
31
- api_version: "3.10"
32
- });
33
- const [isLoading, setIsLoading] = useState(false);
34
- const [isSaving, setIsSaving] = useState(false);
35
- const [isTesting, setIsTesting] = useState(false);
36
- const [testResult, setTestResult] = useState(null);
37
-
38
- // Transaction Management state
39
- const [transactionHistory, setTransactionHistory] = useState([]);
40
- const [isLoadingHistory, setIsLoadingHistory] = useState(false);
41
- const [selectedTransaction, setSelectedTransaction] = useState(null);
42
- const [filters, setFilters] = useState({
43
- status: "",
44
- request_type: "",
45
- txid: "",
46
- reference: "",
47
- date_from: "",
48
- date_to: ""
49
- });
50
-
51
- // Payment Actions state
52
- const [paymentAmount, setPaymentAmount] = useState("1000");
53
- const [preauthReference, setPreauthReference] = useState("");
54
- const [authReference, setAuthReference] = useState("");
55
- const [captureTxid, setCaptureTxid] = useState("");
56
- const [refundTxid, setRefundTxid] = useState("");
57
- const [refundSequenceNumber, setRefundSequenceNumber] = useState("2");
58
- const [refundReference, setRefundReference] = useState("");
59
- const [paymentMethod, setPaymentMethod] = useState("cc");
60
- const [captureMode, setCaptureMode] = useState("full"); // full, partial
61
-
62
-
63
- const [isProcessingPayment, setIsProcessingPayment] = useState(false);
64
- const [paymentResult, setPaymentResult] = useState(null);
65
- const [paymentError, setPaymentError] = useState(null);
66
11
  const [activeTab, setActiveTab] = useState(0);
67
12
 
68
- // Pagination state
69
- const [currentPage, setCurrentPage] = useState(1);
70
- const [pageSize] = useState(10);
71
-
72
- useEffect(() => {
73
- loadSettings();
74
- loadTransactionHistory();
75
- }, []);
76
-
77
- // Pagination calculations
78
- const totalPages = Math.ceil(transactionHistory.length / pageSize);
79
- const startIndex = (currentPage - 1) * pageSize;
80
- const endIndex = startIndex + pageSize;
81
- const paginatedTransactions = transactionHistory.slice(startIndex, endIndex);
82
-
83
- const handlePageChange = (page) => {
84
- setCurrentPage(page);
85
- setSelectedTransaction(null);
86
- };
87
-
88
- const loadSettings = async () => {
89
- setIsLoading(true);
90
- try {
91
- const response = await payoneRequests.getSettings();
92
- if (response?.data) setSettings(response.data);
93
- } catch (error) {
94
- toggleNotification({
95
- type: "warning",
96
- message: "Failed to load settings"
97
- });
98
- } finally {
99
- setIsLoading(false);
100
- }
101
- };
102
-
103
- const handleInputChange = (field, value) => {
104
- setSettings((prev) => ({ ...prev, [field]: value }));
105
- };
106
-
107
- const handleSave = async () => {
108
- setIsSaving(true);
109
- try {
110
- await payoneRequests.updateSettings(settings);
111
- toggleNotification({
112
- type: "success",
113
- message: "Settings saved successfully"
114
- });
115
- } catch (error) {
116
- toggleNotification({
117
- type: "warning",
118
- message: "Failed to save settings"
119
- });
120
- } finally {
121
- setIsSaving(false);
122
- }
123
- };
124
-
125
- const handleTestConnection = async () => {
126
- setIsTesting(true);
127
- setTestResult(null);
128
- try {
129
- const response = await payoneRequests.testConnection();
130
- if (response.data) {
131
- const result = response.data;
132
- setTestResult(result);
133
- if (result.success !== undefined) {
134
- toggleNotification({
135
- type: Boolean(result.success) ? "success" : "warning",
136
- message: result.message || "Test completed"
137
- });
138
- }
139
- } else {
140
- throw new Error("Invalid response format from server");
141
- }
142
- } catch (error) {
143
- toggleNotification({
144
- type: "warning",
145
- message: "Failed to test connection"
146
- });
147
- setTestResult({
148
- success: false,
149
- message:
150
- "Failed to test connection. Please check your network and server logs for details.",
151
- details: {
152
- errorCode: "NETWORK",
153
- rawResponse: error.message || "Network error"
154
- }
155
- });
156
- } finally {
157
- setIsTesting(false);
158
- }
159
- };
160
-
161
- const loadTransactionHistory = async () => {
162
- setIsLoadingHistory(true);
163
- try {
164
- const result = await payoneRequests.getTransactionHistory(filters);
165
- setTransactionHistory(result.data || []);
166
- setCurrentPage(1);
167
- } catch (error) {
168
- toggleNotification({
169
- type: "warning",
170
- message: "Failed to load transaction history"
171
- });
172
- } finally {
173
- setIsLoadingHistory(false);
174
- }
175
- };
176
-
177
- const handleFilterChange = (field, value) => {
178
- setFilters((prev) => ({ ...prev, [field]: value }));
179
- };
180
-
181
- const handleFilterApply = () => {
182
- loadTransactionHistory();
183
- };
184
-
185
- const handleTransactionSelect = (transaction) => {
186
- if (selectedTransaction?.id === transaction?.id) {
187
- setSelectedTransaction(null);
188
- } else {
189
- setSelectedTransaction(transaction);
190
- }
191
- };
192
-
193
- const handlePreauthorization = async () => {
194
- setIsProcessingPayment(true);
195
- setPaymentError(null);
196
- setPaymentResult(null);
197
- try {
198
- const params = {
199
- amount: parseInt(paymentAmount),
200
- currency: "EUR",
201
- reference: preauthReference || `PREAUTH-${Date.now()}`,
202
- clearingtype: "cc",
203
- cardtype: "V",
204
- cardpan: "4111111111111111",
205
- cardexpiredate: "2512",
206
- cardcvc2: "123",
207
- firstname: "John",
208
- lastname: "Doe",
209
- street: "Test Street 123",
210
- zip: "12345",
211
- city: "Test City",
212
- country: "DE",
213
- email: "test@example.com",
214
- salutation: "Herr",
215
- gender: "m",
216
- telephonenumber: "01752345678",
217
- ip: "127.0.0.1",
218
- customer_is_present: "yes",
219
- language: "de"
220
- };
221
- const result = await payoneRequests.preauthorization(params);
222
- setPaymentResult(result);
223
- toggleNotification({
224
- type: "success",
225
- message: "Preauthorization completed successfully"
226
- });
227
- } catch (error) {
228
- const errorMessage =
229
- error.response?.data?.data?.Error?.ErrorMessage ||
230
- error.message ||
231
- "Preauthorization failed";
232
- setPaymentError(errorMessage);
233
- toggleNotification({
234
- type: "warning",
235
- message: "Preauthorization failed"
236
- });
237
- } finally {
238
- setIsProcessingPayment(false);
239
- }
240
- };
241
-
242
- const handleAuthorization = async () => {
243
- setIsProcessingPayment(true);
244
- setPaymentError(null);
245
- setPaymentResult(null);
246
- try {
247
- const params = {
248
- amount: parseInt(paymentAmount),
249
- currency: "EUR",
250
- reference: authReference || `AUTH-${Date.now()}`,
251
- clearingtype: "cc",
252
- cardtype: "V",
253
- cardpan: "4111111111111111",
254
- cardexpiredate: "2512",
255
- cardcvc2: "123",
256
- firstname: "John",
257
- lastname: "Doe",
258
- street: "Test Street 123",
259
- zip: "12345",
260
- city: "Test City",
261
- country: "DE",
262
- email: "test@example.com",
263
- salutation: "Herr",
264
- gender: "m",
265
- telephonenumber: "01752345678",
266
- ip: "127.0.0.1",
267
- customer_is_present: "yes",
268
- language: "de"
269
- };
270
- const result = await payoneRequests.authorization(params);
271
- setPaymentResult(result);
272
- toggleNotification({
273
- type: "success",
274
- message: "Authorization completed successfully"
275
- });
276
- } catch (error) {
277
- const errorMessage =
278
- error.response?.data?.data?.Error?.ErrorMessage ||
279
- error.message ||
280
- "Authorization failed";
281
- setPaymentError(errorMessage);
282
- toggleNotification({ type: "warning", message: "Authorization failed" });
283
- } finally {
284
- setIsProcessingPayment(false);
285
- }
286
- };
287
-
288
- const handleCapture = async () => {
289
- if (!captureTxid.trim()) {
290
- setPaymentError("Transaction ID is required for capture");
291
- return;
292
- }
293
- setIsProcessingPayment(true);
294
- setPaymentError(null);
295
- setPaymentResult(null);
296
- try {
297
- const params = {
298
- txid: captureTxid,
299
- amount: parseInt(paymentAmount),
300
- currency: "EUR"
301
- };
302
- const result = await payoneRequests.capture(params);
303
- setPaymentResult(result);
304
- toggleNotification({
305
- type: "success",
306
- message: "Capture completed successfully"
307
- });
308
- } catch (error) {
309
- const errorMessage =
310
- error.response?.data?.data?.Error?.ErrorMessage ||
311
- error.message ||
312
- "Capture failed";
313
- setPaymentError(errorMessage);
314
- toggleNotification({ type: "warning", message: "Capture failed" });
315
- } finally {
316
- setIsProcessingPayment(false);
317
- }
318
- };
319
-
320
- const handleRefund = async () => {
321
- if (!refundTxid.trim()) {
322
- setPaymentError("Transaction ID is required for refund");
323
- return;
324
- }
325
- setIsProcessingPayment(true);
326
- setPaymentError(null);
327
- setPaymentResult(null);
328
- try {
329
- const params = {
330
- txid: refundTxid,
331
- sequencenumber: parseInt(refundSequenceNumber),
332
- amount: -Math.abs(parseInt(paymentAmount)),
333
- currency: "EUR",
334
- reference: refundReference || `REFUND-${Date.now()}`
335
- };
336
- const result = await payoneRequests.refund(params);
337
- setPaymentResult(result);
338
- toggleNotification({
339
- type: "success",
340
- message: "Refund completed successfully"
341
- });
342
- } catch (error) {
343
- const errorMessage =
344
- error.response?.data?.data?.Error?.ErrorMessage ||
345
- error.message ||
346
- "Refund failed";
347
- setPaymentError(errorMessage);
348
- toggleNotification({ type: "warning", message: "Refund failed" });
349
- } finally {
350
- setIsProcessingPayment(false);
351
- }
352
- };
13
+ // Custom hooks
14
+ const settings = useSettings();
15
+ const transactionHistory = useTransactionHistory();
16
+ const paymentActions = usePaymentActions();
353
17
 
354
18
  return (
355
19
  <Layout>
356
- <HeaderLayout
357
- title={
358
- <Box>
359
- <Typography variant="alpha" as="h1" fontWeight="bold">
360
- Payone Provider
361
- </Typography>
362
- <Typography variant="pi" marginTop={2}>
363
- Configure your Payone integration and manage payment transactions
364
- </Typography>
365
- </Box>
366
- }
367
- primaryAction={
368
- activeTab === 0 ? (
369
- <Button
370
- loading={isSaving}
371
- onClick={handleSave}
372
- startIcon={<Check />}
373
- size="L"
374
- variant="default"
375
- style={{
376
- background: "#28a745",
377
- border: "none",
378
- borderRadius: "8px",
379
- fontWeight: "600"
380
- }}
381
- >
382
- Save Configuration
383
- </Button>
384
- ) : null
385
- }
20
+ <AppHeader
21
+ activeTab={activeTab}
22
+ isSaving={settings.isSaving}
23
+ onSave={settings.handleSave}
386
24
  />
387
25
  <ContentLayout>
388
26
  <Box padding={6}>
389
- <TabGroup
390
- label="Payone Provider Tabs"
391
- onTabChange={(index) => setActiveTab(index)}
392
- >
393
- <Tabs style={{ borderBottom: "2px solid #f6f6f9" }}>
394
- <Tab
395
- style={{
396
- fontWeight: activeTab === 0 ? "600" : "400",
397
- color: activeTab === 0 ? "#4945ff" : "#666687"
398
- }}
399
- >
400
- Configuration
401
- </Tab>
402
- <Tab style={{ fontWeight: activeTab === 1 ? "600" : "400" }}>
403
- Transaction History
404
- </Tab>
405
- <Tab
406
- style={{
407
- fontWeight: activeTab === 2 ? "600" : "400",
408
- color: activeTab === 2 ? "#4945ff" : "#666687"
409
- }}
410
- >
411
- Payment Actions
412
- </Tab>
413
- </Tabs>
414
- <TabPanels>
415
- <TabPanel>
416
- <ConfigurationPanel
417
- settings={settings}
418
- isSaving={isSaving}
419
- isTesting={isTesting}
420
- testResult={testResult}
421
- onSave={handleSave}
422
- onTestConnection={handleTestConnection}
423
- onInputChange={handleInputChange}
424
- />
425
- </TabPanel>
426
-
427
- <TabPanel>
428
- <HistoryPanel
429
- filters={filters}
430
- onFilterChange={handleFilterChange}
431
- onFilterApply={handleFilterApply}
432
- isLoadingHistory={isLoadingHistory}
433
- transactionHistory={transactionHistory}
434
- paginatedTransactions={paginatedTransactions}
435
- currentPage={currentPage}
436
- totalPages={totalPages}
437
- pageSize={pageSize}
438
- onRefresh={loadTransactionHistory}
439
- onPageChange={handlePageChange}
440
- selectedTransaction={selectedTransaction}
441
- onTransactionSelect={handleTransactionSelect}
442
- />
443
- </TabPanel>
444
-
445
- <TabPanel>
446
- <PaymentActionsPanel
447
- paymentAmount={paymentAmount}
448
- setPaymentAmount={setPaymentAmount}
449
- preauthReference={preauthReference}
450
- setPreauthReference={setPreauthReference}
451
- authReference={authReference}
452
- setAuthReference={setAuthReference}
453
- captureTxid={captureTxid}
454
- setCaptureTxid={setCaptureTxid}
455
- setCaptureMode={setCaptureMode}
456
- captureMode={captureMode}
457
- paymentMethod={paymentMethod}
458
- setPaymentMethod={setPaymentMethod}
459
- refundTxid={refundTxid}
460
- setRefundTxid={setRefundTxid}
461
- refundSequenceNumber={refundSequenceNumber}
462
- setRefundSequenceNumber={setRefundSequenceNumber}
463
- refundReference={refundReference}
464
- setRefundReference={setRefundReference}
465
- isProcessingPayment={isProcessingPayment}
466
- paymentError={paymentError}
467
- paymentResult={paymentResult}
468
- onPreauthorization={handlePreauthorization}
469
- onAuthorization={handleAuthorization}
470
- onCapture={handleCapture}
471
- onRefund={handleRefund}
472
- />
473
- </TabPanel>
474
- </TabPanels>
475
- </TabGroup>
27
+ <AppTabs
28
+ activeTab={activeTab}
29
+ setActiveTab={setActiveTab}
30
+ settings={settings.settings}
31
+ isSaving={settings.isSaving}
32
+ isTesting={settings.isTesting}
33
+ testResult={settings.testResult}
34
+ onSave={settings.handleSave}
35
+ onTestConnection={settings.handleTestConnection}
36
+ onInputChange={settings.handleInputChange}
37
+ filters={transactionHistory.filters}
38
+ onFilterChange={transactionHistory.handleFilterChange}
39
+ onFilterApply={transactionHistory.handleFilterApply}
40
+ isLoadingHistory={transactionHistory.isLoadingHistory}
41
+ transactionHistory={transactionHistory.transactionHistory}
42
+ paginatedTransactions={transactionHistory.paginatedTransactions}
43
+ currentPage={transactionHistory.currentPage}
44
+ totalPages={transactionHistory.totalPages}
45
+ pageSize={transactionHistory.pageSize}
46
+ onRefresh={transactionHistory.loadTransactionHistory}
47
+ onPageChange={transactionHistory.handlePageChange}
48
+ selectedTransaction={transactionHistory.selectedTransaction}
49
+ onTransactionSelect={transactionHistory.handleTransactionSelect}
50
+ paymentActions={paymentActions}
51
+ />
476
52
  </Box>
477
53
  </ContentLayout>
478
54
  </Layout>