@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamhoofd/backend",
3
- "version": "2.61.0",
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.61.0",
41
- "@stamhoofd/backend-middleware": "2.61.0",
42
- "@stamhoofd/email": "2.61.0",
43
- "@stamhoofd/models": "2.61.0",
44
- "@stamhoofd/queues": "2.61.0",
45
- "@stamhoofd/sql": "2.61.0",
46
- "@stamhoofd/structures": "2.61.0",
47
- "@stamhoofd/utility": "2.61.0",
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": "3df41cac9090d5e99abdbc51e4a4a02e9ea1784a"
67
+ "gitHead": "e3d5890ed7cbd9774a2b917b758e2ff1a0613b6a"
68
68
  }
@@ -50,7 +50,7 @@ async function saveLog({ email, organization, type, subType, id, response, subje
50
50
 
51
51
  async function checkPostmarkBounces() {
52
52
  if (STAMHOOFD.environment !== 'production') {
53
- // return;
53
+ return;
54
54
  }
55
55
 
56
56
  const token = STAMHOOFD.POSTMARK_SERVER_TOKEN;
@@ -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, Token, Webshop } from '@stamhoofd/models';
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, PrivatePayment, Webshop as WebshopStruct } from '@stamhoofd/structures';
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 (this.isUserManager(member) && permissionLevel !== PermissionLevel.Full) {
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
- // can only be set to null, and only if can access member with full access
1114
- if (!hasFullAccess || data.details.securityCode !== null) {
1115
- // Unset silently
1116
- data.details.securityCode = undefined;
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
+ });