strapi-plugin-payone-provider 4.6.10 → 4.6.12

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 (68) hide show
  1. package/README.md +64 -0
  2. package/admin/src/pages/App/components/AppHeader.jsx +3 -2
  3. package/admin/src/pages/App/components/AppTabs.jsx +34 -88
  4. package/admin/src/pages/App/components/DocsPanel.jsx +1726 -1726
  5. package/admin/src/pages/App/components/GooglePaybutton.jsx +300 -300
  6. package/admin/src/pages/App/components/StatusBadge.jsx +1 -1
  7. package/admin/src/pages/App/components/common/InfoTooltip.jsx +16 -0
  8. package/admin/src/pages/App/components/{ApplePayConfig.jsx → configuration/ApplePayConfig.jsx} +191 -62
  9. package/admin/src/pages/App/components/{ApplePayConfigPanel.jsx → configuration/ApplePayConfigPanel.jsx} +71 -70
  10. package/admin/src/pages/App/components/configuration/ConfigurationFields.jsx +408 -0
  11. package/admin/src/pages/App/components/configuration/ConfigurationPanel.jsx +67 -0
  12. package/admin/src/pages/App/components/{GooglePayConfig.jsx → configuration/GooglePayConfig.jsx} +254 -254
  13. package/admin/src/pages/App/components/{GooglePayConfigPanel.jsx → configuration/GooglePayConfigPanel.jsx} +82 -82
  14. package/admin/src/pages/App/components/configuration/TestConnection.jsx +129 -0
  15. package/admin/src/pages/App/components/paymentActions/ApplePayPanel.jsx +137 -95
  16. package/admin/src/pages/App/components/paymentActions/CaptureForm.jsx +119 -14
  17. package/admin/src/pages/App/components/paymentActions/CardDetailsInput.jsx +85 -24
  18. package/admin/src/pages/App/components/paymentActions/PaymentActionsPanel.jsx +361 -0
  19. package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.jsx +22 -4
  20. package/admin/src/pages/App/components/paymentActions/RefundForm.jsx +91 -20
  21. package/admin/src/pages/App/components/paymentActions/authorization/AuthorizationForm.jsx +157 -0
  22. package/admin/src/pages/App/components/paymentActions/authorization/AuthorizationFormFields.jsx +308 -0
  23. package/admin/src/pages/App/components/paymentActions/authorization/AuthorizationFormHeader.jsx +27 -0
  24. package/admin/src/pages/App/components/paymentActions/authorization/AuthorizationPaymentButtons.jsx +93 -0
  25. package/admin/src/pages/App/components/paymentActions/preauthorization/PreauthorizationForm.jsx +134 -0
  26. package/admin/src/pages/App/components/paymentActions/preauthorization/PreauthorizationFormFields.jsx +295 -0
  27. package/admin/src/pages/App/components/paymentActions/preauthorization/PreauthorizationFormHeader.jsx +27 -0
  28. package/admin/src/pages/App/components/paymentActions/preauthorization/PreauthorizationPaymentButtons.jsx +53 -0
  29. package/admin/src/pages/App/components/transaction-history/FiltersPanel.jsx +182 -0
  30. package/admin/src/pages/App/components/transaction-history/HistoryPanel.jsx +49 -0
  31. package/admin/src/pages/App/components/transaction-history/TransactionTable.jsx +199 -0
  32. package/admin/src/pages/App/components/transaction-history/TransactionTablePagination.jsx +28 -0
  33. package/admin/src/pages/App/components/transaction-history/details/TransactionDetails.jsx +155 -0
  34. package/admin/src/pages/App/index.jsx +5 -29
  35. package/admin/src/pages/hooks/usePaymentActions.js +87 -11
  36. package/admin/src/pages/hooks/useSettings.js +64 -22
  37. package/admin/src/pages/hooks/useTransactionHistory.js +121 -85
  38. package/admin/src/pages/utils/api.js +31 -3
  39. package/admin/src/pages/utils/countryLanguageUtils.js +236 -0
  40. package/admin/src/pages/utils/transactionTableUtils.js +60 -0
  41. package/package.json +2 -2
  42. package/server/bootstrap.js +6 -6
  43. package/server/content-types/index.js +5 -0
  44. package/server/content-types/transactions/index.js +5 -0
  45. package/server/content-types/transactions/schema.json +87 -0
  46. package/server/controllers/payone.js +29 -3
  47. package/server/index.js +2 -1
  48. package/server/policies/index.js +2 -1
  49. package/server/policies/is-payone-notification.js +31 -0
  50. package/server/routes/index.js +10 -0
  51. package/server/services/applePayService.js +0 -2
  52. package/server/services/payone.js +16 -4
  53. package/server/services/settingsService.js +8 -2
  54. package/server/services/testConnectionService.js +11 -72
  55. package/server/services/transactionService.js +147 -154
  56. package/server/services/transactionStatusService.js +63 -0
  57. package/server/utils/sanitize.js +41 -0
  58. package/admin/src/pages/App/components/ConfigurationPanel.jsx +0 -517
  59. package/admin/src/pages/App/components/CustomerInfoPopover.jsx +0 -147
  60. package/admin/src/pages/App/components/HistoryPanel.jsx +0 -94
  61. package/admin/src/pages/App/components/PaymentActionsPanel.jsx +0 -280
  62. package/admin/src/pages/App/components/RawDataPopover.jsx +0 -113
  63. package/admin/src/pages/App/components/TransactionHistoryItem.jsx +0 -522
  64. package/admin/src/pages/App/components/TransactionHistoryTable/TransactionHistoryTableFilters.jsx +0 -113
  65. package/admin/src/pages/App/components/TransactionHistoryTable/TransactionHistoryTablePagination.jsx +0 -180
  66. package/admin/src/pages/App/components/TransactionHistoryTable/index.jsx +0 -225
  67. package/admin/src/pages/App/components/paymentActions/AuthorizationForm.jsx +0 -197
  68. package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.jsx +0 -142
@@ -1,183 +1,176 @@
1
1
  "use strict";
2
2
 
3
- const { getPluginStore } = require("./settingsService");
3
+ const { sanitizeSensitive } = require("../utils/sanitize");
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
- };
5
+ const TRANSACTION_UID = "plugin::strapi-plugin-payone-provider.transaction";
18
6
 
19
7
  const logTransaction = async (strapi, transactionData) => {
20
- const pluginStore = getPluginStore(strapi);
21
- let transactionHistory =
22
- (await pluginStore.get({ key: "transactionHistory" })) || [];
23
-
24
- const logEntry = {
25
- id: Date.now().toString(),
26
- timestamp: new Date().toISOString(),
27
- txid: transactionData.txid || null,
28
- reference: transactionData.reference || null,
29
- invoiceid: transactionData.invoiceid || null,
30
- request_type:
31
- transactionData.request_type || transactionData.request || "unknown",
32
- amount: transactionData.amount || null,
33
- currency: transactionData.currency || "EUR",
34
- status: transactionData.status || transactionData.Status || "unknown",
35
- error_code:
36
- transactionData.error_code || transactionData.Error?.ErrorCode || null,
37
- error_message:
38
- transactionData.error_message ||
39
- transactionData.Error?.ErrorMessage ||
40
- null,
41
- customer_message:
42
- transactionData.customer_message ||
43
- transactionData.Error?.CustomerMessage ||
44
- null,
45
- body: transactionData ? { ...transactionData, raw_request: sanitizeRawRequest(transactionData.raw_request) } : null,
46
- raw_request: transactionData.raw_request
47
- ? sanitizeRawRequest(transactionData.raw_request)
48
- : null,
49
- raw_response: sanitizeRawRequest(transactionData.raw_response) || transactionData,
50
- created_at: new Date().toISOString(),
51
- updated_at: new Date().toISOString()
52
- };
53
-
54
- transactionHistory.unshift(logEntry);
8
+ try {
9
+ const data = {
10
+ txid: transactionData.txid || 'NO TXID',
11
+ reference: transactionData.reference || 'NO REFERENCE',
12
+ invoiceid: transactionData.raw_request.invoiceid || 'NO INVOICE ID',
13
+ request_type: transactionData.request_type || "unknown",
14
+ amount: transactionData.amount || "0",
15
+ currency: transactionData.currency || "EUR",
16
+ status: transactionData.status || transactionData.raw_response.Status || "unknown",
17
+ error_code: transactionData.error_code || "NO ERROR CODE",
18
+ error_message: transactionData.error_message || "NO ERROR MESSAGE",
19
+ customer_message: transactionData.customer_message || "NO CUSTOMER MESSAGE",
20
+ body: transactionData ? { ...transactionData, raw_request: sanitizeSensitive(transactionData.raw_request), raw_response: sanitizeSensitive(transactionData.raw_response) } : {},
21
+ raw_request: sanitizeSensitive(transactionData.raw_request || {}),
22
+ raw_response: sanitizeSensitive(transactionData.raw_response || {}),
23
+ };
24
+
25
+ const entry = await strapi.db.query(TRANSACTION_UID).create({ data });
26
+ console.info("Transaction logged to DB:", {
27
+ id: entry.id,
28
+ txid: entry.txid,
29
+ status: entry.status
30
+ });
55
31
 
56
- if (transactionHistory.length > 5000) {
57
- transactionHistory = transactionHistory.slice(0, 5000);
32
+ return entry;
33
+ } catch (error) {
34
+ console.error("Failed to log transaction:", error);
58
35
  }
36
+ };
59
37
 
60
- await pluginStore.set({
61
- key: "transactionHistory",
62
- value: transactionHistory
63
- });
64
38
 
65
- strapi.log.info("Transaction logged:", logEntry);
66
- };
39
+ const buildWhereFromFilters = (filters = {}) => {
40
+ const conditions = [];
67
41
 
68
- const getTransactionHistory = async (strapi, filters = {}) => {
69
- const pluginStore = getPluginStore(strapi);
70
- let transactionHistory =
71
- (await pluginStore.get({ key: "transactionHistory" })) || [];
72
-
73
- if (filters.search) {
74
- const searchLower = filters.search.toLowerCase().trim();
75
- transactionHistory = transactionHistory.filter((transaction) => {
76
- const status = (transaction.status || "").toLowerCase();
77
- const txid = (transaction.txid || "").toLowerCase();
78
- const reference = (transaction.reference || "").toLowerCase();
79
-
80
- return (
81
- status.includes(searchLower) ||
82
- txid.includes(searchLower) ||
83
- reference.includes(searchLower)
84
- );
42
+ if (filters.search && typeof filters.search === "string" && filters.search.trim() !== "") {
43
+ const search = filters.search.trim();
44
+ conditions.push({
45
+ $or: [
46
+ { txid: { $containsi: search } },
47
+ { reference: { $containsi: search } },
48
+ ],
85
49
  });
86
50
  }
87
51
 
88
- if (filters.request_type) {
89
- transactionHistory = transactionHistory.filter(
90
- (transaction) => transaction.request_type === filters.request_type
91
- );
52
+ if (filters.status) {
53
+ conditions.push({ status: { $eqi: filters.status } });
92
54
  }
93
55
 
94
- if (filters.payment_method) {
95
- transactionHistory = transactionHistory.filter((transaction) => {
96
- const clearingtype = transaction.raw_request?.clearingtype || "";
97
- const wallettype = transaction.raw_request?.wallettype || "";
98
-
99
- switch (filters.payment_method) {
100
- case "credit_card":
101
- return clearingtype === "cc";
102
- case "paypal":
103
- return clearingtype === "wlt" && wallettype === "PPE";
104
- case "google_pay":
105
- return clearingtype === "wlt" && (wallettype === "GPY" || wallettype === "GOOGLEPAY");
106
- case "apple_pay":
107
- return clearingtype === "wlt" && (wallettype === "APL" || wallettype === "APPLEPAY");
108
- case "sofort":
109
- return clearingtype === "sb";
110
- case "sepa":
111
- return clearingtype === "elv";
112
- default:
113
- return false;
114
- }
115
- });
56
+ if (filters.request_type) {
57
+ conditions.push({ request_type: filters.request_type });
116
58
  }
117
59
 
118
60
  if (filters.date_from) {
119
- transactionHistory = transactionHistory.filter(
120
- (transaction) =>
121
- new Date(transaction.timestamp) >= new Date(filters.date_from)
122
- );
61
+ const dateFrom = new Date(filters.date_from);
62
+ dateFrom.setHours(0, 0, 0, 0);
63
+ conditions.push({ createdAt: { $gte: dateFrom.toISOString() } });
123
64
  }
124
65
 
125
66
  if (filters.date_to) {
126
- transactionHistory = transactionHistory.filter(
127
- (transaction) =>
128
- new Date(transaction.timestamp) <= new Date(filters.date_to)
129
- );
67
+ const dateTo = new Date(filters.date_to);
68
+ dateTo.setHours(23, 59, 59, 999);
69
+ conditions.push({ createdAt: { $lte: dateTo.toISOString() } });
130
70
  }
131
71
 
132
- if (filters.status) {
133
- transactionHistory = transactionHistory.filter(
134
- (transaction) => transaction.status === filters.status
135
- );
72
+ if (filters.payment_method) {
73
+ switch (filters.payment_method) {
74
+ case "credit_card":
75
+ conditions.push({ raw_request: { $containsi: '"clearingtype":"cc"' } });
76
+ break;
77
+ case "paypal":
78
+ conditions.push({
79
+ $and: [
80
+ { raw_request: { $containsi: '"clearingtype":"wlt"' } },
81
+ { raw_request: { $containsi: '"wallettype":"PPE"' } },
82
+ ],
83
+ });
84
+ break;
85
+ case "google_pay":
86
+ conditions.push({
87
+ $and: [
88
+ { raw_request: { $containsi: '"clearingtype":"wlt"' } },
89
+ {
90
+ $or: [
91
+ { raw_request: { $containsi: '"wallettype":"GPY"' } },
92
+ { raw_request: { $containsi: '"wallettype":"GOOGLEPAY"' } },
93
+ ],
94
+ },
95
+ ],
96
+ });
97
+ break;
98
+ case "apple_pay":
99
+ conditions.push({
100
+ $and: [
101
+ { raw_request: { $containsi: '"clearingtype":"wlt"' } },
102
+ {
103
+ $or: [
104
+ { raw_request: { $containsi: '"wallettype":"APL"' } },
105
+ { raw_request: { $containsi: '"wallettype":"APPLEPAY"' } },
106
+ ],
107
+ },
108
+ ],
109
+ });
110
+ break;
111
+ case "sofort":
112
+ conditions.push({ raw_request: { $containsi: '"clearingtype":"sb"' } });
113
+ break;
114
+ case "sepa":
115
+ conditions.push({ raw_request: { $containsi: '"clearingtype":"elv"' } });
116
+ break;
117
+ default:
118
+ break;
119
+ }
136
120
  }
137
121
 
138
- // Apply sorting
139
- if (filters.sort_by && filters.sort_order) {
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
- }
173
-
174
- if (aValue < bValue) return -1 * sortOrder;
175
- if (aValue > bValue) return 1 * sortOrder;
176
- return 0;
177
- });
178
- }
122
+ if (conditions.length === 0) return undefined;
123
+ if (conditions.length === 1) return conditions[0];
124
+ return { $and: conditions };
125
+ };
179
126
 
180
- return transactionHistory;
127
+ const ALLOWED_SORT_FIELDS = [
128
+ "txid",
129
+ "reference",
130
+ "amount",
131
+ "request_type",
132
+ "status",
133
+ "createdAt",
134
+ "updatedAt",
135
+ ];
136
+
137
+ const getTransactionHistory = async (
138
+ strapi,
139
+ { filters = {}, pagination = {}, sort_by, sort_order }
140
+ ) => {
141
+ const page = Math.max(1, Number(pagination.page) || 1);
142
+ const pageSize = Math.min(100, Math.max(1, Number(pagination.pageSize) || 10));
143
+ const offset = (page - 1) * pageSize;
144
+
145
+ const where = buildWhereFromFilters(filters);
146
+
147
+ const sortField =
148
+ sort_by && ALLOWED_SORT_FIELDS.includes(sort_by) ? sort_by : "createdAt";
149
+ const order = sort_order === "asc" ? "asc" : "desc";
150
+
151
+ const queryOptions = {
152
+ orderBy: { [sortField]: order },
153
+ limit: pageSize,
154
+ offset,
155
+ };
156
+ if (where !== undefined) queryOptions.where = where;
157
+
158
+ const [data, total] = await strapi.db
159
+ .query(TRANSACTION_UID)
160
+ .findWithCount(queryOptions);
161
+
162
+ const pageCount = Math.max(1, Math.ceil(total / pageSize));
163
+ const validPage = Math.min(page, pageCount);
164
+
165
+ return {
166
+ data,
167
+ pagination: {
168
+ page: validPage,
169
+ pageSize,
170
+ pageCount,
171
+ total,
172
+ },
173
+ };
181
174
  };
182
175
 
183
176
  module.exports = {
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+
3
+ const { getSettings } = require("./settingsService");
4
+ const { sanitizeSensitive } = require("../utils/sanitize");
5
+
6
+ const TRANSACTION_UID = "plugin::strapi-plugin-payone-provider.transaction";
7
+
8
+ const processTransactionStatus = async (strapi, notificationData) => {
9
+ try {
10
+ const settings = await getSettings(strapi);
11
+ const txid = notificationData.txid;
12
+
13
+ if (!settings || !settings.key) {
14
+ console.log("[Payone TransactionStatus] Settings not found or key missing");
15
+ return;
16
+ }
17
+
18
+ if (notificationData.portalid !== settings.portalid || notificationData.aid !== settings.aid) {
19
+ console.log(`[Payone TransactionStatus] Portal ID or AID mismatch txid: ${txid}`);
20
+ return;
21
+ }
22
+
23
+ const existing = await strapi.db.query(TRANSACTION_UID).findOne({ where: { txid } });
24
+ if (!existing) {
25
+ console.log(`[Payone TransactionStatus] Transaction ${txid} not found. Notification ignored.`);
26
+ return;
27
+ }
28
+
29
+ const amount = notificationData.clearing_amount
30
+ ? String(notificationData.clearing_amount)
31
+ : notificationData.price
32
+ ? String(Math.round(parseFloat(notificationData.price) * 100))
33
+ : existing.amount;
34
+
35
+ const safeNotification = sanitizeSensitive({ ...notificationData });
36
+
37
+ const data = {
38
+ status: notificationData.transaction_status || existing.status,
39
+ currency: notificationData.currency || existing.currency,
40
+ reference: notificationData.reference || existing.reference,
41
+ amount,
42
+ body: {
43
+ ...existing.body,
44
+ status: notificationData.transaction_status,
45
+ amount,
46
+ payone_notification_data: safeNotification,
47
+ },
48
+ };
49
+
50
+ await strapi.db.query(TRANSACTION_UID).update({
51
+ where: { id: existing.id },
52
+ data,
53
+ });
54
+
55
+ console.log(`[Payone TransactionStatus] Successfully updated transaction txid: ${txid}`);
56
+ } catch (error) {
57
+ console.log(`[Payone TransactionStatus] Error processing notification: ${error}`);
58
+ }
59
+ };
60
+
61
+ module.exports = {
62
+ processTransactionStatus,
63
+ };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ const SENSITIVE_KEYS = [
4
+ "cardpan",
5
+ "cardexpiredate",
6
+ "cardcvc2",
7
+ "iban",
8
+ "bic",
9
+ "bankaccount",
10
+ "bankcode",
11
+ "bankaccountholder",
12
+ "key",
13
+ "accesscode",
14
+ "accessname",
15
+ "token",
16
+ "redirecturl",
17
+ ];
18
+
19
+ const maskValue = (val) => {
20
+ if (typeof val !== "string") return val;
21
+ return "*".repeat(Math.min(val.length, 20));
22
+ };
23
+
24
+ const sanitizeSensitive = (obj) => {
25
+ if (!obj || typeof obj !== "object") return obj;
26
+ if (Array.isArray(obj)) return obj.map(sanitizeSensitive);
27
+ const out = {};
28
+ for (const [k, v] of Object.entries(obj)) {
29
+ const keyLower = k.toLowerCase();
30
+ if (SENSITIVE_KEYS.includes(keyLower) && v != null) {
31
+ out[k] = maskValue(String(v));
32
+ } else if (v != null && typeof v === "object" && !Array.isArray(v)) {
33
+ out[k] = sanitizeSensitive(v);
34
+ } else {
35
+ out[k] = v;
36
+ }
37
+ }
38
+ return out;
39
+ };
40
+
41
+ module.exports = { sanitizeSensitive };