@stamhoofd/backend 2.61.0 → 2.62.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/package.json +10 -10
- package/src/crons/postmark.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +13 -2
- package/src/helpers/AdminPermissionChecker.ts +15 -6
- package/src/helpers/StripeHelper.ts +8 -0
- package/src/seeds/1733748412-update-deleted-order-numbers.ts +109 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamhoofd/backend",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.62.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
"@simonbackx/simple-encoding": "2.18.0",
|
|
38
38
|
"@simonbackx/simple-endpoints": "1.15.0",
|
|
39
39
|
"@simonbackx/simple-logging": "^1.0.1",
|
|
40
|
-
"@stamhoofd/backend-i18n": "2.
|
|
41
|
-
"@stamhoofd/backend-middleware": "2.
|
|
42
|
-
"@stamhoofd/email": "2.
|
|
43
|
-
"@stamhoofd/models": "2.
|
|
44
|
-
"@stamhoofd/queues": "2.
|
|
45
|
-
"@stamhoofd/sql": "2.
|
|
46
|
-
"@stamhoofd/structures": "2.
|
|
47
|
-
"@stamhoofd/utility": "2.
|
|
40
|
+
"@stamhoofd/backend-i18n": "2.62.0",
|
|
41
|
+
"@stamhoofd/backend-middleware": "2.62.0",
|
|
42
|
+
"@stamhoofd/email": "2.62.0",
|
|
43
|
+
"@stamhoofd/models": "2.62.0",
|
|
44
|
+
"@stamhoofd/queues": "2.62.0",
|
|
45
|
+
"@stamhoofd/sql": "2.62.0",
|
|
46
|
+
"@stamhoofd/structures": "2.62.0",
|
|
47
|
+
"@stamhoofd/utility": "2.62.0",
|
|
48
48
|
"archiver": "^7.0.1",
|
|
49
49
|
"aws-sdk": "^2.885.0",
|
|
50
50
|
"axios": "1.6.8",
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"publishConfig": {
|
|
65
65
|
"access": "public"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "e3d5890ed7cbd9774a2b917b758e2ff1a0613b6a"
|
|
68
68
|
}
|
package/src/crons/postmark.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ArrayDecoder, AutoEncoderPatchType, Data, Decoder, PatchableArray, PatchableArrayAutoEncoder, PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
|
-
import { BalanceItem, BalanceItemPayment, Order, Payment,
|
|
4
|
+
import { BalanceItem, BalanceItemPayment, Order, Payment, Webshop, WebshopCounter } from '@stamhoofd/models';
|
|
5
5
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
6
|
-
import { AuditLogSource, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, OrderStatus, PaymentMethod, PaymentStatus, PermissionLevel, PrivateOrder,
|
|
6
|
+
import { AuditLogSource, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, OrderStatus, PaymentMethod, PaymentStatus, PermissionLevel, PrivateOrder, Webshop as WebshopStruct } from '@stamhoofd/structures';
|
|
7
7
|
|
|
8
8
|
import { Context } from '../../../../helpers/Context';
|
|
9
9
|
import { AuditLogService } from '../../../../services/AuditLogService';
|
|
@@ -83,6 +83,8 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
83
83
|
return new Response([]);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
let clearNumbers = false;
|
|
87
|
+
|
|
86
88
|
// Need to happen in the queue because we are updating the webshop stock
|
|
87
89
|
const orders = await QueueHandler.schedule('webshop-stock/' + request.params.id, async () => {
|
|
88
90
|
const webshop = await Webshop.getByID(request.params.id);
|
|
@@ -244,6 +246,11 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
244
246
|
|
|
245
247
|
if (model.status === OrderStatus.Deleted) {
|
|
246
248
|
model.data.removePersonalData();
|
|
249
|
+
|
|
250
|
+
if (model.number !== null) {
|
|
251
|
+
model.number = Math.floor(Math.random() * 1000000000000) + 1000000000000;
|
|
252
|
+
}
|
|
253
|
+
clearNumbers = true;
|
|
247
254
|
}
|
|
248
255
|
|
|
249
256
|
if (model.status === OrderStatus.Deleted || model.status === OrderStatus.Canceled) {
|
|
@@ -298,6 +305,10 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
298
305
|
return mapped;
|
|
299
306
|
});
|
|
300
307
|
|
|
308
|
+
if (clearNumbers) {
|
|
309
|
+
WebshopCounter.resetNumbers(request.params.id);
|
|
310
|
+
}
|
|
311
|
+
|
|
301
312
|
return new Response(
|
|
302
313
|
await Order.getPrivateStructures(orders),
|
|
303
314
|
);
|
|
@@ -211,7 +211,7 @@ export class AdminPermissionChecker {
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
async canAccessMember(member: MemberWithRegistrations, permissionLevel: PermissionLevel = PermissionLevel.Read) {
|
|
214
|
-
if (
|
|
214
|
+
if (permissionLevel !== PermissionLevel.Full && this.isUserManager(member)) {
|
|
215
215
|
return true;
|
|
216
216
|
}
|
|
217
217
|
|
|
@@ -1107,13 +1107,22 @@ export class AdminPermissionChecker {
|
|
|
1107
1107
|
const isSetFinancialSupportTrue = data.details.shouldApplyReducedPrice;
|
|
1108
1108
|
const isUserManager = this.isUserManager(member);
|
|
1109
1109
|
|
|
1110
|
-
if (data.details.securityCode !== undefined) {
|
|
1110
|
+
if (data.details.securityCode !== undefined || data.details.trackingYear !== undefined) {
|
|
1111
1111
|
const hasFullAccess = await this.canAccessMember(member, PermissionLevel.Full);
|
|
1112
1112
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1113
|
+
if (!hasFullAccess) {
|
|
1114
|
+
if (data.details.securityCode !== undefined) {
|
|
1115
|
+
// can only be set to null, and only if can access member with full access
|
|
1116
|
+
if (data.details.securityCode !== null) {
|
|
1117
|
+
// Unset silently
|
|
1118
|
+
data.details.securityCode = undefined;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
if (data.details.trackingYear !== undefined) {
|
|
1123
|
+
// Unset silently
|
|
1124
|
+
data.details.trackingYear = undefined;
|
|
1125
|
+
}
|
|
1117
1126
|
}
|
|
1118
1127
|
}
|
|
1119
1128
|
|
|
@@ -210,6 +210,14 @@ export class StripeHelper {
|
|
|
210
210
|
|
|
211
211
|
const totalPrice = payment.price;
|
|
212
212
|
|
|
213
|
+
if (totalPrice < 50) {
|
|
214
|
+
throw new SimpleError({
|
|
215
|
+
code: 'minmum_amount',
|
|
216
|
+
message: 'The minimum amount for an online payment is € 0,50',
|
|
217
|
+
human: 'Het minimum bedrag voor een online betaling is € 0,50',
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
213
221
|
let fee = 0;
|
|
214
222
|
let directCharge = false;
|
|
215
223
|
const vat = calculateVATPercentage(organization.address, organization.meta.VATNumber);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Migration } from '@simonbackx/simple-database';
|
|
2
|
+
import { logger } from '@simonbackx/simple-logging';
|
|
3
|
+
import { Order, WebshopCounter } from '@stamhoofd/models';
|
|
4
|
+
import { OrderStatus } from '@stamhoofd/structures';
|
|
5
|
+
|
|
6
|
+
export default new Migration(async () => {
|
|
7
|
+
if (STAMHOOFD.environment == 'test') {
|
|
8
|
+
console.log('skipped in tests');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
process.stdout.write('\n');
|
|
13
|
+
let c = 0;
|
|
14
|
+
let pages = 0;
|
|
15
|
+
let id: string = '';
|
|
16
|
+
|
|
17
|
+
// There is an issue with some deleted orders that can't be stringified anymore
|
|
18
|
+
let limit = 100;
|
|
19
|
+
let restoreLimitAt: number | null = null;
|
|
20
|
+
|
|
21
|
+
await logger.setContext({ tags: ['seed'] }, async () => {
|
|
22
|
+
while (true) {
|
|
23
|
+
try {
|
|
24
|
+
const orders = await Order.where({
|
|
25
|
+
id: {
|
|
26
|
+
value: id,
|
|
27
|
+
sign: '>',
|
|
28
|
+
},
|
|
29
|
+
status: OrderStatus.Deleted,
|
|
30
|
+
}, { limit, sort: ['id'] });
|
|
31
|
+
|
|
32
|
+
if (orders.length === 0) {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pages++;
|
|
37
|
+
process.stdout.write('.');
|
|
38
|
+
if (pages % 100 === 0) {
|
|
39
|
+
process.stdout.write('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (limit === 1 && restoreLimitAt && pages > restoreLimitAt) {
|
|
43
|
+
limit = 100;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const order of orders) {
|
|
47
|
+
c++;
|
|
48
|
+
|
|
49
|
+
if (order.status === OrderStatus.Deleted) {
|
|
50
|
+
order.data.removePersonalData();
|
|
51
|
+
|
|
52
|
+
if (order.number !== null) {
|
|
53
|
+
order.number = Math.floor(Math.random() * 1000000000000) + 1000000000000;
|
|
54
|
+
}
|
|
55
|
+
await order.save();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (orders.length < limit) {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
id = orders[orders.length - 1].id;
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
if (e.toString() && e.toString().includes('RangeError')) {
|
|
66
|
+
console.error('Found decoding issue at ' + id);
|
|
67
|
+
console.error(e);
|
|
68
|
+
if (limit === 1) {
|
|
69
|
+
// We found the causing order.
|
|
70
|
+
|
|
71
|
+
const _orders = await Order.where({
|
|
72
|
+
id: {
|
|
73
|
+
value: id,
|
|
74
|
+
sign: '>',
|
|
75
|
+
},
|
|
76
|
+
status: OrderStatus.Deleted,
|
|
77
|
+
}, { limit: 1, sort: ['id'], select: 'id' });
|
|
78
|
+
|
|
79
|
+
if (_orders.length === 1) {
|
|
80
|
+
console.log('Found broken order: ' + _orders[0].id);
|
|
81
|
+
console.log('Deleting order');
|
|
82
|
+
// Delete
|
|
83
|
+
await _orders[0].delete();
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.error('Could not find causing order');
|
|
87
|
+
throw e;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Something wrong with an order
|
|
91
|
+
// continue
|
|
92
|
+
limit = 1;
|
|
93
|
+
restoreLimitAt = pages + 100;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
console.error('Error at ' + id);
|
|
97
|
+
throw e;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
console.log('Cleared ' + c + ' deleted orders');
|
|
103
|
+
|
|
104
|
+
// Clear all cached order numbers
|
|
105
|
+
WebshopCounter.clearAll();
|
|
106
|
+
|
|
107
|
+
// Do something here
|
|
108
|
+
return Promise.resolve();
|
|
109
|
+
});
|