strapi-plugin-payone-provider 4.6.9 → 5.6.10
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 +156 -11
- package/admin/src/components/Initializer/index.jsx +3 -3
- package/admin/src/components/PluginIcon/index.jsx +3 -3
- package/admin/src/index.js +33 -11
- package/admin/src/pages/App/components/AppHeader.jsx +17 -32
- package/admin/src/pages/App/components/AppTabs.jsx +36 -162
- package/admin/src/pages/App/components/ApplePayBtn.jsx +9 -11
- package/admin/src/pages/App/components/ApplePayConfig.jsx +221 -161
- package/admin/src/pages/App/components/ApplePayConfigPanel.jsx +33 -45
- package/admin/src/pages/App/components/DocsPanel.jsx +66 -1726
- package/admin/src/pages/App/components/GooglePayConfig.jsx +136 -169
- package/admin/src/pages/App/components/GooglePayConfigPanel.jsx +37 -55
- package/admin/src/pages/App/components/GooglePaybutton.jsx +101 -43
- package/admin/src/pages/App/components/RenderInput.jsx +94 -0
- package/admin/src/pages/App/components/StatusBadge.jsx +24 -71
- package/admin/src/pages/App/components/configuration/ConfigurationFields.jsx +255 -0
- package/admin/src/pages/App/components/configuration/ConfigurationPanel.jsx +54 -0
- package/admin/src/pages/App/components/configuration/TestConnection.jsx +130 -0
- package/admin/src/pages/App/components/docs/ApplePaySection.jsx +260 -0
- package/admin/src/pages/App/components/docs/BaseUrlSection.jsx +53 -0
- package/admin/src/pages/App/components/docs/CaptureRefundSection.jsx +113 -0
- package/admin/src/pages/App/components/docs/CodeBlock.jsx +59 -0
- package/admin/src/pages/App/components/docs/CreditCardSection.jsx +93 -0
- package/admin/src/pages/App/components/docs/GooglePaySection.jsx +248 -0
- package/admin/src/pages/App/components/docs/PayPalSection.jsx +116 -0
- package/admin/src/pages/App/components/docs/PaymentMethodsSection.jsx +55 -0
- package/admin/src/pages/App/components/docs/TableOfContents.jsx +47 -0
- package/admin/src/pages/App/components/docs/TestCredentialsSection.jsx +304 -0
- package/admin/src/pages/App/components/docs/ThreeDSecureSection.jsx +188 -0
- package/admin/src/pages/App/components/icons/BankIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/ChevronDownIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/ChevronUpIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/CreditCardIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/ErrorIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/InfoIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/MarkCircle.jsx +19 -0
- package/admin/src/pages/App/components/icons/PaymentIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/PendingIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/PersonIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/SuccessIcon.jsx +1 -1
- package/admin/src/pages/App/components/icons/WalletIcon.jsx +1 -1
- package/admin/src/pages/App/components/payment-actions/ApplePayPanel.jsx +51 -0
- package/admin/src/pages/App/components/payment-actions/AuthorizationForm.jsx +341 -0
- package/admin/src/pages/App/components/payment-actions/CaptureForm.jsx +128 -0
- package/admin/src/pages/App/components/{paymentActions → payment-actions}/CardDetailsInput.jsx +77 -72
- package/admin/src/pages/App/components/payment-actions/PaymentActionsPanel.jsx +194 -0
- package/admin/src/pages/App/components/payment-actions/PaymentMethodSelector.jsx +313 -0
- package/admin/src/pages/App/components/payment-actions/PaymentResult.jsx +133 -0
- package/admin/src/pages/App/components/payment-actions/PreauthorizationForm.jsx +280 -0
- package/admin/src/pages/App/components/payment-actions/RefundForm.jsx +121 -0
- package/admin/src/pages/App/components/transaction-history/FiltersPanel.jsx +145 -0
- package/admin/src/pages/App/components/transaction-history/HistoryPanel.jsx +50 -0
- package/admin/src/pages/App/components/transaction-history/TransactionTable.jsx +163 -0
- package/admin/src/pages/App/components/transaction-history/details/TransactionDetails.jsx +156 -0
- package/admin/src/pages/App/components/{TransactionHistoryItem.jsx → transaction-history/details/TransactionHistoryItem.jsx} +16 -28
- package/admin/src/pages/App/index.jsx +27 -70
- package/admin/src/pages/App/styles.css +46 -169
- package/admin/src/pages/constants/paymentConstants.js +52 -16
- package/admin/src/pages/hooks/use-system-theme.js +27 -0
- package/admin/src/pages/hooks/usePaymentActions.js +273 -210
- package/admin/src/pages/hooks/useSettings.js +87 -48
- package/admin/src/pages/hooks/useTransactionHistory.js +105 -108
- package/admin/src/pages/utils/api.js +57 -72
- package/admin/src/pages/utils/applePayConstants.js +2 -28
- package/admin/src/pages/utils/countryLanguageUtils.js +280 -0
- package/admin/src/pages/utils/getInputComponent.jsx +225 -0
- package/admin/src/pages/utils/googlePayConstants.js +2 -9
- package/admin/src/pages/utils/paymentUtils.js +13 -26
- package/admin/src/pages/utils/tooltipHelpers.js +18 -0
- package/admin/src/pages/utils/transactionTableUtils.js +60 -0
- package/package.json +8 -14
- package/server/config/index.js +18 -2
- package/server/controllers/payone.js +98 -31
- package/server/policies/index.js +2 -1
- package/server/policies/is-auth.js +9 -3
- package/server/policies/is-payone-notification.js +31 -0
- package/server/policies/isSuperAdmin.js +7 -5
- package/server/routes/index.js +11 -0
- package/server/services/paymentService.js +6 -22
- package/server/services/payone.js +10 -3
- package/server/services/settingsService.js +13 -3
- package/server/services/testConnectionService.js +11 -73
- package/server/services/transactionService.js +62 -99
- package/server/services/transactionStatusService.js +87 -0
- package/server/utils/normalize.js +0 -12
- package/server/utils/paymentMethodParams.js +0 -1
- package/server/utils/requestBuilder.js +34 -5
- package/server/utils/responseParser.js +9 -14
- package/strapi-admin.js +3 -1
- package/admin/src/pages/App/components/ConfigurationPanel.jsx +0 -517
- package/admin/src/pages/App/components/CustomerInfoPopover.jsx +0 -147
- package/admin/src/pages/App/components/HistoryPanel.jsx +0 -94
- package/admin/src/pages/App/components/PaymentActionsPanel.jsx +0 -280
- package/admin/src/pages/App/components/RawDataPopover.jsx +0 -113
- package/admin/src/pages/App/components/TransactionHistoryTable/TransactionHistoryTableFilters.jsx +0 -113
- package/admin/src/pages/App/components/TransactionHistoryTable/TransactionHistoryTablePagination.jsx +0 -180
- package/admin/src/pages/App/components/TransactionHistoryTable/index.jsx +0 -225
- package/admin/src/pages/App/components/paymentActions/ApplePayPanel.jsx +0 -95
- package/admin/src/pages/App/components/paymentActions/AuthorizationForm.jsx +0 -197
- package/admin/src/pages/App/components/paymentActions/CaptureForm.jsx +0 -65
- package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.jsx +0 -306
- package/admin/src/pages/App/components/paymentActions/PaymentResult.jsx +0 -192
- package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.jsx +0 -142
- package/admin/src/pages/App/components/paymentActions/RefundForm.jsx +0 -90
|
@@ -51,13 +51,7 @@ const sendRequest = async (strapi, params) => {
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
const responseData = parseResponse(response.data, strapi.log);
|
|
54
|
-
const errorCode =
|
|
55
|
-
responseData.errorcode ||
|
|
56
|
-
responseData.ErrorCode ||
|
|
57
|
-
responseData.Error?.ErrorCode ||
|
|
58
|
-
responseData.error_code ||
|
|
59
|
-
null;
|
|
60
|
-
|
|
54
|
+
const errorCode = responseData?.Error?.ErrorCode;
|
|
61
55
|
const requires3DSErrorCodes = ["4219", 4219];
|
|
62
56
|
const is3DSRequiredError = requires3DSErrorCodes.includes(errorCode);
|
|
63
57
|
|
|
@@ -69,21 +63,11 @@ const sendRequest = async (strapi, params) => {
|
|
|
69
63
|
|
|
70
64
|
}
|
|
71
65
|
|
|
72
|
-
const errorMessage =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
null;
|
|
78
|
-
|
|
79
|
-
const customerMessage =
|
|
80
|
-
responseData.customermessage ||
|
|
81
|
-
responseData.CustomerMessage ||
|
|
82
|
-
responseData.Error?.CustomerMessage ||
|
|
83
|
-
responseData.customer_message ||
|
|
84
|
-
null;
|
|
85
|
-
|
|
86
|
-
const status = (responseData.status || responseData.Status || "unknown").toUpperCase();
|
|
66
|
+
const errorMessage = responseData?.Error?.ErrorMessage || null;
|
|
67
|
+
|
|
68
|
+
const customerMessage = responseData?.Error?.CustomerMessage || null;
|
|
69
|
+
|
|
70
|
+
const status = (responseData?.status || responseData?.Status || "unknown").toUpperCase() || null;
|
|
87
71
|
|
|
88
72
|
await logTransaction(strapi, {
|
|
89
73
|
txid: extractTxId(responseData) || params.txid || null,
|
|
@@ -5,6 +5,7 @@ const transactionService = require("./transactionService");
|
|
|
5
5
|
const paymentService = require("./paymentService");
|
|
6
6
|
const testConnectionService = require("./testConnectionService");
|
|
7
7
|
const applePayService = require("./applePayService");
|
|
8
|
+
const transactionStatusService = require("./transactionStatusService");
|
|
8
9
|
|
|
9
10
|
module.exports = ({ strapi }) => ({
|
|
10
11
|
// Settings
|
|
@@ -16,7 +17,6 @@ module.exports = ({ strapi }) => ({
|
|
|
16
17
|
return await settingsService.updateSettings(strapi, settings);
|
|
17
18
|
},
|
|
18
19
|
|
|
19
|
-
// Payment operations
|
|
20
20
|
async preauthorization(params) {
|
|
21
21
|
return await paymentService.preauthorization(strapi, params);
|
|
22
22
|
},
|
|
@@ -38,8 +38,9 @@ module.exports = ({ strapi }) => ({
|
|
|
38
38
|
return await transactionService.logTransaction(strapi, transactionData);
|
|
39
39
|
},
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
|
|
42
|
+
async getTransactionHistory({ filters = {}, pagination = {} }) {
|
|
43
|
+
return await transactionService.getTransactionHistory(strapi, { filters, pagination });
|
|
43
44
|
},
|
|
44
45
|
|
|
45
46
|
// Test connection
|
|
@@ -59,5 +60,11 @@ module.exports = ({ strapi }) => ({
|
|
|
59
60
|
|
|
60
61
|
async initializeApplePaySession(params) {
|
|
61
62
|
return await applePayService.initializeApplePaySession(strapi, params);
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// TransactionStatus Notification
|
|
66
|
+
async processTransactionStatus(notificationData) {
|
|
67
|
+
return await transactionStatusService.processTransactionStatus(strapi, notificationData);
|
|
62
68
|
}
|
|
69
|
+
|
|
63
70
|
});
|
|
@@ -12,16 +12,26 @@ const getPluginStore = (strapi) => {
|
|
|
12
12
|
|
|
13
13
|
const getSettings = async (strapi) => {
|
|
14
14
|
const pluginStore = getPluginStore(strapi);
|
|
15
|
-
|
|
15
|
+
const settings = await pluginStore.get({ key: "settings" }) || {};
|
|
16
|
+
|
|
17
|
+
return settings;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
const updateSettings = async (strapi, settings) => {
|
|
19
21
|
const pluginStore = getPluginStore(strapi);
|
|
22
|
+
const currentSettings = await getSettings(strapi) || {};
|
|
23
|
+
const mergedSettings = {
|
|
24
|
+
...currentSettings,
|
|
25
|
+
...settings
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
|
|
20
29
|
await pluginStore.set({
|
|
21
30
|
key: "settings",
|
|
22
|
-
value:
|
|
31
|
+
value: mergedSettings
|
|
23
32
|
});
|
|
24
|
-
|
|
33
|
+
|
|
34
|
+
return mergedSettings;
|
|
25
35
|
};
|
|
26
36
|
|
|
27
37
|
const validateSettings = (settings) => {
|
|
@@ -54,82 +54,19 @@ const testConnection = async (strapi) => {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
const result = parseResponse(response.data, strapi.log);
|
|
57
|
-
const status = result
|
|
58
|
-
const errorMessage =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
result.ERRORMESSAGE ||
|
|
62
|
-
result.error ||
|
|
63
|
-
result.Error?.ErrorMessage ||
|
|
64
|
-
"";
|
|
65
|
-
const errorCode =
|
|
66
|
-
result.errorcode ||
|
|
67
|
-
result.Errorcode ||
|
|
68
|
-
result.ERRORCODE ||
|
|
69
|
-
result.Error?.ErrorCode ||
|
|
70
|
-
"";
|
|
71
|
-
const customErrorMessage =
|
|
72
|
-
result.customerrormessage ||
|
|
73
|
-
result.Customerrormessage ||
|
|
74
|
-
result.CUSTOMERRORMESSAGE ||
|
|
75
|
-
result.Error?.CustomerMessage ||
|
|
76
|
-
"";
|
|
57
|
+
const status = result?.status || result?.Status || result?.STATUS;
|
|
58
|
+
const errorMessage = result?.Error?.ErrorMessage;
|
|
59
|
+
const errorCode = result?.Error?.ErrorCode;
|
|
60
|
+
const customErrorMessage = result?.Error?.CustomerMessage;
|
|
77
61
|
|
|
78
62
|
if (status === "ERROR" || status === "error") {
|
|
79
|
-
if (["2006", "920", "921", "922", "401", "403"].includes(errorCode)) {
|
|
80
|
-
return {
|
|
81
|
-
success: false,
|
|
82
|
-
message: `Authentication failed: ${customErrorMessage || errorMessage || "Invalid credentials"}`,
|
|
83
|
-
errorcode: errorCode
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const errorMessageStr = typeof errorMessage === "string" ? errorMessage : JSON.stringify(errorMessage);
|
|
88
|
-
const errorMessageLower = (errorMessageStr || "").toLowerCase();
|
|
89
|
-
const authErrorKeywords = [
|
|
90
|
-
"key incorrect",
|
|
91
|
-
"invalid key",
|
|
92
|
-
"portal key",
|
|
93
|
-
"unauthorized",
|
|
94
|
-
"not authorized",
|
|
95
|
-
"unknown aid",
|
|
96
|
-
"unknown account",
|
|
97
|
-
"unknown portal",
|
|
98
|
-
"unknown merchant",
|
|
99
|
-
"invalid aid",
|
|
100
|
-
"invalid mid",
|
|
101
|
-
"invalid portalid"
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
if (authErrorKeywords.some((keyword) => errorMessageLower.includes(keyword))) {
|
|
105
|
-
return {
|
|
106
|
-
success: false,
|
|
107
|
-
message: `Authentication failed: ${errorMessageStr}`,
|
|
108
|
-
errorcode: errorCode || "AUTH"
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (errorCode === "911") {
|
|
113
|
-
return {
|
|
114
|
-
success: true,
|
|
115
|
-
message: "Connection successful! Your Payone credentials are valid.",
|
|
116
|
-
details: {
|
|
117
|
-
mode: settings.mode,
|
|
118
|
-
aid: settings.aid,
|
|
119
|
-
portalid: settings.portalid,
|
|
120
|
-
mid: settings.mid
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
63
|
return {
|
|
126
64
|
success: false,
|
|
127
|
-
message: `
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
rawResponse: JSON.stringify(result).substring(0, 200)
|
|
65
|
+
message: `Test connection failed: ${errorCode}`,
|
|
66
|
+
error: {
|
|
67
|
+
ErrorCode: errorCode,
|
|
68
|
+
ErrorMessage: errorMessage,
|
|
69
|
+
CustomerMessage: customErrorMessage
|
|
133
70
|
}
|
|
134
71
|
};
|
|
135
72
|
}
|
|
@@ -157,11 +94,12 @@ const testConnection = async (strapi) => {
|
|
|
157
94
|
rawResponse: JSON.stringify(result).substring(0, 200)
|
|
158
95
|
}
|
|
159
96
|
};
|
|
97
|
+
|
|
160
98
|
} catch (error) {
|
|
161
99
|
strapi.log.error("Payone test connection error:", error);
|
|
162
100
|
return {
|
|
163
101
|
success: false,
|
|
164
|
-
message: `
|
|
102
|
+
message: `Test connection error: ${error.message || "Unknown error"}`,
|
|
165
103
|
error: error.toString(),
|
|
166
104
|
details: {
|
|
167
105
|
errorType: error.constructor.name,
|
|
@@ -2,20 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { getPluginStore } = require("./settingsService");
|
|
4
4
|
|
|
5
|
-
const sanitizeRawRequest = (rawRequest) => {
|
|
6
|
-
if (!rawRequest || typeof rawRequest !== "object") return rawRequest
|
|
7
|
-
const sanitized = { ...rawRequest };
|
|
8
|
-
const sensitiveFields = ["cardpan", "cardexpiredate", "cardcvc2"];
|
|
9
|
-
|
|
10
|
-
sensitiveFields.forEach((field) => {
|
|
11
|
-
if (sanitized[field] && typeof sanitized[field] === "string") {
|
|
12
|
-
sanitized[field] = "*".repeat(sanitized[field].length);
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
return sanitized;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
5
|
const logTransaction = async (strapi, transactionData) => {
|
|
20
6
|
const pluginStore = getPluginStore(strapi);
|
|
21
7
|
let transactionHistory =
|
|
@@ -42,19 +28,15 @@ const logTransaction = async (strapi, transactionData) => {
|
|
|
42
28
|
transactionData.customer_message ||
|
|
43
29
|
transactionData.Error?.CustomerMessage ||
|
|
44
30
|
null,
|
|
45
|
-
body: transactionData
|
|
46
|
-
raw_request: transactionData.raw_request
|
|
47
|
-
? sanitizeRawRequest(transactionData.raw_request)
|
|
48
|
-
: null,
|
|
49
|
-
raw_response: sanitizeRawRequest(transactionData.raw_response) || transactionData,
|
|
31
|
+
body: transactionData || null,
|
|
50
32
|
created_at: new Date().toISOString(),
|
|
51
33
|
updated_at: new Date().toISOString()
|
|
52
34
|
};
|
|
53
35
|
|
|
54
36
|
transactionHistory.unshift(logEntry);
|
|
55
37
|
|
|
56
|
-
if (transactionHistory.length >
|
|
57
|
-
transactionHistory = transactionHistory.slice(0,
|
|
38
|
+
if (transactionHistory.length > 1000) {
|
|
39
|
+
transactionHistory = transactionHistory.slice(0, 1000);
|
|
58
40
|
}
|
|
59
41
|
|
|
60
42
|
await pluginStore.set({
|
|
@@ -62,39 +44,35 @@ const logTransaction = async (strapi, transactionData) => {
|
|
|
62
44
|
value: transactionHistory
|
|
63
45
|
});
|
|
64
46
|
|
|
65
|
-
|
|
47
|
+
console.log(`Transaction logged: ${logEntry}`);
|
|
66
48
|
};
|
|
67
49
|
|
|
68
|
-
const getTransactionHistory = async (strapi, filters = {}) => {
|
|
69
|
-
const pluginStore = getPluginStore(strapi);
|
|
70
|
-
let transactionHistory =
|
|
71
|
-
(await pluginStore.get({ key: "transactionHistory" })) || [];
|
|
72
50
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
status.includes(searchLower) ||
|
|
82
|
-
txid.includes(searchLower) ||
|
|
83
|
-
reference.includes(searchLower)
|
|
84
|
-
);
|
|
51
|
+
const applyFilters = (transactions, filters = {}) => {
|
|
52
|
+
let result = [...transactions];
|
|
53
|
+
if (filters.search && typeof filters.search === 'string' && filters.search.trim() !== '') {
|
|
54
|
+
const search = filters.search.toLowerCase().trim();
|
|
55
|
+
result = result.filter((t) => {
|
|
56
|
+
const txid = (t.txid || "").toString().toLowerCase();
|
|
57
|
+
const reference = (t.reference || "").toString().toLowerCase();
|
|
58
|
+
return txid.includes(search) || reference.includes(search);
|
|
85
59
|
});
|
|
86
60
|
}
|
|
87
61
|
|
|
88
|
-
if (filters.
|
|
89
|
-
|
|
90
|
-
(
|
|
62
|
+
if (filters.status) {
|
|
63
|
+
result = result.filter(
|
|
64
|
+
(t) => (t.status || "").toUpperCase() === filters.status.toUpperCase()
|
|
91
65
|
);
|
|
92
66
|
}
|
|
93
67
|
|
|
68
|
+
if (filters.request_type) {
|
|
69
|
+
result = result.filter((t) => t.request_type === filters.request_type);
|
|
70
|
+
}
|
|
71
|
+
|
|
94
72
|
if (filters.payment_method) {
|
|
95
|
-
|
|
96
|
-
const clearingtype =
|
|
97
|
-
const wallettype =
|
|
73
|
+
result = result.filter((t) => {
|
|
74
|
+
const clearingtype = t.raw_request?.clearingtype;
|
|
75
|
+
const wallettype = t.raw_request?.wallettype;
|
|
98
76
|
|
|
99
77
|
switch (filters.payment_method) {
|
|
100
78
|
case "credit_card":
|
|
@@ -102,82 +80,67 @@ const getTransactionHistory = async (strapi, filters = {}) => {
|
|
|
102
80
|
case "paypal":
|
|
103
81
|
return clearingtype === "wlt" && wallettype === "PPE";
|
|
104
82
|
case "google_pay":
|
|
105
|
-
return clearingtype === "wlt" &&
|
|
83
|
+
return clearingtype === "wlt" && ["GPY", "GOOGLEPAY"].includes(wallettype);
|
|
106
84
|
case "apple_pay":
|
|
107
|
-
return clearingtype === "wlt" &&
|
|
85
|
+
return clearingtype === "wlt" && ["APL", "APPLEPAY"].includes(wallettype);
|
|
108
86
|
case "sofort":
|
|
109
87
|
return clearingtype === "sb";
|
|
110
88
|
case "sepa":
|
|
111
89
|
return clearingtype === "elv";
|
|
112
90
|
default:
|
|
113
|
-
return
|
|
91
|
+
return true;
|
|
114
92
|
}
|
|
115
93
|
});
|
|
116
94
|
}
|
|
117
95
|
|
|
118
96
|
if (filters.date_from) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
97
|
+
const dateFrom = new Date(filters.date_from);
|
|
98
|
+
dateFrom.setHours(0, 0, 0, 0);
|
|
99
|
+
result = result.filter(
|
|
100
|
+
(t) => new Date(t.timestamp) >= dateFrom
|
|
122
101
|
);
|
|
123
102
|
}
|
|
124
103
|
|
|
125
104
|
if (filters.date_to) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
105
|
+
const dateTo = new Date(filters.date_to);
|
|
106
|
+
dateTo.setHours(23, 59, 59, 999);
|
|
107
|
+
result = result.filter(
|
|
108
|
+
(t) => new Date(t.timestamp) <= dateTo
|
|
129
109
|
);
|
|
130
110
|
}
|
|
131
111
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
(transaction) => transaction.status === filters.status
|
|
135
|
-
);
|
|
136
|
-
}
|
|
112
|
+
return result;
|
|
113
|
+
};
|
|
137
114
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const sortOrder = filters.sort_order === "desc" ? -1 : 1;
|
|
141
|
-
|
|
142
|
-
transactionHistory.sort((a, b) => {
|
|
143
|
-
let aValue, bValue;
|
|
144
|
-
|
|
145
|
-
switch (filters.sort_by) {
|
|
146
|
-
case "amount":
|
|
147
|
-
aValue = a.amount || 0;
|
|
148
|
-
bValue = b.amount || 0;
|
|
149
|
-
break;
|
|
150
|
-
case "created_at":
|
|
151
|
-
aValue = new Date(a.created_at || a.timestamp || 0).getTime();
|
|
152
|
-
bValue = new Date(b.created_at || b.timestamp || 0).getTime();
|
|
153
|
-
break;
|
|
154
|
-
case "status":
|
|
155
|
-
aValue = (a.status || "").toLowerCase();
|
|
156
|
-
bValue = (b.status || "").toLowerCase();
|
|
157
|
-
break;
|
|
158
|
-
case "reference":
|
|
159
|
-
aValue = (a.reference || "").toLowerCase();
|
|
160
|
-
bValue = (b.reference || "").toLowerCase();
|
|
161
|
-
break;
|
|
162
|
-
case "method":
|
|
163
|
-
const aClearingType = a.raw_request?.clearingtype || "";
|
|
164
|
-
const bClearingType = b.raw_request?.clearingtype || "";
|
|
165
|
-
const aWalletType = a.raw_request?.wallettype || "";
|
|
166
|
-
const bWalletType = b.raw_request?.wallettype || "";
|
|
167
|
-
aValue = `${aClearingType}_${aWalletType}`.toLowerCase();
|
|
168
|
-
bValue = `${bClearingType}_${bWalletType}`.toLowerCase();
|
|
169
|
-
break;
|
|
170
|
-
default:
|
|
171
|
-
return 0;
|
|
172
|
-
}
|
|
115
|
+
const getTransactionHistory = async (strapi, { filters = {}, pagination = {} }) => {
|
|
116
|
+
const pluginStore = getPluginStore(strapi);
|
|
173
117
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
118
|
+
let transactions =
|
|
119
|
+
(await pluginStore.get({ key: "transactionHistory" })) || [];
|
|
120
|
+
|
|
121
|
+
transactions = applyFilters(transactions, filters);
|
|
122
|
+
const page = Number(pagination.page) || 1;
|
|
123
|
+
const pageSize = Number(pagination.pageSize) || 10;
|
|
124
|
+
|
|
125
|
+
const total = transactions.length;
|
|
126
|
+
const pageCount = Math.max(1, Math.ceil(total / pageSize));
|
|
127
|
+
|
|
128
|
+
const validPage = Math.min(Math.max(1, page), pageCount);
|
|
179
129
|
|
|
180
|
-
|
|
130
|
+
const start = (validPage - 1) * pageSize;
|
|
131
|
+
const end = Math.min(start + pageSize, total);
|
|
132
|
+
|
|
133
|
+
const paginatedData = start < total ? transactions.slice(start, end) : [];
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
data: paginatedData,
|
|
137
|
+
pagination: {
|
|
138
|
+
page: validPage,
|
|
139
|
+
pageSize,
|
|
140
|
+
pageCount,
|
|
141
|
+
total,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
181
144
|
};
|
|
182
145
|
|
|
183
146
|
module.exports = {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const { getPluginStore, getSettings } = require("./settingsService");
|
|
5
|
+
|
|
6
|
+
const verifyHash = (notificationData, portalKey) => {
|
|
7
|
+
const {
|
|
8
|
+
portalid = "",
|
|
9
|
+
aid = "",
|
|
10
|
+
txid = "",
|
|
11
|
+
sequencenumber = "",
|
|
12
|
+
price = "",
|
|
13
|
+
currency = "",
|
|
14
|
+
mode = "",
|
|
15
|
+
} = notificationData;
|
|
16
|
+
|
|
17
|
+
const hashString = `${portalid}${aid}${txid}${sequencenumber}${price}${currency}${mode}${portalKey}`;
|
|
18
|
+
const expectedHash = crypto.createHash("md5").update(hashString).digest("hex");
|
|
19
|
+
|
|
20
|
+
return expectedHash.toLowerCase() === (notificationData.key || "").toLowerCase();
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const processTransactionStatus = async (strapi, notificationData) => {
|
|
24
|
+
try {
|
|
25
|
+
const settings = await getSettings(strapi);
|
|
26
|
+
const txid = notificationData.txid;
|
|
27
|
+
|
|
28
|
+
if (!settings || !settings.key) {
|
|
29
|
+
console.log("[Payone TransactionStatus] Settings not found or key missing");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const isValid = verifyHash(notificationData, settings.key);
|
|
34
|
+
if (!isValid) {
|
|
35
|
+
console.log(`[Payone TransactionStatus] Hash verification failed txid: ${txid}`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (notificationData.portalid !== settings.portalid || notificationData.aid !== settings.aid) {
|
|
40
|
+
console.log(`[Payone TransactionStatus] Portal ID or AID mismatch txid: ${txid}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const pluginStore = getPluginStore(strapi);
|
|
45
|
+
let transactionHistory = (await pluginStore.get({ key: "transactionHistory" })) || [];
|
|
46
|
+
|
|
47
|
+
const transaction = transactionHistory.find((t) => t.txid === txid || t.id === txid);
|
|
48
|
+
|
|
49
|
+
if (transaction) {
|
|
50
|
+
Object.assign(transaction, {
|
|
51
|
+
...notificationData,
|
|
52
|
+
status: notificationData?.transaction_status,
|
|
53
|
+
txaction: notificationData?.txaction,
|
|
54
|
+
txtime: notificationData?.txtime,
|
|
55
|
+
sequencenumber: notificationData?.sequencenumber,
|
|
56
|
+
balance: notificationData?.balance,
|
|
57
|
+
receivable: notificationData?.receivable,
|
|
58
|
+
price: notificationData?.price,
|
|
59
|
+
amount: notificationData?.price ? parseFloat(notificationData?.price) * 100 : transaction?.amount,
|
|
60
|
+
userid: notificationData?.userid,
|
|
61
|
+
updated_at: new Date().toISOString(),
|
|
62
|
+
body: {
|
|
63
|
+
...transaction?.body,
|
|
64
|
+
...notificationData,
|
|
65
|
+
status: notificationData?.transaction_status
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
await pluginStore.set({
|
|
70
|
+
key: "transactionHistory",
|
|
71
|
+
value: transactionHistory,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
console.log(`[Payone TransactionStatus] Successfully updated transaction txid: ${txid}`);
|
|
75
|
+
} else {
|
|
76
|
+
console.log(`[Payone TransactionStatus] Transaction ${txid} not found in history. Notification ignored.`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.log(`[Payone TransactionStatus] Error processing notification: ${error}`);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
verifyHash,
|
|
86
|
+
processTransactionStatus,
|
|
87
|
+
};
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Normalize reference string for Payone API
|
|
5
|
-
* @param {string} input - Input reference
|
|
6
|
-
* @param {string} fallbackPrefix - Fallback prefix if input is empty
|
|
7
|
-
* @returns {string} Normalized reference (max 20 chars)
|
|
8
|
-
*/
|
|
9
3
|
const normalizeReference = (input, fallbackPrefix = "REF") => {
|
|
10
4
|
try {
|
|
11
5
|
const raw = input == null ? "" : String(input);
|
|
@@ -22,12 +16,6 @@ const normalizeReference = (input, fallbackPrefix = "REF") => {
|
|
|
22
16
|
}
|
|
23
17
|
};
|
|
24
18
|
|
|
25
|
-
/**
|
|
26
|
-
* Normalize customer ID for Payone API (max 17 characters)
|
|
27
|
-
* @param {string|null} customerid - Customer ID
|
|
28
|
-
* @param {Object|null} logger - Logger instance
|
|
29
|
-
* @returns {string} Normalized customer ID
|
|
30
|
-
*/
|
|
31
19
|
const normalizeCustomerId = (customerid, logger = null) => {
|
|
32
20
|
if (!customerid) {
|
|
33
21
|
const timestamp = Date.now().toString().slice(-10);
|
|
@@ -56,7 +56,6 @@ const addPaymentMethodParams = (params, logger) => {
|
|
|
56
56
|
'clearingtype', 'paymentMethod', 'settings', 'enable3DSecure', 'ecommercemode'
|
|
57
57
|
]);
|
|
58
58
|
|
|
59
|
-
// Extract custom params that are not in known params
|
|
60
59
|
Object.keys(updated).forEach(key => {
|
|
61
60
|
if (!knownParams.has(key) && !key.startsWith('add_paydata[')) {
|
|
62
61
|
customParams[key] = updated[key];
|
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
const crypto = require("crypto");
|
|
4
4
|
const { normalizeCustomerId } = require("./normalize");
|
|
5
|
+
const calculateKeyHash = (settings, params) => {
|
|
6
|
+
const portalKey = settings.portalKey || settings.key;
|
|
7
|
+
const portalid = String(settings.portalid || "");
|
|
8
|
+
const aid = String(settings.aid || "");
|
|
9
|
+
const mode = String(settings.mode || "test");
|
|
10
|
+
|
|
11
|
+
const requestType = params.request || "";
|
|
12
|
+
|
|
13
|
+
// For Capture and Refund operations
|
|
14
|
+
if (requestType === "capture" || requestType === "refund") {
|
|
15
|
+
const txid = String(params.txid || "");
|
|
16
|
+
const sequencenumber = String(params.sequencenumber || "");
|
|
17
|
+
const amount = String(params.amount || "");
|
|
18
|
+
const currency = String(params.currency || "EUR");
|
|
19
|
+
|
|
20
|
+
const hashString = `${portalid}${aid}${txid}${sequencenumber}${amount}${currency}${mode}${portalKey}`;
|
|
21
|
+
return crypto.createHash("md5").update(hashString).digest("hex");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// For Preauthorization and Authorization operations
|
|
25
|
+
if (requestType === "preauthorization" || requestType === "authorization") {
|
|
26
|
+
const amount = String(params.amount || "");
|
|
27
|
+
const currency = String(params.currency || "EUR");
|
|
28
|
+
const reference = String(params.reference || "");
|
|
29
|
+
|
|
30
|
+
const hashString = `${portalid}${aid}${amount}${currency}${reference}${mode}${portalKey}`;
|
|
31
|
+
return crypto.createHash("md5").update(hashString).digest("hex");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const hashString = `${portalid}${aid}${mode}${portalKey}`;
|
|
35
|
+
return crypto.createHash("md5").update(hashString).digest("hex");
|
|
36
|
+
};
|
|
5
37
|
|
|
6
38
|
const buildClientRequestParams = (settings, params, logger = null) => {
|
|
7
39
|
const requestParams = {
|
|
@@ -14,16 +46,13 @@ const buildClientRequestParams = (settings, params, logger = null) => {
|
|
|
14
46
|
...params
|
|
15
47
|
};
|
|
16
48
|
|
|
17
|
-
requestParams.key = crypto
|
|
18
|
-
.createHash("md5")
|
|
19
|
-
.update(settings.portalKey || settings.key)
|
|
20
|
-
.digest("hex");
|
|
21
|
-
|
|
22
49
|
requestParams.customerid = normalizeCustomerId(
|
|
23
50
|
requestParams.customerid,
|
|
24
51
|
logger
|
|
25
52
|
);
|
|
26
53
|
|
|
54
|
+
requestParams.key = calculateKeyHash(settings, requestParams);
|
|
55
|
+
|
|
27
56
|
const isCreditCard = requestParams.clearingtype === "cc";
|
|
28
57
|
const enable3DSecure = settings.enable3DSecure !== false;
|
|
29
58
|
|
|
@@ -20,17 +20,12 @@ const parseResponse = (responseText, logger) => {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// Parse URL-encoded response
|
|
24
23
|
const params = new URLSearchParams(responseText);
|
|
25
24
|
const response = {};
|
|
26
25
|
for (const [key, value] of params) {
|
|
27
|
-
// Store both lowercase and original case
|
|
28
26
|
response[key.toLowerCase()] = value;
|
|
29
27
|
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
|
|
28
|
+
|
|
34
29
|
if (key.includes('add_paydata') || key.includes('addPaydata')) {
|
|
35
30
|
// Store with original key format
|
|
36
31
|
response[key] = value;
|
|
@@ -67,11 +62,11 @@ const extractTxId = (data) => {
|
|
|
67
62
|
const requires3DSRedirect = (data) => {
|
|
68
63
|
const status = (data.status || data.Status || "").toUpperCase();
|
|
69
64
|
const errorCode = data.errorcode || data.ErrorCode || data.Error?.ErrorCode;
|
|
70
|
-
|
|
65
|
+
|
|
71
66
|
// Check for redirect URL in various possible fields
|
|
72
|
-
const redirecturl =
|
|
73
|
-
data.redirecturl ||
|
|
74
|
-
data.RedirectUrl ||
|
|
67
|
+
const redirecturl =
|
|
68
|
+
data.redirecturl ||
|
|
69
|
+
data.RedirectUrl ||
|
|
75
70
|
data.redirect_url ||
|
|
76
71
|
data.redirectUrl ||
|
|
77
72
|
data.RedirectURL ||
|
|
@@ -96,7 +91,7 @@ const requires3DSRedirect = (data) => {
|
|
|
96
91
|
const isErrorResponse = (data) => {
|
|
97
92
|
const status = (data.status || data.Status || "").toUpperCase();
|
|
98
93
|
const errorCode = data.errorcode || data.ErrorCode || data.Error?.ErrorCode;
|
|
99
|
-
|
|
94
|
+
|
|
100
95
|
return status === "ERROR" || status === "INVALID" || !!errorCode;
|
|
101
96
|
};
|
|
102
97
|
|
|
@@ -107,9 +102,9 @@ const isErrorResponse = (data) => {
|
|
|
107
102
|
*/
|
|
108
103
|
const get3DSRedirectUrl = (data) => {
|
|
109
104
|
// Check all possible redirect URL fields
|
|
110
|
-
const redirecturl =
|
|
111
|
-
data.redirecturl ||
|
|
112
|
-
data.RedirectUrl ||
|
|
105
|
+
const redirecturl =
|
|
106
|
+
data.redirecturl ||
|
|
107
|
+
data.RedirectUrl ||
|
|
113
108
|
data.redirect_url ||
|
|
114
109
|
data.redirectUrl ||
|
|
115
110
|
data.RedirectURL ||
|