@stamhoofd/backend 2.30.1 → 2.30.3

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/index.ts CHANGED
@@ -72,7 +72,7 @@ const start = async () => {
72
72
  ios: STAMHOOFD.LATEST_IOS_VERSION,
73
73
  web: Version
74
74
  },
75
- minimumVersion: 168
75
+ minimumVersion: 331
76
76
  })
77
77
  routerServer.addRequestMiddleware(versionMiddleware)
78
78
  routerServer.addResponseMiddleware(versionMiddleware)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamhoofd/backend",
3
- "version": "2.30.1",
3
+ "version": "2.30.3",
4
4
  "main": "./dist/index.js",
5
5
  "exports": {
6
6
  ".": {
@@ -36,14 +36,14 @@
36
36
  "@simonbackx/simple-encoding": "2.15.1",
37
37
  "@simonbackx/simple-endpoints": "1.14.0",
38
38
  "@simonbackx/simple-logging": "^1.0.1",
39
- "@stamhoofd/backend-i18n": "2.30.1",
40
- "@stamhoofd/backend-middleware": "2.30.1",
41
- "@stamhoofd/email": "2.30.1",
42
- "@stamhoofd/models": "2.30.1",
43
- "@stamhoofd/queues": "2.30.1",
44
- "@stamhoofd/sql": "2.30.1",
45
- "@stamhoofd/structures": "2.30.1",
46
- "@stamhoofd/utility": "2.30.1",
39
+ "@stamhoofd/backend-i18n": "2.30.3",
40
+ "@stamhoofd/backend-middleware": "2.30.3",
41
+ "@stamhoofd/email": "2.30.3",
42
+ "@stamhoofd/models": "2.30.3",
43
+ "@stamhoofd/queues": "2.30.3",
44
+ "@stamhoofd/sql": "2.30.3",
45
+ "@stamhoofd/structures": "2.30.3",
46
+ "@stamhoofd/utility": "2.30.3",
47
47
  "archiver": "^7.0.1",
48
48
  "aws-sdk": "^2.885.0",
49
49
  "axios": "1.6.8",
@@ -60,5 +60,5 @@
60
60
  "postmark": "4.0.2",
61
61
  "stripe": "^16.6.0"
62
62
  },
63
- "gitHead": "8ac5ac76d05d84d32ce09ae0a732c7b2c352ceca"
63
+ "gitHead": "1c2d9449b991aad4d358c913650c83156ebf2b31"
64
64
  }
@@ -499,21 +499,23 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
499
499
  throw Context.auth.error("Je hebt niet voldoende rechten om dit lid te verwijderen")
500
500
  }
501
501
 
502
- await MemberUserSyncer.onDeleteMember(member)
503
- await User.deleteForDeletedMember(member.id)
504
- await BalanceItem.deleteForDeletedMember(member.id)
505
- await member.delete()
506
- shouldUpdateSetupSteps = true
507
-
508
- // Update occupancy of this member because we removed registrations
509
- const groupIds = member.registrations.flatMap(r => r.groupId)
510
- for (const id of groupIds) {
511
- const group = await getGroup(id)
512
- if (group) {
513
- // We need to update this group occupancy because we moved one member away from it
514
- updateGroups.set(group.id, group)
515
- }
516
- }
502
+ throw Context.auth.error("Verwijderen van leden is tijdelijk uitgeschakeld.")
503
+
504
+ //await MemberUserSyncer.onDeleteMember(member)
505
+ //await User.deleteForDeletedMember(member.id)
506
+ //await BalanceItem.deleteForDeletedMember(member.id)
507
+ //await member.delete()
508
+ //shouldUpdateSetupSteps = true
509
+ //
510
+ //// Update occupancy of this member because we removed registrations
511
+ //const groupIds = member.registrations.flatMap(r => r.groupId)
512
+ //for (const id of groupIds) {
513
+ // const group = await getGroup(id)
514
+ // if (group) {
515
+ // // We need to update this group occupancy because we moved one member away from it
516
+ // updateGroups.set(group.id, group)
517
+ // }
518
+ //}
517
519
  }
518
520
 
519
521
  await Member.updateOutstandingBalance(Formatter.uniqueArray(balanceItemMemberIds))
@@ -555,12 +557,16 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
555
557
  if (!member.details.birthDay) {
556
558
  return
557
559
  }
558
- const existingMembers = await Member.where({ organizationId: member.organizationId, firstName: member.details.firstName, lastName: member.details.lastName, birthDay: Formatter.dateIso(member.details.birthDay) });
560
+ let existingMembers = await Member.where({ organizationId: member.organizationId, firstName: member.details.firstName, lastName: member.details.lastName, birthDay: Formatter.dateIso(member.details.birthDay) });
561
+
562
+ if (member.existsInDatabase) {
563
+ existingMembers = existingMembers.filter(e => e.id !== member.id)
564
+ }
559
565
 
560
566
  if (existingMembers.length > 0) {
561
567
  const withRegistrations = await Member.getBlobByIds(...existingMembers.map(m => m.id))
562
- for (const member of withRegistrations) {
563
- if (member.registrations.length > 0) {
568
+ for (const m of withRegistrations) {
569
+ if (m.registrations.length > 0) {
564
570
  return member
565
571
  }
566
572
  }
@@ -1,8 +1,9 @@
1
1
  import { XlsxBuiltInNumberFormat } from "@stamhoofd/excel-writer";
2
- import { ExcelExportType, LimitedFilteredRequest, PaginatedResponse, MemberWithRegistrationsBlob, Platform } from "@stamhoofd/structures";
2
+ import { ExcelExportType, Gender, LimitedFilteredRequest, MemberWithRegistrationsBlob, PaginatedResponse, Platform } from "@stamhoofd/structures";
3
3
  import { ExportToExcelEndpoint } from "../endpoints/global/files/ExportToExcelEndpoint";
4
4
  import { GetMembersEndpoint } from "../endpoints/global/members/GetMembersEndpoint";
5
5
  import { Context } from "../helpers/Context";
6
+ import { XlsxTransformerColumnHelper } from "../helpers/xlsxAddressTransformerColumnFactory";
6
7
 
7
8
  ExportToExcelEndpoint.loaders.set(ExcelExportType.Members, {
8
9
  fetch: async (query: LimitedFilteredRequest) => {
@@ -26,6 +27,14 @@ ExportToExcelEndpoint.loaders.set(ExcelExportType.Members, {
26
27
  value: object.id
27
28
  })
28
29
  },
30
+ {
31
+ id: 'memberNumber',
32
+ name: 'Nummer',
33
+ width: 20,
34
+ getValue: (object: MemberWithRegistrationsBlob) => ({
35
+ value: object.details.memberNumber
36
+ })
37
+ },
29
38
  {
30
39
  id: 'firstName',
31
40
  name: 'Voornaam',
@@ -55,6 +64,129 @@ ExportToExcelEndpoint.loaders.set(ExcelExportType.Members, {
55
64
  }
56
65
  })
57
66
  },
67
+ {
68
+ id: 'age',
69
+ name: 'Leeftijd',
70
+ width: 20,
71
+ getValue: (object: MemberWithRegistrationsBlob) => ({
72
+ value: object.details.age,
73
+ })
74
+ },
75
+ {
76
+ id: 'gender',
77
+ name: 'Geslacht',
78
+ width: 20,
79
+ getValue: (object: MemberWithRegistrationsBlob) => {
80
+ const gender = object.details.gender;
81
+
82
+ return ({
83
+ value: formatGender(gender)
84
+ })
85
+ }
86
+ },
87
+ {
88
+ id: 'phone',
89
+ name: 'Telefoonnummer',
90
+ width: 20,
91
+ getValue: (object: MemberWithRegistrationsBlob) => ({
92
+ value: object.details.phone,
93
+ })
94
+ },
95
+ {
96
+ id: 'email',
97
+ name: 'E-mailadres',
98
+ width: 20,
99
+ getValue: (object: MemberWithRegistrationsBlob) => ({
100
+ value: object.details.email,
101
+ })
102
+ },
103
+ XlsxTransformerColumnHelper.createAddressColumns<MemberWithRegistrationsBlob>({
104
+ matchId: 'address',
105
+ identifier: 'Adres',
106
+ getAddress: (object) => {
107
+ // get member address if exists
108
+ const memberAddress = object.details.address;
109
+ if(memberAddress) {
110
+ return memberAddress;
111
+ }
112
+
113
+ // else get address of first parent with address
114
+ for(const parent of object.details.parents) {
115
+ if(parent.address) {
116
+ return parent.address;
117
+ }
118
+ }
119
+
120
+ return null;
121
+ }
122
+ }),
123
+ {
124
+ id: 'securityCode',
125
+ name: 'Beveiligingscode',
126
+ width: 20,
127
+ getValue: (object: MemberWithRegistrationsBlob) => ({
128
+ value: object.details.securityCode,
129
+ })
130
+ },
131
+ {
132
+ id: 'uitpasNumber',
133
+ name: 'UiTPAS-nummer',
134
+ width: 20,
135
+ getValue: (object: MemberWithRegistrationsBlob) => ({
136
+ value: object.details.uitpasNumber,
137
+ })
138
+ },
139
+ {
140
+ id: 'requiresFinancialSupport',
141
+ // todo: use correct term
142
+ name: 'Financiële ondersteuning',
143
+ width: 20,
144
+ getValue: (object: MemberWithRegistrationsBlob) => ({
145
+ value: XlsxTransformerColumnHelper.formatBoolean(object.details.requiresFinancialSupport?.value),
146
+ })
147
+ },
148
+ {
149
+ id: 'notes',
150
+ name: 'Notities',
151
+ width: 20,
152
+ getValue: (object: MemberWithRegistrationsBlob) => ({
153
+ value: object.details.notes,
154
+ })
155
+ },
156
+
157
+ ...XlsxTransformerColumnHelper.creatColumnsForParents(),
158
+
159
+ // unverified data
160
+ {
161
+ id: 'unverifiedPhones',
162
+ name: 'Niet-geverifieerde telefoonnummers',
163
+ width: 20,
164
+ getValue: (object: MemberWithRegistrationsBlob) => ({
165
+ value: object.details.unverifiedPhones.join(', '),
166
+ })
167
+ },
168
+ {
169
+ id: 'unverifiedEmails',
170
+ name: 'Niet-geverifieerde e-mailadressen',
171
+ width: 20,
172
+ getValue: (object: MemberWithRegistrationsBlob) => ({
173
+ value: object.details.unverifiedEmails.join(', '),
174
+ })
175
+ },
176
+ ...XlsxTransformerColumnHelper.createColumnsForAddresses<MemberWithRegistrationsBlob>({
177
+ matchIdStart: 'unverifiedAddresses',
178
+ identifier: 'Niet-geverifieerd adres',
179
+ getAddresses: (object) => object.details.unverifiedAddresses,
180
+ limit: 2
181
+ }),
182
+ {
183
+ id: 'unverifiedAddresses',
184
+ name: 'Niet-geverifieerde adressen',
185
+ width: 20,
186
+ getValue: (object: MemberWithRegistrationsBlob) => ({
187
+ value: object.details.unverifiedAddresses.map(a => a.toString()).join('; '),
188
+ })
189
+ },
58
190
 
59
191
  // Dynamic records
60
192
  {
@@ -99,3 +231,11 @@ ExportToExcelEndpoint.loaders.set(ExcelExportType.Members, {
99
231
  }
100
232
  ]
101
233
  })
234
+
235
+ function formatGender(gender: Gender) {
236
+ switch(gender) {
237
+ case Gender.Male: return 'Man';
238
+ case Gender.Female: return 'Vrouw';
239
+ default: return 'Andere';
240
+ }
241
+ }
@@ -1,10 +1,11 @@
1
+ import { field } from "@simonbackx/simple-encoding";
1
2
  import { XlsxBuiltInNumberFormat, XlsxTransformerColumn, XlsxTransformerConcreteColumn } from "@stamhoofd/excel-writer";
2
- import { StripeAccount as StripeAccountStruct, BalanceItemPaymentDetailed, BalanceItemRelationType, CountryHelper, ExcelExportType, getBalanceItemRelationTypeName, getBalanceItemTypeName, PaymentGeneral, PaymentMethodHelper, PaymentStatusHelper, PaginatedResponse, PaymentProvider } from "@stamhoofd/structures";
3
+ import { StripeAccount } from "@stamhoofd/models";
4
+ import { BalanceItemPaymentDetailed, BalanceItemRelationType, ExcelExportType, getBalanceItemRelationTypeName, getBalanceItemTypeName, PaginatedResponse, PaymentGeneral, PaymentMethodHelper, PaymentStatusHelper, StripeAccount as StripeAccountStruct } from "@stamhoofd/structures";
5
+ import { Formatter } from "@stamhoofd/utility";
3
6
  import { ExportToExcelEndpoint } from "../endpoints/global/files/ExportToExcelEndpoint";
4
7
  import { GetPaymentsEndpoint } from "../endpoints/organization/dashboard/payments/GetPaymentsEndpoint";
5
- import { Formatter } from "@stamhoofd/utility";
6
- import { StripeAccount } from "@stamhoofd/models";
7
- import { field } from "@simonbackx/simple-encoding";
8
+ import { XlsxTransformerColumnHelper } from "../helpers/xlsxAddressTransformerColumnFactory";
8
9
 
9
10
  type PaymentWithItem = {
10
11
  payment: PaymentGeneral,
@@ -499,64 +500,11 @@ function getInvoiceColumns(): XlsxTransformerColumn<PaymentGeneral>[] {
499
500
  }
500
501
  }
501
502
  },
502
- {
503
- match: (id) => {
504
- if (id === 'customer.company.address') {
505
- return [
506
- {
507
- id: 'customer.company.address.street',
508
- name: 'Adres - Straat',
509
- width: 30,
510
- getValue: (object: PaymentGeneralWithStripeAccount) => {
511
- return {
512
- value: object.customer?.company?.address?.street || ''
513
- }
514
- }
515
- },
516
- {
517
- id: 'customer.company.address.number',
518
- name: 'Adres - Nummer',
519
- width: 20,
520
- getValue: (object: PaymentGeneralWithStripeAccount) => {
521
- return {
522
- value: object.customer?.company?.address?.number || ''
523
- }
524
- }
525
- },
526
- {
527
- id: 'customer.company.address.postalCode',
528
- name: 'Adres - Postcode',
529
- width: 20,
530
- getValue: (object: PaymentGeneralWithStripeAccount) => {
531
- return {
532
- value: object.customer?.company?.address?.postalCode || ''
533
- }
534
- }
535
- },
536
- {
537
- id: 'customer.company.address.city',
538
- name: 'Adres - Stad',
539
- width: 20,
540
- getValue: (object: PaymentGeneralWithStripeAccount) => {
541
- return {
542
- value: object.customer?.company?.address?.city || ''
543
- }
544
- }
545
- },
546
- {
547
- id: 'customer.company.address.country',
548
- name: 'Adres - Land',
549
- width: 20,
550
- getValue: (object: PaymentGeneralWithStripeAccount) => {
551
- return {
552
- value: object.customer?.company?.address?.country ? CountryHelper.getName(object.customer?.company?.address?.country) : ''
553
- }
554
- }
555
- }
556
- ]
557
- }
558
- }
559
- },
503
+ XlsxTransformerColumnHelper.createAddressColumns<PaymentGeneralWithStripeAccount>({
504
+ matchId: 'customer.company.address',
505
+ getAddress: (object) => object.customer?.company?.address,
506
+ identifier: 'Adres'
507
+ }),
560
508
  {
561
509
  id: 'customer.company.administrationEmail',
562
510
  name: 'E-mailadres administratie',
@@ -0,0 +1,177 @@
1
+ import { XlsxTransformerColumn } from "@stamhoofd/excel-writer";
2
+ import { Address, CountryHelper, MemberWithRegistrationsBlob, Parent, ParentTypeHelper } from "@stamhoofd/structures";
3
+
4
+ export class XlsxTransformerColumnHelper {
5
+ static formatBoolean(value: boolean | undefined | null): string {
6
+ if(value === true) {
7
+ return "Ja";
8
+ }
9
+
10
+ if(value === false) {
11
+ return 'Nee'
12
+ }
13
+
14
+ return '';
15
+ }
16
+
17
+ static creatColumnsForParents(): XlsxTransformerColumn<unknown>[] {
18
+ return [
19
+ ...this.createColumnsForParent(0),
20
+ ...this.createColumnsForParent(1),
21
+ ]
22
+ }
23
+
24
+ static createColumnsForAddresses<T>({limit, getAddresses, matchIdStart, identifier}: {limit: number, getAddresses: (object: T) => Address[], matchIdStart: string, identifier: string}): XlsxTransformerColumn<unknown>[] {
25
+ const result: XlsxTransformerColumn<unknown>[] = [];
26
+
27
+ for(let i = 0; i <= limit; i++) {
28
+ const column = this.createAddressColumns({
29
+ matchId: `${matchIdStart}.${i}`,
30
+ getAddress: (object: T) => getAddresses(object)[i],
31
+ identifier: `${identifier} ${i + 1}`,
32
+ });
33
+
34
+ result.push(column);
35
+ }
36
+
37
+ return result;
38
+ }
39
+
40
+ static createColumnsForParent(parentIndex: number): XlsxTransformerColumn<unknown>[] {
41
+ const getParent = (member: MemberWithRegistrationsBlob): Parent | null | undefined => member.details.parents[parentIndex];
42
+
43
+ const parentNumber = parentIndex + 1;
44
+
45
+ const identifier = `Ouder ${parentNumber}`
46
+ const getId = (value: string) => `parent.${parentIndex}.${value}`;
47
+ const getName = (value: string) => `${identifier} - ${value}`
48
+
49
+ return [
50
+ {
51
+ id: getId('type'),
52
+ name: getName('Type'),
53
+ width: 20,
54
+ getValue: (member: MemberWithRegistrationsBlob) => {
55
+ const parent = getParent(member);
56
+
57
+ return {
58
+ value: parent ? ParentTypeHelper.getName(parent.type) : ''
59
+ }
60
+ }
61
+ },
62
+ {
63
+ id: getId('firstName'),
64
+ name: getName('Voornaam'),
65
+ width: 20,
66
+ getValue: (member: MemberWithRegistrationsBlob) => ({
67
+ value: getParent(member)?.firstName ?? ''
68
+ })
69
+ },
70
+ {
71
+ id: getId('lastName'),
72
+ name: getName('Achternaam'),
73
+ width: 20,
74
+ getValue: (member: MemberWithRegistrationsBlob) => ({
75
+ value: getParent(member)?.lastName ?? ''
76
+ })
77
+ },
78
+ {
79
+ id: getId('phone'),
80
+ name: getName('Telefoonnummer'),
81
+ width: 20,
82
+ getValue: (member: MemberWithRegistrationsBlob) => ({
83
+ value: getParent(member)?.phone ?? ''
84
+ })
85
+ },
86
+ {
87
+ id: getId('email'),
88
+ name: getName('E-mailadres'),
89
+ width: 20,
90
+ getValue: (member: MemberWithRegistrationsBlob) => ({
91
+ value: getParent(member)?.email ?? ''
92
+ })
93
+ },
94
+ XlsxTransformerColumnHelper.createAddressColumns<MemberWithRegistrationsBlob>({
95
+ matchId: getId('address'),
96
+ getAddress: (member) => getParent(member)?.address,
97
+ identifier: getName('Adres')
98
+ }),
99
+ ]
100
+ }
101
+
102
+ static createAddressColumns<T>({matchId, identifier, getAddress} : {matchId: string, identifier?: string, getAddress: (object: T) => Address | null | undefined}): XlsxTransformerColumn<T> {
103
+ const getId = (value: string) => matchId + '.' + value;
104
+ const identifierText = identifier ? `${identifier} - ` : '';
105
+ const getName = (value: string) => {
106
+ const name =`${identifierText}${value}`;
107
+ return name[0].toUpperCase() + name.slice(1);
108
+ };
109
+
110
+ return {
111
+ match: (id) => {
112
+ if(id === matchId) {
113
+ return [
114
+ {
115
+ id: getId('street'),
116
+ name: getName(`Straat`),
117
+ width: 30,
118
+ getValue: (object: T) => {
119
+ const address = getAddress(object);
120
+ return {
121
+ value: address?.street || ''
122
+ }
123
+ }
124
+ },
125
+ {
126
+ id: getId('number'),
127
+ name: getName('Nummer'),
128
+ width: 20,
129
+ getValue: (object: T) => {
130
+ const address = getAddress(object);
131
+ return {
132
+ value: address?.number || ''
133
+ }
134
+ }
135
+ },
136
+ {
137
+ id: getId('postalCode'),
138
+ name: getName('Postcode'),
139
+ width: 20,
140
+ getValue: (object: T) => {
141
+ const address = getAddress(object);
142
+ return {
143
+ value: address?.postalCode || ''
144
+ }
145
+ }
146
+ },
147
+ {
148
+ id: getId('city'),
149
+ name: getName('Stad'),
150
+ width: 20,
151
+ getValue: (object: T) => {
152
+ const address = getAddress(object);
153
+ return {
154
+ value: address?.city || ''
155
+ }
156
+ }
157
+ },
158
+ {
159
+ id: getId('country'),
160
+ name: getName('Land'),
161
+ width: 20,
162
+ getValue: (object: T) => {
163
+ const address = getAddress(object);
164
+ const country = address?.country;
165
+ return {
166
+ value: country ? CountryHelper.getName(country) : ''
167
+ }
168
+ }
169
+ }
170
+ ]
171
+ }
172
+
173
+ }
174
+ }
175
+
176
+ }
177
+ }