strapi-plugin-payone-provider 1.1.3 → 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 +1041 -377
  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
@@ -0,0 +1,93 @@
1
+ import React from "react";
2
+ import { Box, Flex, Typography, TextInput, Button } from "@strapi/design-system";
3
+ import { Play } from "@strapi/icons";
4
+ import GooglePayButton from "../GooglePaybutton";
5
+
6
+ const AuthorizationForm = ({
7
+ paymentAmount,
8
+ setPaymentAmount,
9
+ authReference,
10
+ setAuthReference,
11
+ isProcessingPayment,
12
+ onAuthorization,
13
+ paymentMethod,
14
+ settings,
15
+ googlePayToken,
16
+ setGooglePayToken
17
+ }) => {
18
+ const handleGooglePayToken = (token, paymentData) => {
19
+ if (!token) {
20
+ return;
21
+ }
22
+ setGooglePayToken(token);
23
+ onAuthorization(token);
24
+ };
25
+
26
+ const handleGooglePayError = (error) => {
27
+ if (onError) {
28
+ onError(error);
29
+ }
30
+ };
31
+ return (
32
+ <Flex direction="column" alignItems="stretch" gap={4}>
33
+ <Flex direction="row" gap={2}>
34
+ <Typography variant="omega" fontWeight="semiBold" textColor="neutral800" className="payment-form-title">
35
+ Authorization
36
+ </Typography>
37
+ <Typography variant="pi" textColor="neutral600" className="payment-form-description">
38
+ Authorize and capture an amount immediately.
39
+ </Typography>
40
+ </Flex>
41
+
42
+ <Flex gap={4} wrap="wrap">
43
+ <TextInput
44
+ label="Amount (in cents) *"
45
+ name="authAmount"
46
+ value={paymentAmount}
47
+ onChange={(e) => setPaymentAmount(e.target.value)}
48
+ placeholder="Enter amount (e.g., 1000 for €10.00)"
49
+ hint="Amount in cents (e.g., 1000 = €10.00)"
50
+ required
51
+ className="payment-input"
52
+ style={{ flex: 1, minWidth: "250px" }}
53
+ />
54
+
55
+ <TextInput
56
+ label="Reference *"
57
+ name="authReference"
58
+ value={authReference}
59
+ onChange={(e) => setAuthReference(e.target.value)}
60
+ placeholder="Enter reference"
61
+ hint="Reference for this transaction"
62
+ required
63
+ className="payment-input"
64
+ style={{ flex: 1, minWidth: "250px" }}
65
+ />
66
+ </Flex>
67
+
68
+ {paymentMethod === "gpp" ? (
69
+ <GooglePayButton
70
+ amount={paymentAmount}
71
+ currency="EUR"
72
+ onTokenReceived={handleGooglePayToken}
73
+ onError={handleGooglePayError}
74
+ settings={settings}
75
+ />
76
+ ) : (
77
+ <Button
78
+ variant="default"
79
+ onClick={onAuthorization}
80
+ loading={isProcessingPayment}
81
+ startIcon={<Play />}
82
+ className="payment-button payment-button-primary"
83
+ disabled={!paymentAmount.trim() || !authReference.trim()}
84
+ >
85
+ Process Authorization
86
+ </Button>
87
+ )}
88
+ </Flex>
89
+ );
90
+ };
91
+
92
+ export default AuthorizationForm;
93
+
@@ -0,0 +1,64 @@
1
+ import React from "react";
2
+ import { Box, Flex, Typography, TextInput, Button } from "@strapi/design-system";
3
+ import { Play } from "@strapi/icons";
4
+
5
+ const CaptureForm = ({
6
+ paymentAmount,
7
+ setPaymentAmount,
8
+ captureTxid,
9
+ setCaptureTxid,
10
+ isProcessingPayment,
11
+ onCapture
12
+ }) => {
13
+ return (
14
+ <Flex direction="column" alignItems="stretch" gap={4}>
15
+ <Flex direction="row" gap={2}>
16
+ <Typography variant="omega" fontWeight="semiBold" textColor="neutral800" className="payment-form-title">
17
+ Capture
18
+ </Typography>
19
+ <Typography variant="pi" textColor="neutral600" className="payment-form-description">
20
+ Capture a previously authorized amount. Note: Reference parameter is
21
+ not supported by Payone capture.
22
+ </Typography>
23
+ </Flex>
24
+
25
+ <Flex gap={4} wrap="wrap">
26
+ <TextInput
27
+ label="Transaction ID"
28
+ name="captureTxid"
29
+ value={captureTxid}
30
+ onChange={(e) => setCaptureTxid(e.target.value)}
31
+ placeholder="Enter TxId from preauthorization"
32
+ hint="Transaction ID from a previous preauthorization"
33
+ className="payment-input"
34
+ style={{ flex: 1, minWidth: "250px" }}
35
+ />
36
+
37
+ <TextInput
38
+ label="Amount (in cents)"
39
+ name="captureAmount"
40
+ value={paymentAmount}
41
+ onChange={(e) => setPaymentAmount(e.target.value)}
42
+ placeholder="1000"
43
+ hint="Amount in cents to capture"
44
+ className="payment-input"
45
+ style={{ flex: 1, minWidth: "250px" }}
46
+ />
47
+ </Flex>
48
+
49
+ <Button
50
+ variant="default"
51
+ onClick={onCapture}
52
+ loading={isProcessingPayment}
53
+ startIcon={<Play />}
54
+ className="payment-button payment-button-primary"
55
+ disabled={!captureTxid.trim() || !paymentAmount.trim()}
56
+ >
57
+ Process Capture
58
+ </Button>
59
+ </Flex>
60
+ );
61
+ };
62
+
63
+ export default CaptureForm;
64
+
@@ -0,0 +1,52 @@
1
+ import React from "react";
2
+ import { Box, Flex, Select, Option } from "@strapi/design-system";
3
+ import {
4
+ getPaymentMethodOptions,
5
+ supportsCaptureMode,
6
+ getCaptureModeOptions,
7
+ getPaymentMethodDisplayName
8
+ } from "../../../utils/paymentUtils";
9
+
10
+ const PaymentMethodSelector = ({
11
+ paymentMethod,
12
+ setPaymentMethod,
13
+ captureMode,
14
+ setCaptureMode
15
+ }) => {
16
+ return (
17
+ <Box>
18
+ <Flex direction="column" alignItems="stretch" gap={4}>
19
+ <Select
20
+ label="Select Payment Method"
21
+ name="paymentMethod"
22
+ value={paymentMethod}
23
+ onChange={(value) => setPaymentMethod(value)}
24
+ hint={`Current: ${getPaymentMethodDisplayName(paymentMethod)}`}
25
+ >
26
+ {getPaymentMethodOptions().map((option) => (
27
+ <Option key={option.value} value={option.value}>
28
+ {option.label}
29
+ </Option>
30
+ ))}
31
+ </Select>
32
+ {supportsCaptureMode(paymentMethod) && (
33
+ <Select
34
+ label="Capture Mode"
35
+ name="captureMode"
36
+ value={captureMode}
37
+ onChange={(value) => setCaptureMode(value)}
38
+ hint="Select capture mode for wallet payments"
39
+ >
40
+ {getCaptureModeOptions().map((option) => (
41
+ <Option key={option.value} value={option.value}>
42
+ {option.label}
43
+ </Option>
44
+ ))}
45
+ </Select>
46
+ )}
47
+ </Flex>
48
+ </Box>
49
+ );
50
+ };
51
+
52
+ export default PaymentMethodSelector;
@@ -0,0 +1,85 @@
1
+ import React from "react";
2
+ import {
3
+ Box,
4
+ Card,
5
+ CardBody,
6
+ Divider,
7
+ Flex,
8
+ Stack,
9
+ Typography,
10
+ Alert
11
+ } from "@strapi/design-system";
12
+ import StatusBadge from "../StatusBadge";
13
+ import { formatTransactionData } from "../../../utils/formatTransactionData";
14
+
15
+ const PaymentResult = ({ paymentError, paymentResult }) => {
16
+ if (!paymentError && !paymentResult) {
17
+ return null;
18
+ }
19
+
20
+ return (
21
+ <>
22
+ {paymentError && (
23
+ <Alert
24
+ variant="danger"
25
+ title="Error"
26
+ className="payment-alert"
27
+ >
28
+ {paymentError}
29
+ </Alert>
30
+ )}
31
+
32
+ {paymentResult && (
33
+ <Card className="payment-result-card">
34
+ <CardBody>
35
+ <Stack spacing={4}>
36
+ <Flex justifyContent="space-between" alignItems="center">
37
+ <Typography variant="delta" as="h3" className="payment-section-title">
38
+ Payment Result
39
+ </Typography>
40
+ {paymentResult.Status && (
41
+ <StatusBadge status={paymentResult.Status} />
42
+ )}
43
+ </Flex>
44
+
45
+ <hr className="payment-divider" style={{ margin: '16px 0' }} />
46
+
47
+ <Box>
48
+ <Stack spacing={3}>
49
+ {formatTransactionData(paymentResult).map((item, index) => (
50
+ <Flex
51
+ key={index}
52
+ justifyContent="space-between"
53
+ alignItems="start"
54
+ style={{
55
+ padding: '8px 0',
56
+ borderBottom: index < formatTransactionData(paymentResult).length - 1 ? '1px solid #e8e8ea' : 'none'
57
+ }}
58
+ >
59
+ <Typography
60
+ variant="pi"
61
+ textColor="neutral600"
62
+ style={{ minWidth: "200px", fontWeight: '500' }}
63
+ >
64
+ {item.key}:
65
+ </Typography>
66
+ <Typography
67
+ variant="pi"
68
+ style={{ flex: 1, textAlign: "right", fontWeight: '400' }}
69
+ >
70
+ {item.value}
71
+ </Typography>
72
+ </Flex>
73
+ ))}
74
+ </Stack>
75
+ </Box>
76
+ </Stack>
77
+ </CardBody>
78
+ </Card>
79
+ )}
80
+ </>
81
+ );
82
+ };
83
+
84
+ export default PaymentResult;
85
+
@@ -0,0 +1,93 @@
1
+ import React from "react";
2
+ import { Box, Flex, Typography, TextInput, Button } from "@strapi/design-system";
3
+ import { Play } from "@strapi/icons";
4
+ import GooglePayButton from "../GooglePaybutton";
5
+
6
+ const PreauthorizationForm = ({
7
+ paymentAmount,
8
+ setPaymentAmount,
9
+ preauthReference,
10
+ setPreauthReference,
11
+ isProcessingPayment,
12
+ onPreauthorization,
13
+ paymentMethod,
14
+ settings,
15
+ googlePayToken,
16
+ setGooglePayToken
17
+ }) => {
18
+ const handleGooglePayToken = (token, paymentData) => {
19
+ if (!token) {
20
+ return;
21
+ }
22
+ setGooglePayToken(token);
23
+ onPreauthorization(token);
24
+ };
25
+
26
+ const handleGooglePayError = (error) => {
27
+ if (onError) {
28
+ onError(error);
29
+ }
30
+ };
31
+ return (
32
+ <Flex direction="column" alignItems="stretch" gap={4}>
33
+ <Flex direction="row" gap={2}>
34
+ <Typography variant="omega" fontWeight="semiBold" textColor="neutral800" className="payment-form-title">
35
+ Preauthorization
36
+ </Typography>
37
+ <Typography variant="pi" textColor="neutral600" className="payment-form-description">
38
+ Reserve an amount on a credit card without capturing it immediately.
39
+ </Typography>
40
+ </Flex>
41
+
42
+ <Flex gap={4} wrap="wrap">
43
+ <TextInput
44
+ label="Amount (in cents) *"
45
+ name="paymentAmount"
46
+ value={paymentAmount}
47
+ onChange={(e) => setPaymentAmount(e.target.value)}
48
+ placeholder="Enter amount (e.g., 1000 for €10.00)"
49
+ hint="Amount in cents (e.g., 1000 = €10.00)"
50
+ required
51
+ className="payment-input"
52
+ style={{ flex: 1, minWidth: "250px" }}
53
+ />
54
+
55
+ <TextInput
56
+ label="Reference *"
57
+ name="preauthReference"
58
+ value={preauthReference}
59
+ onChange={(e) => setPreauthReference(e.target.value)}
60
+ placeholder="Enter reference"
61
+ hint="Reference for this transaction"
62
+ required
63
+ className="payment-input"
64
+ style={{ flex: 1, minWidth: "250px" }}
65
+ />
66
+ </Flex>
67
+
68
+ {paymentMethod === "gpp" ? (
69
+ <GooglePayButton
70
+ amount={paymentAmount}
71
+ currency="EUR"
72
+ onTokenReceived={handleGooglePayToken}
73
+ onError={handleGooglePayError}
74
+ settings={settings}
75
+ />
76
+ ) : (
77
+ <Button
78
+ variant="default"
79
+ onClick={onPreauthorization}
80
+ loading={isProcessingPayment}
81
+ startIcon={<Play />}
82
+ className="payment-button payment-button-primary"
83
+ disabled={!paymentAmount.trim() || !preauthReference.trim()}
84
+ >
85
+ Process Preauthorization
86
+ </Button>
87
+ )}
88
+ </Flex>
89
+ );
90
+ };
91
+
92
+ export default PreauthorizationForm;
93
+
@@ -0,0 +1,89 @@
1
+ import React from "react";
2
+ import { Box, Flex, Typography, TextInput, Button } from "@strapi/design-system";
3
+ import { Play } from "@strapi/icons";
4
+
5
+ const RefundForm = ({
6
+ paymentAmount,
7
+ setPaymentAmount,
8
+ refundTxid,
9
+ setRefundTxid,
10
+ refundSequenceNumber,
11
+ setRefundSequenceNumber,
12
+ refundReference,
13
+ setRefundReference,
14
+ isProcessingPayment,
15
+ onRefund
16
+ }) => {
17
+ return (
18
+ <Flex direction="column" alignItems="stretch" gap={4}>
19
+ <Flex direction="row" gap={2}>
20
+ <Typography variant="omega" fontWeight="semiBold" textColor="neutral800" className="payment-form-title">
21
+ Refund
22
+ </Typography>
23
+ <Typography variant="pi" textColor="neutral600" className="payment-form-description">
24
+ Refund a previously captured amount.
25
+ </Typography>
26
+ </Flex>
27
+
28
+ <Flex gap={4} wrap="wrap">
29
+ <TextInput
30
+ label="Transaction ID"
31
+ name="refundTxid"
32
+ value={refundTxid}
33
+ onChange={(e) => setRefundTxid(e.target.value)}
34
+ placeholder="Enter TxId from capture"
35
+ hint="Transaction ID from a previous capture"
36
+ className="payment-input"
37
+ style={{ flex: 1, minWidth: "200px" }}
38
+ />
39
+
40
+ <TextInput
41
+ label="Sequence Number"
42
+ name="refundSequenceNumber"
43
+ value={refundSequenceNumber}
44
+ onChange={(e) => setRefundSequenceNumber(e.target.value)}
45
+ placeholder="2"
46
+ hint="Sequence number for this refund (1-127) and by default for first 2"
47
+ className="payment-input"
48
+ style={{ flex: 1, minWidth: "200px" }}
49
+ />
50
+
51
+ <TextInput
52
+ label="Amount (in cents)"
53
+ name="refundAmount"
54
+ value={paymentAmount}
55
+ onChange={(e) => setPaymentAmount(e.target.value)}
56
+ placeholder="1000"
57
+ hint="Amount in cents to refund (will be negative)"
58
+ className="payment-input"
59
+ style={{ flex: 1, minWidth: "200px" }}
60
+ />
61
+
62
+ <TextInput
63
+ label="Reference"
64
+ name="refundReference"
65
+ value={refundReference}
66
+ onChange={(e) => setRefundReference(e.target.value)}
67
+ placeholder="Optional reference"
68
+ hint="Optional reference for this refund"
69
+ className="payment-input"
70
+ style={{ flex: 1, minWidth: "200px" }}
71
+ />
72
+ </Flex>
73
+
74
+ <Button
75
+ variant="default"
76
+ onClick={onRefund}
77
+ loading={isProcessingPayment}
78
+ startIcon={<Play />}
79
+ className="payment-button payment-button-primary"
80
+ disabled={!refundTxid.trim() || !paymentAmount.trim()}
81
+ >
82
+ Process Refund
83
+ </Button>
84
+ </Flex>
85
+ );
86
+ };
87
+
88
+ export default RefundForm;
89
+