strapi-plugin-payone-provider 1.4.2 → 1.5.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.
- package/APPLE_PAY_INTEGRATION.md +472 -0
- package/CSP_SETUP.md +184 -0
- package/HTTPS_REQUIREMENT.md +136 -0
- package/admin/src/pages/App/components/AppTabs.js +2 -0
- package/admin/src/pages/App/components/ApplePayButton.js +704 -0
- package/admin/src/pages/App/components/ApplePayConfig.js +305 -0
- package/admin/src/pages/App/components/PaymentActionsPanel.js +6 -0
- package/admin/src/pages/App/components/paymentActions/AuthorizationForm.js +29 -2
- package/admin/src/pages/App/components/paymentActions/CaptureForm.js +1 -0
- package/admin/src/pages/App/components/paymentActions/CardDetailsInput.js +18 -16
- package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.js +44 -2
- package/admin/src/pages/App/components/paymentActions/RefundForm.js +1 -0
- package/admin/src/pages/hooks/usePaymentActions.js +13 -2
- package/admin/src/pages/utils/applePayConstants.js +222 -0
- package/admin/src/pages/utils/paymentUtils.js +22 -74
- package/package.json +1 -1
- package/server/bootstrap.js +5 -1
- package/server/config/index.js +5 -1
- package/server/controllers/payone.js +10 -0
- package/server/routes/index.js +17 -0
- package/server/services/applePayService.js +261 -0
- package/server/services/payone.js +10 -0
- package/server/utils/paymentMethodParams.js +19 -2
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const axios = require("axios");
|
|
4
|
+
const { buildClientRequestParams, toFormData } = require("../utils/requestBuilder");
|
|
5
|
+
const { getSettings, validateSettings } = require("./settingsService");
|
|
6
|
+
|
|
7
|
+
const POST_GATEWAY_URL = "https://api.pay1.de/post-gateway/";
|
|
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
|
+
*/
|
|
23
|
+
const initializeApplePaySession = async (strapi, params) => {
|
|
24
|
+
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
|
+
const settings = await getSettings(strapi);
|
|
29
|
+
|
|
30
|
+
if (!validateSettings(settings)) {
|
|
31
|
+
strapi.log.error("[Apple Pay] Payone settings not configured");
|
|
32
|
+
throw new Error("Payone settings not configured");
|
|
33
|
+
}
|
|
34
|
+
|
|
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 = {
|
|
65
|
+
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
|
+
clearingtype: "wlt",
|
|
72
|
+
wallettype: "APL",
|
|
73
|
+
currency: "EUR", // Default, can be overridden
|
|
74
|
+
"add_paydata[action]": "init_applepay_session",
|
|
75
|
+
"add_paydata[display_name]": merchantName,
|
|
76
|
+
"add_paydata[domain_name]": domain
|
|
77
|
+
};
|
|
78
|
+
|
|
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
|
+
});
|
|
87
|
+
|
|
88
|
+
const formData = toFormData(requestParams);
|
|
89
|
+
|
|
90
|
+
const response = await axios.post(POST_GATEWAY_URL, formData, {
|
|
91
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
92
|
+
timeout: 30000
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
strapi.log.info("[Apple Pay] Payone response received:", {
|
|
96
|
+
status: response.status,
|
|
97
|
+
statusText: response.statusText
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Parse response
|
|
101
|
+
const responseData = parseResponse(response.data, strapi.log);
|
|
102
|
+
|
|
103
|
+
strapi.log.info("[Apple Pay] Session initialization response:", JSON.stringify(responseData, null, 2));
|
|
104
|
+
strapi.log.info("[Apple Pay] Response status:", responseData.status || responseData.Status);
|
|
105
|
+
|
|
106
|
+
if (responseData.errorcode || responseData.ErrorCode) {
|
|
107
|
+
strapi.log.warn("[Apple Pay] Response contains error:", {
|
|
108
|
+
errorcode: responseData.errorcode || responseData.ErrorCode,
|
|
109
|
+
errormessage: responseData.errormessage || responseData.ErrorMessage
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return responseData;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
strapi.log.error("[Apple Pay] Session initialization error:", {
|
|
116
|
+
message: error.message,
|
|
117
|
+
stack: error.stack,
|
|
118
|
+
response: error.response?.data
|
|
119
|
+
});
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Validate Apple Pay merchant with Payone
|
|
126
|
+
* This is called when Apple Pay requests merchant validation
|
|
127
|
+
*/
|
|
128
|
+
const validateApplePayMerchant = async (strapi, params) => {
|
|
129
|
+
try {
|
|
130
|
+
strapi.log.info("[Apple Pay] Validating merchant with Payone");
|
|
131
|
+
strapi.log.info("[Apple Pay] Validation params:", JSON.stringify({
|
|
132
|
+
validationURL: params.validationURL,
|
|
133
|
+
domain: params.domain,
|
|
134
|
+
displayName: params.displayName,
|
|
135
|
+
mid: params.mid,
|
|
136
|
+
portalid: params.portalid
|
|
137
|
+
}, null, 2));
|
|
138
|
+
|
|
139
|
+
const settings = await getSettings(strapi);
|
|
140
|
+
|
|
141
|
+
if (!validateSettings(settings)) {
|
|
142
|
+
strapi.log.error("[Apple Pay] Payone settings not configured for merchant validation");
|
|
143
|
+
throw new Error("Payone settings not configured");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const {
|
|
147
|
+
validationURL,
|
|
148
|
+
mid,
|
|
149
|
+
portalid,
|
|
150
|
+
domain,
|
|
151
|
+
displayName
|
|
152
|
+
} = params;
|
|
153
|
+
|
|
154
|
+
// Get merchant data from settings (test or live mode)
|
|
155
|
+
const merchantName = displayName || settings.merchantName || settings.displayName || "Test Store";
|
|
156
|
+
const merchantId = mid || settings.mid || settings.merchantIdentifier;
|
|
157
|
+
const portalId = portalid || settings.portalid;
|
|
158
|
+
|
|
159
|
+
// Get domain from params or settings or server config
|
|
160
|
+
const domainName = domain || settings.domainName ||
|
|
161
|
+
(strapi.config.get("server.url") ? new URL(strapi.config.get("server.url")).hostname : null) ||
|
|
162
|
+
"localhost";
|
|
163
|
+
|
|
164
|
+
// For Payone integration without developer account,
|
|
165
|
+
// Payone handles merchant validation
|
|
166
|
+
// We need to initialize the session first
|
|
167
|
+
const sessionParams = {
|
|
168
|
+
displayName: merchantName,
|
|
169
|
+
domainName: domainName,
|
|
170
|
+
mid: merchantId,
|
|
171
|
+
portalid: portalId
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
strapi.log.info("[Apple Pay] Initializing session with params:", JSON.stringify(sessionParams, null, 2));
|
|
175
|
+
|
|
176
|
+
// Initialize Apple Pay session with Payone
|
|
177
|
+
const sessionResponse = await initializeApplePaySession(strapi, sessionParams);
|
|
178
|
+
|
|
179
|
+
strapi.log.info("[Apple Pay] Session initialization result:", {
|
|
180
|
+
status: sessionResponse.status || sessionResponse.Status,
|
|
181
|
+
hasMerchantIdentifier: !!(sessionResponse.merchantIdentifier || sessionResponse.merchantSessionIdentifier)
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// If session initialization is successful, return merchant session
|
|
185
|
+
// Payone will provide the merchant identifier and validation data
|
|
186
|
+
if (sessionResponse.status === "APPROVED" || sessionResponse.status === "REDIRECT") {
|
|
187
|
+
strapi.log.info("[Apple Pay] Session approved, creating merchant session object");
|
|
188
|
+
// Get merchant identifier from Payone response or settings
|
|
189
|
+
const merchantIdentifier = sessionResponse.merchantIdentifier ||
|
|
190
|
+
sessionResponse.merchantSessionIdentifier ||
|
|
191
|
+
settings.merchantIdentifier ||
|
|
192
|
+
settings.mid ||
|
|
193
|
+
settings.portalid ||
|
|
194
|
+
`merchant.${domainName}`;
|
|
195
|
+
|
|
196
|
+
// Return merchant session object
|
|
197
|
+
// In a real implementation, you would get this from Payone's response
|
|
198
|
+
const merchantSession = {
|
|
199
|
+
epochTimestamp: Date.now(),
|
|
200
|
+
expiresAt: Date.now() + (5 * 60 * 1000), // 5 minutes
|
|
201
|
+
merchantSessionIdentifier: sessionResponse.merchantSessionIdentifier || `merchant.${domainName}`,
|
|
202
|
+
nonce: sessionResponse.nonce || generateNonce(),
|
|
203
|
+
merchantIdentifier: merchantIdentifier,
|
|
204
|
+
domainName: domainName,
|
|
205
|
+
displayName: merchantName
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
strapi.log.info("[Apple Pay] Merchant session created:", {
|
|
209
|
+
merchantIdentifier: merchantSession.merchantIdentifier,
|
|
210
|
+
domainName: merchantSession.domainName,
|
|
211
|
+
expiresAt: new Date(merchantSession.expiresAt).toISOString()
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return merchantSession;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// If initialization failed, return empty object
|
|
218
|
+
// Payment Request API will handle it
|
|
219
|
+
strapi.log.warn("[Apple Pay] Session initialization failed, returning empty object");
|
|
220
|
+
return {};
|
|
221
|
+
} catch (error) {
|
|
222
|
+
strapi.log.error("[Apple Pay] Merchant validation error:", {
|
|
223
|
+
message: error.message,
|
|
224
|
+
stack: error.stack,
|
|
225
|
+
response: error.response?.data
|
|
226
|
+
});
|
|
227
|
+
// Return empty object on error - Payone will handle validation
|
|
228
|
+
return {};
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Parse Payone response
|
|
234
|
+
*/
|
|
235
|
+
const parseResponse = (responseData, logger) => {
|
|
236
|
+
if (typeof responseData === 'string') {
|
|
237
|
+
// Parse form-encoded response
|
|
238
|
+
const params = new URLSearchParams(responseData);
|
|
239
|
+
const parsed = {};
|
|
240
|
+
for (const [key, value] of params.entries()) {
|
|
241
|
+
parsed[key] = value;
|
|
242
|
+
}
|
|
243
|
+
return parsed;
|
|
244
|
+
}
|
|
245
|
+
return responseData;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Generate nonce for merchant session
|
|
250
|
+
*/
|
|
251
|
+
const generateNonce = () => {
|
|
252
|
+
return Math.random().toString(36).substring(2, 15) +
|
|
253
|
+
Math.random().toString(36).substring(2, 15);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
module.exports = {
|
|
257
|
+
initializeApplePaySession,
|
|
258
|
+
validateApplePayMerchant
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
|
|
@@ -4,6 +4,7 @@ const settingsService = require("./settingsService");
|
|
|
4
4
|
const transactionService = require("./transactionService");
|
|
5
5
|
const paymentService = require("./paymentService");
|
|
6
6
|
const testConnectionService = require("./testConnectionService");
|
|
7
|
+
const applePayService = require("./applePayService");
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Main Payone service - aggregates all sub-services
|
|
@@ -52,5 +53,14 @@ module.exports = ({ strapi }) => ({
|
|
|
52
53
|
// 3D Secure callback handler
|
|
53
54
|
async handle3DSCallback(callbackData, resultType) {
|
|
54
55
|
return await paymentService.handle3DSCallback(strapi, callbackData, resultType);
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Apple Pay
|
|
59
|
+
async validateApplePayMerchant(params) {
|
|
60
|
+
return await applePayService.validateApplePayMerchant(strapi, params);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
async initializeApplePaySession(params) {
|
|
64
|
+
return await applePayService.initializeApplePaySession(strapi, params);
|
|
55
65
|
}
|
|
56
66
|
});
|
|
@@ -84,11 +84,28 @@ const addPaymentMethodParams = (params, logger) => {
|
|
|
84
84
|
}
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
+
// Handle Apple Pay token if present
|
|
88
|
+
if (updated.applePayToken || updated["add_paydata[paymentmethod_token_data]"]) {
|
|
89
|
+
const token = updated.applePayToken || updated["add_paydata[paymentmethod_token_data]"];
|
|
90
|
+
const gatewayMerchantId = updated.mid || updated.portalid || '';
|
|
91
|
+
|
|
92
|
+
updated["add_paydata[paymentmethod_token_data]"] = token;
|
|
93
|
+
updated["add_paydata[paymentmethod]"] = "APL";
|
|
94
|
+
updated["add_paydata[paymentmethod_type]"] = "APPLEPAY";
|
|
95
|
+
updated["add_paydata[gatewayid]"] = "payonegmbh";
|
|
96
|
+
if (gatewayMerchantId) {
|
|
97
|
+
updated["add_paydata[gateway_merchantid]"] = gatewayMerchantId;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Remove applePayToken from params as it's now in add_paydata
|
|
101
|
+
delete updated.applePayToken;
|
|
102
|
+
}
|
|
103
|
+
|
|
87
104
|
// Ensure wallettype is set for wallet payments
|
|
88
105
|
if (updated.clearingtype === "wlt" && !updated.wallettype) {
|
|
89
|
-
if (clearingtype === "gpp" || updated.paymentMethod === "gpp" || updated["add_paydata[
|
|
106
|
+
if (clearingtype === "gpp" || updated.paymentMethod === "gpp" || (updated["add_paydata[paymentmethod]"] === "GGP")) {
|
|
90
107
|
updated.wallettype = "GGP";
|
|
91
|
-
} else if (clearingtype === "apl" || updated.paymentMethod === "apl") {
|
|
108
|
+
} else if (clearingtype === "apl" || updated.paymentMethod === "apl" || (updated["add_paydata[paymentmethod]"] === "APL")) {
|
|
92
109
|
updated.wallettype = "APL";
|
|
93
110
|
} else {
|
|
94
111
|
updated.wallettype = "PPE";
|