strapi-plugin-payone-provider 5.6.11 → 5.6.13
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/README.md +102 -545
- package/admin/src/components/PluginIcon/index.jsx +14 -3
- package/admin/src/pages/App/components/AppHeader.jsx +1 -1
- package/admin/src/pages/App/components/AppTabs.jsx +69 -16
- package/admin/src/pages/App/components/RenderInput.jsx +9 -25
- package/admin/src/pages/App/components/StatusBadge.jsx +69 -17
- package/admin/src/pages/App/components/configuration/ConfigurationPanel.jsx +2 -2
- package/admin/src/pages/App/components/icons/index.jsx +1 -0
- package/admin/src/pages/App/components/transaction-history/FiltersPanel.jsx +4 -3
- package/admin/src/pages/App/components/transaction-history/TransactionTable.jsx +6 -5
- package/admin/src/pages/App/components/transaction-history/details/TransactionDetails.jsx +10 -10
- package/admin/src/pages/App/index.jsx +3 -3
- package/admin/src/pages/App/styles.css +28 -23
- package/admin/src/pages/utils/api.js +3 -2
- package/admin/src/pages/utils/getInputComponent.jsx +20 -45
- package/admin/src/pages/utils/transactionTableUtils.js +2 -1
- package/package.json +1 -1
- package/server/content-types/index.js +5 -0
- package/server/content-types/transactions/index.js +5 -0
- package/server/content-types/transactions/schema.json +87 -0
- package/server/controllers/payone.js +24 -13
- package/server/index.js +2 -0
- package/server/policies/is-payone-notification.js +12 -23
- package/server/services/transactionService.js +137 -104
- package/server/services/transactionStatusService.js +55 -61
- package/server/utils/sanitize.js +42 -0
|
@@ -4,14 +4,27 @@ import {
|
|
|
4
4
|
SingleSelect,
|
|
5
5
|
SingleSelectOption,
|
|
6
6
|
Switch,
|
|
7
|
-
DesignSystemProvider,
|
|
8
7
|
Tooltip,
|
|
9
8
|
Textarea,
|
|
10
9
|
Toggle,
|
|
11
10
|
Checkbox,
|
|
12
|
-
Typography
|
|
11
|
+
Typography
|
|
13
12
|
} from "@strapi/design-system";
|
|
14
13
|
import { Information } from "@strapi/icons";
|
|
14
|
+
|
|
15
|
+
const TooltipIcon = ({ tooltipContent }) => {
|
|
16
|
+
if (!tooltipContent) return null;
|
|
17
|
+
return (
|
|
18
|
+
<Tooltip label={tooltipContent ?? ""}>
|
|
19
|
+
<Information
|
|
20
|
+
style={{
|
|
21
|
+
cursor: "pointer"
|
|
22
|
+
}}
|
|
23
|
+
/>
|
|
24
|
+
</Tooltip>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
15
28
|
export const InputComponent = ({
|
|
16
29
|
inputType,
|
|
17
30
|
name,
|
|
@@ -23,8 +36,6 @@ export const InputComponent = ({
|
|
|
23
36
|
placeholder = "",
|
|
24
37
|
onLabel = "True",
|
|
25
38
|
offLabel = "False",
|
|
26
|
-
systemTheme,
|
|
27
|
-
theme,
|
|
28
39
|
className = "payment-input",
|
|
29
40
|
type = "text",
|
|
30
41
|
...props
|
|
@@ -43,16 +54,7 @@ export const InputComponent = ({
|
|
|
43
54
|
type={type}
|
|
44
55
|
endAction={
|
|
45
56
|
tooltipContent ? (
|
|
46
|
-
<
|
|
47
|
-
<Tooltip label={tooltipContent ?? ""}>
|
|
48
|
-
<Information
|
|
49
|
-
style={{
|
|
50
|
-
cursor: "pointer",
|
|
51
|
-
color: systemTheme === "dark" ? "#fff" : "#000",
|
|
52
|
-
}}
|
|
53
|
-
/>
|
|
54
|
-
</Tooltip>
|
|
55
|
-
</DesignSystemProvider>
|
|
57
|
+
<TooltipIcon tooltipContent={tooltipContent} />
|
|
56
58
|
) : null
|
|
57
59
|
}
|
|
58
60
|
{...props}
|
|
@@ -71,16 +73,7 @@ export const InputComponent = ({
|
|
|
71
73
|
required={required}
|
|
72
74
|
startAction={
|
|
73
75
|
tooltipContent ? (
|
|
74
|
-
<
|
|
75
|
-
<Tooltip label={tooltipContent ?? ""}>
|
|
76
|
-
<Information
|
|
77
|
-
style={{
|
|
78
|
-
cursor: "pointer",
|
|
79
|
-
color: systemTheme === "dark" ? "#fff" : "#000",
|
|
80
|
-
}}
|
|
81
|
-
/>
|
|
82
|
-
</Tooltip>
|
|
83
|
-
</DesignSystemProvider>
|
|
76
|
+
<TooltipIcon tooltipContent={tooltipContent} />
|
|
84
77
|
) : null
|
|
85
78
|
}
|
|
86
79
|
{...props}
|
|
@@ -143,16 +136,7 @@ export const InputComponent = ({
|
|
|
143
136
|
type="date"
|
|
144
137
|
startAction={
|
|
145
138
|
tooltipContent ? (
|
|
146
|
-
<
|
|
147
|
-
<Tooltip label={tooltipContent ?? ""}>
|
|
148
|
-
<Information
|
|
149
|
-
style={{
|
|
150
|
-
cursor: "pointer",
|
|
151
|
-
color: systemTheme === "dark" ? "#fff" : "#000",
|
|
152
|
-
}}
|
|
153
|
-
/>
|
|
154
|
-
</Tooltip>
|
|
155
|
-
</DesignSystemProvider>
|
|
139
|
+
<TooltipIcon tooltipContent={tooltipContent} />
|
|
156
140
|
) : null
|
|
157
141
|
}
|
|
158
142
|
{...props}
|
|
@@ -179,7 +163,7 @@ export const InputComponent = ({
|
|
|
179
163
|
if (typeof onChange === "function") {
|
|
180
164
|
const syntheticEvent = {
|
|
181
165
|
target: { value: selectedValue },
|
|
182
|
-
currentTarget: { value: selectedValue }
|
|
166
|
+
currentTarget: { value: selectedValue }
|
|
183
167
|
};
|
|
184
168
|
onChange(syntheticEvent);
|
|
185
169
|
}
|
|
@@ -188,16 +172,7 @@ export const InputComponent = ({
|
|
|
188
172
|
placeholder={placeholder}
|
|
189
173
|
startIcon={
|
|
190
174
|
tooltipContent ? (
|
|
191
|
-
<
|
|
192
|
-
<Tooltip label={tooltipContent ?? ""}>
|
|
193
|
-
<Information
|
|
194
|
-
style={{
|
|
195
|
-
cursor: "pointer",
|
|
196
|
-
color: systemTheme === "dark" ? "#fff" : "#000",
|
|
197
|
-
}}
|
|
198
|
-
/>
|
|
199
|
-
</Tooltip>
|
|
200
|
-
</DesignSystemProvider>
|
|
175
|
+
<TooltipIcon tooltipContent={tooltipContent} />
|
|
201
176
|
) : null
|
|
202
177
|
}
|
|
203
178
|
{...props}
|
|
@@ -31,8 +31,9 @@ export const formatDate = (dateString) => {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export const getPaymentMethodName = (clearingtype, wallettype) => {
|
|
34
|
+
|
|
34
35
|
switch (clearingtype) {
|
|
35
|
-
case "cc":
|
|
36
|
+
case "cc" || "card" | "c":
|
|
36
37
|
return "Credit Card";
|
|
37
38
|
case "sb":
|
|
38
39
|
return "Online Banking";
|
package/package.json
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "collectionType",
|
|
3
|
+
"collectionName": "transactions",
|
|
4
|
+
"info": {
|
|
5
|
+
"singularName": "transaction",
|
|
6
|
+
"pluralName": "transactions",
|
|
7
|
+
"displayName": "Transaction"
|
|
8
|
+
},
|
|
9
|
+
"options": {
|
|
10
|
+
"draftAndPublish": false
|
|
11
|
+
},
|
|
12
|
+
"pluginOptions": {
|
|
13
|
+
"content-manager": {
|
|
14
|
+
"visible": false
|
|
15
|
+
},
|
|
16
|
+
"content-type-builder": {
|
|
17
|
+
"visible": false
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"attributes": {
|
|
21
|
+
"txid": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"required": false,
|
|
24
|
+
"default": "NO TXID"
|
|
25
|
+
},
|
|
26
|
+
"reference": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"required": false,
|
|
29
|
+
"default": "NO REFERENCE"
|
|
30
|
+
},
|
|
31
|
+
"invoiceid": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"required": false,
|
|
34
|
+
"default": "NO INVOICE ID"
|
|
35
|
+
},
|
|
36
|
+
"amount": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"required": false,
|
|
39
|
+
"default": "0"
|
|
40
|
+
},
|
|
41
|
+
"currency": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"required": false,
|
|
44
|
+
"default": "EUR"
|
|
45
|
+
},
|
|
46
|
+
"status": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"required": false,
|
|
49
|
+
"default": "unknown"
|
|
50
|
+
},
|
|
51
|
+
"error_code": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"required": false,
|
|
54
|
+
"default": "NO ERROR CODE"
|
|
55
|
+
},
|
|
56
|
+
"request_type": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"required": false,
|
|
59
|
+
"default": "unknown"
|
|
60
|
+
},
|
|
61
|
+
"error_message": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"required": false,
|
|
64
|
+
"default": "NO ERROR MESSAGE"
|
|
65
|
+
},
|
|
66
|
+
"customer_message": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"required": false,
|
|
69
|
+
"default": "NO CUSTOMER MESSAGE"
|
|
70
|
+
},
|
|
71
|
+
"body": {
|
|
72
|
+
"type": "json",
|
|
73
|
+
"required": false,
|
|
74
|
+
"default": {}
|
|
75
|
+
},
|
|
76
|
+
"raw_request": {
|
|
77
|
+
"type": "json",
|
|
78
|
+
"required": false,
|
|
79
|
+
"default": {}
|
|
80
|
+
},
|
|
81
|
+
"raw_response": {
|
|
82
|
+
"type": "json",
|
|
83
|
+
"required": false,
|
|
84
|
+
"default": {}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -156,12 +156,22 @@ module.exports = ({ strapi }) => ({
|
|
|
156
156
|
|
|
157
157
|
async getTransactionHistory(ctx) {
|
|
158
158
|
try {
|
|
159
|
-
const { filters = {}, pagination = {} } = ctx.query || {};
|
|
159
|
+
const { filters: rawFilters = {}, pagination = {} } = ctx.query || {};
|
|
160
160
|
const page = parseInt(pagination.page || "1", 10);
|
|
161
161
|
const pageSize = parseInt(pagination.pageSize || "10", 10);
|
|
162
162
|
|
|
163
|
+
const filters = {};
|
|
164
|
+
if (rawFilters && typeof rawFilters === "object") {
|
|
165
|
+
for (const [key, value] of Object.entries(rawFilters)) {
|
|
166
|
+
const v = value == null ? "" : String(value).trim();
|
|
167
|
+
if (v !== "" && v.toLowerCase() !== "all") {
|
|
168
|
+
filters[key] = value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
163
173
|
const result = await getPayoneService(strapi).getTransactionHistory({
|
|
164
|
-
filters
|
|
174
|
+
filters,
|
|
165
175
|
pagination: { page, pageSize }
|
|
166
176
|
});
|
|
167
177
|
|
|
@@ -299,19 +309,20 @@ module.exports = ({ strapi }) => ({
|
|
|
299
309
|
|
|
300
310
|
async handleTransactionStatus(ctx) {
|
|
301
311
|
try {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
312
|
+
if (!ctx.state.payoneAllowed) {
|
|
313
|
+
console.log("[Payone] Notification ignored (policy failed)");
|
|
314
|
+
} else {
|
|
315
|
+
const notificationData = ctx.request.body || {};
|
|
316
|
+
console.log(notificationData);
|
|
317
|
+
await getPayoneService(strapi).processTransactionStatus(notificationData);
|
|
318
|
+
}
|
|
309
319
|
} catch (error) {
|
|
310
|
-
console.log("[Payone TransactionStatus] Error
|
|
311
|
-
ctx.status = 200;
|
|
312
|
-
ctx.body = "TSOK";
|
|
313
|
-
ctx.type = "text/plain";
|
|
320
|
+
console.log("[Payone TransactionStatus] Error:", error);
|
|
314
321
|
}
|
|
322
|
+
|
|
323
|
+
ctx.status = 200;
|
|
324
|
+
ctx.body = "TSOK";
|
|
325
|
+
ctx.type = "text/plain";
|
|
315
326
|
}
|
|
316
327
|
|
|
317
328
|
});
|
package/server/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const controllers = require("./controllers");
|
|
|
8
8
|
const routes = require("./routes");
|
|
9
9
|
const services = require("./services");
|
|
10
10
|
const policies = require("./policies");
|
|
11
|
+
const contentTypes = require("./content-types");
|
|
11
12
|
|
|
12
13
|
module.exports = {
|
|
13
14
|
register,
|
|
@@ -15,6 +16,7 @@ module.exports = {
|
|
|
15
16
|
destroy,
|
|
16
17
|
config,
|
|
17
18
|
controllers,
|
|
19
|
+
contentTypes,
|
|
18
20
|
routes,
|
|
19
21
|
services,
|
|
20
22
|
policies
|
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
module.exports = async (ctx) => {
|
|
2
|
+
const { request } = ctx;
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const userAgent = request.headers["user-agent"] || "";
|
|
5
|
+
const clientIp =
|
|
6
|
+
request.headers["x-payone-client-ip"]?.trim() ||
|
|
7
|
+
request.headers["x-forwarded-for"]?.split(",")[0]?.trim() ||
|
|
8
|
+
request.ip ||
|
|
9
|
+
"";
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
console.log(`[Payone TransactionStatus] Invalid User-Agent: ${userAgent}, IP: ${clientIp}`);
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const isValidIp = (ip) => {
|
|
15
|
-
if (ip.startsWith("185.60.20.")) {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
11
|
+
const isValid = userAgent === "PAYONE FinanceGate" && (clientIp.startsWith("185.60.20.") || clientIp === "54.246.203.105");
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
return false;
|
|
23
|
-
};
|
|
13
|
+
ctx.state.payoneAllowed = isValid;
|
|
24
14
|
|
|
25
|
-
if (!
|
|
26
|
-
console.log(
|
|
27
|
-
return false;
|
|
15
|
+
if (!isValid) {
|
|
16
|
+
console.log("[Payone] Policy failed", { userAgent, clientIp });
|
|
28
17
|
}
|
|
29
18
|
|
|
30
19
|
return true;
|
|
@@ -1,139 +1,172 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { sanitizeSensitive } = require("../utils/sanitize");
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const pluginStore = getPluginStore(strapi);
|
|
7
|
-
let transactionHistory =
|
|
8
|
-
(await pluginStore.get({ key: "transactionHistory" })) || [];
|
|
9
|
-
|
|
10
|
-
const logEntry = {
|
|
11
|
-
id: Date.now().toString(),
|
|
12
|
-
timestamp: new Date().toISOString(),
|
|
13
|
-
txid: transactionData.txid || null,
|
|
14
|
-
reference: transactionData.reference || null,
|
|
15
|
-
invoiceid: transactionData.invoiceid || null,
|
|
16
|
-
request_type:
|
|
17
|
-
transactionData.request_type || transactionData.request || "unknown",
|
|
18
|
-
amount: transactionData.amount || null,
|
|
19
|
-
currency: transactionData.currency || "EUR",
|
|
20
|
-
status: transactionData.status || transactionData.Status || "unknown",
|
|
21
|
-
error_code:
|
|
22
|
-
transactionData.error_code || transactionData.Error?.ErrorCode || null,
|
|
23
|
-
error_message:
|
|
24
|
-
transactionData.error_message ||
|
|
25
|
-
transactionData.Error?.ErrorMessage ||
|
|
26
|
-
null,
|
|
27
|
-
customer_message:
|
|
28
|
-
transactionData.customer_message ||
|
|
29
|
-
transactionData.Error?.CustomerMessage ||
|
|
30
|
-
null,
|
|
31
|
-
body: transactionData || null,
|
|
32
|
-
created_at: new Date().toISOString(),
|
|
33
|
-
updated_at: new Date().toISOString()
|
|
34
|
-
};
|
|
5
|
+
const TRANSACTION_UID = "plugin::strapi-plugin-payone-provider.transaction";
|
|
35
6
|
|
|
36
|
-
|
|
7
|
+
const logTransaction = async (strapi, transactionData) => {
|
|
8
|
+
try {
|
|
9
|
+
const data = {
|
|
10
|
+
txid: transactionData.txid || 'NO TXID',
|
|
11
|
+
reference: transactionData.reference || 'NO REFERENCE',
|
|
12
|
+
invoiceid: transactionData.raw_request.invoiceid || 'NO INVOICE ID',
|
|
13
|
+
request_type: transactionData.request_type || "unknown",
|
|
14
|
+
amount: transactionData.amount || "0",
|
|
15
|
+
currency: transactionData.currency || "EUR",
|
|
16
|
+
status: transactionData.status || transactionData.raw_response.Status || "unknown",
|
|
17
|
+
error_code: transactionData.error_code || "NO ERROR CODE",
|
|
18
|
+
error_message: transactionData.error_message || "NO ERROR MESSAGE",
|
|
19
|
+
customer_message: transactionData.customer_message || "NO CUSTOMER MESSAGE",
|
|
20
|
+
body: transactionData ? { ...transactionData, raw_request: sanitizeSensitive(transactionData.raw_request), raw_response: sanitizeSensitive(transactionData.raw_response) } : {},
|
|
21
|
+
raw_request: sanitizeSensitive(transactionData.raw_request || {}),
|
|
22
|
+
raw_response: sanitizeSensitive(transactionData.raw_response || {}),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const entry = await strapi.db.query(TRANSACTION_UID).create({ data });
|
|
26
|
+
console.info("Transaction logged to DB:", {
|
|
27
|
+
id: entry.id,
|
|
28
|
+
txid: entry.txid,
|
|
29
|
+
status: entry.status
|
|
30
|
+
});
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
return entry;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("Failed to log transaction:", error);
|
|
40
35
|
}
|
|
36
|
+
};
|
|
41
37
|
|
|
42
|
-
await pluginStore.set({
|
|
43
|
-
key: "transactionHistory",
|
|
44
|
-
value: transactionHistory
|
|
45
|
-
});
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
const hasFilterValue = (v) =>
|
|
40
|
+
typeof v === "string" && v.trim() !== "" && v.trim().toLowerCase() !== "all";
|
|
49
41
|
|
|
42
|
+
const buildWhereFromFilters = (filters = {}) => {
|
|
43
|
+
const conditions = [];
|
|
50
44
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return txid.includes(search) || reference.includes(search);
|
|
45
|
+
if (hasFilterValue(filters.search)) {
|
|
46
|
+
const search = String(filters.search).trim();
|
|
47
|
+
conditions.push({
|
|
48
|
+
$or: [
|
|
49
|
+
{ txid: { $containsi: search } },
|
|
50
|
+
{ reference: { $containsi: search } },
|
|
51
|
+
],
|
|
59
52
|
});
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
if (filters.status) {
|
|
63
|
-
|
|
64
|
-
(t) => (t.status || "").toUpperCase() === filters.status.toUpperCase()
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (filters.request_type) {
|
|
69
|
-
result = result.filter((t) => t.request_type === filters.request_type);
|
|
55
|
+
if (hasFilterValue(filters.status)) {
|
|
56
|
+
conditions.push({ status: { $eqi: String(filters.status).trim() } });
|
|
70
57
|
}
|
|
71
58
|
|
|
72
|
-
if (filters.
|
|
73
|
-
|
|
74
|
-
const clearingtype = t.raw_request?.clearingtype;
|
|
75
|
-
const wallettype = t.raw_request?.wallettype;
|
|
76
|
-
|
|
77
|
-
switch (filters.payment_method) {
|
|
78
|
-
case "credit_card":
|
|
79
|
-
return clearingtype === "cc";
|
|
80
|
-
case "paypal":
|
|
81
|
-
return clearingtype === "wlt" && wallettype === "PPE";
|
|
82
|
-
case "google_pay":
|
|
83
|
-
return clearingtype === "wlt" && ["GPY", "GOOGLEPAY"].includes(wallettype);
|
|
84
|
-
case "apple_pay":
|
|
85
|
-
return clearingtype === "wlt" && ["APL", "APPLEPAY"].includes(wallettype);
|
|
86
|
-
case "sofort":
|
|
87
|
-
return clearingtype === "sb";
|
|
88
|
-
case "sepa":
|
|
89
|
-
return clearingtype === "elv";
|
|
90
|
-
default:
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
});
|
|
59
|
+
if (hasFilterValue(filters.request_type)) {
|
|
60
|
+
conditions.push({ request_type: String(filters.request_type).trim() });
|
|
94
61
|
}
|
|
95
62
|
|
|
96
|
-
if (filters.date_from) {
|
|
63
|
+
if (hasFilterValue(filters.date_from)) {
|
|
97
64
|
const dateFrom = new Date(filters.date_from);
|
|
98
65
|
dateFrom.setHours(0, 0, 0, 0);
|
|
99
|
-
|
|
100
|
-
(t) => new Date(t.timestamp) >= dateFrom
|
|
101
|
-
);
|
|
66
|
+
conditions.push({ createdAt: { $gte: dateFrom.toISOString() } });
|
|
102
67
|
}
|
|
103
68
|
|
|
104
|
-
if (filters.date_to) {
|
|
69
|
+
if (hasFilterValue(filters.date_to)) {
|
|
105
70
|
const dateTo = new Date(filters.date_to);
|
|
106
71
|
dateTo.setHours(23, 59, 59, 999);
|
|
107
|
-
|
|
108
|
-
(t) => new Date(t.timestamp) <= dateTo
|
|
109
|
-
);
|
|
72
|
+
conditions.push({ createdAt: { $lte: dateTo.toISOString() } });
|
|
110
73
|
}
|
|
111
74
|
|
|
112
|
-
|
|
113
|
-
|
|
75
|
+
if (hasFilterValue(filters.payment_method)) {
|
|
76
|
+
switch (filters.payment_method) {
|
|
77
|
+
case "credit_card":
|
|
78
|
+
conditions.push({ raw_request: { $containsi: '"clearingtype":"cc"' } });
|
|
79
|
+
break;
|
|
80
|
+
case "paypal":
|
|
81
|
+
conditions.push({
|
|
82
|
+
$and: [
|
|
83
|
+
{ raw_request: { $containsi: '"clearingtype":"wlt"' } },
|
|
84
|
+
{ raw_request: { $containsi: '"wallettype":"PPE"' } },
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
break;
|
|
88
|
+
case "google_pay":
|
|
89
|
+
conditions.push({
|
|
90
|
+
$and: [
|
|
91
|
+
{ raw_request: { $containsi: '"clearingtype":"wlt"' } },
|
|
92
|
+
{
|
|
93
|
+
$or: [
|
|
94
|
+
{ raw_request: { $containsi: '"wallettype":"GPY"' } },
|
|
95
|
+
{ raw_request: { $containsi: '"wallettype":"GOOGLEPAY"' } },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
break;
|
|
101
|
+
case "apple_pay":
|
|
102
|
+
conditions.push({
|
|
103
|
+
$and: [
|
|
104
|
+
{ raw_request: { $containsi: '"clearingtype":"wlt"' } },
|
|
105
|
+
{
|
|
106
|
+
$or: [
|
|
107
|
+
{ raw_request: { $containsi: '"wallettype":"APL"' } },
|
|
108
|
+
{ raw_request: { $containsi: '"wallettype":"APPLEPAY"' } },
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
break;
|
|
114
|
+
case "sofort":
|
|
115
|
+
conditions.push({ raw_request: { $containsi: '"clearingtype":"sb"' } });
|
|
116
|
+
break;
|
|
117
|
+
case "sepa":
|
|
118
|
+
conditions.push({ raw_request: { $containsi: '"clearingtype":"elv"' } });
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
if (conditions.length === 0) return undefined;
|
|
126
|
+
if (conditions.length === 1) return conditions[0];
|
|
127
|
+
return { $and: conditions };
|
|
128
|
+
};
|
|
117
129
|
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
const ALLOWED_SORT_FIELDS = [
|
|
131
|
+
"txid",
|
|
132
|
+
"reference",
|
|
133
|
+
"amount",
|
|
134
|
+
"request_type",
|
|
135
|
+
"status",
|
|
136
|
+
"createdAt",
|
|
137
|
+
"updatedAt",
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
const getTransactionHistory = async (
|
|
141
|
+
strapi,
|
|
142
|
+
{ filters = {}, pagination = {}, sort_by, sort_order }
|
|
143
|
+
) => {
|
|
144
|
+
const page = Math.max(1, Number(pagination.page) || 1);
|
|
145
|
+
const pageSize = Math.min(100, Math.max(1, Number(pagination.pageSize) || 10));
|
|
146
|
+
const offset = (page - 1) * pageSize;
|
|
147
|
+
|
|
148
|
+
const where = buildWhereFromFilters(filters);
|
|
149
|
+
|
|
150
|
+
const sortField =
|
|
151
|
+
sort_by && ALLOWED_SORT_FIELDS.includes(sort_by) ? sort_by : "createdAt";
|
|
152
|
+
const order = sort_order === "asc" ? "asc" : "desc";
|
|
153
|
+
|
|
154
|
+
const queryOptions = {
|
|
155
|
+
orderBy: { [sortField]: order },
|
|
156
|
+
limit: pageSize,
|
|
157
|
+
offset,
|
|
158
|
+
};
|
|
159
|
+
if (where !== undefined) queryOptions.where = where;
|
|
120
160
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
161
|
+
const [data, total] = await strapi.db
|
|
162
|
+
.query(TRANSACTION_UID)
|
|
163
|
+
.findWithCount(queryOptions);
|
|
124
164
|
|
|
125
|
-
const total = transactions.length;
|
|
126
165
|
const pageCount = Math.max(1, Math.ceil(total / pageSize));
|
|
127
|
-
|
|
128
|
-
const validPage = Math.min(Math.max(1, page), pageCount);
|
|
129
|
-
|
|
130
|
-
const start = (validPage - 1) * pageSize;
|
|
131
|
-
const end = Math.min(start + pageSize, total);
|
|
132
|
-
|
|
133
|
-
const paginatedData = start < total ? transactions.slice(start, end) : [];
|
|
166
|
+
const validPage = Math.min(page, pageCount);
|
|
134
167
|
|
|
135
168
|
return {
|
|
136
|
-
data
|
|
169
|
+
data,
|
|
137
170
|
pagination: {
|
|
138
171
|
page: validPage,
|
|
139
172
|
pageSize,
|