@stamhoofd/backend 2.75.0 → 2.75.1
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/endpoints/auth/OpenIDConnectStartEndpoint.ts +0 -5
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +329 -1
- package/src/services/FileSignService.ts +8 -18
- package/src/services/SSOService.ts +7 -2
- package/tests/e2e/register.test.ts +459 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamhoofd/backend",
|
|
3
|
-
"version": "2.75.
|
|
3
|
+
"version": "2.75.1",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
"@simonbackx/simple-encoding": "2.20.0",
|
|
38
38
|
"@simonbackx/simple-endpoints": "1.19.0",
|
|
39
39
|
"@simonbackx/simple-logging": "^1.0.1",
|
|
40
|
-
"@stamhoofd/backend-i18n": "2.75.
|
|
41
|
-
"@stamhoofd/backend-middleware": "2.75.
|
|
42
|
-
"@stamhoofd/email": "2.75.
|
|
43
|
-
"@stamhoofd/models": "2.75.
|
|
44
|
-
"@stamhoofd/queues": "2.75.
|
|
45
|
-
"@stamhoofd/sql": "2.75.
|
|
46
|
-
"@stamhoofd/structures": "2.75.
|
|
47
|
-
"@stamhoofd/utility": "2.75.
|
|
40
|
+
"@stamhoofd/backend-i18n": "2.75.1",
|
|
41
|
+
"@stamhoofd/backend-middleware": "2.75.1",
|
|
42
|
+
"@stamhoofd/email": "2.75.1",
|
|
43
|
+
"@stamhoofd/models": "2.75.1",
|
|
44
|
+
"@stamhoofd/queues": "2.75.1",
|
|
45
|
+
"@stamhoofd/sql": "2.75.1",
|
|
46
|
+
"@stamhoofd/structures": "2.75.1",
|
|
47
|
+
"@stamhoofd/utility": "2.75.1",
|
|
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": "4c6a7f14c62e4832885325d02c5aaeeccf27568b"
|
|
68
68
|
}
|
|
@@ -30,11 +30,6 @@ export class OpenIDConnectStartEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
30
30
|
// Check webshop and/or organization
|
|
31
31
|
await Context.setUserOrganizationScope();
|
|
32
32
|
await Context.optionalAuthenticate({ allowWithoutAccount: false });
|
|
33
|
-
console.log('Full start connect body;', await request.request.body);
|
|
34
|
-
|
|
35
|
-
if (Context.user) {
|
|
36
|
-
console.log('User:', Context.user);
|
|
37
|
-
}
|
|
38
33
|
const service = await SSOService.fromContext(request.body.provider);
|
|
39
34
|
return await service.validateAndStartAuthCodeFlow(request.body);
|
|
40
35
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Request } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { Email } from '@stamhoofd/email';
|
|
3
3
|
import { BalanceItemFactory, Group, GroupFactory, MemberFactory, MemberWithRegistrations, Organization, OrganizationFactory, Registration, RegistrationFactory, RegistrationPeriod, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
|
|
4
|
-
import { BalanceItemCartItem, BalanceItemType, Company, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, OrganizationPackages, PayconiqAccount, PaymentCustomer, PaymentMethod, PermissionLevel, Permissions, STPackageStatus, STPackageType, UserPermissions, Version } from '@stamhoofd/structures';
|
|
4
|
+
import { BalanceItemCartItem, BalanceItemType, Company, GroupOption, GroupOptionMenu, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, OrganizationPackages, PayconiqAccount, PaymentCustomer, PaymentMethod, PermissionLevel, Permissions, ReduceablePrice, RegisterItemOption, STPackageStatus, STPackageType, UserPermissions, Version } from '@stamhoofd/structures';
|
|
5
5
|
import nock from 'nock';
|
|
6
6
|
import { v4 as uuidv4 } from 'uuid';
|
|
7
7
|
import { testServer } from '../../../../tests/helpers/TestServer';
|
|
@@ -1011,6 +1011,334 @@ describe('Endpoint.RegisterMembers', () => {
|
|
|
1011
1011
|
jest.useFakeTimers().resetAllMocks();
|
|
1012
1012
|
}
|
|
1013
1013
|
});
|
|
1014
|
+
|
|
1015
|
+
test('Should update group stock reservations', async () => {
|
|
1016
|
+
// #region arrange
|
|
1017
|
+
const { organization, group, groupPrice, token, member } = await initData();
|
|
1018
|
+
groupPrice.stock = 5;
|
|
1019
|
+
await group.save();
|
|
1020
|
+
|
|
1021
|
+
const body = IDRegisterCheckout.create({
|
|
1022
|
+
cart: IDRegisterCart.create({
|
|
1023
|
+
items: [
|
|
1024
|
+
IDRegisterItem.create({
|
|
1025
|
+
id: uuidv4(),
|
|
1026
|
+
replaceRegistrationIds: [],
|
|
1027
|
+
options: [],
|
|
1028
|
+
groupPrice,
|
|
1029
|
+
organizationId: organization.id,
|
|
1030
|
+
groupId: group.id,
|
|
1031
|
+
memberId: member.id,
|
|
1032
|
+
}),
|
|
1033
|
+
],
|
|
1034
|
+
balanceItems: [],
|
|
1035
|
+
deleteRegistrationIds: [],
|
|
1036
|
+
}),
|
|
1037
|
+
administrationFee: 0,
|
|
1038
|
+
freeContribution: 0,
|
|
1039
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
1040
|
+
totalPrice: 25,
|
|
1041
|
+
asOrganizationId: organization.id,
|
|
1042
|
+
customer: null,
|
|
1043
|
+
});
|
|
1044
|
+
// #endregion
|
|
1045
|
+
|
|
1046
|
+
// #region act and assert
|
|
1047
|
+
expect(group?.stockReservations.length).toBe(0);
|
|
1048
|
+
|
|
1049
|
+
await post(body, organization, token);
|
|
1050
|
+
|
|
1051
|
+
const updatedGroup = await Group.getByID(group.id);
|
|
1052
|
+
expect(updatedGroup?.stockReservations.length).toBe(1);
|
|
1053
|
+
// #endregion
|
|
1054
|
+
});
|
|
1055
|
+
|
|
1056
|
+
test('Should fail if group price stock sold out', async () => {
|
|
1057
|
+
// #region arrange
|
|
1058
|
+
const { organization, group, groupPrice, token, member, otherMembers } = await initData({
|
|
1059
|
+
permissionLevel: PermissionLevel.Read, otherMemberAmount: 3 });
|
|
1060
|
+
groupPrice.stock = 2;
|
|
1061
|
+
await group.save();
|
|
1062
|
+
|
|
1063
|
+
const body = IDRegisterCheckout.create({
|
|
1064
|
+
cart: IDRegisterCart.create({
|
|
1065
|
+
items: [
|
|
1066
|
+
IDRegisterItem.create({
|
|
1067
|
+
id: uuidv4(),
|
|
1068
|
+
replaceRegistrationIds: [],
|
|
1069
|
+
options: [],
|
|
1070
|
+
groupPrice,
|
|
1071
|
+
organizationId: organization.id,
|
|
1072
|
+
groupId: group.id,
|
|
1073
|
+
memberId: member.id,
|
|
1074
|
+
}),
|
|
1075
|
+
...otherMembers.map(m => IDRegisterItem.create({
|
|
1076
|
+
id: uuidv4(),
|
|
1077
|
+
replaceRegistrationIds: [],
|
|
1078
|
+
options: [],
|
|
1079
|
+
groupPrice,
|
|
1080
|
+
organizationId: organization.id,
|
|
1081
|
+
groupId: group.id,
|
|
1082
|
+
memberId: m.id,
|
|
1083
|
+
})),
|
|
1084
|
+
],
|
|
1085
|
+
balanceItems: [],
|
|
1086
|
+
deleteRegistrationIds: [],
|
|
1087
|
+
}),
|
|
1088
|
+
administrationFee: 0,
|
|
1089
|
+
freeContribution: 0,
|
|
1090
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
1091
|
+
totalPrice: 75,
|
|
1092
|
+
customer: null,
|
|
1093
|
+
});
|
|
1094
|
+
// #endregion
|
|
1095
|
+
|
|
1096
|
+
// #region act and assert
|
|
1097
|
+
expect(group?.stockReservations.length).toBe(0);
|
|
1098
|
+
|
|
1099
|
+
await expect(async () => await post(body, organization, token))
|
|
1100
|
+
.rejects
|
|
1101
|
+
.toThrow(new RegExp('Maximum reached'));
|
|
1102
|
+
// #endregion
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
test('Should fail if option stock sold out', async () => {
|
|
1106
|
+
// #region arrange
|
|
1107
|
+
const { organization, group, groupPrice, token, member } = await initData();
|
|
1108
|
+
|
|
1109
|
+
const option1 = GroupOption.create({
|
|
1110
|
+
name: 'option 1',
|
|
1111
|
+
stock: 4,
|
|
1112
|
+
price: ReduceablePrice.create({
|
|
1113
|
+
price: 5,
|
|
1114
|
+
reducedPrice: 3,
|
|
1115
|
+
}),
|
|
1116
|
+
});
|
|
1117
|
+
|
|
1118
|
+
const option2 = GroupOption.create({
|
|
1119
|
+
name: 'option 2',
|
|
1120
|
+
stock: 4,
|
|
1121
|
+
price: ReduceablePrice.create({
|
|
1122
|
+
price: 3,
|
|
1123
|
+
reducedPrice: 1,
|
|
1124
|
+
}),
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
const optionMenu = GroupOptionMenu.create({
|
|
1128
|
+
name: 'option menu 1',
|
|
1129
|
+
multipleChoice: true,
|
|
1130
|
+
options: [option1, option2],
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
group.settings.optionMenus = [
|
|
1134
|
+
optionMenu,
|
|
1135
|
+
];
|
|
1136
|
+
|
|
1137
|
+
await group.save();
|
|
1138
|
+
|
|
1139
|
+
const body = IDRegisterCheckout.create({
|
|
1140
|
+
cart: IDRegisterCart.create({
|
|
1141
|
+
items: [
|
|
1142
|
+
IDRegisterItem.create({
|
|
1143
|
+
id: uuidv4(),
|
|
1144
|
+
replaceRegistrationIds: [],
|
|
1145
|
+
options: [
|
|
1146
|
+
RegisterItemOption.create({
|
|
1147
|
+
option: option1,
|
|
1148
|
+
amount: 2,
|
|
1149
|
+
optionMenu,
|
|
1150
|
+
}),
|
|
1151
|
+
RegisterItemOption.create({
|
|
1152
|
+
option: option2,
|
|
1153
|
+
amount: 5,
|
|
1154
|
+
optionMenu,
|
|
1155
|
+
}),
|
|
1156
|
+
],
|
|
1157
|
+
groupPrice,
|
|
1158
|
+
organizationId: organization.id,
|
|
1159
|
+
groupId: group.id,
|
|
1160
|
+
memberId: member.id,
|
|
1161
|
+
}),
|
|
1162
|
+
],
|
|
1163
|
+
balanceItems: [
|
|
1164
|
+
],
|
|
1165
|
+
deleteRegistrationIds: [],
|
|
1166
|
+
}),
|
|
1167
|
+
administrationFee: 0,
|
|
1168
|
+
freeContribution: 0,
|
|
1169
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
1170
|
+
totalPrice: 50,
|
|
1171
|
+
customer: null,
|
|
1172
|
+
});
|
|
1173
|
+
// #endregion
|
|
1174
|
+
|
|
1175
|
+
// #region act and assert
|
|
1176
|
+
await expect(async () => await post(body, organization, token))
|
|
1177
|
+
.rejects
|
|
1178
|
+
.toThrow(new RegExp('Stock empty'));
|
|
1179
|
+
// #endregion
|
|
1180
|
+
});
|
|
1181
|
+
|
|
1182
|
+
test('Should fail if max option exceeded', async () => {
|
|
1183
|
+
// #region arrange
|
|
1184
|
+
const { organization, group, groupPrice, token, member } = await initData();
|
|
1185
|
+
|
|
1186
|
+
const option1 = GroupOption.create({
|
|
1187
|
+
name: 'option 1',
|
|
1188
|
+
stock: 4,
|
|
1189
|
+
maximum: 5,
|
|
1190
|
+
allowAmount: true,
|
|
1191
|
+
price: ReduceablePrice.create({
|
|
1192
|
+
price: 5,
|
|
1193
|
+
reducedPrice: 3,
|
|
1194
|
+
}),
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
const option2 = GroupOption.create({
|
|
1198
|
+
name: 'option 2',
|
|
1199
|
+
stock: 5,
|
|
1200
|
+
maximum: 2,
|
|
1201
|
+
allowAmount: true,
|
|
1202
|
+
price: ReduceablePrice.create({
|
|
1203
|
+
price: 3,
|
|
1204
|
+
reducedPrice: 1,
|
|
1205
|
+
}),
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
const optionMenu = GroupOptionMenu.create({
|
|
1209
|
+
name: 'option menu 1',
|
|
1210
|
+
multipleChoice: true,
|
|
1211
|
+
options: [option1, option2],
|
|
1212
|
+
});
|
|
1213
|
+
|
|
1214
|
+
group.settings.optionMenus = [
|
|
1215
|
+
optionMenu,
|
|
1216
|
+
];
|
|
1217
|
+
|
|
1218
|
+
await group.save();
|
|
1219
|
+
|
|
1220
|
+
const body = IDRegisterCheckout.create({
|
|
1221
|
+
cart: IDRegisterCart.create({
|
|
1222
|
+
items: [
|
|
1223
|
+
IDRegisterItem.create({
|
|
1224
|
+
id: uuidv4(),
|
|
1225
|
+
replaceRegistrationIds: [],
|
|
1226
|
+
options: [
|
|
1227
|
+
RegisterItemOption.create({
|
|
1228
|
+
option: option1,
|
|
1229
|
+
amount: 2,
|
|
1230
|
+
optionMenu,
|
|
1231
|
+
}),
|
|
1232
|
+
RegisterItemOption.create({
|
|
1233
|
+
option: option2,
|
|
1234
|
+
amount: 5,
|
|
1235
|
+
optionMenu,
|
|
1236
|
+
}),
|
|
1237
|
+
],
|
|
1238
|
+
groupPrice,
|
|
1239
|
+
organizationId: organization.id,
|
|
1240
|
+
groupId: group.id,
|
|
1241
|
+
memberId: member.id,
|
|
1242
|
+
}),
|
|
1243
|
+
],
|
|
1244
|
+
balanceItems: [
|
|
1245
|
+
],
|
|
1246
|
+
deleteRegistrationIds: [],
|
|
1247
|
+
}),
|
|
1248
|
+
administrationFee: 0,
|
|
1249
|
+
freeContribution: 0,
|
|
1250
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
1251
|
+
totalPrice: 50,
|
|
1252
|
+
customer: null,
|
|
1253
|
+
});
|
|
1254
|
+
// #endregion
|
|
1255
|
+
|
|
1256
|
+
// #region act and assert
|
|
1257
|
+
await expect(async () => await post(body, organization, token))
|
|
1258
|
+
.rejects
|
|
1259
|
+
.toThrow(new RegExp('Option maximum exceeded'));
|
|
1260
|
+
// #endregion
|
|
1261
|
+
});
|
|
1262
|
+
|
|
1263
|
+
test('Should not fail if max option not exceeded', async () => {
|
|
1264
|
+
// #region arrange
|
|
1265
|
+
const { organization, group, groupPrice, token, member } = await initData();
|
|
1266
|
+
|
|
1267
|
+
const option1 = GroupOption.create({
|
|
1268
|
+
name: 'option 1',
|
|
1269
|
+
stock: 4,
|
|
1270
|
+
maximum: 5,
|
|
1271
|
+
allowAmount: true,
|
|
1272
|
+
price: ReduceablePrice.create({
|
|
1273
|
+
price: 5,
|
|
1274
|
+
reducedPrice: 3,
|
|
1275
|
+
}),
|
|
1276
|
+
});
|
|
1277
|
+
|
|
1278
|
+
const option2 = GroupOption.create({
|
|
1279
|
+
name: 'option 2',
|
|
1280
|
+
stock: 5,
|
|
1281
|
+
maximum: 5,
|
|
1282
|
+
allowAmount: true,
|
|
1283
|
+
price: ReduceablePrice.create({
|
|
1284
|
+
price: 3,
|
|
1285
|
+
reducedPrice: 1,
|
|
1286
|
+
}),
|
|
1287
|
+
});
|
|
1288
|
+
|
|
1289
|
+
const optionMenu = GroupOptionMenu.create({
|
|
1290
|
+
name: 'option menu 1',
|
|
1291
|
+
multipleChoice: true,
|
|
1292
|
+
options: [option1, option2],
|
|
1293
|
+
});
|
|
1294
|
+
|
|
1295
|
+
group.settings.optionMenus = [
|
|
1296
|
+
optionMenu,
|
|
1297
|
+
];
|
|
1298
|
+
|
|
1299
|
+
await group.save();
|
|
1300
|
+
|
|
1301
|
+
const body = IDRegisterCheckout.create({
|
|
1302
|
+
cart: IDRegisterCart.create({
|
|
1303
|
+
items: [
|
|
1304
|
+
IDRegisterItem.create({
|
|
1305
|
+
id: uuidv4(),
|
|
1306
|
+
replaceRegistrationIds: [],
|
|
1307
|
+
options: [
|
|
1308
|
+
RegisterItemOption.create({
|
|
1309
|
+
option: option1,
|
|
1310
|
+
amount: 2,
|
|
1311
|
+
optionMenu,
|
|
1312
|
+
}),
|
|
1313
|
+
RegisterItemOption.create({
|
|
1314
|
+
option: option2,
|
|
1315
|
+
amount: 5,
|
|
1316
|
+
optionMenu,
|
|
1317
|
+
}),
|
|
1318
|
+
],
|
|
1319
|
+
groupPrice,
|
|
1320
|
+
organizationId: organization.id,
|
|
1321
|
+
groupId: group.id,
|
|
1322
|
+
memberId: member.id,
|
|
1323
|
+
}),
|
|
1324
|
+
],
|
|
1325
|
+
balanceItems: [
|
|
1326
|
+
],
|
|
1327
|
+
deleteRegistrationIds: [],
|
|
1328
|
+
}),
|
|
1329
|
+
administrationFee: 0,
|
|
1330
|
+
freeContribution: 0,
|
|
1331
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
1332
|
+
totalPrice: 50,
|
|
1333
|
+
customer: null,
|
|
1334
|
+
});
|
|
1335
|
+
// #endregion
|
|
1336
|
+
|
|
1337
|
+
// #region act and assert
|
|
1338
|
+
const result = await post(body, organization, token);
|
|
1339
|
+
expect(result).toBeDefined();
|
|
1340
|
+
// #endregion
|
|
1341
|
+
});
|
|
1014
1342
|
});
|
|
1015
1343
|
|
|
1016
1344
|
describe('Register by other organization', () => {
|
|
@@ -87,24 +87,14 @@ export class FileSignService {
|
|
|
87
87
|
|
|
88
88
|
file.signature = jws;
|
|
89
89
|
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
static async fillSignedUrl(file: File, duration = 60 * 60) {
|
|
93
|
-
if (!file.isPrivate) {
|
|
94
|
-
if (file.signedUrl) {
|
|
95
|
-
console.error('Warning: public file has a signed url');
|
|
96
|
-
// this will not be encoded because of the file encode implementation
|
|
97
|
-
}
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
90
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
91
|
+
File.getWithSignedUrl = async (file: File) => {
|
|
92
|
+
return this.withSignedUrl(file);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
106
95
|
|
|
107
|
-
|
|
96
|
+
static async withSignedUrl(file: File, duration = 60 * 60) {
|
|
97
|
+
console.log('Generating signed url:', file.id);
|
|
108
98
|
|
|
109
99
|
if (file.signedUrl) {
|
|
110
100
|
console.error('Warning: file already signed');
|
|
@@ -126,13 +116,13 @@ export class FileSignService {
|
|
|
126
116
|
}
|
|
127
117
|
catch (e) {
|
|
128
118
|
console.error('Failed to sign file:', e);
|
|
129
|
-
return
|
|
119
|
+
return null;
|
|
130
120
|
}
|
|
131
121
|
}
|
|
132
122
|
|
|
133
123
|
static async fillSignedUrlsForStruct(data: any) {
|
|
134
124
|
if (data instanceof File) {
|
|
135
|
-
return await
|
|
125
|
+
return (await data.withSignedUrl()) ?? undefined; // never return null if it fails because we'll want to use the original file in that case
|
|
136
126
|
}
|
|
137
127
|
|
|
138
128
|
if (Array.isArray(data)) {
|
|
@@ -81,7 +81,7 @@ export class SSOService {
|
|
|
81
81
|
const platform = await Platform.getShared();
|
|
82
82
|
|
|
83
83
|
const service = new SSOService({ provider, platform, organization, user: Context.user });
|
|
84
|
-
service.
|
|
84
|
+
service.validateConfiguration();
|
|
85
85
|
|
|
86
86
|
return service;
|
|
87
87
|
}
|
|
@@ -138,11 +138,13 @@ export class SSOService {
|
|
|
138
138
|
return loginConfiguration;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
validateConfiguration() {
|
|
142
142
|
// Validate configuration exists
|
|
143
143
|
const _ = this.configuration;
|
|
144
144
|
const __ = this.loginConfiguration;
|
|
145
|
+
}
|
|
145
146
|
|
|
147
|
+
validateUser() {
|
|
146
148
|
if (this.user) {
|
|
147
149
|
this.validateEmail(this.user.email);
|
|
148
150
|
}
|
|
@@ -317,6 +319,9 @@ export class SSOService {
|
|
|
317
319
|
const code_challenge = generators.codeChallenge(code_verifier);
|
|
318
320
|
const expires = new Date(Date.now() + 1000 * 60 * 15);
|
|
319
321
|
|
|
322
|
+
// Validate user id
|
|
323
|
+
this.validateUser();
|
|
324
|
+
|
|
320
325
|
const session: SSOSessionContext = {
|
|
321
326
|
expires,
|
|
322
327
|
code_verifier,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Request } from '@simonbackx/simple-endpoints';
|
|
2
|
-
import { BalanceItemFactory, GroupFactory, MemberFactory, MemberWithRegistrations, Organization, OrganizationFactory, OrganizationRegistrationPeriod, Platform,
|
|
3
|
-
import { AdministrationFeeSettings, BalanceItemCartItem, BalanceItemType, DefaultAgeGroup, FreeContributionSettings, GroupOption, GroupOptionMenu, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, PaymentMethod, PermissionLevel, Permissions, PlatformMembershipType, PlatformMembershipTypeConfig, ReceivableBalanceType, ReduceablePrice, RegisterItemOption, Version } from '@stamhoofd/structures';
|
|
2
|
+
import { BalanceItemFactory, GroupFactory, MemberFactory, MemberWithRegistrations, Organization, OrganizationFactory, OrganizationRegistrationPeriod, Platform, RegistrationPeriod, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
|
|
3
|
+
import { AdministrationFeeSettings, BalanceItemCartItem, BalanceItemStatus, BalanceItemType, BooleanStatus, DefaultAgeGroup, FreeContributionSettings, GroupOption, GroupOptionMenu, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, PaymentMethod, PermissionLevel, Permissions, PlatformMembershipType, PlatformMembershipTypeConfig, ReceivableBalanceType, ReduceablePrice, RegisterItemOption, Version } from '@stamhoofd/structures';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
import { GetMemberFamilyEndpoint } from '../../src/endpoints/global/members/GetMemberFamilyEndpoint';
|
|
6
6
|
import { RegisterMembersEndpoint } from '../../src/endpoints/global/registration/RegisterMembersEndpoint';
|
|
@@ -87,6 +87,7 @@ describe('E2E.Register', () => {
|
|
|
87
87
|
const group = await new GroupFactory({
|
|
88
88
|
organization,
|
|
89
89
|
price: 25,
|
|
90
|
+
reducedPrice: 21,
|
|
90
91
|
stock: 5,
|
|
91
92
|
})
|
|
92
93
|
.create();
|
|
@@ -152,10 +153,6 @@ describe('E2E.Register', () => {
|
|
|
152
153
|
// #endregion
|
|
153
154
|
});
|
|
154
155
|
|
|
155
|
-
// todo: test max option + allowAmount
|
|
156
|
-
// todo: test stock?
|
|
157
|
-
// todo: test reduced price?
|
|
158
|
-
|
|
159
156
|
test('Should create balance items for options', async () => {
|
|
160
157
|
// #region arrange
|
|
161
158
|
const { organization, group, groupPrice, token, member } = await initData();
|
|
@@ -492,19 +489,195 @@ describe('E2E.Register', () => {
|
|
|
492
489
|
]));
|
|
493
490
|
// #endregion
|
|
494
491
|
});
|
|
492
|
+
|
|
493
|
+
test('Should apply reduced price if member requires financial support', async () => {
|
|
494
|
+
// #region arrange
|
|
495
|
+
const { organization, group, groupPrice, token, member } = await initData();
|
|
496
|
+
member.details.requiresFinancialSupport = BooleanStatus.create({
|
|
497
|
+
value: true,
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
await member.save();
|
|
501
|
+
|
|
502
|
+
const body = IDRegisterCheckout.create({
|
|
503
|
+
cart: IDRegisterCart.create({
|
|
504
|
+
items: [
|
|
505
|
+
IDRegisterItem.create({
|
|
506
|
+
id: uuidv4(),
|
|
507
|
+
replaceRegistrationIds: [],
|
|
508
|
+
options: [],
|
|
509
|
+
groupPrice,
|
|
510
|
+
organizationId: organization.id,
|
|
511
|
+
groupId: group.id,
|
|
512
|
+
memberId: member.id,
|
|
513
|
+
}),
|
|
514
|
+
],
|
|
515
|
+
balanceItems: [
|
|
516
|
+
],
|
|
517
|
+
deleteRegistrationIds: [],
|
|
518
|
+
}),
|
|
519
|
+
administrationFee: 0,
|
|
520
|
+
freeContribution: 0,
|
|
521
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
522
|
+
totalPrice: 21,
|
|
523
|
+
customer: null,
|
|
524
|
+
});
|
|
525
|
+
// #endregion
|
|
526
|
+
|
|
527
|
+
// #region act and assert
|
|
528
|
+
const balanceBefore = await getBalance(member.id, organization, token);
|
|
529
|
+
expect(balanceBefore).toBeDefined();
|
|
530
|
+
expect(balanceBefore.body.length).toBe(0);
|
|
531
|
+
|
|
532
|
+
await register(body, organization, token);
|
|
533
|
+
|
|
534
|
+
const balance = await getBalance(member.id, organization, token);
|
|
535
|
+
expect(balance).toBeDefined();
|
|
536
|
+
expect(balance.body.length).toBe(1);
|
|
537
|
+
expect(balance.body[0].price).toBe(21);
|
|
538
|
+
expect(balance.body[0].pricePaid).toBe(0);
|
|
539
|
+
// #endregion
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
test('Should apply reduced price for options if member requires financial support', async () => {
|
|
543
|
+
// #region arrange
|
|
544
|
+
const { organization, group, groupPrice, token, member } = await initData();
|
|
545
|
+
member.details.requiresFinancialSupport = BooleanStatus.create({
|
|
546
|
+
value: true,
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
await member.save();
|
|
550
|
+
|
|
551
|
+
const option1 = GroupOption.create({
|
|
552
|
+
name: 'option 1',
|
|
553
|
+
price: ReduceablePrice.create({
|
|
554
|
+
price: 5,
|
|
555
|
+
reducedPrice: 3,
|
|
556
|
+
}),
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
const option2 = GroupOption.create({
|
|
560
|
+
name: 'option 2',
|
|
561
|
+
price: ReduceablePrice.create({
|
|
562
|
+
price: 3,
|
|
563
|
+
reducedPrice: 1,
|
|
564
|
+
}),
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
const optionMenu = GroupOptionMenu.create({
|
|
568
|
+
name: 'option menu 1',
|
|
569
|
+
multipleChoice: true,
|
|
570
|
+
options: [option1, option2],
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
group.settings.optionMenus = [
|
|
574
|
+
optionMenu,
|
|
575
|
+
];
|
|
576
|
+
|
|
577
|
+
await group.save();
|
|
578
|
+
|
|
579
|
+
const body = IDRegisterCheckout.create({
|
|
580
|
+
cart: IDRegisterCart.create({
|
|
581
|
+
items: [
|
|
582
|
+
IDRegisterItem.create({
|
|
583
|
+
id: uuidv4(),
|
|
584
|
+
replaceRegistrationIds: [],
|
|
585
|
+
options: [
|
|
586
|
+
RegisterItemOption.create({
|
|
587
|
+
option: option1,
|
|
588
|
+
amount: 2,
|
|
589
|
+
optionMenu,
|
|
590
|
+
}),
|
|
591
|
+
RegisterItemOption.create({
|
|
592
|
+
option: option2,
|
|
593
|
+
amount: 5,
|
|
594
|
+
optionMenu,
|
|
595
|
+
}),
|
|
596
|
+
],
|
|
597
|
+
groupPrice,
|
|
598
|
+
organizationId: organization.id,
|
|
599
|
+
groupId: group.id,
|
|
600
|
+
memberId: member.id,
|
|
601
|
+
}),
|
|
602
|
+
],
|
|
603
|
+
balanceItems: [
|
|
604
|
+
],
|
|
605
|
+
deleteRegistrationIds: [],
|
|
606
|
+
}),
|
|
607
|
+
administrationFee: 0,
|
|
608
|
+
freeContribution: 0,
|
|
609
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
610
|
+
totalPrice: 32,
|
|
611
|
+
customer: null,
|
|
612
|
+
});
|
|
613
|
+
// #endregion
|
|
614
|
+
|
|
615
|
+
// #region act and assert
|
|
616
|
+
const balanceBefore = await getBalance(member.id, organization, token);
|
|
617
|
+
expect(balanceBefore).toBeDefined();
|
|
618
|
+
expect(balanceBefore.body.length).toBe(0);
|
|
619
|
+
|
|
620
|
+
await register(body, organization, token);
|
|
621
|
+
|
|
622
|
+
const balance = await getBalance(member.id, organization, token);
|
|
623
|
+
expect(balance).toBeDefined();
|
|
624
|
+
expect(balance.body.length).toBe(3);
|
|
625
|
+
expect.arrayContaining([
|
|
626
|
+
expect.objectContaining({
|
|
627
|
+
price: 6,
|
|
628
|
+
pricePaid: 0,
|
|
629
|
+
status: BalanceItemStatus.Due,
|
|
630
|
+
}),
|
|
631
|
+
expect.objectContaining({
|
|
632
|
+
price: 5,
|
|
633
|
+
pricePaid: 0,
|
|
634
|
+
status: BalanceItemStatus.Due,
|
|
635
|
+
}),
|
|
636
|
+
expect.objectContaining({
|
|
637
|
+
price: 25,
|
|
638
|
+
pricePaid: 0,
|
|
639
|
+
status: BalanceItemStatus.Due,
|
|
640
|
+
}),
|
|
641
|
+
]);
|
|
642
|
+
// #endregion
|
|
643
|
+
});
|
|
495
644
|
});
|
|
496
645
|
|
|
497
646
|
describe('Delete registrations', () => {
|
|
498
|
-
|
|
499
|
-
test.skip('Should create negative balance items', async () => {
|
|
647
|
+
test('Should cancel balance item for deleted registration', async () => {
|
|
500
648
|
// #region arrange
|
|
501
649
|
const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
|
|
502
650
|
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
651
|
+
const body1 = IDRegisterCheckout.create({
|
|
652
|
+
cart: IDRegisterCart.create({
|
|
653
|
+
items: [
|
|
654
|
+
IDRegisterItem.create({
|
|
655
|
+
id: uuidv4(),
|
|
656
|
+
replaceRegistrationIds: [],
|
|
657
|
+
options: [],
|
|
658
|
+
groupPrice: groupPrice1,
|
|
659
|
+
organizationId: organization.id,
|
|
660
|
+
groupId: group1.id,
|
|
661
|
+
memberId: member.id,
|
|
662
|
+
}),
|
|
663
|
+
],
|
|
664
|
+
balanceItems: [
|
|
665
|
+
],
|
|
666
|
+
deleteRegistrationIds: [],
|
|
667
|
+
}),
|
|
668
|
+
administrationFee: 0,
|
|
669
|
+
freeContribution: 0,
|
|
670
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
671
|
+
totalPrice: 25,
|
|
672
|
+
customer: null,
|
|
673
|
+
asOrganizationId: organization.id,
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
const response1 = await register(body1, organization, token);
|
|
677
|
+
expect(response1.body).toBeDefined();
|
|
678
|
+
expect(response1.body.registrations.length).toBe(1);
|
|
679
|
+
|
|
680
|
+
const registrationToDelete = response1.body.registrations[0];
|
|
508
681
|
|
|
509
682
|
const group = await new GroupFactory({
|
|
510
683
|
organization,
|
|
@@ -514,7 +687,7 @@ describe('E2E.Register', () => {
|
|
|
514
687
|
|
|
515
688
|
const groupPrice = group.settings.prices[0];
|
|
516
689
|
|
|
517
|
-
const
|
|
690
|
+
const body2 = IDRegisterCheckout.create({
|
|
518
691
|
cart: IDRegisterCart.create({
|
|
519
692
|
items: [
|
|
520
693
|
IDRegisterItem.create({
|
|
@@ -527,31 +700,293 @@ describe('E2E.Register', () => {
|
|
|
527
700
|
memberId: member.id,
|
|
528
701
|
}),
|
|
529
702
|
],
|
|
530
|
-
balanceItems: [
|
|
531
|
-
|
|
703
|
+
balanceItems: [
|
|
704
|
+
],
|
|
705
|
+
deleteRegistrationIds: [registrationToDelete.id],
|
|
532
706
|
}),
|
|
533
707
|
administrationFee: 0,
|
|
534
708
|
freeContribution: 0,
|
|
535
709
|
paymentMethod: PaymentMethod.PointOfSale,
|
|
536
|
-
totalPrice:
|
|
537
|
-
asOrganizationId: organization.id,
|
|
710
|
+
totalPrice: 30,
|
|
538
711
|
customer: null,
|
|
712
|
+
asOrganizationId: organization.id,
|
|
539
713
|
});
|
|
540
714
|
// #endregion
|
|
541
715
|
|
|
542
716
|
// #region act and assert
|
|
543
|
-
const
|
|
717
|
+
const balanceBefore = await getBalance(member.id, organization, token);
|
|
718
|
+
expect(balanceBefore).toBeDefined();
|
|
719
|
+
expect(balanceBefore.body.length).toBe(1);
|
|
720
|
+
expect(balanceBefore.body[0].price).toBe(25);
|
|
721
|
+
expect(balanceBefore.body[0].pricePaid).toBe(0);
|
|
722
|
+
|
|
723
|
+
await register(body2, organization, token);
|
|
724
|
+
|
|
725
|
+
const balance = await getBalance(member.id, organization, token);
|
|
726
|
+
expect(balance).toBeDefined();
|
|
727
|
+
expect(balance.body.length).toBe(2);
|
|
544
728
|
|
|
545
|
-
|
|
729
|
+
expect.arrayContaining([
|
|
730
|
+
expect.objectContaining({
|
|
731
|
+
price: 25,
|
|
732
|
+
pricePaid: 0,
|
|
733
|
+
status: BalanceItemStatus.Canceled,
|
|
734
|
+
}),
|
|
735
|
+
expect.objectContaining({
|
|
736
|
+
price: 30,
|
|
737
|
+
pricePaid: 0,
|
|
738
|
+
status: BalanceItemStatus.Due,
|
|
739
|
+
}),
|
|
740
|
+
]);
|
|
546
741
|
// #endregion
|
|
547
742
|
});
|
|
548
743
|
|
|
549
|
-
test
|
|
550
|
-
|
|
744
|
+
test('Should cancel all related balance item for deleted registration', async () => {
|
|
745
|
+
// #region arrange
|
|
746
|
+
const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
|
|
747
|
+
|
|
748
|
+
const option1 = GroupOption.create({
|
|
749
|
+
name: 'option 1',
|
|
750
|
+
price: ReduceablePrice.create({
|
|
751
|
+
price: 5,
|
|
752
|
+
reducedPrice: 3,
|
|
753
|
+
}),
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
const option2 = GroupOption.create({
|
|
757
|
+
name: 'option 2',
|
|
758
|
+
price: ReduceablePrice.create({
|
|
759
|
+
price: 3,
|
|
760
|
+
reducedPrice: 1,
|
|
761
|
+
}),
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
const optionMenu = GroupOptionMenu.create({
|
|
765
|
+
name: 'option menu 1',
|
|
766
|
+
multipleChoice: true,
|
|
767
|
+
options: [option1, option2],
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
group1.settings.optionMenus = [
|
|
771
|
+
optionMenu,
|
|
772
|
+
];
|
|
773
|
+
|
|
774
|
+
await group1.save();
|
|
775
|
+
|
|
776
|
+
const body1 = IDRegisterCheckout.create({
|
|
777
|
+
cart: IDRegisterCart.create({
|
|
778
|
+
items: [
|
|
779
|
+
IDRegisterItem.create({
|
|
780
|
+
id: uuidv4(),
|
|
781
|
+
replaceRegistrationIds: [],
|
|
782
|
+
options: [
|
|
783
|
+
RegisterItemOption.create({
|
|
784
|
+
option: option1,
|
|
785
|
+
amount: 2,
|
|
786
|
+
optionMenu,
|
|
787
|
+
}),
|
|
788
|
+
RegisterItemOption.create({
|
|
789
|
+
option: option2,
|
|
790
|
+
amount: 5,
|
|
791
|
+
optionMenu,
|
|
792
|
+
}),
|
|
793
|
+
],
|
|
794
|
+
groupPrice: groupPrice1,
|
|
795
|
+
organizationId: organization.id,
|
|
796
|
+
groupId: group1.id,
|
|
797
|
+
memberId: member.id,
|
|
798
|
+
}),
|
|
799
|
+
],
|
|
800
|
+
balanceItems: [
|
|
801
|
+
],
|
|
802
|
+
deleteRegistrationIds: [],
|
|
803
|
+
}),
|
|
804
|
+
administrationFee: 0,
|
|
805
|
+
freeContribution: 0,
|
|
806
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
807
|
+
totalPrice: 50,
|
|
808
|
+
customer: null,
|
|
809
|
+
asOrganizationId: organization.id,
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
const response1 = await register(body1, organization, token);
|
|
813
|
+
expect(response1.body).toBeDefined();
|
|
814
|
+
expect(response1.body.registrations.length).toBe(1);
|
|
815
|
+
|
|
816
|
+
const registrationToDelete = response1.body.registrations[0];
|
|
817
|
+
|
|
818
|
+
const group = await new GroupFactory({
|
|
819
|
+
organization,
|
|
820
|
+
price: 30,
|
|
821
|
+
stock: 5,
|
|
822
|
+
}).create();
|
|
823
|
+
|
|
824
|
+
const groupPrice = group.settings.prices[0];
|
|
825
|
+
|
|
826
|
+
const body2 = IDRegisterCheckout.create({
|
|
827
|
+
cart: IDRegisterCart.create({
|
|
828
|
+
items: [
|
|
829
|
+
IDRegisterItem.create({
|
|
830
|
+
id: uuidv4(),
|
|
831
|
+
replaceRegistrationIds: [],
|
|
832
|
+
options: [],
|
|
833
|
+
groupPrice,
|
|
834
|
+
organizationId: organization.id,
|
|
835
|
+
groupId: group.id,
|
|
836
|
+
memberId: member.id,
|
|
837
|
+
}),
|
|
838
|
+
],
|
|
839
|
+
balanceItems: [
|
|
840
|
+
],
|
|
841
|
+
deleteRegistrationIds: [registrationToDelete.id],
|
|
842
|
+
}),
|
|
843
|
+
administrationFee: 0,
|
|
844
|
+
freeContribution: 0,
|
|
845
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
846
|
+
totalPrice: 30,
|
|
847
|
+
customer: null,
|
|
848
|
+
asOrganizationId: organization.id,
|
|
849
|
+
});
|
|
850
|
+
// #endregion
|
|
851
|
+
|
|
852
|
+
// #region act and assert
|
|
853
|
+
const balanceBefore = await getBalance(member.id, organization, token);
|
|
854
|
+
expect(balanceBefore).toBeDefined();
|
|
855
|
+
expect(balanceBefore.body.length).toBe(3);
|
|
856
|
+
|
|
857
|
+
await register(body2, organization, token);
|
|
858
|
+
|
|
859
|
+
const balance = await getBalance(member.id, organization, token);
|
|
860
|
+
expect(balance).toBeDefined();
|
|
861
|
+
expect(balance.body.length).toBe(4);
|
|
862
|
+
|
|
863
|
+
expect.arrayContaining([
|
|
864
|
+
expect.objectContaining({
|
|
865
|
+
price: 10,
|
|
866
|
+
pricePaid: 0,
|
|
867
|
+
status: BalanceItemStatus.Canceled,
|
|
868
|
+
}),
|
|
869
|
+
expect.objectContaining({
|
|
870
|
+
price: 15,
|
|
871
|
+
pricePaid: 0,
|
|
872
|
+
status: BalanceItemStatus.Canceled,
|
|
873
|
+
}),
|
|
874
|
+
expect.objectContaining({
|
|
875
|
+
price: 25,
|
|
876
|
+
pricePaid: 0,
|
|
877
|
+
status: BalanceItemStatus.Canceled,
|
|
878
|
+
}),
|
|
879
|
+
expect.objectContaining({
|
|
880
|
+
price: 30,
|
|
881
|
+
pricePaid: 0,
|
|
882
|
+
status: BalanceItemStatus.Due,
|
|
883
|
+
}),
|
|
884
|
+
]);
|
|
885
|
+
// #endregion
|
|
551
886
|
});
|
|
552
887
|
|
|
553
|
-
test
|
|
554
|
-
|
|
888
|
+
test('Should apply cancelation fee', async () => {
|
|
889
|
+
// #region arrange
|
|
890
|
+
const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
|
|
891
|
+
|
|
892
|
+
const body1 = IDRegisterCheckout.create({
|
|
893
|
+
cart: IDRegisterCart.create({
|
|
894
|
+
items: [
|
|
895
|
+
IDRegisterItem.create({
|
|
896
|
+
id: uuidv4(),
|
|
897
|
+
replaceRegistrationIds: [],
|
|
898
|
+
options: [],
|
|
899
|
+
groupPrice: groupPrice1,
|
|
900
|
+
organizationId: organization.id,
|
|
901
|
+
groupId: group1.id,
|
|
902
|
+
memberId: member.id,
|
|
903
|
+
}),
|
|
904
|
+
],
|
|
905
|
+
balanceItems: [
|
|
906
|
+
],
|
|
907
|
+
deleteRegistrationIds: [],
|
|
908
|
+
}),
|
|
909
|
+
administrationFee: 0,
|
|
910
|
+
freeContribution: 0,
|
|
911
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
912
|
+
totalPrice: 25,
|
|
913
|
+
customer: null,
|
|
914
|
+
asOrganizationId: organization.id,
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
const response1 = await register(body1, organization, token);
|
|
918
|
+
expect(response1.body).toBeDefined();
|
|
919
|
+
expect(response1.body.registrations.length).toBe(1);
|
|
920
|
+
|
|
921
|
+
const registrationToDelete = response1.body.registrations[0];
|
|
922
|
+
|
|
923
|
+
const group = await new GroupFactory({
|
|
924
|
+
organization,
|
|
925
|
+
price: 30,
|
|
926
|
+
stock: 5,
|
|
927
|
+
}).create();
|
|
928
|
+
|
|
929
|
+
const groupPrice = group.settings.prices[0];
|
|
930
|
+
|
|
931
|
+
const body2 = IDRegisterCheckout.create({
|
|
932
|
+
cart: IDRegisterCart.create({
|
|
933
|
+
items: [
|
|
934
|
+
IDRegisterItem.create({
|
|
935
|
+
id: uuidv4(),
|
|
936
|
+
replaceRegistrationIds: [],
|
|
937
|
+
options: [],
|
|
938
|
+
groupPrice,
|
|
939
|
+
organizationId: organization.id,
|
|
940
|
+
groupId: group.id,
|
|
941
|
+
memberId: member.id,
|
|
942
|
+
}),
|
|
943
|
+
],
|
|
944
|
+
balanceItems: [
|
|
945
|
+
],
|
|
946
|
+
deleteRegistrationIds: [registrationToDelete.id],
|
|
947
|
+
}),
|
|
948
|
+
administrationFee: 0,
|
|
949
|
+
freeContribution: 0,
|
|
950
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
951
|
+
totalPrice: 30,
|
|
952
|
+
customer: null,
|
|
953
|
+
asOrganizationId: organization.id,
|
|
954
|
+
cancellationFeePercentage: 2000,
|
|
955
|
+
});
|
|
956
|
+
// #endregion
|
|
957
|
+
|
|
958
|
+
// #region act and assert
|
|
959
|
+
const balanceBefore = await getBalance(member.id, organization, token);
|
|
960
|
+
expect(balanceBefore).toBeDefined();
|
|
961
|
+
expect(balanceBefore.body.length).toBe(1);
|
|
962
|
+
expect(balanceBefore.body[0].price).toBe(25);
|
|
963
|
+
expect(balanceBefore.body[0].pricePaid).toBe(0);
|
|
964
|
+
|
|
965
|
+
await register(body2, organization, token);
|
|
966
|
+
|
|
967
|
+
const balance = await getBalance(member.id, organization, token);
|
|
968
|
+
expect(balance).toBeDefined();
|
|
969
|
+
expect(balance.body.length).toBe(3);
|
|
970
|
+
|
|
971
|
+
expect.arrayContaining([
|
|
972
|
+
expect.objectContaining({
|
|
973
|
+
price: 25,
|
|
974
|
+
pricePaid: 0,
|
|
975
|
+
status: BalanceItemStatus.Canceled,
|
|
976
|
+
}),
|
|
977
|
+
expect.objectContaining({
|
|
978
|
+
price: 30,
|
|
979
|
+
pricePaid: 0,
|
|
980
|
+
status: BalanceItemStatus.Due,
|
|
981
|
+
}),
|
|
982
|
+
expect.objectContaining({
|
|
983
|
+
price: 5,
|
|
984
|
+
pricePaid: 0,
|
|
985
|
+
type: BalanceItemType.CancellationFee,
|
|
986
|
+
status: BalanceItemStatus.Due,
|
|
987
|
+
}),
|
|
988
|
+
]);
|
|
989
|
+
// #endregion
|
|
555
990
|
});
|
|
556
991
|
});
|
|
557
992
|
|