strapi-plugin-payone-provider 1.6.5 → 1.6.7
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/.well-known/.gitkeep +3 -0
- package/.well-known/apple-developer-merchant-id-domain-association.txt +1 -0
- package/admin/src/pages/App/components/AppTabs.jsx +31 -16
- package/admin/src/pages/App/components/ApplePayBtn.jsx +63 -28
- package/admin/src/pages/App/components/ConfigurationPanel.jsx +189 -10
- package/admin/src/pages/App/components/DocsPanel.jsx +864 -194
- package/admin/src/pages/App/components/HistoryPanel.jsx +73 -46
- package/admin/src/pages/App/components/PaymentActionsPanel.jsx +8 -2
- package/admin/src/pages/App/components/TransactionHistoryItem.jsx +232 -87
- package/admin/src/pages/App/components/paymentActions/ApplePayPanel.jsx +45 -1
- package/admin/src/pages/App/components/paymentActions/PaymentResult.jsx +74 -30
- package/admin/src/pages/App/index.jsx +1 -0
- package/admin/src/pages/hooks/usePaymentActions.js +4 -0
- package/admin/src/pages/hooks/useSettings.js +26 -1
- package/admin/src/pages/hooks/useTransactionHistory.js +2 -3
- package/admin/src/pages/utils/paymentUtils.js +64 -6
- package/package.json +1 -1
- package/server/bootstrap.js +9 -3
- package/server/controllers/payone.js +14 -1
- package/server/services/applePayService.js +103 -93
- package/server/services/paymentService.js +56 -13
- package/server/services/transactionService.js +37 -14
- package/server/utils/paymentMethodParams.js +89 -19
|
@@ -8,13 +8,35 @@ const POST_GATEWAY_URL = "https://api.pay1.de/post-gateway/";
|
|
|
8
8
|
|
|
9
9
|
const parseResponse = (responseData) => {
|
|
10
10
|
if (typeof responseData === 'string') {
|
|
11
|
+
if (responseData.trim().startsWith('{')) {
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(responseData);
|
|
14
|
+
} catch (e) {
|
|
15
|
+
// Fall through to URL-encoded parsing
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
const params = new URLSearchParams(responseData);
|
|
12
20
|
const parsed = {};
|
|
13
21
|
for (const [key, value] of params.entries()) {
|
|
14
22
|
parsed[key] = value;
|
|
23
|
+
const normalizedKey = key.toLowerCase().replace(/\[/g, '_').replace(/\]/g, '');
|
|
24
|
+
if (normalizedKey !== key.toLowerCase()) {
|
|
25
|
+
parsed[normalizedKey] = value;
|
|
26
|
+
}
|
|
15
27
|
}
|
|
16
28
|
return parsed;
|
|
17
29
|
}
|
|
30
|
+
|
|
31
|
+
if (typeof responseData === 'object' && responseData !== null) {
|
|
32
|
+
const result = { ...responseData };
|
|
33
|
+
if (result['add_paydata[applepay_payment_session]']) {
|
|
34
|
+
result.add_paydata = result.add_paydata || {};
|
|
35
|
+
result.add_paydata.applepay_payment_session = result['add_paydata[applepay_payment_session]'];
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
18
40
|
return responseData;
|
|
19
41
|
};
|
|
20
42
|
|
|
@@ -45,8 +67,6 @@ const initializeApplePaySession = async (strapi, params) => {
|
|
|
45
67
|
|
|
46
68
|
const applePayConfig = settings?.applePayConfig || {};
|
|
47
69
|
const currency = params.currency || applePayConfig.currencyCode || "EUR";
|
|
48
|
-
const countryCode = params.countryCode || applePayConfig.countryCode || "DE";
|
|
49
|
-
|
|
50
70
|
const merchantName = params.displayName || settings?.merchantName || "Store";
|
|
51
71
|
const domain = params.domain || params.domainName || "localhost";
|
|
52
72
|
|
|
@@ -63,18 +83,14 @@ const initializeApplePaySession = async (strapi, params) => {
|
|
|
63
83
|
const requestParams = buildClientRequestParams(settings, baseParams, strapi.log);
|
|
64
84
|
const formData = toFormData(requestParams);
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
});
|
|
75
|
-
} catch (axiosError) {
|
|
76
|
-
throw axiosError;
|
|
77
|
-
}
|
|
86
|
+
const response = await axios.post(`${POST_GATEWAY_URL}Genericpayment`, formData, {
|
|
87
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
88
|
+
timeout: 30000,
|
|
89
|
+
validateStatus: function (status) {
|
|
90
|
+
return status >= 200 && status < 600;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
78
94
|
|
|
79
95
|
if (response.status === 403) {
|
|
80
96
|
const responseData = parseResponse(response.data);
|
|
@@ -88,12 +104,7 @@ const initializeApplePaySession = async (strapi, params) => {
|
|
|
88
104
|
|
|
89
105
|
const detailedError = new Error("403 Forbidden: Authentication failed with Payone API. " +
|
|
90
106
|
(errorCode ? `Error Code: ${errorCode}. ` : "") +
|
|
91
|
-
(errorMessage ? `Error: ${errorMessage}. ` : "")
|
|
92
|
-
"Please check: 1) Your Payone credentials (aid, portalid, mid, key) in plugin settings, " +
|
|
93
|
-
"2) Mode is set to 'live' (Apple Pay only works in live mode), " +
|
|
94
|
-
"3) Your domain is registered with Payone Merchant Services, " +
|
|
95
|
-
"4) Merchant ID (mid) matches your merchantIdentifier in PMI, " +
|
|
96
|
-
"5) Apple Pay is enabled for your portal in PMI.");
|
|
107
|
+
(errorMessage ? `Error: ${errorMessage}. ` : ""));
|
|
97
108
|
Object.assign(detailedError, { status: 403, response: response });
|
|
98
109
|
throw detailedError;
|
|
99
110
|
}
|
|
@@ -138,71 +149,7 @@ const initializeApplePaySession = async (strapi, params) => {
|
|
|
138
149
|
|
|
139
150
|
return responseData;
|
|
140
151
|
} catch (error) {
|
|
141
|
-
|
|
142
|
-
const errorResponseData = error.response?.data;
|
|
143
|
-
|
|
144
|
-
// Provide more specific error messages
|
|
145
|
-
if (errorStatus === 403 || error.message?.includes('403')) {
|
|
146
|
-
let responseData = {};
|
|
147
|
-
let errorCode = null;
|
|
148
|
-
let errorMessage = null;
|
|
149
|
-
|
|
150
|
-
if (errorResponseData) {
|
|
151
|
-
try {
|
|
152
|
-
responseData = parseResponse(errorResponseData);
|
|
153
|
-
errorCode = responseData.errorcode || responseData.ErrorCode;
|
|
154
|
-
errorMessage = responseData.errormessage || responseData.ErrorMessage || responseData.customermessage || responseData.CustomerMessage;
|
|
155
|
-
} catch (parseErr) {
|
|
156
|
-
if (typeof errorResponseData === 'string') {
|
|
157
|
-
errorMessage = errorResponseData;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (errorCode || errorMessage) {
|
|
163
|
-
strapi.log.error("[Apple Pay] 403 Forbidden from Payone:", {
|
|
164
|
-
errorcode: errorCode,
|
|
165
|
-
errormessage: errorMessage
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
let detailedMessage = "403 Forbidden: Authentication failed with Payone API. ";
|
|
170
|
-
|
|
171
|
-
if (errorCode) {
|
|
172
|
-
detailedMessage += `Error Code: ${errorCode}. `;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (errorMessage) {
|
|
176
|
-
detailedMessage += `Error: ${errorMessage}. `;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
detailedMessage += "Please check:\n" +
|
|
180
|
-
"1. Your Payone credentials (aid, portalid, mid, key) in plugin settings\n" +
|
|
181
|
-
"2. Mode is set to 'live' (Apple Pay only works in live mode according to Payone docs)\n" +
|
|
182
|
-
"3. Your domain is registered with Payone Merchant Services\n" +
|
|
183
|
-
"4. Merchant ID (mid) matches your merchantIdentifier in PMI\n" +
|
|
184
|
-
"5. Apple Pay is enabled for your portal in PMI (CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Payment type configuration tab)";
|
|
185
|
-
|
|
186
|
-
throw new Error(detailedMessage);
|
|
187
|
-
} else if (errorStatus === 401 || error.message?.includes('401')) {
|
|
188
|
-
if (errorResponseData) {
|
|
189
|
-
const responseData = parseResponse(errorResponseData);
|
|
190
|
-
strapi.log.error("[Apple Pay] 401 Unauthorized from Payone:", {
|
|
191
|
-
errorcode: responseData.errorcode || responseData.ErrorCode,
|
|
192
|
-
errormessage: responseData.errormessage || responseData.ErrorMessage
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
throw new Error("401 Unauthorized: Invalid credentials. Please verify your Payone key in plugin settings.");
|
|
196
|
-
} else if (errorStatus && errorStatus >= 500) {
|
|
197
|
-
const responseData = errorResponseData ? parseResponse(errorResponseData) : {};
|
|
198
|
-
strapi.log.error("[Apple Pay] Payone server error:", {
|
|
199
|
-
status: error.response?.status,
|
|
200
|
-
errorcode: responseData.errorcode || responseData.ErrorCode,
|
|
201
|
-
errormessage: responseData.errormessage || responseData.ErrorMessage
|
|
202
|
-
});
|
|
203
|
-
throw new Error(`Payone server error (${error.response?.status}): ${error.response?.statusText || 'Internal server error'}`);
|
|
204
|
-
}
|
|
205
|
-
|
|
152
|
+
strapi.log.error("[Apple Pay] Error:", error instanceof Error ? error.message : error);
|
|
206
153
|
throw error;
|
|
207
154
|
}
|
|
208
155
|
};
|
|
@@ -215,28 +162,89 @@ const validateApplePayMerchant = async (strapi, params) => {
|
|
|
215
162
|
throw new Error("Payone settings are not properly configured. Please check your plugin settings (aid, portalid, mid, key).");
|
|
216
163
|
}
|
|
217
164
|
|
|
218
|
-
// Get currency and country from Apple Pay config
|
|
219
165
|
const applePayConfig = settings?.applePayConfig || {};
|
|
220
|
-
const currency = params.currency || applePayConfig.currencyCode || "EUR";
|
|
221
|
-
const countryCode = params.countryCode || applePayConfig.countryCode || "DE";
|
|
222
166
|
|
|
223
|
-
// Update params with config values
|
|
224
167
|
if (!params.currency && applePayConfig.currencyCode) {
|
|
225
168
|
params.currency = applePayConfig.currencyCode;
|
|
226
169
|
}
|
|
170
|
+
|
|
227
171
|
if (!params.countryCode && applePayConfig.countryCode) {
|
|
228
172
|
params.countryCode = applePayConfig.countryCode;
|
|
229
173
|
}
|
|
230
174
|
|
|
231
175
|
const sessionResponse = await initializeApplePaySession(strapi, params);
|
|
232
176
|
|
|
233
|
-
|
|
234
|
-
|
|
177
|
+
// Extract add_paydata[applepay_payment_session] from response
|
|
178
|
+
// Payone returns this in URL-encoded format: add_paydata[applepay_payment_session]=BASE64_STRING
|
|
179
|
+
const applePaySessionBase64 =
|
|
180
|
+
sessionResponse["add_paydata[applepay_payment_session]"] ||
|
|
181
|
+
sessionResponse["add_paydata_applepay_payment_session"] ||
|
|
182
|
+
sessionResponse.add_paydata?.applepay_payment_session ||
|
|
183
|
+
(sessionResponse.add_paydata && typeof sessionResponse.add_paydata === 'object'
|
|
184
|
+
? sessionResponse.add_paydata["applepay_payment_session"]
|
|
185
|
+
: null);
|
|
186
|
+
|
|
187
|
+
strapi.log.info("[Apple Pay] Genericpayment response:", {
|
|
188
|
+
status: sessionResponse.status,
|
|
189
|
+
workorderid: sessionResponse.workorderid,
|
|
190
|
+
hasApplePaySession: !!applePaySessionBase64,
|
|
191
|
+
applePaySessionLength: applePaySessionBase64 ? applePaySessionBase64.length : 0,
|
|
192
|
+
responseKeys: Object.keys(sessionResponse),
|
|
193
|
+
hasAddPaydataKey: !!sessionResponse["add_paydata[applepay_payment_session]"],
|
|
194
|
+
hasAddPaydataObject: !!sessionResponse.add_paydata,
|
|
195
|
+
addPaydataKeys: sessionResponse.add_paydata ? Object.keys(sessionResponse.add_paydata) : null
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
if (!applePaySessionBase64) {
|
|
199
|
+
strapi.log.error("[Apple Pay] Missing applepay_payment_session in response:", {
|
|
200
|
+
status: sessionResponse.status,
|
|
201
|
+
responseKeys: Object.keys(sessionResponse),
|
|
202
|
+
responseSample: JSON.stringify(sessionResponse).substring(0, 1000),
|
|
203
|
+
addPaydataKeys: sessionResponse.add_paydata ? Object.keys(sessionResponse.add_paydata) : null
|
|
204
|
+
});
|
|
205
|
+
throw new Error("Missing applepay_payment_session in Payone response. Please check your Payone Apple Pay configuration in PMI.");
|
|
206
|
+
}
|
|
235
207
|
|
|
236
208
|
if (sessionResponse.status === "OK" && applePaySessionBase64 && applePaySessionBase64.length > 0) {
|
|
237
209
|
try {
|
|
238
|
-
|
|
239
|
-
|
|
210
|
+
strapi.log.info("[Apple Pay] Extracting merchant session from Base64:", {
|
|
211
|
+
base64Length: applePaySessionBase64.length,
|
|
212
|
+
base64Preview: applePaySessionBase64.substring(0, 100) + "...",
|
|
213
|
+
base64End: applePaySessionBase64.substring(Math.max(0, applePaySessionBase64.length - 50))
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Decode Base64 to get merchant session JSON
|
|
217
|
+
let merchantSessionJson;
|
|
218
|
+
try {
|
|
219
|
+
merchantSessionJson = Buffer.from(applePaySessionBase64, 'base64').toString('utf-8');
|
|
220
|
+
strapi.log.info("[Apple Pay] Base64 decoded successfully, JSON length:", merchantSessionJson.length);
|
|
221
|
+
} catch (decodeError) {
|
|
222
|
+
strapi.log.error("[Apple Pay] Failed to decode Base64:", {
|
|
223
|
+
error: decodeError.message,
|
|
224
|
+
base64Length: applePaySessionBase64.length
|
|
225
|
+
});
|
|
226
|
+
throw new Error(`Failed to decode Base64 merchant session: ${decodeError.message}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Parse JSON merchant session
|
|
230
|
+
let merchantSession;
|
|
231
|
+
try {
|
|
232
|
+
merchantSession = JSON.parse(merchantSessionJson);
|
|
233
|
+
strapi.log.info("[Apple Pay] Merchant session JSON parsed successfully");
|
|
234
|
+
} catch (parseError) {
|
|
235
|
+
strapi.log.error("[Apple Pay] Failed to parse merchant session JSON:", {
|
|
236
|
+
error: parseError.message,
|
|
237
|
+
jsonPreview: merchantSessionJson.substring(0, 500)
|
|
238
|
+
});
|
|
239
|
+
throw new Error(`Failed to parse merchant session JSON: ${parseError.message}`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
strapi.log.info("[Apple Pay] Merchant session extracted successfully:", {
|
|
243
|
+
hasMerchantIdentifier: !!merchantSession.merchantIdentifier,
|
|
244
|
+
hasEpochTimestamp: !!merchantSession.epochTimestamp,
|
|
245
|
+
hasExpiresAt: !!merchantSession.expiresAt,
|
|
246
|
+
merchantSessionKeys: Object.keys(merchantSession)
|
|
247
|
+
});
|
|
240
248
|
|
|
241
249
|
if (merchantSession.epochTimestamp && merchantSession.epochTimestamp > 1000000000000) {
|
|
242
250
|
merchantSession.epochTimestamp = Math.floor(merchantSession.epochTimestamp / 1000);
|
|
@@ -274,7 +282,9 @@ const validateApplePayMerchant = async (strapi, params) => {
|
|
|
274
282
|
throw new Error(
|
|
275
283
|
`Payone Apple Pay initialization failed: ${errorCode ? `Error ${errorCode}` : 'Unknown error'} - ${errorMessage || 'Please check your Payone Apple Pay configuration in PMI'}`
|
|
276
284
|
);
|
|
285
|
+
|
|
277
286
|
} catch (error) {
|
|
287
|
+
strapi.log.error("[Apple Pay] Error:", error instanceof Error ? error.message : error);
|
|
278
288
|
throw error;
|
|
279
289
|
}
|
|
280
290
|
};
|
|
@@ -9,6 +9,31 @@ const { logTransaction } = require("./transactionService");
|
|
|
9
9
|
|
|
10
10
|
const POST_GATEWAY_URL = "https://api.pay1.de/post-gateway/";
|
|
11
11
|
|
|
12
|
+
const getInvoiceIdObject = (invoiceid) => {
|
|
13
|
+
if (!invoiceid || typeof invoiceid !== 'string') {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const invoiceIdVariants = [
|
|
18
|
+
'invoiceid',
|
|
19
|
+
'invoiceId',
|
|
20
|
+
'invoice_id',
|
|
21
|
+
'invoiceID',
|
|
22
|
+
'InvoiceId',
|
|
23
|
+
'InvoiceID',
|
|
24
|
+
'Invoice_Id',
|
|
25
|
+
'INVOICEID',
|
|
26
|
+
'INVOICE_ID'
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
let invoiceIdObject = {}
|
|
30
|
+
for (const variant of invoiceIdVariants) {
|
|
31
|
+
invoiceIdObject[variant] = invoiceid;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return invoiceIdObject;
|
|
35
|
+
};
|
|
36
|
+
|
|
12
37
|
const sendRequest = async (strapi, params) => {
|
|
13
38
|
try {
|
|
14
39
|
const settings = await getSettings(strapi);
|
|
@@ -87,30 +112,45 @@ const sendRequest = async (strapi, params) => {
|
|
|
87
112
|
};
|
|
88
113
|
|
|
89
114
|
const preauthorization = async (strapi, params) => {
|
|
115
|
+
|
|
90
116
|
const requiredParams = {
|
|
91
117
|
request: "preauthorization",
|
|
92
|
-
clearingtype: params.clearingtype
|
|
93
|
-
amount: params.amount
|
|
94
|
-
currency: params.currency
|
|
95
|
-
reference: params.reference
|
|
96
|
-
firstname: params.firstname
|
|
97
|
-
lastname: params.lastname
|
|
98
|
-
street: params.street
|
|
99
|
-
zip: params.zip
|
|
100
|
-
city: params.city
|
|
101
|
-
country: params.country
|
|
102
|
-
email: params.email
|
|
118
|
+
clearingtype: params.clearingtype,
|
|
119
|
+
amount: params.amount,
|
|
120
|
+
currency: params.currency,
|
|
121
|
+
reference: params.reference,
|
|
122
|
+
firstname: params.firstname,
|
|
123
|
+
lastname: params.lastname,
|
|
124
|
+
street: params.street,
|
|
125
|
+
zip: params.zip,
|
|
126
|
+
city: params.city,
|
|
127
|
+
country: params.country,
|
|
128
|
+
email: params.email,
|
|
129
|
+
narrative_text: params.narrative_text,
|
|
130
|
+
...getInvoiceIdObject(params.invoiceid),
|
|
103
131
|
...params
|
|
104
132
|
};
|
|
105
133
|
|
|
134
|
+
|
|
106
135
|
const updatedParams = addPaymentMethodParams(requiredParams, strapi.log);
|
|
107
136
|
return await sendRequest(strapi, updatedParams);
|
|
108
137
|
};
|
|
109
138
|
|
|
110
139
|
const authorization = async (strapi, params) => {
|
|
140
|
+
|
|
111
141
|
const requiredParams = {
|
|
112
142
|
request: "authorization",
|
|
113
|
-
clearingtype: params.clearingtype
|
|
143
|
+
clearingtype: params.clearingtype,
|
|
144
|
+
reference: params.reference,
|
|
145
|
+
firstname: params.firstname,
|
|
146
|
+
lastname: params.lastname,
|
|
147
|
+
street: params.street,
|
|
148
|
+
zip: params.zip,
|
|
149
|
+
city: params.city,
|
|
150
|
+
country: params.country,
|
|
151
|
+
email: params.email,
|
|
152
|
+
narrative_text: params.narrative_text,
|
|
153
|
+
...getInvoiceIdObject(params.invoiceid),
|
|
114
154
|
...params
|
|
115
155
|
};
|
|
116
156
|
|
|
@@ -123,15 +163,16 @@ const capture = async (strapi, params) => {
|
|
|
123
163
|
throw new Error("Transaction ID (txid) is required for capture");
|
|
124
164
|
}
|
|
125
165
|
|
|
166
|
+
|
|
126
167
|
const requiredParams = {
|
|
127
168
|
request: "capture",
|
|
128
169
|
txid: params.txid,
|
|
129
170
|
amount: params.amount || 1000,
|
|
130
171
|
currency: params.currency || "EUR",
|
|
172
|
+
...getInvoiceIdObject(params.invoiceid),
|
|
131
173
|
...params
|
|
132
174
|
};
|
|
133
175
|
|
|
134
|
-
delete requiredParams.reference;
|
|
135
176
|
return await sendRequest(strapi, requiredParams);
|
|
136
177
|
};
|
|
137
178
|
|
|
@@ -140,12 +181,14 @@ const refund = async (strapi, params) => {
|
|
|
140
181
|
throw new Error("Transaction ID (txid) is required for refund");
|
|
141
182
|
}
|
|
142
183
|
|
|
184
|
+
|
|
143
185
|
const requiredParams = {
|
|
144
186
|
request: "refund",
|
|
145
187
|
txid: params.txid,
|
|
146
188
|
amount: params.amount || 1000,
|
|
147
189
|
currency: params.currency || "EUR",
|
|
148
190
|
reference: params.reference || `REFUND-${Date.now()}`,
|
|
191
|
+
...getInvoiceIdObject(params.invoiceid),
|
|
149
192
|
...params
|
|
150
193
|
};
|
|
151
194
|
|
|
@@ -12,6 +12,7 @@ const logTransaction = async (strapi, transactionData) => {
|
|
|
12
12
|
timestamp: new Date().toISOString(),
|
|
13
13
|
txid: transactionData.txid || null,
|
|
14
14
|
reference: transactionData.reference || null,
|
|
15
|
+
invoiceid: transactionData.invoiceid || null,
|
|
15
16
|
request_type:
|
|
16
17
|
transactionData.request_type || transactionData.request || "unknown",
|
|
17
18
|
amount: transactionData.amount || null,
|
|
@@ -27,6 +28,7 @@ const logTransaction = async (strapi, transactionData) => {
|
|
|
27
28
|
transactionData.customer_message ||
|
|
28
29
|
transactionData.Error?.CustomerMessage ||
|
|
29
30
|
null,
|
|
31
|
+
body: transactionData || null,
|
|
30
32
|
raw_request: transactionData.raw_request || null,
|
|
31
33
|
raw_response: transactionData.raw_response || transactionData,
|
|
32
34
|
created_at: new Date().toISOString(),
|
|
@@ -52,10 +54,19 @@ const getTransactionHistory = async (strapi, filters = {}) => {
|
|
|
52
54
|
let transactionHistory =
|
|
53
55
|
(await pluginStore.get({ key: "transactionHistory" })) || [];
|
|
54
56
|
|
|
55
|
-
if (filters.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
if (filters.search) {
|
|
58
|
+
const searchLower = filters.search.toLowerCase().trim();
|
|
59
|
+
transactionHistory = transactionHistory.filter((transaction) => {
|
|
60
|
+
const status = (transaction.status || "").toLowerCase();
|
|
61
|
+
const txid = (transaction.txid || "").toLowerCase();
|
|
62
|
+
const reference = (transaction.reference || "").toLowerCase();
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
status.includes(searchLower) ||
|
|
66
|
+
txid.includes(searchLower) ||
|
|
67
|
+
reference.includes(searchLower)
|
|
68
|
+
);
|
|
69
|
+
});
|
|
59
70
|
}
|
|
60
71
|
|
|
61
72
|
if (filters.request_type) {
|
|
@@ -64,16 +75,28 @@ const getTransactionHistory = async (strapi, filters = {}) => {
|
|
|
64
75
|
);
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
if (filters.
|
|
68
|
-
transactionHistory = transactionHistory.filter(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
if (filters.payment_method) {
|
|
79
|
+
transactionHistory = transactionHistory.filter((transaction) => {
|
|
80
|
+
const clearingtype = transaction.raw_request?.clearingtype || "";
|
|
81
|
+
const wallettype = transaction.raw_request?.wallettype || "";
|
|
82
|
+
|
|
83
|
+
switch (filters.payment_method) {
|
|
84
|
+
case "credit_card":
|
|
85
|
+
return clearingtype === "cc";
|
|
86
|
+
case "paypal":
|
|
87
|
+
return clearingtype === "wlt" && wallettype === "PPE";
|
|
88
|
+
case "google_pay":
|
|
89
|
+
return clearingtype === "wlt" && (wallettype === "GPY" || wallettype === "GOOGLEPAY");
|
|
90
|
+
case "apple_pay":
|
|
91
|
+
return clearingtype === "wlt" && (wallettype === "APL" || wallettype === "APPLEPAY");
|
|
92
|
+
case "sofort":
|
|
93
|
+
return clearingtype === "sb";
|
|
94
|
+
case "sepa":
|
|
95
|
+
return clearingtype === "elv";
|
|
96
|
+
default:
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
77
100
|
}
|
|
78
101
|
|
|
79
102
|
if (filters.date_from) {
|
|
@@ -43,6 +43,26 @@ const addPaymentMethodParams = (params, logger) => {
|
|
|
43
43
|
const updated = { ...params };
|
|
44
44
|
const clearingtype = updated.clearingtype || "cc";
|
|
45
45
|
|
|
46
|
+
const customParams = {};
|
|
47
|
+
const knownParams = new Set([
|
|
48
|
+
'cardpan', 'cardexpiredate', 'cardcvc2', 'cardtype', 'wallettype',
|
|
49
|
+
'bankcountry', 'iban', 'bic', 'bankaccountholder', 'onlinebanktransfertype',
|
|
50
|
+
'recurrence', 'financingtype', 'invoicetype',
|
|
51
|
+
// Common defaults
|
|
52
|
+
'salutation', 'gender', 'telephonenumber', 'ip', 'language', 'customer_is_present',
|
|
53
|
+
// Payment method tokens
|
|
54
|
+
'applePayToken', 'googlePayToken',
|
|
55
|
+
// Other known params
|
|
56
|
+
'clearingtype', 'paymentMethod', 'settings', 'enable3DSecure', 'ecommercemode'
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
// Extract custom params that are not in known params
|
|
60
|
+
Object.keys(updated).forEach(key => {
|
|
61
|
+
if (!knownParams.has(key) && !key.startsWith('add_paydata[')) {
|
|
62
|
+
customParams[key] = updated[key];
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
46
66
|
const methodDefaults = {
|
|
47
67
|
cc: {
|
|
48
68
|
cardpan: "4111111111111111",
|
|
@@ -123,18 +143,27 @@ const addPaymentMethodParams = (params, logger) => {
|
|
|
123
143
|
if (updated.applePayToken) {
|
|
124
144
|
let tokenData;
|
|
125
145
|
try {
|
|
126
|
-
// Decode Base64 token
|
|
127
146
|
const tokenString = Buffer.from(updated.applePayToken, 'base64').toString('utf-8');
|
|
128
147
|
tokenData = JSON.parse(tokenString);
|
|
148
|
+
|
|
149
|
+
if (logger) {
|
|
150
|
+
logger.info("[Apple Pay] Token decoded from Base64 successfully");
|
|
151
|
+
}
|
|
129
152
|
} catch (e) {
|
|
130
153
|
try {
|
|
131
|
-
// Try parsing as JSON string directly
|
|
132
154
|
tokenData = typeof updated.applePayToken === 'string'
|
|
133
155
|
? JSON.parse(updated.applePayToken)
|
|
134
156
|
: updated.applePayToken;
|
|
157
|
+
|
|
158
|
+
if (logger) {
|
|
159
|
+
logger.info("[Apple Pay] Token parsed as JSON string directly");
|
|
160
|
+
}
|
|
135
161
|
} catch (e2) {
|
|
136
|
-
// If already an object, use as-is
|
|
137
162
|
tokenData = updated.applePayToken;
|
|
163
|
+
|
|
164
|
+
if (logger) {
|
|
165
|
+
logger.info("[Apple Pay] Token used as-is (already an object)");
|
|
166
|
+
}
|
|
138
167
|
}
|
|
139
168
|
}
|
|
140
169
|
|
|
@@ -143,7 +172,10 @@ const addPaymentMethodParams = (params, logger) => {
|
|
|
143
172
|
|
|
144
173
|
if (!paymentData) {
|
|
145
174
|
if (logger) {
|
|
146
|
-
logger.error("[Apple Pay] Invalid token structure: missing paymentData field"
|
|
175
|
+
logger.error("[Apple Pay] Invalid token structure: missing paymentData field", {
|
|
176
|
+
tokenKeys: Object.keys(tokenData),
|
|
177
|
+
tokenStructure: JSON.stringify(tokenData).substring(0, 500)
|
|
178
|
+
});
|
|
147
179
|
}
|
|
148
180
|
delete updated.applePayToken;
|
|
149
181
|
return updated;
|
|
@@ -152,30 +184,66 @@ const addPaymentMethodParams = (params, logger) => {
|
|
|
152
184
|
const header = paymentData.header || {};
|
|
153
185
|
|
|
154
186
|
// Payone required fields according to docs
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
187
|
+
// Extract version, data, signature from paymentData
|
|
188
|
+
const tokenVersion = paymentData.version || "EC_v1";
|
|
189
|
+
const tokenDataValue = paymentData.data || "";
|
|
190
|
+
const tokenSignature = paymentData.signature || "";
|
|
191
|
+
|
|
192
|
+
// Extract from header
|
|
193
|
+
const ephemeralPublicKey = header.ephemeralPublicKey || "";
|
|
194
|
+
const publicKeyHash = header.publicKeyHash || "";
|
|
195
|
+
const transactionId = paymentData.transactionId || header.transactionId || "";
|
|
196
|
+
|
|
197
|
+
// Set Payone required fields
|
|
198
|
+
updated["add_paydata[paymentdata_token_version]"] = tokenVersion;
|
|
199
|
+
updated["add_paydata[paymentdata_token_data]"] = tokenDataValue;
|
|
200
|
+
updated["add_paydata[paymentdata_token_signature]"] = tokenSignature;
|
|
201
|
+
updated["add_paydata[paymentdata_token_ephemeral_publickey]"] = ephemeralPublicKey;
|
|
202
|
+
updated["add_paydata[paymentdata_token_publickey_hash]"] = publicKeyHash;
|
|
160
203
|
|
|
161
204
|
// Transaction ID is optional according to Payone docs
|
|
162
|
-
if (
|
|
163
|
-
updated["add_paydata[paymentdata_token_transaction_id]"] =
|
|
205
|
+
if (transactionId) {
|
|
206
|
+
updated["add_paydata[paymentdata_token_transaction_id]"] = transactionId;
|
|
164
207
|
}
|
|
165
208
|
|
|
166
|
-
if (
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
209
|
+
if (logger) {
|
|
210
|
+
logger.info("[Apple Pay] Token extracted successfully:", {
|
|
211
|
+
hasVersion: !!tokenVersion,
|
|
212
|
+
hasData: !!tokenDataValue,
|
|
213
|
+
hasSignature: !!tokenSignature,
|
|
214
|
+
hasEphemeralPublicKey: !!ephemeralPublicKey,
|
|
215
|
+
hasPublicKeyHash: !!publicKeyHash,
|
|
216
|
+
hasTransactionId: !!transactionId,
|
|
217
|
+
dataLength: tokenDataValue.length,
|
|
218
|
+
signatureLength: tokenSignature.length,
|
|
219
|
+
ephemeralPublicKeyLength: ephemeralPublicKey.length,
|
|
220
|
+
publicKeyHashLength: publicKeyHash.length
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Validate required fields
|
|
225
|
+
if (!tokenDataValue ||
|
|
226
|
+
!tokenSignature ||
|
|
227
|
+
!ephemeralPublicKey ||
|
|
228
|
+
!publicKeyHash) {
|
|
170
229
|
if (logger) {
|
|
171
230
|
logger.error("[Apple Pay] Missing required token fields:", {
|
|
172
|
-
hasData: !!
|
|
173
|
-
hasSignature: !!
|
|
174
|
-
hasEphemeralPublicKey: !!
|
|
175
|
-
hasPublicKeyHash: !!
|
|
231
|
+
hasData: !!tokenDataValue,
|
|
232
|
+
hasSignature: !!tokenSignature,
|
|
233
|
+
hasEphemeralPublicKey: !!ephemeralPublicKey,
|
|
234
|
+
hasPublicKeyHash: !!publicKeyHash,
|
|
235
|
+
paymentDataKeys: Object.keys(paymentData),
|
|
236
|
+
headerKeys: Object.keys(header)
|
|
176
237
|
});
|
|
177
238
|
}
|
|
178
239
|
}
|
|
240
|
+
} else {
|
|
241
|
+
if (logger) {
|
|
242
|
+
logger.error("[Apple Pay] Token is not a valid object:", {
|
|
243
|
+
tokenType: typeof tokenData,
|
|
244
|
+
tokenValue: typeof tokenData === 'string' ? tokenData.substring(0, 200) : String(tokenData).substring(0, 200)
|
|
245
|
+
});
|
|
246
|
+
}
|
|
179
247
|
}
|
|
180
248
|
|
|
181
249
|
delete updated.applePayToken;
|
|
@@ -210,6 +278,8 @@ const addPaymentMethodParams = (params, logger) => {
|
|
|
210
278
|
}
|
|
211
279
|
});
|
|
212
280
|
|
|
281
|
+
Object.assign(updated, customParams);
|
|
282
|
+
|
|
213
283
|
return updated;
|
|
214
284
|
};
|
|
215
285
|
|