strapi-plugin-payone-provider 4.6.10 → 4.6.11

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 (62) 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 +169 -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 +100 -88
  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 +1 -1
  42. package/server/bootstrap.js +6 -6
  43. package/server/controllers/payone.js +27 -3
  44. package/server/policies/index.js +2 -1
  45. package/server/policies/is-payone-notification.js +31 -0
  46. package/server/routes/index.js +10 -0
  47. package/server/services/payone.js +11 -4
  48. package/server/services/settingsService.js +8 -2
  49. package/server/services/testConnectionService.js +11 -72
  50. package/server/services/transactionService.js +58 -78
  51. package/server/services/transactionStatusService.js +87 -0
  52. package/admin/src/pages/App/components/ConfigurationPanel.jsx +0 -517
  53. package/admin/src/pages/App/components/CustomerInfoPopover.jsx +0 -147
  54. package/admin/src/pages/App/components/HistoryPanel.jsx +0 -94
  55. package/admin/src/pages/App/components/PaymentActionsPanel.jsx +0 -280
  56. package/admin/src/pages/App/components/RawDataPopover.jsx +0 -113
  57. package/admin/src/pages/App/components/TransactionHistoryItem.jsx +0 -522
  58. package/admin/src/pages/App/components/TransactionHistoryTable/TransactionHistoryTableFilters.jsx +0 -113
  59. package/admin/src/pages/App/components/TransactionHistoryTable/TransactionHistoryTablePagination.jsx +0 -180
  60. package/admin/src/pages/App/components/TransactionHistoryTable/index.jsx +0 -225
  61. package/admin/src/pages/App/components/paymentActions/AuthorizationForm.jsx +0 -197
  62. package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.jsx +0 -142
@@ -0,0 +1,60 @@
1
+ export const getStatusColor = (status) => {
2
+ switch (status) {
3
+ case "APPROVED":
4
+ return "success200";
5
+ case "ERROR":
6
+ return "danger200";
7
+ case "PENDING":
8
+ return "warning200";
9
+ case "REDIRECT":
10
+ return "success100";
11
+ default:
12
+ return "success100";
13
+ }
14
+ };
15
+
16
+ export const formatAmount = (amount, currency) => {
17
+ if (amount === null || amount === undefined) return "N/A";
18
+ return `${(amount / 100).toFixed(2)} ${currency || "EUR"}`;
19
+ };
20
+
21
+ export const formatDate = (dateString) => {
22
+ if (!dateString) return "N/A";
23
+ return new Date(dateString).toLocaleString("de-DE", {
24
+ year: "numeric",
25
+ month: "2-digit",
26
+ day: "2-digit",
27
+ hour: "2-digit",
28
+ minute: "2-digit",
29
+ });
30
+ };
31
+
32
+ export const getPaymentMethodName = (clearingtype, wallettype, cardtype) => {
33
+ switch (clearingtype) {
34
+ case "cc":
35
+ return cardtype ? `CC / ${cardtype}` : "Credit Card";
36
+ case "sb":
37
+ return "Online Banking";
38
+ case "wlt":
39
+ return wallettype === "PPE" ? "PayPal" : "Wallet";
40
+ case "elv":
41
+ return "Direct Debit (SEPA)";
42
+ default:
43
+ return clearingtype || "Unknown";
44
+ }
45
+ };
46
+
47
+ export const getCardTypeName = (cardtype) => {
48
+ switch (cardtype) {
49
+ case "V":
50
+ return "Visa";
51
+ case "M":
52
+ return "Mastercard";
53
+ case "A":
54
+ return "American Express";
55
+ default:
56
+ return cardtype || "Unknown";
57
+ }
58
+ };
59
+
60
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-payone-provider",
3
- "version": "4.6.10",
3
+ "version": "4.6.11",
4
4
  "description": "Strapi plugin for Payone payment gateway integration",
5
5
  "license": "MIT",
6
6
  "maintainers": [
@@ -22,12 +22,12 @@ module.exports = async ({ strapi }) => {
22
22
  displayName: "",
23
23
  domainName: "",
24
24
  merchantIdentifier: "",
25
- enableCreditCard: true,
26
- enablePayPal: true,
27
- enableGooglePay: true,
28
- enableApplePay: true,
29
- enableSofort: true,
30
- enableSepaDirectDebit: true
25
+ enable3DSecure: false,
26
+ enableCreditCard: false,
27
+ enablePayPal: false,
28
+ enableGooglePay: false,
29
+ enableApplePay: false,
30
+ enableSepaDirectDebit: false
31
31
  }
32
32
  });
33
33
  }
@@ -118,9 +118,15 @@ module.exports = ({ strapi }) => ({
118
118
 
119
119
  async getTransactionHistory(ctx) {
120
120
  try {
121
- const filters = ctx.query || {};
122
- const history = await getPayoneService(strapi).getTransactionHistory(filters);
123
- ctx.body = { data: history };
121
+ const { filters = {}, pagination = {} } = ctx.query || {};
122
+ const page = parseInt(pagination.page || "1", 10);
123
+ const pageSize = parseInt(pagination.pageSize || "10", 10);
124
+
125
+ const result = await getPayoneService(strapi).getTransactionHistory({
126
+ filters: filters || {},
127
+ pagination: { page, pageSize }
128
+ });
129
+ ctx.body = result
124
130
  } catch (error) {
125
131
  handleError(ctx, error);
126
132
  }
@@ -246,5 +252,23 @@ module.exports = ({ strapi }) => ({
246
252
  }
247
253
  };
248
254
  }
255
+ },
256
+
257
+ async handleTransactionStatus(ctx) {
258
+ try {
259
+ const notificationData = ctx.request.body || {};
260
+ await getPayoneService(strapi).processTransactionStatus(notificationData);
261
+
262
+ ctx.status = 200;
263
+ ctx.body = "TSOK";
264
+ ctx.type = "text/plain";
265
+ console.log(`[Payone TransactionStatus] Responded TSOK`);
266
+ } catch (error) {
267
+ console.log("[Payone TransactionStatus] Error handling notification:", error);
268
+ ctx.status = 200;
269
+ ctx.body = "TSOK";
270
+ ctx.type = "text/plain";
271
+ }
249
272
  }
273
+
250
274
  });
@@ -2,5 +2,6 @@
2
2
 
3
3
  module.exports = {
4
4
  "is-auth": require("./is-auth"),
5
- "is-super-admin": require("./isSuperAdmin")
5
+ "is-super-admin": require("./isSuperAdmin"),
6
+ "is-payone-notification": require("./is-payone-notification")
6
7
  };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ module.exports = async (ctx, config, { strapi }) => {
4
+ const { request } = ctx;
5
+ const userAgent = request.header["user-agent"] || request.header["User-Agent"] || "";
6
+ const clientIp = request.ip || request.connection?.remoteAddress || "";
7
+
8
+ if (userAgent !== "PAYONE FinanceGate") {
9
+ console.log(`[Payone TransactionStatus] Invalid User-Agent: ${userAgent}, IP: ${clientIp}`);
10
+ return false;
11
+ }
12
+
13
+
14
+ const isValidIp = (ip) => {
15
+ if (ip.startsWith("185.60.20.")) {
16
+ return true;
17
+ }
18
+
19
+ if (ip === "54.246.203.105") {
20
+ return true;
21
+ }
22
+ return false;
23
+ };
24
+
25
+ if (!isValidIp(clientIp)) {
26
+ console.log(`[Payone TransactionStatus] Invalid IP address: ${clientIp}, User-Agent: ${userAgent}`);
27
+ return false;
28
+ }
29
+
30
+ return true;
31
+ };
@@ -162,6 +162,16 @@ module.exports = {
162
162
  auth: false
163
163
  }
164
164
  },
165
+
166
+ {
167
+ method: "POST",
168
+ path: "/transaction-status",
169
+ handler: "payone.handleTransactionStatus",
170
+ config: {
171
+ policies: ["plugin::strapi-plugin-payone-provider.is-payone-notification"],
172
+ auth: false
173
+ }
174
+ },
165
175
  ]
166
176
  }
167
177
  };
@@ -5,7 +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
-
8
+ const transactionStatusService = require("./transactionStatusService");
9
9
  module.exports = ({ strapi }) => ({
10
10
  // Settings
11
11
  async getSettings() {
@@ -38,8 +38,9 @@ module.exports = ({ strapi }) => ({
38
38
  return await transactionService.logTransaction(strapi, transactionData);
39
39
  },
40
40
 
41
- async getTransactionHistory(filters = {}) {
42
- return await transactionService.getTransactionHistory(strapi, filters);
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);
62
- }
63
+ },
64
+
65
+ // TransactionStatus Notification
66
+ async processTransactionStatus(notificationData) {
67
+ return await transactionStatusService.processTransactionStatus(strapi, notificationData);
68
+ },
69
+
63
70
  });
@@ -17,11 +17,17 @@ const getSettings = async (strapi) => {
17
17
 
18
18
  const updateSettings = async (strapi, settings) => {
19
19
  const pluginStore = getPluginStore(strapi);
20
+ const currentSettings = await getSettings(strapi) || {};
21
+ const mergedSettings = {
22
+ ...currentSettings,
23
+ ...settings
24
+ };
25
+
20
26
  await pluginStore.set({
21
27
  key: "settings",
22
- value: settings
28
+ value: mergedSettings
23
29
  });
24
- return settings;
30
+ return mergedSettings;
25
31
  };
26
32
 
27
33
  const validateSettings = (settings) => {
@@ -55,81 +55,18 @@ const testConnection = async (strapi) => {
55
55
 
56
56
  const result = parseResponse(response.data, strapi.log);
57
57
  const status = result.status || result.Status || result.STATUS;
58
- const errorMessage =
59
- result.errormessage ||
60
- result.Errormessage ||
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
- "";
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: `Connection failed: ${customErrorMessage || errorMessageStr || "Unknown error"}`,
128
- errorcode: errorCode,
129
- details: {
130
- status,
131
- errorCode,
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
  }
@@ -147,6 +84,7 @@ const testConnection = async (strapi) => {
147
84
  };
148
85
  }
149
86
 
87
+
150
88
  return {
151
89
  success: false,
152
90
  message: "Unexpected response format from Payone API",
@@ -157,11 +95,12 @@ const testConnection = async (strapi) => {
157
95
  rawResponse: JSON.stringify(result).substring(0, 200)
158
96
  }
159
97
  };
98
+
160
99
  } catch (error) {
161
100
  strapi.log.error("Payone test connection error:", error);
162
101
  return {
163
102
  success: false,
164
- message: `Connection error: ${error.message || "Unknown error"}`,
103
+ message: `Test connection error: ${error.message || "Unknown error"}`,
165
104
  error: error.toString(),
166
105
  details: {
167
106
  errorType: error.constructor.name,
@@ -65,36 +65,32 @@ const logTransaction = async (strapi, transactionData) => {
65
65
  strapi.log.info("Transaction logged:", logEntry);
66
66
  };
67
67
 
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
- );
68
+ const applyFilters = (transactions, filters = {}) => {
69
+ let result = [...transactions];
70
+
71
+ if (filters.search && typeof filters.search === 'string' && filters.search.trim() !== '') {
72
+ const search = filters.search.toLowerCase().trim();
73
+ result = result.filter((t) => {
74
+ const txid = (t.txid || "").toString().toLowerCase();
75
+ const reference = (t.reference || "").toString().toLowerCase();
76
+ return txid.includes(search) || reference.includes(search);
85
77
  });
86
78
  }
87
79
 
88
- if (filters.request_type) {
89
- transactionHistory = transactionHistory.filter(
90
- (transaction) => transaction.request_type === filters.request_type
80
+ if (filters.status) {
81
+ result = result.filter(
82
+ (t) => (t.status || "").toUpperCase() === filters.status.toUpperCase()
91
83
  );
92
84
  }
93
85
 
86
+ if (filters.request_type) {
87
+ result = result.filter((t) => t.request_type === filters.request_type);
88
+ }
89
+
94
90
  if (filters.payment_method) {
95
- transactionHistory = transactionHistory.filter((transaction) => {
96
- const clearingtype = transaction.raw_request?.clearingtype || "";
97
- const wallettype = transaction.raw_request?.wallettype || "";
91
+ result = result.filter((t) => {
92
+ const clearingtype = t.raw_request?.clearingtype;
93
+ const wallettype = t.raw_request?.wallettype;
98
94
 
99
95
  switch (filters.payment_method) {
100
96
  case "credit_card":
@@ -102,82 +98,66 @@ const getTransactionHistory = async (strapi, filters = {}) => {
102
98
  case "paypal":
103
99
  return clearingtype === "wlt" && wallettype === "PPE";
104
100
  case "google_pay":
105
- return clearingtype === "wlt" && (wallettype === "GPY" || wallettype === "GOOGLEPAY");
101
+ return clearingtype === "wlt" && ["GPY", "GOOGLEPAY"].includes(wallettype);
106
102
  case "apple_pay":
107
- return clearingtype === "wlt" && (wallettype === "APL" || wallettype === "APPLEPAY");
103
+ return clearingtype === "wlt" && ["APL", "APPLEPAY"].includes(wallettype);
108
104
  case "sofort":
109
105
  return clearingtype === "sb";
110
106
  case "sepa":
111
107
  return clearingtype === "elv";
112
108
  default:
113
- return false;
109
+ return true;
114
110
  }
115
111
  });
116
112
  }
117
113
 
118
114
  if (filters.date_from) {
119
- transactionHistory = transactionHistory.filter(
120
- (transaction) =>
121
- new Date(transaction.timestamp) >= new Date(filters.date_from)
115
+ const dateFrom = new Date(filters.date_from);
116
+ dateFrom.setHours(0, 0, 0, 0);
117
+ result = result.filter(
118
+ (t) => new Date(t.timestamp || t.created_at) >= dateFrom
122
119
  );
123
120
  }
124
121
 
125
122
  if (filters.date_to) {
126
- transactionHistory = transactionHistory.filter(
127
- (transaction) =>
128
- new Date(transaction.timestamp) <= new Date(filters.date_to)
123
+ const dateTo = new Date(filters.date_to);
124
+ dateTo.setHours(23, 59, 59, 999);
125
+ result = result.filter(
126
+ (t) => new Date(t.timestamp || t.created_at) <= dateTo
129
127
  );
130
128
  }
131
129
 
132
- if (filters.status) {
133
- transactionHistory = transactionHistory.filter(
134
- (transaction) => transaction.status === filters.status
135
- );
136
- }
130
+ return result;
131
+ };
137
132
 
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
- }
133
+ const getTransactionHistory = async (strapi, { filters = {}, pagination = {} }) => {
134
+ const pluginStore = getPluginStore(strapi);
173
135
 
174
- if (aValue < bValue) return -1 * sortOrder;
175
- if (aValue > bValue) return 1 * sortOrder;
176
- return 0;
177
- });
178
- }
136
+ let transactions =
137
+ (await pluginStore.get({ key: "transactionHistory" })) || [];
138
+
139
+ transactions = applyFilters(transactions, filters);
140
+ const page = Number(pagination.page) || 1;
141
+ const pageSize = Number(pagination.pageSize) || 10;
142
+
143
+ const total = transactions.length;
144
+ const pageCount = Math.max(1, Math.ceil(total / pageSize));
179
145
 
180
- return transactionHistory;
146
+ const validPage = Math.min(Math.max(1, page), pageCount);
147
+
148
+ const start = (validPage - 1) * pageSize;
149
+ const end = Math.min(start + pageSize, total);
150
+
151
+ const paginatedData = start < total ? transactions.slice(start, end) : [];
152
+ return {
153
+ data: paginatedData,
154
+ pagination: {
155
+ page: validPage,
156
+ pageSize,
157
+ pageCount,
158
+ total,
159
+ },
160
+ };
181
161
  };
182
162
 
183
163
  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
+ };