@stamhoofd/backend 2.48.0 → 2.49.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 +11 -11
- package/src/endpoints/global/members/GetMembersEndpoint.ts +1 -1
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +9 -7
- package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +5 -5
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +3 -10
- package/src/helpers/ModelHelper.ts +4 -0
- package/src/helpers/TagHelper.test.ts +3 -3
- package/src/seeds/1729253172-update-orders.ts +5 -1
- package/src/sql-filters/members.ts +32 -0
- package/src/sql-filters/orders.ts +8 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamhoofd/backend",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.49.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -33,17 +33,17 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@mollie/api-client": "3.7.0",
|
|
35
35
|
"@simonbackx/simple-database": "1.25.0",
|
|
36
|
-
"@simonbackx/simple-encoding": "2.
|
|
36
|
+
"@simonbackx/simple-encoding": "2.16.1",
|
|
37
37
|
"@simonbackx/simple-endpoints": "1.14.0",
|
|
38
38
|
"@simonbackx/simple-logging": "^1.0.1",
|
|
39
|
-
"@stamhoofd/backend-i18n": "2.
|
|
40
|
-
"@stamhoofd/backend-middleware": "2.
|
|
41
|
-
"@stamhoofd/email": "2.
|
|
42
|
-
"@stamhoofd/models": "2.
|
|
43
|
-
"@stamhoofd/queues": "2.
|
|
44
|
-
"@stamhoofd/sql": "2.
|
|
45
|
-
"@stamhoofd/structures": "2.
|
|
46
|
-
"@stamhoofd/utility": "2.
|
|
39
|
+
"@stamhoofd/backend-i18n": "2.49.0",
|
|
40
|
+
"@stamhoofd/backend-middleware": "2.49.0",
|
|
41
|
+
"@stamhoofd/email": "2.49.0",
|
|
42
|
+
"@stamhoofd/models": "2.49.0",
|
|
43
|
+
"@stamhoofd/queues": "2.49.0",
|
|
44
|
+
"@stamhoofd/sql": "2.49.0",
|
|
45
|
+
"@stamhoofd/structures": "2.49.0",
|
|
46
|
+
"@stamhoofd/utility": "2.49.0",
|
|
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.5",
|
|
61
61
|
"stripe": "^16.6.0"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "ee78a53466f94dd4c58e7a3140198422f25ee961"
|
|
64
64
|
}
|
|
@@ -71,7 +71,7 @@ export class GetMembersEndpoint extends Endpoint<Params, Query, Body, ResponseBo
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
if (organization) {
|
|
74
|
+
if (organization && !Context.auth.canAccessAllPlatformMembers()) {
|
|
75
75
|
// Add organization scope filter
|
|
76
76
|
const groups = await Context.auth.getAccessibleGroups(organization.id);
|
|
77
77
|
|
|
@@ -65,7 +65,7 @@ export class RegisterMembersEndpoint extends Endpoint<Params, Query, Body, Respo
|
|
|
65
65
|
const { user } = await Context.authenticate();
|
|
66
66
|
|
|
67
67
|
if (request.body.asOrganizationId && request.body.asOrganizationId !== organization.id) {
|
|
68
|
-
if (!await Context.auth.
|
|
68
|
+
if (!await Context.auth.canManageFinances(request.body.asOrganizationId)) {
|
|
69
69
|
throw new SimpleError({
|
|
70
70
|
code: 'forbidden',
|
|
71
71
|
message: 'No permission to register as this organization for a different organization',
|
|
@@ -73,13 +73,15 @@ export class GetEmailTemplatesEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
73
73
|
);
|
|
74
74
|
|
|
75
75
|
const defaultTemplateTypes = organization ? types.filter(type => type !== EmailTemplateType.SavedMembersEmail) : types;
|
|
76
|
-
const defaultTemplates =
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
const defaultTemplates = defaultTemplateTypes.length === 0
|
|
77
|
+
? []
|
|
78
|
+
: (await EmailTemplate.where({
|
|
79
|
+
organizationId: null,
|
|
80
|
+
type: {
|
|
81
|
+
sign: 'IN',
|
|
82
|
+
value: defaultTemplateTypes,
|
|
83
|
+
},
|
|
84
|
+
}));
|
|
83
85
|
|
|
84
86
|
return new Response(templates.concat(defaultTemplates).map(template => EmailTemplateStruct.create(template)));
|
|
85
87
|
}
|
|
@@ -94,11 +94,11 @@ export class PatchBalanceItemsEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
if (patch.unitPrice !== undefined) {
|
|
97
|
-
throw new SimpleError({
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
});
|
|
97
|
+
// throw new SimpleError({
|
|
98
|
+
// code: 'invalid_field',
|
|
99
|
+
// message: 'You cannot change the unit price of a balance item',
|
|
100
|
+
// human: 'Het is niet mogelijk om de eenheidsprijs van een openstaande schuld te wijzigen. Je kan de openstaande schuld verwijderen en opnieuw aanmaken indien noodzakelijk.',
|
|
101
|
+
// });
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// Check permissions
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Decoder } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
|
-
import { assertSort, CountFilteredRequest, getSortFilter, LimitedFilteredRequest, PaginatedResponse, PrivateOrder, StamhoofdFilter } from '@stamhoofd/structures';
|
|
3
|
+
import { assertSort, CountFilteredRequest, getOrderSearchFilter, getSortFilter, LimitedFilteredRequest, PaginatedResponse, PrivateOrder, StamhoofdFilter } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
5
|
import { Order } from '@stamhoofd/models';
|
|
6
6
|
import { compileToSQLFilter, compileToSQLSorter, SQL, SQLFilterDefinitions, SQLSortDefinitions } from '@stamhoofd/sql';
|
|
7
|
+
import { parsePhoneNumber } from 'libphonenumber-js/max';
|
|
7
8
|
import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
|
|
8
9
|
import { Context } from '../../../../helpers/Context';
|
|
9
10
|
import { LimitedFilteredRequestHelper } from '../../../../helpers/LimitedFilteredRequestHelper';
|
|
@@ -51,16 +52,8 @@ export class GetWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Resp
|
|
|
51
52
|
query.where(compileToSQLFilter(q.filter, filterCompilers));
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
// todo: use same logic as frontend
|
|
55
55
|
if (q.search) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// todo: detect special search patterns and adjust search filter if needed
|
|
59
|
-
searchFilter = {
|
|
60
|
-
name: {
|
|
61
|
-
$contains: q.search,
|
|
62
|
-
},
|
|
63
|
-
};
|
|
56
|
+
const searchFilter: StamhoofdFilter | null = getOrderSearchFilter(q.search, parsePhoneNumber);
|
|
64
57
|
|
|
65
58
|
if (searchFilter) {
|
|
66
59
|
query.where(compileToSQLFilter(searchFilter, filterCompilers));
|
|
@@ -50,9 +50,9 @@ describe('TagHelper', () => {
|
|
|
50
50
|
]);
|
|
51
51
|
|
|
52
52
|
// act
|
|
53
|
-
const doesTag3ContainTag4 = TagHelper.containsDeep('id3', 'id4', tags);
|
|
54
|
-
const doesTag3ContainTag5 = TagHelper.containsDeep('id3', 'id5', tags);
|
|
55
|
-
const doesTag3ContainTag1 = TagHelper.containsDeep('id3', 'id1', tags);
|
|
53
|
+
const doesTag3ContainTag4 = TagHelper.containsDeep('id3', 'id4', { tagMap: tags });
|
|
54
|
+
const doesTag3ContainTag5 = TagHelper.containsDeep('id3', 'id5', { tagMap: tags });
|
|
55
|
+
const doesTag3ContainTag1 = TagHelper.containsDeep('id3', 'id1', { tagMap: tags });
|
|
56
56
|
|
|
57
57
|
// assert
|
|
58
58
|
expect(doesTag3ContainTag4).toBe(true);
|
|
@@ -16,8 +16,12 @@ export default new Migration(async () => {
|
|
|
16
16
|
|
|
17
17
|
await ModelHelper.loop(Order, 'id', async (batch: Order[]) => {
|
|
18
18
|
console.log('Saving orders...', `(${count})`);
|
|
19
|
+
|
|
19
20
|
// save all orders to update the new columns
|
|
20
|
-
|
|
21
|
+
for (const order of batch) {
|
|
22
|
+
await order.save();
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
count += limit;
|
|
22
26
|
},
|
|
23
27
|
{ limit });
|
|
@@ -27,6 +27,7 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
|
|
|
27
27
|
SQL.jsonValue(SQL.column('details'), '$.value.gender'),
|
|
28
28
|
{ isJSONValue: true, type: SQLValueType.JSONString },
|
|
29
29
|
),
|
|
30
|
+
|
|
30
31
|
'birthDay': createSQLColumnFilterCompiler('birthDay', {
|
|
31
32
|
normalizeValue: (d) => {
|
|
32
33
|
if (typeof d === 'number') {
|
|
@@ -36,6 +37,7 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
|
|
|
36
37
|
return d;
|
|
37
38
|
},
|
|
38
39
|
}),
|
|
40
|
+
|
|
39
41
|
'organizationName': createSQLExpressionFilterCompiler(
|
|
40
42
|
SQL.column('organizations', 'name'),
|
|
41
43
|
),
|
|
@@ -55,6 +57,28 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
|
|
|
55
57
|
{ isJSONValue: true, isJSONObject: true, type: SQLValueType.JSONString },
|
|
56
58
|
),
|
|
57
59
|
|
|
60
|
+
'details.parents[0]': createSQLFilterNamespace({
|
|
61
|
+
name: createSQLExpressionFilterCompiler(
|
|
62
|
+
new SQLConcat(
|
|
63
|
+
SQL.jsonUnquotedValue(SQL.column('details'), '$.value.parents[0].firstName'),
|
|
64
|
+
new SQLScalar(' '),
|
|
65
|
+
SQL.jsonUnquotedValue(SQL.column('details'), '$.value.parents[0].lastName'),
|
|
66
|
+
),
|
|
67
|
+
{ isJSONValue: true, isJSONObject: false, type: SQLValueType.JSONString },
|
|
68
|
+
),
|
|
69
|
+
}),
|
|
70
|
+
|
|
71
|
+
'details.parents[1]': createSQLFilterNamespace({
|
|
72
|
+
name: createSQLExpressionFilterCompiler(
|
|
73
|
+
new SQLConcat(
|
|
74
|
+
SQL.jsonUnquotedValue(SQL.column('details'), '$.value.parents[1].firstName'),
|
|
75
|
+
new SQLScalar(' '),
|
|
76
|
+
SQL.jsonUnquotedValue(SQL.column('details'), '$.value.parents[1].lastName'),
|
|
77
|
+
),
|
|
78
|
+
{ isJSONValue: true, isJSONObject: false, type: SQLValueType.JSONString },
|
|
79
|
+
),
|
|
80
|
+
}),
|
|
81
|
+
|
|
58
82
|
'unverifiedEmail': createSQLExpressionFilterCompiler(
|
|
59
83
|
SQL.jsonValue(SQL.column('details'), '$.value.unverifiedEmails'),
|
|
60
84
|
{ isJSONValue: true, isJSONObject: true, type: SQLValueType.JSONString },
|
|
@@ -78,6 +102,10 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
|
|
|
78
102
|
SQL.jsonValue(SQL.column('details'), '$.value.address.street'),
|
|
79
103
|
{ isJSONValue: true, type: SQLValueType.JSONString },
|
|
80
104
|
),
|
|
105
|
+
number: createSQLExpressionFilterCompiler(
|
|
106
|
+
SQL.jsonValue(SQL.column('details'), '$.value.address.number'),
|
|
107
|
+
{ isJSONValue: true, type: SQLValueType.JSONString },
|
|
108
|
+
),
|
|
81
109
|
}),
|
|
82
110
|
|
|
83
111
|
'details.parents[*].address': createSQLFilterNamespace({
|
|
@@ -93,6 +121,10 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
|
|
|
93
121
|
SQL.jsonValue(SQL.column('details'), '$.value.parents[*].address.street'),
|
|
94
122
|
{ isJSONValue: true, isJSONObject: true },
|
|
95
123
|
),
|
|
124
|
+
number: createSQLExpressionFilterCompiler(
|
|
125
|
+
SQL.jsonValue(SQL.column('details'), '$.value.parents[*].address.number'),
|
|
126
|
+
{ isJSONValue: true, isJSONObject: true },
|
|
127
|
+
),
|
|
96
128
|
}),
|
|
97
129
|
|
|
98
130
|
'parentPhone': createSQLExpressionFilterCompiler(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { baseSQLFilterCompilers, createSQLColumnFilterCompiler, createSQLExpressionFilterCompiler, SQL, SQLConcat, SQLFilterDefinitions, SQLScalar, SQLValueType } from '@stamhoofd/sql';
|
|
1
|
+
import { baseSQLFilterCompilers, createSQLColumnFilterCompiler, createSQLExpressionFilterCompiler, SQL, SQLCast, SQLConcat, SQLFilterDefinitions, SQLJsonUnquote, SQLScalar, SQLValueType } from '@stamhoofd/sql';
|
|
2
2
|
|
|
3
3
|
export const orderFilterCompilers: SQLFilterDefinitions = {
|
|
4
4
|
...baseSQLFilterCompilers,
|
|
@@ -36,17 +36,14 @@ export const orderFilterCompilers: SQLFilterDefinitions = {
|
|
|
36
36
|
{ isJSONValue: true, type: SQLValueType.JSONString },
|
|
37
37
|
),
|
|
38
38
|
validAt: createSQLColumnFilterCompiler('validAt'),
|
|
39
|
-
|
|
40
|
-
// todo: TEST!
|
|
41
39
|
name: createSQLExpressionFilterCompiler(
|
|
42
|
-
new
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{ isJSONValue: true, type: SQLValueType.JSONString },
|
|
40
|
+
new SQLCast(
|
|
41
|
+
new SQLConcat(
|
|
42
|
+
new SQLJsonUnquote(SQL.jsonValue(SQL.column('data'), '$.value.customer.firstName')),
|
|
43
|
+
new SQLScalar(' '),
|
|
44
|
+
new SQLJsonUnquote(SQL.jsonValue(SQL.column('data'), '$.value.customer.lastName')),
|
|
45
|
+
),
|
|
46
|
+
'CHAR'),
|
|
50
47
|
),
|
|
51
48
|
email: createSQLExpressionFilterCompiler(
|
|
52
49
|
SQL.jsonValue(SQL.column('data'), '$.value.customer.email'),
|
|
@@ -61,8 +58,4 @@ export const orderFilterCompilers: SQLFilterDefinitions = {
|
|
|
61
58
|
totalPrice: createSQLColumnFilterCompiler('totalPrice'),
|
|
62
59
|
amount: createSQLColumnFilterCompiler('amount'),
|
|
63
60
|
timeSlotTime: createSQLColumnFilterCompiler('timeSlotTime'),
|
|
64
|
-
|
|
65
|
-
// only frontend
|
|
66
|
-
// openBalance
|
|
67
|
-
// location
|
|
68
61
|
};
|