@stamhoofd/backend 2.108.0 → 2.110.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/index.ts +2 -2
- package/package.json +20 -20
- package/src/crons/disable-auto-update-documents.test.ts +164 -0
- package/src/crons/disable-auto-update-documents.ts +82 -0
- package/src/endpoints/global/members/GetMembersEndpoint.ts +5 -5
- package/src/endpoints/global/registration/GetRegistrationsEndpoint.ts +8 -7
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +9 -8
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesCountEndpoint.ts +48 -0
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +95 -19
- package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.test.ts +282 -0
- package/src/endpoints/organization/dashboard/documents/{PatchDocumentTemplateEndpoint.ts → PatchDocumentTemplatesEndpoint.ts} +56 -3
- package/src/excel-loaders/members.ts +61 -7
- package/src/excel-loaders/registrations.ts +123 -2
- package/src/helpers/LimitedFilteredRequestHelper.ts +24 -0
- package/src/helpers/SQLTranslatedString.ts +14 -0
- package/src/helpers/TagHelper.test.ts +9 -9
- package/src/helpers/outstandingBalanceJoin.ts +49 -0
- package/src/seeds/1765896674-document-update-year.test.ts +179 -0
- package/src/seeds/1765896674-document-update-year.ts +66 -0
- package/src/seeds/1766150402-document-published-at.test.ts +46 -0
- package/src/seeds/1766150402-document-published-at.ts +20 -0
- package/src/services/PaymentService.ts +14 -32
- package/src/sql-filters/base-registration-filter-compilers.ts +51 -4
- package/src/sql-filters/document-templates.ts +45 -0
- package/src/sql-filters/documents.ts +1 -1
- package/src/sql-filters/events.ts +6 -6
- package/src/sql-filters/groups.ts +7 -6
- package/src/sql-filters/members.ts +31 -26
- package/src/sql-filters/orders.ts +16 -16
- package/src/sql-filters/organizations.ts +11 -11
- package/src/sql-filters/payments.ts +10 -10
- package/src/sql-filters/registrations.ts +14 -6
- package/src/sql-sorters/document-templates.ts +79 -0
- package/src/sql-sorters/documents.ts +1 -1
- package/src/sql-sorters/members.ts +22 -0
- package/src/sql-sorters/orders.ts +5 -5
- package/src/sql-sorters/organizations.ts +3 -3
- package/src/sql-sorters/registrations.ts +186 -15
|
@@ -71,7 +71,7 @@ export const orderSorters: SQLSortDefinitions<Order> = {
|
|
|
71
71
|
},
|
|
72
72
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
73
73
|
return new SQLOrderBy({
|
|
74
|
-
column: SQL.
|
|
74
|
+
column: SQL.jsonExtract(SQL.column('data'), '$.value.paymentMethod'),
|
|
75
75
|
direction,
|
|
76
76
|
});
|
|
77
77
|
},
|
|
@@ -82,7 +82,7 @@ export const orderSorters: SQLSortDefinitions<Order> = {
|
|
|
82
82
|
},
|
|
83
83
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
84
84
|
return new SQLOrderBy({
|
|
85
|
-
column: SQL.
|
|
85
|
+
column: SQL.jsonExtract(SQL.column('data'), '$.value.checkoutMethod.type'),
|
|
86
86
|
direction,
|
|
87
87
|
});
|
|
88
88
|
},
|
|
@@ -93,7 +93,7 @@ export const orderSorters: SQLSortDefinitions<Order> = {
|
|
|
93
93
|
},
|
|
94
94
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
95
95
|
return new SQLOrderBy({
|
|
96
|
-
column: SQL.
|
|
96
|
+
column: SQL.jsonExtract(SQL.column('data'), '$.value.timeSlot.date'),
|
|
97
97
|
direction,
|
|
98
98
|
});
|
|
99
99
|
},
|
|
@@ -104,7 +104,7 @@ export const orderSorters: SQLSortDefinitions<Order> = {
|
|
|
104
104
|
},
|
|
105
105
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
106
106
|
return new SQLOrderBy({
|
|
107
|
-
column: SQL.
|
|
107
|
+
column: SQL.jsonExtract(SQL.column('data'), '$.value.timeSlot.endTime'),
|
|
108
108
|
direction,
|
|
109
109
|
});
|
|
110
110
|
},
|
|
@@ -126,7 +126,7 @@ export const orderSorters: SQLSortDefinitions<Order> = {
|
|
|
126
126
|
},
|
|
127
127
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
128
128
|
return new SQLOrderBy({
|
|
129
|
-
column: SQL.
|
|
129
|
+
column: SQL.jsonExtract(SQL.column('data'), '$.value.totalPrice'),
|
|
130
130
|
direction,
|
|
131
131
|
});
|
|
132
132
|
},
|
|
@@ -60,7 +60,7 @@ export const organizationSorters: SQLSortDefinitions<Organization> = {
|
|
|
60
60
|
},
|
|
61
61
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
62
62
|
return new SQLOrderBy({
|
|
63
|
-
column: SQL.
|
|
63
|
+
column: SQL.jsonExtract(SQL.column('meta'), '$.value.type'),
|
|
64
64
|
direction,
|
|
65
65
|
});
|
|
66
66
|
},
|
|
@@ -71,7 +71,7 @@ export const organizationSorters: SQLSortDefinitions<Organization> = {
|
|
|
71
71
|
},
|
|
72
72
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
73
73
|
return new SQLOrderBy({
|
|
74
|
-
column: SQL.
|
|
74
|
+
column: SQL.jsonExtract(SQL.column('address'), '$.value.city'),
|
|
75
75
|
direction,
|
|
76
76
|
});
|
|
77
77
|
},
|
|
@@ -82,7 +82,7 @@ export const organizationSorters: SQLSortDefinitions<Organization> = {
|
|
|
82
82
|
},
|
|
83
83
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
84
84
|
return new SQLOrderBy({
|
|
85
|
-
column: SQL.
|
|
85
|
+
column: SQL.jsonExtract(SQL.column('address'), '$.value.country'),
|
|
86
86
|
direction,
|
|
87
87
|
});
|
|
88
88
|
},
|
|
@@ -1,10 +1,31 @@
|
|
|
1
|
-
import { Member } from '@stamhoofd/models';
|
|
2
|
-
import { SQL, SQLOrderBy, SQLOrderByDirection, SQLSortDefinitions } from '@stamhoofd/sql';
|
|
3
|
-
import { RegistrationWithMemberBlob } from '@stamhoofd/structures';
|
|
1
|
+
import { Group, Member, Organization } from '@stamhoofd/models';
|
|
2
|
+
import { SQL, SQLIfNull, SQLOrderBy, SQLOrderByDirection, SQLSortDefinitions } from '@stamhoofd/sql';
|
|
3
|
+
import { MemberWithRegistrationsBlob, Organization as OrganizationStruct, RegistrationWithMemberBlob } from '@stamhoofd/structures';
|
|
4
4
|
import { Formatter } from '@stamhoofd/utility';
|
|
5
|
-
import {
|
|
5
|
+
import { memberCachedBalanceForOrganizationJoin, registrationCachedBalanceJoin } from '../helpers/outstandingBalanceJoin.js';
|
|
6
|
+
import { SQLTranslatedString } from '../helpers/SQLTranslatedString.js';
|
|
7
|
+
import { groupJoin, memberJoin, organizationJoin } from '../sql-filters/registrations.js';
|
|
6
8
|
|
|
7
|
-
export
|
|
9
|
+
export class RegistrationSortData {
|
|
10
|
+
readonly registration: RegistrationWithMemberBlob;
|
|
11
|
+
private organizations: OrganizationStruct[];
|
|
12
|
+
|
|
13
|
+
constructor({ registration, organizations }: { registration: RegistrationWithMemberBlob; organizations: OrganizationStruct[] }) {
|
|
14
|
+
this.registration = registration;
|
|
15
|
+
this.organizations = organizations;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get organization() {
|
|
19
|
+
const organization = this.organizations.find(o => o.id === this.registration.organizationId);
|
|
20
|
+
if (!organization) {
|
|
21
|
+
throw new Error('Organization not found for registration');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return organization;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const registrationSorters: SQLSortDefinitions<RegistrationSortData> = {
|
|
8
29
|
// WARNING! TEST NEW SORTERS THOROUGHLY!
|
|
9
30
|
// Try to avoid creating sorters on fields that er not 1:1 with the database, that often causes pagination issues if not thought through
|
|
10
31
|
// An example: sorting on 'name' is not a good idea, because it is a concatenation of two fields.
|
|
@@ -14,8 +35,8 @@ export const registrationSorters: SQLSortDefinitions<RegistrationWithMemberBlob>
|
|
|
14
35
|
// What if you need mapping? simply map the sorters in the frontend: name -> firstname, lastname, age -> birthDay, etc.
|
|
15
36
|
|
|
16
37
|
'id': {
|
|
17
|
-
getValue(
|
|
18
|
-
return
|
|
38
|
+
getValue({ registration }) {
|
|
39
|
+
return registration.id;
|
|
19
40
|
},
|
|
20
41
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
21
42
|
return new SQLOrderBy({
|
|
@@ -25,8 +46,8 @@ export const registrationSorters: SQLSortDefinitions<RegistrationWithMemberBlob>
|
|
|
25
46
|
},
|
|
26
47
|
},
|
|
27
48
|
'registeredAt': {
|
|
28
|
-
getValue(
|
|
29
|
-
return
|
|
49
|
+
getValue({ registration }) {
|
|
50
|
+
return registration.registeredAt;
|
|
30
51
|
},
|
|
31
52
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
32
53
|
return new SQLOrderBy({
|
|
@@ -35,9 +56,95 @@ export const registrationSorters: SQLSortDefinitions<RegistrationWithMemberBlob>
|
|
|
35
56
|
});
|
|
36
57
|
},
|
|
37
58
|
},
|
|
59
|
+
'groupPrice': {
|
|
60
|
+
getValue: ({ registration }) => registration.groupPrice.name.toString(),
|
|
61
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
62
|
+
return new SQLOrderBy({
|
|
63
|
+
column: new SQLTranslatedString(SQL.column('groupPrice'), '$.value.name'),
|
|
64
|
+
direction,
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
'trialUntil': {
|
|
69
|
+
getValue({ registration }) {
|
|
70
|
+
return registration.trialUntil;
|
|
71
|
+
},
|
|
72
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
73
|
+
return new SQLOrderBy({
|
|
74
|
+
column: SQL.column('trialUntil'),
|
|
75
|
+
direction,
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
'startDate': {
|
|
80
|
+
getValue({ registration }) {
|
|
81
|
+
return registration.startDate;
|
|
82
|
+
},
|
|
83
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
84
|
+
return new SQLOrderBy({
|
|
85
|
+
column: SQL.column('startDate'),
|
|
86
|
+
direction,
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
'endDate': {
|
|
91
|
+
getValue({ registration }) {
|
|
92
|
+
return registration.endDate;
|
|
93
|
+
},
|
|
94
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
95
|
+
return new SQLOrderBy({
|
|
96
|
+
column: SQL.column('endDate'),
|
|
97
|
+
direction,
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
'memberCachedBalance.amountOpen': {
|
|
102
|
+
getValue({ registration }) {
|
|
103
|
+
return registration.member.balances.reduce((sum, r) => sum + (r.amountOpen), 0);
|
|
104
|
+
},
|
|
105
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
106
|
+
return new SQLOrderBy({
|
|
107
|
+
column: new SQLIfNull(SQL.column('memberCachedBalance', 'amountOpen'), 0),
|
|
108
|
+
direction,
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
join: memberCachedBalanceForOrganizationJoin,
|
|
112
|
+
select: [SQL.column('memberCachedBalance', 'amountOpen')],
|
|
113
|
+
},
|
|
114
|
+
'registrationCachedBalance.toPay': {
|
|
115
|
+
getValue({ registration }) {
|
|
116
|
+
return registration.balances.reduce((sum, r) => sum + (r.amountOpen + r.amountPending), 0);
|
|
117
|
+
},
|
|
118
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
119
|
+
return new SQLOrderBy({
|
|
120
|
+
column: new SQLIfNull(SQL.column('registrationCachedBalance', 'toPay'), 0),
|
|
121
|
+
direction,
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
join: registrationCachedBalanceJoin,
|
|
125
|
+
select: [SQL.column('registrationCachedBalance', 'toPay')],
|
|
126
|
+
},
|
|
127
|
+
'registrationCachedBalance.price': {
|
|
128
|
+
getValue({ registration }) {
|
|
129
|
+
return registration.balances.reduce((sum, r) => sum + (r.amountOpen + r.amountPaid + r.amountPending), 0);
|
|
130
|
+
},
|
|
131
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
132
|
+
return new SQLOrderBy({
|
|
133
|
+
column: new SQLIfNull(SQL.column('registrationCachedBalance', 'price'), 0),
|
|
134
|
+
direction,
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
join: registrationCachedBalanceJoin,
|
|
138
|
+
select: [SQL.column('registrationCachedBalance', 'price')],
|
|
139
|
+
},
|
|
140
|
+
'member.memberNumber': createMemberColumnSorter({
|
|
141
|
+
columnName: 'memberNumber',
|
|
142
|
+
getValue: member => member.details.memberNumber ?? '',
|
|
143
|
+
|
|
144
|
+
}),
|
|
38
145
|
'member.firstName': {
|
|
39
|
-
getValue(
|
|
40
|
-
return
|
|
146
|
+
getValue({ registration }) {
|
|
147
|
+
return registration.member.firstName;
|
|
41
148
|
},
|
|
42
149
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
43
150
|
return new SQLOrderBy({
|
|
@@ -49,8 +156,8 @@ export const registrationSorters: SQLSortDefinitions<RegistrationWithMemberBlob>
|
|
|
49
156
|
select: [SQL.column(Member.table, 'firstName')],
|
|
50
157
|
},
|
|
51
158
|
'member.lastName': {
|
|
52
|
-
getValue(
|
|
53
|
-
return
|
|
159
|
+
getValue({ registration }) {
|
|
160
|
+
return registration.member.lastName;
|
|
54
161
|
},
|
|
55
162
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
56
163
|
return new SQLOrderBy({
|
|
@@ -62,8 +169,8 @@ export const registrationSorters: SQLSortDefinitions<RegistrationWithMemberBlob>
|
|
|
62
169
|
select: [SQL.column(Member.table, 'lastName')],
|
|
63
170
|
},
|
|
64
171
|
'member.birthDay': {
|
|
65
|
-
getValue(
|
|
66
|
-
return
|
|
172
|
+
getValue({ registration }) {
|
|
173
|
+
return registration.member.details.birthDay === null ? null : Formatter.dateIso(registration.member.details.birthDay);
|
|
67
174
|
},
|
|
68
175
|
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
69
176
|
return new SQLOrderBy({
|
|
@@ -74,4 +181,68 @@ export const registrationSorters: SQLSortDefinitions<RegistrationWithMemberBlob>
|
|
|
74
181
|
join: memberJoin,
|
|
75
182
|
select: [SQL.column(Member.table, 'birthDay')],
|
|
76
183
|
},
|
|
184
|
+
'member.createdAt': {
|
|
185
|
+
getValue({ registration }) {
|
|
186
|
+
return registration.member.createdAt;
|
|
187
|
+
},
|
|
188
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
189
|
+
return new SQLOrderBy({
|
|
190
|
+
column: SQL.column(Member.table, 'createdAt'),
|
|
191
|
+
direction,
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
join: memberJoin,
|
|
195
|
+
select: [SQL.column(Member.table, 'createdAt')],
|
|
196
|
+
},
|
|
197
|
+
'organization.name': {
|
|
198
|
+
getValue: ({ organization }) => organization.name,
|
|
199
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
200
|
+
return new SQLOrderBy({
|
|
201
|
+
column: SQL.column(Organization.table, 'name'),
|
|
202
|
+
direction,
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
join: organizationJoin,
|
|
206
|
+
select: [SQL.column(Organization.table, 'name')],
|
|
207
|
+
},
|
|
208
|
+
'organization.uri': {
|
|
209
|
+
getValue: ({ organization }) => organization.uri,
|
|
210
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
211
|
+
return new SQLOrderBy({
|
|
212
|
+
column: SQL.column(Organization.table, 'uri'),
|
|
213
|
+
direction,
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
join: organizationJoin,
|
|
217
|
+
select: [SQL.column(Organization.table, 'uri')],
|
|
218
|
+
},
|
|
219
|
+
'group.name': {
|
|
220
|
+
getValue: ({ registration }) => registration.group.settings.name.toString(),
|
|
221
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
222
|
+
return new SQLOrderBy({
|
|
223
|
+
column: new SQLTranslatedString(SQL.column(Group.table, 'settings'), '$.value.name'),
|
|
224
|
+
direction,
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
join: groupJoin,
|
|
228
|
+
},
|
|
77
229
|
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Helper function for simple sort on member column
|
|
233
|
+
* @param param0
|
|
234
|
+
* @returns
|
|
235
|
+
*/
|
|
236
|
+
function createMemberColumnSorter<T>({ columnName, getValue }: { columnName: string; getValue: (member: MemberWithRegistrationsBlob) => T }) {
|
|
237
|
+
return {
|
|
238
|
+
getValue: ({ registration }: RegistrationSortData) => getValue(registration.member),
|
|
239
|
+
toSQL: (direction: SQLOrderByDirection): SQLOrderBy => {
|
|
240
|
+
return new SQLOrderBy({
|
|
241
|
+
column: SQL.column(Member.table, columnName),
|
|
242
|
+
direction,
|
|
243
|
+
});
|
|
244
|
+
},
|
|
245
|
+
join: memberJoin,
|
|
246
|
+
select: [SQL.column(Member.table, columnName)],
|
|
247
|
+
};
|
|
248
|
+
}
|