strapi-plugin-payone-provider 1.5.8-beta.1 → 1.6.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 (53) hide show
  1. package/admin/src/index.js +3 -3
  2. package/admin/src/pages/App/components/ApplePayBtn.jsx +304 -0
  3. package/admin/src/pages/App/components/{ApplePayButton.js → ApplePayButton.jsx} +4 -46
  4. package/admin/src/pages/App/components/{ApplePayConfig.js → ApplePayConfig.jsx} +64 -130
  5. package/admin/src/pages/App/components/{PaymentActionsPanel.js → PaymentActionsPanel.jsx} +62 -14
  6. package/admin/src/pages/App/components/icons/index.jsx +11 -0
  7. package/admin/src/pages/App/components/paymentActions/{AuthorizationForm.js → AuthorizationForm.jsx} +45 -35
  8. package/admin/src/pages/App/components/paymentActions/{PaymentMethodSelector.js → PaymentMethodSelector.jsx} +111 -31
  9. package/admin/src/pages/App/components/paymentActions/{PreauthorizationForm.js → PreauthorizationForm.jsx} +3 -70
  10. package/admin/src/pages/constants/paymentConstants.js +1 -2
  11. package/admin/src/pages/hooks/usePaymentActions.js +1 -76
  12. package/package.json +49 -49
  13. package/server/bootstrap.js +59 -1
  14. package/server/controllers/payone.js +6 -77
  15. package/server/routes/index.js +1 -1
  16. package/server/services/applePayService.js +51 -509
  17. package/server/services/paymentService.js +0 -68
  18. package/server/services/payone.js +0 -3
  19. package/server/services/settingsService.js +0 -21
  20. package/server/services/testConnectionService.js +0 -14
  21. package/server/services/transactionService.js +2 -16
  22. package/server/utils/paymentMethodParams.js +60 -21
  23. package/server/utils/requestBuilder.js +0 -22
  24. package/admin/src/pages/App/components/icons/index.js +0 -11
  25. /package/admin/src/components/Initializer/{index.js → index.jsx} +0 -0
  26. /package/admin/src/components/PluginIcon/{index.js → index.jsx} +0 -0
  27. /package/admin/src/pages/App/components/{AppHeader.js → AppHeader.jsx} +0 -0
  28. /package/admin/src/pages/App/components/{AppTabs.js → AppTabs.jsx} +0 -0
  29. /package/admin/src/pages/App/components/{ApplePayConfigPanel.js → ApplePayConfigPanel.jsx} +0 -0
  30. /package/admin/src/pages/App/components/{ConfigurationPanel.js → ConfigurationPanel.jsx} +0 -0
  31. /package/admin/src/pages/App/components/{DocsPanel.js → DocsPanel.jsx} +0 -0
  32. /package/admin/src/pages/App/components/{GooglePayConfig.js → GooglePayConfig.jsx} +0 -0
  33. /package/admin/src/pages/App/components/{GooglePayConfigPanel.js → GooglePayConfigPanel.jsx} +0 -0
  34. /package/admin/src/pages/App/components/{GooglePaybutton.js → GooglePaybutton.jsx} +0 -0
  35. /package/admin/src/pages/App/components/{HistoryPanel.js → HistoryPanel.jsx} +0 -0
  36. /package/admin/src/pages/App/components/{StatusBadge.js → StatusBadge.jsx} +0 -0
  37. /package/admin/src/pages/App/components/{TransactionHistoryItem.js → TransactionHistoryItem.jsx} +0 -0
  38. /package/admin/src/pages/App/components/icons/{BankIcon.js → BankIcon.jsx} +0 -0
  39. /package/admin/src/pages/App/components/icons/{ChevronDownIcon.js → ChevronDownIcon.jsx} +0 -0
  40. /package/admin/src/pages/App/components/icons/{ChevronUpIcon.js → ChevronUpIcon.jsx} +0 -0
  41. /package/admin/src/pages/App/components/icons/{CreditCardIcon.js → CreditCardIcon.jsx} +0 -0
  42. /package/admin/src/pages/App/components/icons/{ErrorIcon.js → ErrorIcon.jsx} +0 -0
  43. /package/admin/src/pages/App/components/icons/{InfoIcon.js → InfoIcon.jsx} +0 -0
  44. /package/admin/src/pages/App/components/icons/{PaymentIcon.js → PaymentIcon.jsx} +0 -0
  45. /package/admin/src/pages/App/components/icons/{PendingIcon.js → PendingIcon.jsx} +0 -0
  46. /package/admin/src/pages/App/components/icons/{PersonIcon.js → PersonIcon.jsx} +0 -0
  47. /package/admin/src/pages/App/components/icons/{SuccessIcon.js → SuccessIcon.jsx} +0 -0
  48. /package/admin/src/pages/App/components/icons/{WalletIcon.js → WalletIcon.jsx} +0 -0
  49. /package/admin/src/pages/App/components/paymentActions/{CaptureForm.js → CaptureForm.jsx} +0 -0
  50. /package/admin/src/pages/App/components/paymentActions/{CardDetailsInput.js → CardDetailsInput.jsx} +0 -0
  51. /package/admin/src/pages/App/components/paymentActions/{PaymentResult.js → PaymentResult.jsx} +0 -0
  52. /package/admin/src/pages/App/components/paymentActions/{RefundForm.js → RefundForm.jsx} +0 -0
  53. /package/admin/src/pages/App/{index.js → index.jsx} +0 -0
@@ -6,183 +6,48 @@ const { getSettings, validateSettings } = require("./settingsService");
6
6
 
7
7
  const POST_GATEWAY_URL = "https://api.pay1.de/post-gateway/";
8
8
 
9
- /**
10
- * Initialize Apple Pay session with Payone
11
- * According to Payone documentation:
12
- * https://docs.payone.com/payment-methods/apple-pay/apple-pay-without-dev
13
- *
14
- * Request: genericpayment
15
- * Required parameters:
16
- * - request="genericpayment"
17
- * - clearingtype="wlt"
18
- * - wallettype="APL"
19
- * - add_paydata[action]="init_applepay_session"
20
- * - add_paydata[display_name]="Store Name"
21
- * - add_paydata[domain_name]="yourdomain.com"
22
- */
9
+ const parseResponse = (responseData) => {
10
+ if (typeof responseData === 'string') {
11
+ const params = new URLSearchParams(responseData);
12
+ const parsed = {};
13
+ for (const [key, value] of params.entries()) {
14
+ parsed[key] = value;
15
+ }
16
+ return parsed;
17
+ }
18
+ return responseData;
19
+ };
20
+
23
21
  const initializeApplePaySession = async (strapi, params) => {
24
22
  try {
25
- strapi.log.info("[Apple Pay] Initializing Apple Pay session with Payone");
26
- strapi.log.info("[Apple Pay] Request params:", JSON.stringify(params, null, 2));
27
-
28
23
  const settings = await getSettings(strapi);
24
+ const { displayName, domainName } = params;
29
25
 
30
- if (!validateSettings(settings)) {
31
- strapi.log.error("[Apple Pay] Payone settings not configured");
32
- throw new Error("Payone settings not configured");
33
- }
26
+ const merchantName = displayName || "Store";
27
+ const domain = domainName;
34
28
 
35
- strapi.log.info("[Apple Pay] Settings loaded:", {
36
- mode: settings.mode,
37
- mid: settings.mid,
38
- portalid: settings.portalid,
39
- hasKey: !!settings.key
40
- });
41
-
42
- const {
43
- displayName,
44
- domainName,
45
- mid,
46
- portalid
47
- } = params;
48
-
49
- // Get merchant data from settings (test or live mode)
50
- const merchantName = displayName || settings.merchantName || settings.displayName || "Test Store";
51
- const merchantId = mid || settings.mid || settings.merchantIdentifier;
52
- const portalId = portalid || settings.portalid;
53
- const accountId = settings.aid;
54
- const apiKey = settings.key;
55
- const mode = settings.mode || "test"; // test or live
56
-
57
- // Get domain from params or settings or server config
58
- const domain = domainName || settings.domainName ||
59
- (strapi.config.get("server.url") ? new URL(strapi.config.get("server.url")).hostname : null) ||
60
- "localhost";
61
-
62
- // Build request parameters for Apple Pay session initialization
63
- // According to Payone documentation: request="genericpayment"
64
- const requestParams = {
29
+ const baseParams = {
65
30
  request: "genericpayment",
66
- mid: merchantId,
67
- aid: accountId,
68
- portalid: portalId,
69
- key: apiKey,
70
- mode: mode, // Use test or live mode from settings
71
31
  clearingtype: "wlt",
72
32
  wallettype: "APL",
73
- currency: "EUR", // Default, can be overridden
33
+ currency: params.currency,
74
34
  "add_paydata[action]": "init_applepay_session",
75
35
  "add_paydata[display_name]": merchantName,
76
36
  "add_paydata[domain_name]": domain
77
37
  };
78
38
 
79
- strapi.log.info("[Apple Pay] Sending request to Payone:", {
80
- url: POST_GATEWAY_URL,
81
- mode: mode,
82
- merchantName: merchantName,
83
- domain: domain,
84
- merchantId: merchantId,
85
- portalId: portalId
86
- });
39
+ const requestParams = buildClientRequestParams(settings, baseParams, strapi.log);
87
40
 
88
41
  const formData = toFormData(requestParams);
89
-
90
- strapi.log.info("[Apple Pay] Sending request to Payone API:", {
91
- url: POST_GATEWAY_URL,
92
- params: {
93
- ...requestParams,
94
- key: "***HIDDEN***" // Hide API key in logs
95
- }
42
+ const response = await axios.post(`${POST_GATEWAY_URL}Genericpayment`, formData, {
43
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
44
+ timeout: 30000
96
45
  });
97
46
 
98
- let response;
99
- try {
100
- response = await axios.post(POST_GATEWAY_URL, formData, {
101
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
102
- timeout: 30000
103
- });
104
- } catch (axiosError) {
105
- strapi.log.error("[Apple Pay] Payone API request failed:", {
106
- message: axiosError.message,
107
- status: axiosError.response?.status,
108
- statusText: axiosError.response?.statusText,
109
- data: axiosError.response?.data,
110
- config: {
111
- url: axiosError.config?.url,
112
- method: axiosError.config?.method
113
- }
114
- });
115
- throw axiosError;
116
- }
117
-
118
- strapi.log.info("[Apple Pay] ========== PAYONE RESPONSE START ==========");
119
- strapi.log.info("[Apple Pay] HTTP Status:", response.status);
120
- strapi.log.info("[Apple Pay] HTTP Status Text:", response.statusText);
121
- strapi.log.info("[Apple Pay] Response Headers:", JSON.stringify(response.headers, null, 2));
122
- strapi.log.info("[Apple Pay] Raw Response Data Type:", typeof response.data);
123
- strapi.log.info("[Apple Pay] Raw Response Data:", response.data);
124
-
125
- // Parse response
126
- const responseData = parseResponse(response.data, strapi.log);
127
-
128
- strapi.log.info("[Apple Pay] ========== PARSED RESPONSE ==========");
129
- strapi.log.info("[Apple Pay] Full Parsed Response (JSON):", JSON.stringify(responseData, null, 2));
130
- strapi.log.info("[Apple Pay] Response Type:", typeof responseData);
131
- strapi.log.info("[Apple Pay] Is Object:", responseData instanceof Object);
132
- strapi.log.info("[Apple Pay] All Response Keys:", Object.keys(responseData));
133
- strapi.log.info("[Apple Pay] Response Keys Count:", Object.keys(responseData).length);
134
-
135
- // Log each key-value pair
136
- strapi.log.info("[Apple Pay] ========== RESPONSE KEY-VALUE PAIRS ==========");
137
- for (const [key, value] of Object.entries(responseData)) {
138
- if (typeof value === 'string' && value.length > 200) {
139
- strapi.log.info(`[Apple Pay] ${key}:`, value.substring(0, 200) + "... (truncated, length: " + value.length + ")");
140
- } else {
141
- strapi.log.info(`[Apple Pay] ${key}:`, value);
142
- }
143
- }
144
-
145
- strapi.log.info("[Apple Pay] ========== IMPORTANT FIELDS ==========");
146
- strapi.log.info("[Apple Pay] status:", responseData.status || responseData.Status || "NOT_SET");
147
- strapi.log.info("[Apple Pay] Status (lowercase):", responseData.status || "NOT_SET");
148
- strapi.log.info("[Apple Pay] Status (uppercase):", responseData.Status || "NOT_SET");
149
- strapi.log.info("[Apple Pay] errorcode:", responseData.errorcode || responseData.ErrorCode || responseData.error_code || "none");
150
- strapi.log.info("[Apple Pay] errormessage:", responseData.errormessage || responseData.ErrorMessage || responseData.errortxt || responseData.ErrorTxt || responseData.error_message || "none");
151
- strapi.log.info("[Apple Pay] workorderid:", responseData.workorderid || responseData.workorderId || responseData.WorkorderId || "none");
152
- strapi.log.info("[Apple Pay] txid:", responseData.txid || responseData.TxId || responseData.tx_id || "none");
153
-
154
- // Check for Apple Pay session in various formats
155
- strapi.log.info("[Apple Pay] ========== APPLE PAY SESSION CHECK ==========");
156
- const applePaySessionKeys = [
157
- "add_paydata[applepay_payment_session]",
158
- "add_paydata_applepay_payment_session",
159
- "addPaydata[applepay_payment_session]",
160
- "addPaydata_applepay_payment_session",
161
- "applepay_payment_session",
162
- "applePayPaymentSession",
163
- "payment_session",
164
- "paymentSession"
165
- ];
166
-
167
- for (const key of applePaySessionKeys) {
168
- if (responseData[key]) {
169
- strapi.log.info(`[Apple Pay] Found Apple Pay session in key: ${key}`);
170
- strapi.log.info(`[Apple Pay] Session value length: ${responseData[key].length}`);
171
- strapi.log.info(`[Apple Pay] Session value preview: ${responseData[key].substring(0, 100)}...`);
172
- }
173
- }
174
-
175
- // Check add_paydata object if it exists
176
- if (responseData.add_paydata) {
177
- strapi.log.info("[Apple Pay] add_paydata object exists:", typeof responseData.add_paydata);
178
- strapi.log.info("[Apple Pay] add_paydata keys:", Object.keys(responseData.add_paydata));
179
- strapi.log.info("[Apple Pay] add_paydata content:", JSON.stringify(responseData.add_paydata, null, 2));
180
- }
181
-
182
- strapi.log.info("[Apple Pay] ========== PAYONE RESPONSE END ==========");
47
+ const responseData = parseResponse(response.data);
183
48
 
184
49
  if (responseData.errorcode || responseData.ErrorCode) {
185
- strapi.log.warn("[Apple Pay] Response contains error:", {
50
+ strapi.log.error("[Apple Pay] Payone error:", {
186
51
  errorcode: responseData.errorcode || responseData.ErrorCode,
187
52
  errormessage: responseData.errormessage || responseData.ErrorMessage
188
53
  });
@@ -199,374 +64,51 @@ const initializeApplePaySession = async (strapi, params) => {
199
64
  }
200
65
  };
201
66
 
202
- /**
203
- * Validate Apple Pay merchant with Payone
204
- * This is called when Apple Pay requests merchant validation
205
- */
206
67
  const validateApplePayMerchant = async (strapi, params) => {
207
- try {
208
- strapi.log.info("[Apple Pay] Validating merchant with Payone");
209
- strapi.log.info("[Apple Pay] Validation params:", JSON.stringify({
210
- validationURL: params.validationURL,
211
- domain: params.domain,
212
- displayName: params.displayName,
213
- mid: params.mid,
214
- portalid: params.portalid
215
- }, null, 2));
216
-
217
- const settings = await getSettings(strapi);
218
-
219
- if (!validateSettings(settings)) {
220
- strapi.log.error("[Apple Pay] Payone settings not configured for merchant validation");
221
- throw new Error("Payone settings not configured");
222
- }
223
-
224
- // Log all settings to verify MerchantId is being read correctly
225
- strapi.log.info("[Apple Pay] ========== SETTINGS FROM CONFIG ==========");
226
- strapi.log.info("[Apple Pay] Full Settings Object:", JSON.stringify(settings, null, 2));
227
- strapi.log.info("[Apple Pay] Settings Keys:", Object.keys(settings || {}));
228
- strapi.log.info("[Apple Pay] MerchantId (mid) from config:", settings.mid || "NOT_SET");
229
- strapi.log.info("[Apple Pay] MerchantId type:", typeof settings.mid);
230
- strapi.log.info("[Apple Pay] MerchantId length:", settings.mid ? settings.mid.length : 0);
231
- strapi.log.info("[Apple Pay] merchantIdentifier from config:", settings.merchantIdentifier || "NOT_SET");
232
- strapi.log.info("[Apple Pay] portalid from config:", settings.portalid || "NOT_SET");
233
- strapi.log.info("[Apple Pay] mode from config:", settings.mode || "NOT_SET");
234
- strapi.log.info("[Apple Pay] ==========================================");
235
-
236
- const {
237
- validationURL,
238
- mid,
239
- portalid,
240
- domain,
241
- displayName
242
- } = params;
243
-
244
- // Get merchant data from settings (test or live mode)
245
- const merchantName = displayName || settings.merchantName || settings.displayName || "Test Store";
68
+ const settings = await getSettings(strapi);
246
69
 
247
- // Use MerchantId (mid) from config as merchantIdentifier
248
- // Priority: params.mid > settings.mid > settings.merchantIdentifier
249
- const merchantId = mid || settings.mid || settings.merchantIdentifier;
250
- const portalId = portalid || settings.portalid;
251
-
252
- strapi.log.info("[Apple Pay] ========== MERCHANT ID SELECTION ==========");
253
- strapi.log.info("[Apple Pay] mid from params:", mid || "NOT_PROVIDED");
254
- strapi.log.info("[Apple Pay] settings.mid:", settings.mid || "NOT_SET");
255
- strapi.log.info("[Apple Pay] settings.merchantIdentifier:", settings.merchantIdentifier || "NOT_SET");
256
- strapi.log.info("[Apple Pay] Selected merchantId:", merchantId || "NOT_SET");
257
- strapi.log.info("[Apple Pay] Selected merchantId type:", typeof merchantId);
258
- strapi.log.info("[Apple Pay] Selected merchantId length:", merchantId ? merchantId.length : 0);
259
- strapi.log.info("[Apple Pay] ==========================================");
260
-
261
- // Get domain from params or settings or server config
262
- const domainName = domain || settings.domainName ||
263
- (strapi.config.get("server.url") ? new URL(strapi.config.get("server.url")).hostname : null) ||
264
- "localhost";
70
+ if (!validateSettings(settings)) {
71
+ strapi.log.error("Payone settings not configured");
72
+ return null;
73
+ }
265
74
 
266
- // For Payone integration without developer account,
267
- // Payone handles merchant validation
268
- // We need to initialize the session first
269
- const sessionParams = {
270
- displayName: merchantName,
271
- domainName: domainName,
272
- mid: merchantId,
273
- portalid: portalId
274
- };
75
+ const sessionResponse = await initializeApplePaySession(strapi, params);
76
+ const applePaySessionBase64 = sessionResponse["add_paydata[applepay_payment_session]"] ||
77
+ sessionResponse.add_paydata?.applepay_payment_session;
275
78
 
276
- strapi.log.info("[Apple Pay] Initializing session with params:", JSON.stringify(sessionParams, null, 2));
79
+ if (sessionResponse.status === "OK" && applePaySessionBase64 && applePaySessionBase64.length > 0) {
80
+ const merchantSessionJson = Buffer.from(applePaySessionBase64, 'base64').toString('utf-8');
81
+ const merchantSession = JSON.parse(merchantSessionJson);
277
82
 
278
- // Initialize Apple Pay session with Payone
279
- let sessionResponse;
280
- try {
281
- sessionResponse = await initializeApplePaySession(strapi, sessionParams);
282
- } catch (error) {
283
- strapi.log.error("[Apple Pay] Failed to initialize session with Payone:", {
284
- message: error.message,
285
- status: error.response?.status,
286
- data: error.response?.data,
287
- stack: error.stack
288
- });
289
- // DO NOT return empty object - throw error instead
290
- // Empty object causes Apple Pay to close dialog without proper error message
291
- throw new Error(`Failed to initialize Apple Pay session with Payone: ${error.message}. Please check your Payone configuration and ensure Apple Pay is properly set up in PMI.`);
83
+ if (merchantSession.epochTimestamp && merchantSession.epochTimestamp > 1000000000000) {
84
+ merchantSession.epochTimestamp = Math.floor(merchantSession.epochTimestamp / 1000);
292
85
  }
293
86
 
294
- strapi.log.info("[Apple Pay] Session initialization result:", {
295
- status: sessionResponse.status || sessionResponse.Status,
296
- hasMerchantIdentifier: !!(sessionResponse.merchantIdentifier || sessionResponse.merchantSessionIdentifier),
297
- hasApplePaySession: !!(sessionResponse["add_paydata[applepay_payment_session]"] ||
298
- sessionResponse["add_paydata[applepay_payment_session]"] ||
299
- sessionResponse.add_paydata?.applepay_payment_session),
300
- fullResponse: JSON.stringify(sessionResponse, null, 2)
301
- });
302
-
303
- // If session initialization is successful, extract merchant session from Payone response
304
- // Payone returns: add_paydata[applepay_payment_session] = BASE64 encoded merchant session
305
- // Check for both uppercase and lowercase status
306
- const responseStatus = sessionResponse.status || sessionResponse.Status;
307
- if (responseStatus === "APPROVED" || responseStatus === "OK" ||
308
- responseStatus === "approved" || responseStatus === "ok") {
309
-
310
- // Extract BASE64 encoded merchant session from Payone response
311
- // Payone returns it in: add_paydata[applepay_payment_session]
312
- // Try all possible variations of the field name
313
- const applePaySessionBase64 =
314
- sessionResponse["add_paydata[applepay_payment_session]"] ||
315
- sessionResponse["add_paydata[applepay_payment_session]"] ||
316
- sessionResponse["add_paydata_applepay_payment_session"] ||
317
- sessionResponse.add_paydata?.applepay_payment_session ||
318
- sessionResponse.add_paydata?.["applepay_payment_session"] ||
319
- sessionResponse["addPaydata[applepay_payment_session]"] ||
320
- sessionResponse["addPaydata_applepay_payment_session"] ||
321
- null;
322
-
323
- strapi.log.info("[Apple Pay] Checking for merchant session in response:", {
324
- hasWorkorderid: !!sessionResponse.workorderid,
325
- workorderid: sessionResponse.workorderid,
326
- allKeys: Object.keys(sessionResponse).filter(k => k.includes('applepay') || k.includes('session') || k.includes('paydata')),
327
- responseKeys: Object.keys(sessionResponse)
328
- });
329
-
330
- strapi.log.info("[Apple Pay] Extracted Apple Pay session data:", {
331
- hasBase64Session: !!applePaySessionBase64,
332
- sessionLength: applePaySessionBase64?.length,
333
- workorderid: sessionResponse.workorderid,
334
- allResponseKeys: Object.keys(sessionResponse),
335
- responseSample: JSON.stringify(sessionResponse).substring(0, 500)
336
- });
337
-
338
- if (applePaySessionBase64 && applePaySessionBase64.length > 0) {
339
- try {
340
- // Decode BASE64 merchant session
341
- const merchantSessionJson = Buffer.from(applePaySessionBase64, 'base64').toString('utf-8');
342
- const merchantSession = JSON.parse(merchantSessionJson);
343
-
344
- strapi.log.info("[Apple Pay] Decoded merchant session:", {
345
- merchantIdentifier: merchantSession.merchantIdentifier,
346
- domainName: merchantSession.domainName,
347
- displayName: merchantSession.displayName,
348
- hasEpochTimestamp: !!merchantSession.epochTimestamp,
349
- hasExpiresAt: !!merchantSession.expiresAt,
350
- fullSession: merchantSession
351
- });
352
-
353
- // Validate decoded merchant session
354
- if (!merchantSession.merchantIdentifier) {
355
- strapi.log.warn("[Apple Pay] Decoded merchant session missing merchantIdentifier, using MerchantId from config");
356
- // Use MerchantId (mid) from config as merchantIdentifier
357
- // Priority: settings.mid (MerchantId) > settings.merchantIdentifier > settings.portalid
358
- strapi.log.info("[Apple Pay] Available MerchantId values from config:");
359
- strapi.log.info("[Apple Pay] settings.mid:", settings.mid || "NOT_SET");
360
- strapi.log.info("[Apple Pay] settings.merchantIdentifier:", settings.merchantIdentifier || "NOT_SET");
361
- strapi.log.info("[Apple Pay] settings.portalid:", settings.portalid || "NOT_SET");
362
-
363
- const fallbackMerchantId = settings.mid || settings.merchantIdentifier || settings.portalid;
364
- merchantSession.merchantIdentifier = fallbackMerchantId || `merchant.${domainName}`;
365
-
366
- strapi.log.info("[Apple Pay] Selected MerchantId from config:", fallbackMerchantId || "NOT_SET");
367
- strapi.log.info("[Apple Pay] Final merchantIdentifier set to:", merchantSession.merchantIdentifier);
368
- } else {
369
- strapi.log.info("[Apple Pay] Using merchantIdentifier from decoded Payone session:", merchantSession.merchantIdentifier);
370
- }
371
-
372
- // Ensure epochTimestamp and expiresAt are in seconds (not milliseconds)
373
- if (merchantSession.epochTimestamp && merchantSession.epochTimestamp > 1000000000000) {
374
- // If timestamp is in milliseconds, convert to seconds
375
- merchantSession.epochTimestamp = Math.floor(merchantSession.epochTimestamp / 1000);
376
- }
377
- if (merchantSession.expiresAt && merchantSession.expiresAt > 1000000000000) {
378
- // If timestamp is in milliseconds, convert to seconds
379
- merchantSession.expiresAt = Math.floor(merchantSession.expiresAt / 1000);
380
- }
381
-
382
- // Validate final merchant session
383
- if (!merchantSession.merchantIdentifier || merchantSession.merchantIdentifier === 'undefined' || merchantSession.merchantIdentifier === 'null') {
384
- throw new Error("Decoded merchant session has invalid merchantIdentifier");
385
- }
386
-
387
- strapi.log.info("[Apple Pay] Validated merchant session:", {
388
- merchantIdentifier: merchantSession.merchantIdentifier,
389
- domainName: merchantSession.domainName,
390
- epochTimestamp: merchantSession.epochTimestamp,
391
- expiresAt: merchantSession.expiresAt
392
- });
393
-
394
- return merchantSession;
395
- } catch (decodeError) {
396
- strapi.log.error("[Apple Pay] Failed to decode merchant session:", {
397
- error: decodeError.message,
398
- base64Length: applePaySessionBase64?.length,
399
- base64Preview: applePaySessionBase64?.substring(0, 100)
400
- });
401
-
402
- // If decoding fails, we cannot proceed - merchant session is invalid
403
- throw new Error(`Failed to decode Apple Pay merchant session: ${decodeError.message}`);
404
- }
405
- } else {
406
- // CRITICAL: If Payone doesn't return merchant session, we cannot proceed
407
- // Apple Pay requires the merchant session to be validated by Apple's servers
408
- // Payone should return add_paydata[applepay_payment_session] after successful initialization
409
- strapi.log.error("[Apple Pay] CRITICAL: No Apple Pay session data in Payone response!");
410
- strapi.log.error("[Apple Pay] This means merchant validation will fail. Possible causes:");
411
- strapi.log.error("[Apple Pay] 1. Apple Pay not properly configured in Payone PMI");
412
- strapi.log.error("[Apple Pay] 2. Domain not verified in Payone PMI");
413
- strapi.log.error("[Apple Pay] 3. Merchant identifier not configured in Payone PMI");
414
- strapi.log.error("[Apple Pay] 4. Apple Pay onboarding not completed in Payone PMI");
415
- strapi.log.error("[Apple Pay] Response status:", responseStatus);
416
- strapi.log.error("[Apple Pay] Full response keys:", Object.keys(sessionResponse));
417
- strapi.log.error("[Apple Pay] Response sample:", JSON.stringify(sessionResponse).substring(0, 1000));
418
-
419
- // DO NOT create a fallback session - it will fail validation
420
- // Instead, throw an error so the frontend knows validation failed
421
- throw new Error("Payone did not return Apple Pay merchant session. Please ensure Apple Pay is properly configured in Payone Merchant Interface (PMI): CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay configuration. The merchant session must come from Payone after successful Apple Pay onboarding.");
422
-
423
- // Get merchant identifier from settings
424
- // Use MerchantId (mid) from config as merchantIdentifier
425
- // According to Payone docs, merchant identifier should be visible in PMI after onboarding
426
- // Path: CONFIGURATION/PAYMENT PORTALS - choose an onboarded Portal - Payment type configuration tab
427
- strapi.log.info("[Apple Pay] ========== CREATING MERCHANT SESSION FROM CONFIG ==========");
428
- strapi.log.info("[Apple Pay] Available MerchantId values from config:");
429
- strapi.log.info("[Apple Pay] settings.mid:", settings.mid || "NOT_SET");
430
- strapi.log.info("[Apple Pay] settings.merchantIdentifier:", settings.merchantIdentifier || "NOT_SET");
431
- strapi.log.info("[Apple Pay] settings.portalid:", settings.portalid || "NOT_SET");
432
-
433
- // Priority: settings.mid (MerchantId) > settings.merchantIdentifier > settings.portalid
434
- let merchantIdentifier = settings.mid || settings.merchantIdentifier || settings.portalid;
435
-
436
- strapi.log.info("[Apple Pay] Selected merchantIdentifier:", merchantIdentifier || "NOT_SET");
437
- strapi.log.info("[Apple Pay] merchantIdentifier type:", typeof merchantIdentifier);
438
- strapi.log.info("[Apple Pay] merchantIdentifier length:", merchantIdentifier ? merchantIdentifier.length : 0);
439
-
440
- // If still no merchant identifier, try to construct one from domain
441
- // But this is not ideal - merchant identifier should come from Payone PMI
442
- if (!merchantIdentifier) {
443
- strapi.log.warn("[Apple Pay] No merchant identifier found in settings, using domain-based fallback");
444
- merchantIdentifier = `merchant.${domainName}`;
445
- }
446
-
447
- // Ensure merchant identifier is a string and not empty
448
- merchantIdentifier = merchantIdentifier.toString().trim();
449
- if (!merchantIdentifier || merchantIdentifier === 'undefined' || merchantIdentifier === 'null') {
450
- strapi.log.error("[Apple Pay] Invalid merchant identifier:", merchantIdentifier);
451
- throw new Error("Merchant identifier is invalid. Please configure a valid merchant identifier in Payone Merchant Interface (PMI) after Apple Pay onboarding. Path: CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Payment type configuration tab");
452
- }
453
-
454
- // Create a valid merchant session object
455
- // This format is required by Apple Pay Payment Request API
456
- // IMPORTANT: epochTimestamp and expiresAt must be in seconds (Unix timestamp), not milliseconds
457
- // IMPORTANT: merchantIdentifier must be the MerchantId (mid) from Payone config
458
- const merchantSession = {
459
- epochTimestamp: Math.floor(Date.now() / 1000), // Unix timestamp in seconds
460
- expiresAt: Math.floor((Date.now() + (5 * 60 * 1000)) / 1000), // 5 minutes from now, in seconds
461
- merchantSessionIdentifier: `merchant.${domainName}`,
462
- nonce: generateNonce(),
463
- merchantIdentifier: merchantIdentifier, // MerchantId (mid) from config - already validated and converted to string
464
- domainName: domainName,
465
- displayName: merchantName
466
- };
467
-
468
- strapi.log.info("[Apple Pay] Created merchant session with MerchantId from config:");
469
- strapi.log.info("[Apple Pay] merchantIdentifier:", merchantSession.merchantIdentifier);
470
- strapi.log.info("[Apple Pay] domainName:", merchantSession.domainName);
471
- strapi.log.info("[Apple Pay] displayName:", merchantSession.displayName);
472
- strapi.log.info("[Apple Pay] epochTimestamp:", merchantSession.epochTimestamp);
473
- strapi.log.info("[Apple Pay] expiresAt:", merchantSession.expiresAt);
474
- strapi.log.info("[Apple Pay] ==========================================");
475
-
476
- // Validate merchant session before returning
477
- if (!merchantSession.merchantIdentifier || merchantSession.merchantIdentifier === 'undefined' || merchantSession.merchantIdentifier === 'null') {
478
- strapi.log.error("[Apple Pay] Created merchant session is missing or invalid merchantIdentifier!", {
479
- merchantIdentifier: merchantSession.merchantIdentifier,
480
- settings: {
481
- hasMerchantIdentifier: !!settings.merchantIdentifier,
482
- hasMid: !!settings.mid,
483
- hasPortalid: !!settings.portalid,
484
- mid: settings.mid,
485
- portalid: settings.portalid
486
- }
487
- });
488
- throw new Error("Merchant identifier is required but not found in settings. Please configure merchant identifier in Payone Merchant Interface (PMI) after Apple Pay onboarding.");
489
- }
490
-
491
- strapi.log.info("[Apple Pay] Created merchant session from settings:", {
492
- merchantIdentifier: merchantSession.merchantIdentifier,
493
- domainName: merchantSession.domainName,
494
- displayName: merchantSession.displayName,
495
- epochTimestamp: merchantSession.epochTimestamp,
496
- expiresAt: merchantSession.expiresAt
497
- });
498
-
499
- return merchantSession;
500
- }
87
+ if (merchantSession.expiresAt && merchantSession.expiresAt > 1000000000000) {
88
+ merchantSession.expiresAt = Math.floor(merchantSession.expiresAt / 1000);
501
89
  }
502
90
 
503
- // If initialization failed, we cannot proceed
504
- // Payment Request API requires a valid merchant session
505
- strapi.log.error("[Apple Pay] Session initialization failed - status:", responseStatus);
506
- strapi.log.error("[Apple Pay] Full Payone response:", JSON.stringify(sessionResponse, null, 2));
507
- strapi.log.error("[Apple Pay] This means merchant validation will fail.");
508
- strapi.log.error("[Apple Pay] Possible causes:");
509
- strapi.log.error("[Apple Pay] 1. Payone returned ERROR status - check errorcode and errormessage in response");
510
- strapi.log.error("[Apple Pay] 2. Apple Pay not configured in Payone PMI");
511
- strapi.log.error("[Apple Pay] 3. Domain not verified in Payone PMI");
512
- strapi.log.error("[Apple Pay] 4. Merchant identifier not configured correctly");
513
- strapi.log.error("[Apple Pay] 5. Apple Pay onboarding not completed");
514
-
515
- // Extract error details from Payone response
516
- const errorCode = sessionResponse.errorcode || sessionResponse.ErrorCode;
517
- const errorMessage = sessionResponse.errormessage || sessionResponse.ErrorMessage || sessionResponse.errortxt || sessionResponse.ErrorTxt;
518
-
519
- if (errorCode || errorMessage) {
520
- strapi.log.error("[Apple Pay] Payone error details:", {
521
- errorCode: errorCode,
522
- errorMessage: errorMessage
523
- });
524
- throw new Error(`Payone Apple Pay initialization failed: ${errorCode ? `Error ${errorCode}` : ''} ${errorMessage || 'Unknown error'}. Please check your Payone Apple Pay configuration in PMI (CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay).`);
525
- } else {
526
- throw new Error(`Apple Pay session initialization failed with status: ${responseStatus || 'UNKNOWN'}. Please check your Payone Apple Pay configuration in PMI (CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay).`);
91
+ if (!merchantSession.merchantIdentifier ||
92
+ merchantSession.merchantIdentifier === 'undefined' ||
93
+ merchantSession.merchantIdentifier === 'null') {
94
+ strapi.log.error("Decoded merchant session has invalid merchantIdentifier");
527
95
  }
528
- } catch (error) {
529
- strapi.log.error("[Apple Pay] Merchant validation error:", {
530
- message: error.message,
531
- stack: error.stack,
532
- response: error.response?.data,
533
- status: error.response?.status
534
- });
535
96
 
536
- // DO NOT return empty object - this causes Apple Pay to close the dialog
537
- // Instead, re-throw the error so the frontend can handle it properly
538
- // The error message will help the user understand what went wrong
539
- throw error;
97
+ return merchantSession;
540
98
  }
541
- };
542
99
 
543
- /**
544
- * Parse Payone response
545
- */
546
- const parseResponse = (responseData, logger) => {
547
- if (typeof responseData === 'string') {
548
- // Parse form-encoded response
549
- const params = new URLSearchParams(responseData);
550
- const parsed = {};
551
- for (const [key, value] of params.entries()) {
552
- parsed[key] = value;
553
- }
554
- return parsed;
555
- }
556
- return responseData;
557
- };
100
+ const errorCode = sessionResponse.errorcode || sessionResponse.ErrorCode;
101
+ const errorMessage = sessionResponse.errormessage || sessionResponse.ErrorMessage ||
102
+ sessionResponse.errortxt || sessionResponse.ErrorTxt;
558
103
 
559
- /**
560
- * Generate nonce for merchant session
561
- */
562
- const generateNonce = () => {
563
- return Math.random().toString(36).substring(2, 15) +
564
- Math.random().toString(36).substring(2, 15);
104
+ strapi.log.error(
105
+ `Payone Apple Pay initialization failed: ${errorCode ? `Error ${errorCode}` : ''} ${errorMessage || 'Unknown error'}`
106
+ );
107
+
108
+ return null;
565
109
  };
566
110
 
567
111
  module.exports = {
568
112
  initializeApplePaySession,
569
113
  validateApplePayMerchant
570
114
  };
571
-
572
-