@universis/accommodation 1.1.1 → 1.1.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.
Files changed (50) hide show
  1. package/dist/config/models/AccommodationChildFinancialAttribute.json +5 -0
  2. package/dist/config/models/AccommodationGuardianFinancialAttribute.json +5 -0
  3. package/dist/config/models/AccommodationPlace.json +50 -38
  4. package/dist/config/models/AccommodationPlaceLocale.json +5 -0
  5. package/dist/config/models/AccommodationRequestAction.json +10 -0
  6. package/dist/config/models/AccommodationRequestActionMessage.json +5 -0
  7. package/dist/config/models/AccommodationRequestActionReview.json +5 -0
  8. package/dist/config/models/AccommodationRequestAttachmentConfiguration.json +5 -0
  9. package/dist/config/models/AccommodationRequestCategory.json +19 -14
  10. package/dist/config/models/AccommodationRequestEvent.json +19 -14
  11. package/dist/config/models/AccommodationRequestFinancialAttribute.json +5 -0
  12. package/dist/config/models/AccommodationRoom.json +18 -1
  13. package/dist/config/models/AccommodationRoomLocale.json +5 -0
  14. package/dist/config/models/AccommodationSiblingFinancialAttribute.json +1 -7
  15. package/dist/config/models/CancelAccommodationCardAction.json +10 -4
  16. package/dist/config/models/GuardianType.json +5 -0
  17. package/dist/config/models/Review.json +5 -0
  18. package/dist/config/models/RoomType.json +5 -0
  19. package/dist/config/models/RoomTypeLocale.json +19 -14
  20. package/dist/config/models/StudentAccommodationCard.json +81 -79
  21. package/dist/config/scope.access.js +296 -80
  22. package/dist/config/scope.access.js.map +1 -1
  23. package/dist/listeners/OnUpdateAccommodationRoomListener.js +151 -0
  24. package/dist/listeners/OnUpdateAccommodationRoomListener.js.map +1 -0
  25. package/dist/listeners/StudentAccommodationCardSaveListener.js +9 -3
  26. package/dist/listeners/StudentAccommodationCardSaveListener.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/config/models/AccommodationChildFinancialAttribute.json +5 -0
  29. package/src/config/models/AccommodationGuardianFinancialAttribute.json +5 -0
  30. package/src/config/models/AccommodationPlace.json +50 -38
  31. package/src/config/models/AccommodationPlaceLocale.json +5 -0
  32. package/src/config/models/AccommodationRequestAction.json +10 -0
  33. package/src/config/models/AccommodationRequestActionMessage.json +5 -0
  34. package/src/config/models/AccommodationRequestActionReview.json +5 -0
  35. package/src/config/models/AccommodationRequestAttachmentConfiguration.json +5 -0
  36. package/src/config/models/AccommodationRequestCategory.json +19 -14
  37. package/src/config/models/AccommodationRequestEvent.json +19 -14
  38. package/src/config/models/AccommodationRequestFinancialAttribute.json +5 -0
  39. package/src/config/models/AccommodationRoom.json +18 -1
  40. package/src/config/models/AccommodationRoomLocale.json +5 -0
  41. package/src/config/models/AccommodationSiblingFinancialAttribute.json +1 -7
  42. package/src/config/models/CancelAccommodationCardAction.json +10 -4
  43. package/src/config/models/GuardianType.json +5 -0
  44. package/src/config/models/Review.json +5 -0
  45. package/src/config/models/RoomType.json +5 -0
  46. package/src/config/models/RoomTypeLocale.json +19 -14
  47. package/src/config/models/StudentAccommodationCard.json +81 -79
  48. package/src/config/scope.access.js +296 -80
  49. package/src/listeners/OnUpdateAccommodationRoomListener.js +150 -0
  50. package/src/listeners/StudentAccommodationCardSaveListener.js +9 -3
@@ -1,138 +1,354 @@
1
1
  export default [
2
2
  {
3
- "scope": [
4
- "registrar"
3
+ 'scope': [
4
+ 'accommodation'
5
5
  ],
6
- "resource": "/api/TestActions/?$",
7
- "access": [
8
- "read",
9
- "write"
6
+ 'resource': '/api/users/me',
7
+ 'access': [
8
+ 'read'
10
9
  ]
11
10
  },
12
11
  {
13
- "scope": [
14
- "registrar"
12
+ 'scope': [
13
+ 'accommodation'
15
14
  ],
16
- "resource": "/api/AccommodationPlaces/?$",
17
- "access": [
18
- "read",
19
- "write"
15
+ 'resource': '/api/content/private',
16
+ 'access': [
17
+ 'read'
20
18
  ]
21
19
  },
22
20
  {
23
- "scope": [
24
- "students"
21
+ 'scope': [
22
+ 'accommodation'
25
23
  ],
26
- "resource": "/api/TestActions/?$",
27
- "access": [
28
- "read",
29
- "write"
24
+ 'resource': '/api/ActionStatusTypes',
25
+ 'access': [
26
+ 'read'
30
27
  ]
31
28
  },
32
29
  {
33
- "scope": [
34
- "students"
30
+ 'scope': [
31
+ 'accommodation'
35
32
  ],
36
- "resource": "/api/Accommodations/?$",
37
- "access": [
38
- "read"
33
+ 'resource': '/api/StudentStatuses',
34
+ 'access': [
35
+ 'read'
39
36
  ]
40
37
  },
41
38
  {
42
- "scope": [
43
- "students"
39
+ 'scope': [
40
+ 'accommodation'
44
41
  ],
45
- "resource": "/api/AccommodationRequestActions",
46
- "access": [
47
- "read",
48
- "write"
42
+ 'resource': '/api/StudentCategories',
43
+ 'access': [
44
+ 'read'
49
45
  ]
50
46
  },
51
47
  {
52
- "scope": [
53
- "students"
48
+ 'scope': [
49
+ 'accommodation'
54
50
  ],
55
- "resource": "/api/AccommodationRequestEvents",
56
- "access": [
57
- "read"
51
+ 'resource': '/api/FamilyStatuses',
52
+ 'access': [
53
+ 'read'
58
54
  ]
59
55
  },
60
56
  {
61
- "scope": [
62
- "students"
57
+ 'scope': [
58
+ 'accommodation'
63
59
  ],
64
- "resource": "/api/AccommodationRequestCategories",
65
- "access": [
66
- "read"
60
+ 'resource': '/api/LocalDepartments',
61
+ 'access': [
62
+ 'read'
67
63
  ]
68
64
  },
69
65
  {
70
- "scope": [
71
- "students"
66
+ 'scope': [
67
+ 'accommodation'
72
68
  ],
73
- "resource": "/api/StudentAccommodationCards",
74
- "access": [
75
- "read"
69
+ 'resource': '/api/EventStatusTypes',
70
+ 'access': [
71
+ 'read'
76
72
  ]
77
73
  },
78
74
  {
79
- "scope": [
80
- "registrar"
75
+ 'scope': [
76
+ 'accommodation'
81
77
  ],
82
- "resource": "/api/AccommodationRequestActions",
83
- "access": [
84
- "read",
85
- "write"
78
+ 'resource': '/api/JsonAttachments',
79
+ 'access': [
80
+ 'read'
86
81
  ]
87
82
  },
88
83
  {
89
- "scope": [
90
- "registrar"
84
+ 'scope': [
85
+ 'registrar',
86
+ 'accommodation'
91
87
  ],
92
- "resource": "/api/AccommodationRequestEvents",
93
- "access": [
94
- "read",
95
- "write"
88
+ 'resource': '/api/AccommodationInscriptionModeTags',
89
+ 'access': [
90
+ 'read',
91
+ 'write'
96
92
  ]
97
93
  },
98
94
  {
99
- "scope": [
100
- "registrar"
95
+ 'scope': [
96
+ 'accommodation'
101
97
  ],
102
- "resource": "/api/AccommodationRequestEffectiveStatusTypes",
103
- "access": [
104
- "read",
105
- "write"
98
+ 'resource': '/api/AccommodationRequestActions',
99
+ 'access': [
100
+ 'read',
101
+ 'write'
106
102
  ]
107
103
  },
108
104
  {
109
- "scope": [
110
- "registrar"
105
+ 'scope': [
106
+ 'accommodation'
111
107
  ],
112
- "resource": "/api/AccommodationCardEffectiveStatusTypes",
113
- "access": [
114
- "read",
115
- "write"
108
+ 'resource': '/api/SpecialAccommodationRequestActions',
109
+ 'access': [
110
+ 'read',
111
+ 'write'
116
112
  ]
117
113
  },
118
114
  {
119
- "scope": [
120
- "registrar"
115
+ 'scope': [
116
+ 'accommodation'
121
117
  ],
122
- "resource": "/api/AccommodationRequestCategories",
123
- "access": [
124
- "read",
125
- "write"
118
+ 'resource': '/api/AccommodationRequestActionMessages',
119
+ 'access': [
120
+ 'read',
121
+ 'write'
126
122
  ]
127
123
  },
128
124
  {
129
- "scope": [
130
- "registrar"
125
+ 'scope': [
126
+ 'accommodation'
131
127
  ],
132
- "resource": "/api/StudentAccommodationCards/?$",
133
- "access": [
134
- "read",
135
- "write"
128
+ 'resource': '/api/AccommodationRequestActionReviews',
129
+ 'access': [
130
+ 'read',
131
+ 'write'
132
+ ]
133
+ },
134
+ {
135
+ 'scope': [
136
+ 'accommodation'
137
+ ],
138
+ 'resource': '/api/AccommodationRequestAttachmentConfigurations',
139
+ 'access': [
140
+ 'read',
141
+ 'write'
142
+ ]
143
+ },
144
+ {
145
+ 'scope': [
146
+ 'registrar',
147
+ 'accommodation'
148
+ ],
149
+ 'resource': '/api/AccommodationRequestEffectiveStatusTypes',
150
+ 'access': [
151
+ 'read',
152
+ 'write'
153
+ ]
154
+ },
155
+ {
156
+ 'scope': [
157
+ 'accommodation'
158
+ ],
159
+ 'resource': '/api/AccommodationRequestEvents',
160
+ 'access': [
161
+ 'read',
162
+ 'write'
163
+ ]
164
+ },
165
+ {
166
+ 'scope': [
167
+ 'accommodation'
168
+ ],
169
+ 'resource': '/api/AcademicYears',
170
+ 'access': [
171
+ 'read'
172
+ ]
173
+ },
174
+ {
175
+ 'scope': [
176
+ 'accommodation'
177
+ ],
178
+ 'resource': '/api/AcademicPeriods',
179
+ 'access': [
180
+ 'read'
181
+ ]
182
+ },
183
+ {
184
+ 'scope': [
185
+ 'accommodation'
186
+ ],
187
+ 'resource': '/api/StudentAccommodationCards',
188
+ 'access': [
189
+ 'read',
190
+ 'write'
191
+ ]
192
+ },
193
+ {
194
+ 'scope': [
195
+ 'accommodation'
196
+ ],
197
+ 'resource': '/api/AccommodationPlaces',
198
+ 'access': [
199
+ 'read',
200
+ 'write'
201
+ ]
202
+ },
203
+ {
204
+ 'scope': [
205
+ 'accommodation'
206
+ ],
207
+ 'resource': '/api/AccommodationRooms',
208
+ 'access': [
209
+ 'read',
210
+ 'write'
211
+ ]
212
+ },
213
+ {
214
+ 'scope': [
215
+ 'accommodation'
216
+ ],
217
+ 'resource': '/api/AccommodationConfigurations',
218
+ 'access': [
219
+ 'read',
220
+ 'write'
221
+ ]
222
+ },
223
+ {
224
+ 'scope': [
225
+ 'accommodation'
226
+ ],
227
+ 'resource': '/api/ReportTemplates',
228
+ 'access': [
229
+ 'read',
230
+ 'write'
231
+ ]
232
+ },
233
+ {
234
+ 'scope': [
235
+ 'accommodation'
236
+ ],
237
+ 'resource': '/api/AccommodationRequestCategories',
238
+ 'access': [
239
+ 'read',
240
+ 'write'
241
+ ]
242
+ },
243
+ {
244
+ 'scope': [
245
+ 'accommodation'
246
+ ],
247
+ 'resource': '/api/AccommodationRequestPreferences',
248
+ 'access': [
249
+ 'read'
250
+ ]
251
+ },
252
+ {
253
+ 'scope': [
254
+ 'accommodation'
255
+ ],
256
+ 'resource': '/api/UpdateAccommodationRequestEventActions',
257
+ 'access': [
258
+ 'read',
259
+ 'write'
260
+ ]
261
+ },
262
+ {
263
+ 'scope': [
264
+ 'accommodation'
265
+ ],
266
+ 'resource': '/api/RoomTypes',
267
+ 'access': [
268
+ 'read'
269
+ ]
270
+ },
271
+ {
272
+ 'scope': [
273
+ 'accommodation'
274
+ ],
275
+ 'resource': '/api/Regions',
276
+ 'access': [
277
+ 'read'
278
+ ]
279
+ },
280
+ {
281
+ 'scope': [
282
+ 'accommodation'
283
+ ],
284
+ 'resource': '/api/Countries',
285
+ 'access': [
286
+ 'read'
287
+ ]
288
+ },
289
+ {
290
+ 'scope': [
291
+ 'accommodation'
292
+ ],
293
+ 'resource': '/api/Institutes',
294
+ 'access': [
295
+ 'read'
296
+ ]
297
+ },
298
+ {
299
+ 'scope': [
300
+ 'students'
301
+ ],
302
+ 'resource': '/api/TestActions/?$',
303
+ 'access': [
304
+ 'read',
305
+ 'write'
306
+ ]
307
+ },
308
+ {
309
+ 'scope': [
310
+ 'students'
311
+ ],
312
+ 'resource': '/api/AccommodationPlaces/?$',
313
+ 'access': [
314
+ 'read'
315
+ ]
316
+ },
317
+ {
318
+ 'scope': [
319
+ 'students'
320
+ ],
321
+ 'resource': '/api/AccommodationRequestActions',
322
+ 'access': [
323
+ 'read',
324
+ 'write'
325
+ ]
326
+ },
327
+ {
328
+ 'scope': [
329
+ 'students'
330
+ ],
331
+ 'resource': '/api/AccommodationRequestEvents',
332
+ 'access': [
333
+ 'read'
334
+ ]
335
+ },
336
+ {
337
+ 'scope': [
338
+ 'students'
339
+ ],
340
+ 'resource': '/api/AccommodationRequestCategories',
341
+ 'access': [
342
+ 'read'
343
+ ]
344
+ },
345
+ {
346
+ 'scope': [
347
+ 'students'
348
+ ],
349
+ 'resource': '/api/StudentAccommodationCards',
350
+ 'access': [
351
+ 'read'
136
352
  ]
137
353
  }
138
354
  ]
@@ -0,0 +1,150 @@
1
+
2
+ import { DataError } from '@themost/common';
3
+
4
+ async function beforeSaveAsync(event) {
5
+ //
6
+ if (event.state !== 2) {
7
+ return;
8
+ }
9
+
10
+ const context = event.model.context;
11
+ const target = event.target;
12
+ const previous = event.previous;
13
+
14
+ if (previous == null) {
15
+ throw new DataError('E_PREVIOUS', 'The previous state of the object cannot be determined');
16
+ }
17
+
18
+ const previousActionStatus = await context.model('ActionStatusType').find(previous.cardStatus).select('alternateName').value();
19
+ const targetActionStatus = await context.model('ActionStatusType').find(event.target.cardStatus).select('alternateName').value();
20
+
21
+ if (previousActionStatus === 'CompletedActionStatus' && targetActionStatus === 'ActiveActionStatus') {
22
+ target.accommodationRoom = null
23
+ }
24
+
25
+ if (Object.prototype.hasOwnProperty.call(target, 'accommodationRoom') === true) {
26
+ const targetAccommodationRoom = target.accommodationRoom?.id || target.accommodationRoom;
27
+
28
+ if (previous.accommodationRoom !== targetAccommodationRoom && targetAccommodationRoom != null && previous.accommodationRoom != null) {
29
+
30
+ if (targetActionStatus !== 'CompletedActionStatus') {
31
+ throw new DataError('E_STATE', 'The accommodation room cannot be changed for inactive accommodation card');
32
+ }
33
+
34
+ target.cancelReason = target.cancelReason || context.translate('Change Room');
35
+ target.dateCancelled = target.dateCancelled || new Date();
36
+ target.validThrough = target.dateCancelled;
37
+
38
+ }
39
+ }
40
+ }
41
+
42
+ async function afterSaveAsync(event) {
43
+
44
+ if (event.state !== 2) {
45
+ return;
46
+ }
47
+
48
+ const previous = event.previous;
49
+ if (previous == null) {
50
+ throw new DataError('E_PREVIOUS', 'The previous state of the object cannot be determined');
51
+ }
52
+
53
+ const target = event.target;
54
+
55
+ if (Object.prototype.hasOwnProperty.call(target, 'accommodationRoom') === false) {
56
+ return;
57
+ }
58
+
59
+
60
+ const context = event.model.context;
61
+ const previousActionStatus = await context.model('ActionStatusType').find(previous.cardStatus).select('alternateName').value();
62
+ const targetActionStatus = await context.model('ActionStatusType').find(event.target.cardStatus).select('alternateName').value();
63
+ const targetAccommodationRoom = target.accommodationRoom?.id || target.accommodationRoom;
64
+
65
+ if (previousActionStatus === 'CompletedActionStatus' && targetActionStatus === 'ActiveActionStatus' && previous.accommodationRoom != null) {
66
+ // update previous room occupancy
67
+ await calculateOccupancy(context, previous.accommodationRoom);
68
+ }
69
+
70
+ if (['CompletedActionStatus', 'ActiveActionStatus'].includes(previousActionStatus) && targetActionStatus === 'CancelledActionStatus') {
71
+ // on cancel student accommodation card status
72
+ await calculateOccupancy(context, targetAccommodationRoom);
73
+ }
74
+
75
+ if (['CompletedActionStatus', 'ActiveActionStatus'].includes(previousActionStatus) && targetActionStatus === 'CompletedActionStatus') {
76
+
77
+
78
+ if (previous.accommodationRoom === targetAccommodationRoom) {
79
+ return;
80
+ }
81
+
82
+ if (previousActionStatus === 'CompletedActionStatus') {
83
+ const newCard = {
84
+ action: previous.action,
85
+ student: previous.student,
86
+ accommodationRoom: targetAccommodationRoom,
87
+ academicYear: previous.academicYear,
88
+ validFrom: target.validThrough,
89
+ validThrough: previous.validThrough,
90
+ cardStatus: {
91
+ alternateName: 'CompletedActionStatus'
92
+ }
93
+
94
+ }
95
+
96
+ await context.model('StudentAccommodationCards').save(newCard);
97
+ }
98
+
99
+ await calculateOccupancy(context, targetAccommodationRoom);
100
+
101
+ if (previous.accommodationRoom != null) {
102
+ await calculateOccupancy(context, previous.accommodationRoom);
103
+ }
104
+ }
105
+ }
106
+
107
+ async function calculateOccupancy(context, accommodationRoom) {
108
+
109
+ const currentOccupancy = await context.model('StudentAccommodationCard')
110
+ .where('accommodationRoom').equal(accommodationRoom)
111
+ .and('isActive').equal(1)
112
+ .select('count(id) as total', 'accommodationRoom/occupancy as maxOccupancy')
113
+ .groupBy('accommodationRoom/occupancy')
114
+ .silent()
115
+ .getItem();
116
+
117
+ const totalOccupancy= (currentOccupancy && currentOccupancy.total ) || 0;
118
+ if (totalOccupancy && totalOccupancy > currentOccupancy.maxOccupancy) {
119
+ throw new DataError('E_STATE', 'No room space for new resident');
120
+ }
121
+
122
+ await context.model('AccommodationRoom').save({
123
+ id: accommodationRoom,
124
+ currentOccupancy: totalOccupancy
125
+ });
126
+ }
127
+
128
+ /**
129
+ * @param {DataEventArgs} event
130
+ * @param {Function} callback
131
+ */
132
+ export function beforeSave(event, callback) {
133
+ return beforeSaveAsync(event).then(() => {
134
+ return callback();
135
+ }).catch((err) => {
136
+ return callback(err);
137
+ });
138
+ }
139
+
140
+ /**
141
+ * @param {DataEventArgs} event
142
+ * @param {Function} callback
143
+ */
144
+ export function afterSave(event, callback) {
145
+ return afterSaveAsync(event).then(() => {
146
+ return callback();
147
+ }).catch((err) => {
148
+ return callback(err);
149
+ });
150
+ }
@@ -13,7 +13,15 @@ export function beforeSave(event, callback) {
13
13
  /**
14
14
  * @type {Student|DataObject|*}
15
15
  */
16
- const student = context.model('Student').convert(event.target.student);
16
+ const previous = event.previous;
17
+ let student = context.model('Student').convert(event.target.student);
18
+ if (!student){
19
+ if (previous){
20
+ student = context.model('Student').convert(previous.student);
21
+ }else{
22
+ throw new DataError('ERR_STATUS','Student cannot be found');
23
+ }
24
+ }
17
25
  // const isActive = await student.silent().isActive();
18
26
  const isActive = await student.is(':active');
19
27
  if (!isActive) {
@@ -23,8 +31,6 @@ export function beforeSave(event, callback) {
23
31
  'Student', 'studentStatus');
24
32
  }
25
33
 
26
- const studentObject = await context.model('Student').where('id').equal(student.id).silent().flatten().getItem();
27
-
28
34
  const academicYear = context.model('AcademicYear').convert(event.target.academicYear).getId();
29
35
  if (Number.isInteger(academicYear) === false) {
30
36
  throw new DataError('E_VALUE', 'Invalid academic year. Expected number.', null, 'AcademicYear', 'id');