strapi-plugin-payone-provider 1.1.3 → 1.3.0

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 (38) hide show
  1. package/README.md +1156 -380
  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 +134 -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 +119 -280
  9. package/admin/src/pages/App/components/StatusBadge.js +3 -1
  10. package/admin/src/pages/App/components/TransactionHistoryItem.js +4 -1
  11. package/admin/src/pages/App/components/paymentActions/AuthorizationForm.js +122 -0
  12. package/admin/src/pages/App/components/paymentActions/CaptureForm.js +64 -0
  13. package/admin/src/pages/App/components/paymentActions/CardDetailsInput.js +189 -0
  14. package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.js +52 -0
  15. package/admin/src/pages/App/components/paymentActions/PaymentResult.js +148 -0
  16. package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.js +122 -0
  17. package/admin/src/pages/App/components/paymentActions/RefundForm.js +89 -0
  18. package/admin/src/pages/App/index.js +41 -465
  19. package/admin/src/pages/App/styles.css +294 -0
  20. package/admin/src/pages/constants/paymentConstants.js +37 -0
  21. package/admin/src/pages/hooks/usePaymentActions.js +456 -0
  22. package/admin/src/pages/hooks/useSettings.js +111 -0
  23. package/admin/src/pages/hooks/useTransactionHistory.js +87 -0
  24. package/admin/src/pages/utils/api.js +10 -0
  25. package/admin/src/pages/utils/injectGooglePayScript.js +31 -0
  26. package/admin/src/pages/utils/paymentUtils.js +119 -15
  27. package/package.json +1 -1
  28. package/server/controllers/payone.js +71 -64
  29. package/server/routes/index.js +17 -0
  30. package/server/services/paymentService.js +271 -0
  31. package/server/services/payone.js +25 -648
  32. package/server/services/settingsService.js +59 -0
  33. package/server/services/testConnectionService.js +190 -0
  34. package/server/services/transactionService.js +114 -0
  35. package/server/utils/normalize.js +51 -0
  36. package/server/utils/paymentMethodParams.js +126 -0
  37. package/server/utils/requestBuilder.js +121 -0
  38. package/server/utils/responseParser.js +134 -0
@@ -11,6 +11,8 @@
11
11
  * Supported Payment Methods:
12
12
  * - Credit Card (cc)
13
13
  * - PayPal (wlt)
14
+ * - Google Pay (gpp)
15
+ * - Apple Pay (apl)
14
16
  * - Sofort Banking (sb)
15
17
  * - SEPA Direct Debit (elv)
16
18
  */
@@ -45,8 +47,18 @@ export const getBaseParams = (options = {}) => {
45
47
  backurl = "https://www.example.com/back"
46
48
  } = options;
47
49
 
48
- // Generate unique customer ID if not provided
49
- const finalCustomerId = customerid || `CUST-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
50
+ const generateCustomerId = () => {
51
+ const timestamp = Date.now().toString().slice(-10);
52
+ const random = Math.random().toString(36).substring(2, 6).toUpperCase();
53
+ const id = `${timestamp}${random}`.slice(0, 17);
54
+ return id;
55
+ };
56
+
57
+ let finalCustomerId = customerid || generateCustomerId();
58
+
59
+ if (finalCustomerId && finalCustomerId.length > 17) {
60
+ finalCustomerId = finalCustomerId.slice(0, 17);
61
+ }
50
62
 
51
63
  return {
52
64
  // Required core parameters (Payone v1)
@@ -88,21 +100,49 @@ export const getBaseParams = (options = {}) => {
88
100
  */
89
101
  export const getPaymentMethodParams = (paymentMethod, options = {}) => {
90
102
  const {
91
- cardType = "V",
103
+ cardType,
104
+ cardtype,
92
105
  captureMode = "full",
93
106
  cardpan,
94
107
  cardexpiredate,
95
108
  cardcvc2,
96
109
  iban,
97
110
  bic,
98
- bankaccountholder
111
+ bankaccountholder,
112
+ // Shipping address for wallet payments (Google Pay, Apple Pay, PayPal)
113
+ shipping_firstname,
114
+ shipping_lastname,
115
+ shipping_street,
116
+ shipping_zip,
117
+ shipping_city,
118
+ shipping_country,
119
+ // Billing address (used as fallback for shipping)
120
+ firstname,
121
+ lastname,
122
+ street,
123
+ zip,
124
+ city,
125
+ country
99
126
  } = options;
100
127
 
128
+ // Use cardtype if provided, otherwise fall back to cardType, otherwise default to "V"
129
+ const finalCardType = cardtype || cardType || "V";
130
+
131
+ // Helper to get shipping params for wallet payments
132
+ const getShippingParams = () => ({
133
+ shipping_firstname: shipping_firstname || firstname || "John",
134
+ shipping_lastname: shipping_lastname || lastname || "Doe",
135
+ shipping_street: shipping_street || street || "Test Street 123",
136
+ shipping_zip: shipping_zip || zip || "12345",
137
+ shipping_city: shipping_city || city || "Test City",
138
+ shipping_country: (shipping_country || country || "DE").toUpperCase()
139
+ });
140
+
101
141
  switch (paymentMethod) {
102
142
  case "cc": // Credit Card (Visa, Mastercard, Amex)
103
143
  return {
104
144
  clearingtype: "cc",
105
- cardtype: cardType, // V = Visa, M = Mastercard, A = Amex
145
+ cardtype: finalCardType, // V = Visa, M = Mastercard, A = Amex
106
146
  cardpan: cardpan || "4111111111111111", // Test Visa card
107
147
  cardexpiredate: cardexpiredate || "2512", // MMYY format
108
148
  cardcvc2: cardcvc2 || "123" // 3-digit security code
@@ -112,12 +152,34 @@ export const getPaymentMethodParams = (paymentMethod, options = {}) => {
112
152
  return {
113
153
  clearingtype: "wlt",
114
154
  wallettype: "PPE", // PayPal Express
115
- shipping_firstname: "John",
116
- shipping_lastname: "Doe",
117
- shipping_street: "Test Street 123",
118
- shipping_zip: "12345",
119
- shipping_city: "Test City",
120
- shipping_country: "DE"
155
+ ...getShippingParams()
156
+ };
157
+
158
+ case "gpp":
159
+ const googlePayParams = {
160
+ clearingtype: "wlt",
161
+ wallettype: "GGP",
162
+ ...getShippingParams()
163
+ };
164
+
165
+ if (options.googlePayToken) {
166
+ const gatewayMerchantId = options.settings?.mid || options.settings?.portalid || '';
167
+ googlePayParams["add_paydata[paymentmethod_token_data]"] = options.googlePayToken;
168
+ googlePayParams["add_paydata[paymentmethod]"] = "GGP";
169
+ googlePayParams["add_paydata[paymentmethod_type]"] = "GOOGLEPAY";
170
+ googlePayParams["add_paydata[gatewayid]"] = "payonegmbh";
171
+ if (gatewayMerchantId) {
172
+ googlePayParams["add_paydata[gateway_merchantid]"] = gatewayMerchantId;
173
+ }
174
+ }
175
+
176
+ return googlePayParams;
177
+
178
+ case "apl": // Apple Pay
179
+ return {
180
+ clearingtype: "wlt",
181
+ wallettype: "APL", // Apple Pay
182
+ ...getShippingParams()
121
183
  };
122
184
 
123
185
  case "sb": // Sofort Banking
@@ -159,11 +221,19 @@ export const getPreauthorizationParams = (paymentMethod, options = {}) => {
159
221
  const baseParams = getBaseParams(options);
160
222
  const methodParams = getPaymentMethodParams(paymentMethod, options);
161
223
 
162
- return {
224
+ const params = {
163
225
  ...baseParams,
164
226
  ...methodParams,
165
227
  request: "preauthorization" // Required for Payone API
166
228
  };
229
+
230
+ // Add 3D Secure parameters for credit card payments if enabled
231
+ if (paymentMethod === "cc" && options.enable3DSecure !== false) {
232
+ params["3dsecure"] = "yes";
233
+ params.ecommercemode = options.ecommercemode || "internet";
234
+ }
235
+
236
+ return params;
167
237
  };
168
238
 
169
239
  /**
@@ -177,11 +247,19 @@ export const getAuthorizationParams = (paymentMethod, options = {}) => {
177
247
  const baseParams = getBaseParams(options);
178
248
  const methodParams = getPaymentMethodParams(paymentMethod, options);
179
249
 
180
- return {
250
+ const params = {
181
251
  ...baseParams,
182
252
  ...methodParams,
183
253
  request: "authorization" // Required for Payone API
184
254
  };
255
+
256
+ // Add 3D Secure parameters for credit card payments if enabled
257
+ if (paymentMethod === "cc" && options.enable3DSecure !== false) {
258
+ params["3dsecure"] = "yes";
259
+ params.ecommercemode = options.ecommercemode || "internet";
260
+ }
261
+
262
+ return params;
185
263
  };
186
264
 
187
265
  /**
@@ -220,6 +298,8 @@ export const getCaptureParams = (paymentMethod, options = {}) => {
220
298
  break;
221
299
 
222
300
  case "wlt": // PayPal
301
+ case "gpp": // Google Pay
302
+ case "apl": // Apple Pay
223
303
  methodParams = {
224
304
  capturemode: captureMode // full or partial
225
305
  };
@@ -279,7 +359,9 @@ export const getRefundParams = (paymentMethod, options = {}) => {
279
359
  break;
280
360
 
281
361
  case "wlt": // PayPal
282
- // PayPal specific refund parameters (if needed)
362
+ case "gpp": // Google Pay
363
+ case "apl": // Apple Pay
364
+ // Wallet payment specific refund parameters (if needed)
283
365
  break;
284
366
 
285
367
  case "sb": // Sofort Banking
@@ -310,6 +392,8 @@ export const getPaymentMethodDisplayName = (paymentMethod) => {
310
392
  const displayNames = {
311
393
  cc: "Credit Card (Visa, Mastercard)",
312
394
  wlt: "PayPal",
395
+ gpp: "Google Pay",
396
+ apl: "Apple Pay",
313
397
  sb: "Sofort Banking",
314
398
  elv: "SEPA Direct Debit"
315
399
  };
@@ -325,6 +409,8 @@ export const getPaymentMethodOptions = () => {
325
409
  return [
326
410
  { value: "cc", label: "Credit Card (Visa, Mastercard)" },
327
411
  { value: "wlt", label: "PayPal" },
412
+ { value: "gpp", label: "Google Pay" },
413
+ { value: "apl", label: "Apple Pay" },
328
414
  { value: "sb", label: "Sofort Banking" },
329
415
  { value: "elv", label: "SEPA Direct Debit" }
330
416
  ];
@@ -336,7 +422,7 @@ export const getPaymentMethodOptions = () => {
336
422
  * @returns {boolean} True if supports capture mode
337
423
  */
338
424
  export const supportsCaptureMode = (paymentMethod) => {
339
- return paymentMethod === "wlt"; // Only PayPal supports capture mode
425
+ return paymentMethod === "wlt" || paymentMethod === "gpp" || paymentMethod === "apl"; // PayPal, Google Pay, and Apple Pay support capture mode
340
426
  };
341
427
 
342
428
  /**
@@ -487,6 +573,24 @@ export const validatePaymentParams = (operation, paymentMethod, params) => {
487
573
  }
488
574
  break;
489
575
 
576
+ case "gpp":
577
+ if (!params.wallettype) {
578
+ errors.push("Wallet type is required for Google Pay payments");
579
+ }
580
+ if (params.wallettype && params.wallettype !== "GGP") {
581
+ errors.push("Wallet type must be GGP for Google Pay payments");
582
+ }
583
+ break;
584
+
585
+ case "apl":
586
+ if (!params.wallettype) {
587
+ errors.push("Wallet type is required for Apple Pay payments");
588
+ }
589
+ if (params.wallettype && params.wallettype !== "APL") {
590
+ errors.push("Wallet type must be APL for Apple Pay payments");
591
+ }
592
+ break;
593
+
490
594
  case "sb":
491
595
  if (!params.bankcountry) {
492
596
  errors.push("Bank country is required for Sofort payments");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-payone-provider",
3
- "version": "1.1.3",
3
+ "version": "1.3.0",
4
4
  "description": "Strapi plugin for Payone payment gateway integration",
5
5
  "license": "MIT",
6
6
  "maintainers": [
@@ -1,62 +1,72 @@
1
1
  "use strict";
2
2
 
3
+ const PLUGIN_NAME = "strapi-plugin-payone-provider";
4
+
5
+ /**
6
+ * Get Payone service
7
+ * @param {Object} strapi - Strapi instance
8
+ * @returns {Object} Payone service
9
+ */
10
+ const getPayoneService = (strapi) => {
11
+ return strapi.plugin(PLUGIN_NAME).service("payone");
12
+ };
13
+
14
+ /**
15
+ * Handle error response
16
+ * @param {Object} ctx - Koa context
17
+ * @param {Error} error - Error object
18
+ */
19
+ const handleError = (ctx, error) => {
20
+ strapi.log.error("Payone controller error:", error);
21
+ ctx.throw(500, error);
22
+ };
23
+
24
+ /**
25
+ * Hide sensitive key in settings
26
+ * @param {Object} settings - Settings object
27
+ * @returns {Object} Settings with hidden key
28
+ */
29
+ const hideKey = (settings) => {
30
+ if (settings && settings.key) {
31
+ settings.key = "***HIDDEN***";
32
+ }
33
+ return settings;
34
+ };
35
+
3
36
  module.exports = ({ strapi }) => ({
4
37
  async getSettings(ctx) {
5
38
  try {
6
- const settings = await strapi
7
- .plugin("strapi-plugin-payone-provider")
8
- .service("payone")
9
- .getSettings();
10
-
11
- if (settings && settings.key) {
12
- settings.key = "***HIDDEN***";
13
- }
14
-
15
- ctx.body = { data: settings };
39
+ const settings = await getPayoneService(strapi).getSettings();
40
+ ctx.body = { data: hideKey(settings) };
16
41
  } catch (error) {
17
- ctx.throw(500, error);
42
+ handleError(ctx, error);
18
43
  }
19
44
  },
20
45
 
21
46
  async updateSettings(ctx) {
22
47
  try {
23
48
  const { body } = ctx.request;
49
+ const currentSettings = await getPayoneService(strapi).getSettings();
24
50
 
25
- const currentSettings = await strapi
26
- .plugin("strapi-plugin-payone-provider")
27
- .service("payone")
28
- .getSettings();
29
-
51
+ // Preserve existing key if hidden or not provided
30
52
  if (body.key === "***HIDDEN***" || !body.key) {
31
- body.key = currentSettings.key;
53
+ body.key = currentSettings?.key;
32
54
  }
33
55
 
34
- const settings = await strapi
35
- .plugin("strapi-plugin-payone-provider")
36
- .service("payone")
37
- .updateSettings(body);
38
-
39
- if (settings && settings.key) {
40
- settings.key = "***HIDDEN***";
41
- }
42
-
43
- ctx.body = { data: settings };
56
+ const settings = await getPayoneService(strapi).updateSettings(body);
57
+ ctx.body = { data: hideKey(settings) };
44
58
  } catch (error) {
45
- ctx.throw(500, error);
59
+ handleError(ctx, error);
46
60
  }
47
61
  },
48
62
 
49
63
  async preauthorization(ctx) {
50
64
  try {
51
65
  const params = ctx.request.body;
52
- const result = await strapi
53
- .plugin("strapi-plugin-payone-provider")
54
- .service("payone")
55
- .preauthorization(params);
56
-
66
+ const result = await getPayoneService(strapi).preauthorization(params);
57
67
  ctx.body = { data: result };
58
68
  } catch (error) {
59
- ctx.throw(500, error);
69
+ handleError(ctx, error);
60
70
  }
61
71
  },
62
72
 
@@ -64,71 +74,68 @@ module.exports = ({ strapi }) => ({
64
74
  try {
65
75
  const params = ctx.request.body;
66
76
  strapi.log.info("Payone authorization controller called with:", params);
67
-
68
- const result = await strapi
69
- .plugin("strapi-plugin-payone-provider")
70
- .service("payone")
71
- .authorization(params);
72
-
77
+ const result = await getPayoneService(strapi).authorization(params);
73
78
  ctx.body = { data: result };
74
79
  } catch (error) {
75
80
  strapi.log.error("Payone authorization error:", error);
76
- ctx.throw(500, error);
81
+ handleError(ctx, error);
77
82
  }
78
83
  },
79
84
 
80
85
  async capture(ctx) {
81
86
  try {
82
87
  const params = ctx.request.body;
83
- const result = await strapi
84
- .plugin("strapi-plugin-payone-provider")
85
- .service("payone")
86
- .capture(params);
87
-
88
+ const result = await getPayoneService(strapi).capture(params);
88
89
  ctx.body = { data: result };
89
90
  } catch (error) {
90
- ctx.throw(500, error);
91
+ handleError(ctx, error);
91
92
  }
92
93
  },
93
94
 
94
95
  async refund(ctx) {
95
96
  try {
96
97
  const params = ctx.request.body;
97
- const result = await strapi
98
- .plugin("strapi-plugin-payone-provider")
99
- .service("payone")
100
- .refund(params);
101
-
98
+ const result = await getPayoneService(strapi).refund(params);
102
99
  ctx.body = { data: result };
103
100
  } catch (error) {
104
- ctx.throw(500, error);
101
+ handleError(ctx, error);
105
102
  }
106
103
  },
107
104
 
108
105
  async getTransactionHistory(ctx) {
109
106
  try {
110
107
  const filters = ctx.query || {};
111
- const history = await strapi
112
- .plugin("strapi-plugin-payone-provider")
113
- .service("payone")
114
- .getTransactionHistory(filters);
115
-
108
+ const history = await getPayoneService(strapi).getTransactionHistory(filters);
116
109
  ctx.body = { data: history };
117
110
  } catch (error) {
118
- ctx.throw(500, error);
111
+ handleError(ctx, error);
119
112
  }
120
113
  },
121
114
 
122
115
  async testConnection(ctx) {
123
116
  try {
124
- const result = await strapi
125
- .plugin("strapi-plugin-payone-provider")
126
- .service("payone")
127
- .testConnection();
117
+ const result = await getPayoneService(strapi).testConnection();
118
+ ctx.body = { data: result };
119
+ } catch (error) {
120
+ handleError(ctx, error);
121
+ }
122
+ },
123
+
124
+ /**
125
+ * Handle 3D Secure callback from Payone
126
+ * This endpoint receives the callback after customer completes 3DS authentication
127
+ */
128
+ async handle3DSCallback(ctx) {
129
+ try {
130
+ strapi.log.info("3DS callback received:", ctx.request.body);
131
+
132
+ const callbackData = ctx.request.body;
133
+ const result = await getPayoneService(strapi).handle3DSCallback(callbackData);
128
134
 
129
135
  ctx.body = { data: result };
130
136
  } catch (error) {
131
- ctx.throw(500, error);
137
+ strapi.log.error("3DS callback error:", error);
138
+ handleError(ctx, error);
132
139
  }
133
140
  }
134
141
  });
@@ -67,6 +67,14 @@ module.exports = {
67
67
  config: {
68
68
  policies: ["admin::isAuthenticatedAdmin"]
69
69
  }
70
+ },
71
+ {
72
+ method: "POST",
73
+ path: "/3ds-callback",
74
+ handler: "payone.handle3DSCallback",
75
+ config: {
76
+ policies: ["admin::isAuthenticatedAdmin"]
77
+ }
70
78
  }
71
79
  ]
72
80
  },
@@ -118,6 +126,15 @@ module.exports = {
118
126
  policies: ["plugin::strapi-plugin-payone-provider.is-auth"],
119
127
  auth: false
120
128
  }
129
+ },
130
+ {
131
+ method: "POST",
132
+ path: "/3ds-callback",
133
+ handler: "payone.handle3DSCallback",
134
+ config: {
135
+ policies: ["plugin::strapi-plugin-payone-provider.is-auth"],
136
+ auth: false
137
+ }
121
138
  }
122
139
  ]
123
140
  }