@universis/accommodation 1.0.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.
Files changed (134) hide show
  1. package/.gitlab-ci.yml +23 -0
  2. package/LICENSE +163 -0
  3. package/README.md +3 -0
  4. package/dist/AccommodationSchemaLoader.js +35 -0
  5. package/dist/AccommodationSchemaLoader.js.map +1 -0
  6. package/dist/AccommodationService.js +68 -0
  7. package/dist/AccommodationService.js.map +1 -0
  8. package/dist/DepartmentReplacer.js +54 -0
  9. package/dist/DepartmentReplacer.js.map +1 -0
  10. package/dist/StudentReplacer.js +75 -0
  11. package/dist/StudentReplacer.js.map +1 -0
  12. package/dist/config/models/Accommodation.json +96 -0
  13. package/dist/config/models/AccommodationCardEffectiveStatusType.json +107 -0
  14. package/dist/config/models/AccommodationCardEffectiveStatusTypeLocale.json +85 -0
  15. package/dist/config/models/AccommodationChildFinancialAttribute.json +46 -0
  16. package/dist/config/models/AccommodationGuardianFinancialAttribute.json +46 -0
  17. package/dist/config/models/AccommodationInscriptionModeTag.json +100 -0
  18. package/dist/config/models/AccommodationRequestAction.json +500 -0
  19. package/dist/config/models/AccommodationRequestActionMessage.json +46 -0
  20. package/dist/config/models/AccommodationRequestActionReview.json +31 -0
  21. package/dist/config/models/AccommodationRequestAttachmentConfiguration.json +72 -0
  22. package/dist/config/models/AccommodationRequestCategory.json +50 -0
  23. package/dist/config/models/AccommodationRequestEffectiveStatusType.json +212 -0
  24. package/dist/config/models/AccommodationRequestEffectiveStatusTypeLocale.json +85 -0
  25. package/dist/config/models/AccommodationRequestEvent.json +117 -0
  26. package/dist/config/models/AccommodationRequestFinancialAttribute.json +53 -0
  27. package/dist/config/models/AccommodationRoom.json +151 -0
  28. package/dist/config/models/AccommodationSiblingFinancialAttribute.json +57 -0
  29. package/dist/config/models/CancelAccommodationCardAction.json +32 -0
  30. package/dist/config/models/GuardianType.json +78 -0
  31. package/dist/config/models/Review.json +50 -0
  32. package/dist/config/models/RoomType.json +320 -0
  33. package/dist/config/models/RoomTypeLocale.json +86 -0
  34. package/dist/config/models/StudentAccommodationCard.json +158 -0
  35. package/dist/config/models/TestAction.json +50 -0
  36. package/dist/config/scope.access.js +148 -0
  37. package/dist/config/scope.access.js.map +1 -0
  38. package/dist/index.d.ts +2 -0
  39. package/dist/index.js +3 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/listeners/AddDefaultAttachmentConfiguration.js +44 -0
  42. package/dist/listeners/AddDefaultAttachmentConfiguration.js.map +1 -0
  43. package/dist/listeners/DefaultAttachmentConfigurations.json +277 -0
  44. package/dist/listeners/DefaultAttachmentTypes.json +523 -0
  45. package/dist/listeners/GenerateRequestNumberListener.js +87 -0
  46. package/dist/listeners/GenerateRequestNumberListener.js.map +1 -0
  47. package/dist/listeners/OnActionCompleteListener.js +96 -0
  48. package/dist/listeners/OnActionCompleteListener.js.map +1 -0
  49. package/dist/listeners/OnCancelAccommodationCardListener.js +87 -0
  50. package/dist/listeners/OnCancelAccommodationCardListener.js.map +1 -0
  51. package/dist/listeners/OnReactivateAccommodationCardListener.js +87 -0
  52. package/dist/listeners/OnReactivateAccommodationCardListener.js.map +1 -0
  53. package/dist/listeners/SendEmailAfterActionStatusChangeListener.js +98 -0
  54. package/dist/listeners/SendEmailAfterActionStatusChangeListener.js.map +1 -0
  55. package/dist/listeners/SendEmailAfterCardStatusChangeListener.js +139 -0
  56. package/dist/listeners/SendEmailAfterCardStatusChangeListener.js.map +1 -0
  57. package/dist/listeners/StudentAccommodationCardSaveListener.js +90 -0
  58. package/dist/listeners/StudentAccommodationCardSaveListener.js.map +1 -0
  59. package/dist/listeners/UpdateStudentAccommodationCardListener.js +70 -0
  60. package/dist/listeners/UpdateStudentAccommodationCardListener.js.map +1 -0
  61. package/dist/listeners/ValidateActionListener.js +348 -0
  62. package/dist/listeners/ValidateActionListener.js.map +1 -0
  63. package/dist/listeners/data-localization.js +209 -0
  64. package/dist/listeners/data-localization.js.map +1 -0
  65. package/dist/listeners/lookup-cache-listener.js +90 -0
  66. package/dist/listeners/lookup-cache-listener.js.map +1 -0
  67. package/dist/models/Accommodation.js +53 -0
  68. package/dist/models/Accommodation.js.map +1 -0
  69. package/dist/models/AccommodationRequestAction.js +214 -0
  70. package/dist/models/AccommodationRequestAction.js.map +1 -0
  71. package/dist/models/AccommodationRequestEvent.js +277 -0
  72. package/dist/models/AccommodationRequestEvent.js.map +1 -0
  73. package/dist/models/EnableAttachmentModel.js +210 -0
  74. package/dist/models/EnableAttachmentModel.js.map +1 -0
  75. package/dist/models/StudentAccommodationCard.js +93 -0
  76. package/dist/models/StudentAccommodationCard.js.map +1 -0
  77. package/dist/models/TestAction.d.ts +5 -0
  78. package/dist/models/TestAction.js +5 -0
  79. package/dist/models/TestAction.js.map +1 -0
  80. package/dist/templates/mail-after-dining-request-status-change/html.ejs +27 -0
  81. package/package.json +57 -0
  82. package/src/AccommodationSchemaLoader.js +35 -0
  83. package/src/AccommodationService.js +67 -0
  84. package/src/DepartmentReplacer.js +53 -0
  85. package/src/StudentReplacer.js +74 -0
  86. package/src/config/models/Accommodation.json +96 -0
  87. package/src/config/models/AccommodationCardEffectiveStatusType.json +107 -0
  88. package/src/config/models/AccommodationCardEffectiveStatusTypeLocale.json +85 -0
  89. package/src/config/models/AccommodationChildFinancialAttribute.json +46 -0
  90. package/src/config/models/AccommodationGuardianFinancialAttribute.json +46 -0
  91. package/src/config/models/AccommodationInscriptionModeTag.json +100 -0
  92. package/src/config/models/AccommodationRequestAction.json +500 -0
  93. package/src/config/models/AccommodationRequestActionMessage.json +46 -0
  94. package/src/config/models/AccommodationRequestActionReview.json +31 -0
  95. package/src/config/models/AccommodationRequestAttachmentConfiguration.json +72 -0
  96. package/src/config/models/AccommodationRequestCategory.json +50 -0
  97. package/src/config/models/AccommodationRequestEffectiveStatusType.json +212 -0
  98. package/src/config/models/AccommodationRequestEffectiveStatusTypeLocale.json +85 -0
  99. package/src/config/models/AccommodationRequestEvent.json +117 -0
  100. package/src/config/models/AccommodationRequestFinancialAttribute.json +53 -0
  101. package/src/config/models/AccommodationRoom.json +151 -0
  102. package/src/config/models/AccommodationSiblingFinancialAttribute.json +57 -0
  103. package/src/config/models/CancelAccommodationCardAction.json +32 -0
  104. package/src/config/models/GuardianType.json +78 -0
  105. package/src/config/models/Review.json +50 -0
  106. package/src/config/models/RoomType.json +320 -0
  107. package/src/config/models/RoomTypeLocale.json +86 -0
  108. package/src/config/models/StudentAccommodationCard.json +158 -0
  109. package/src/config/models/TestAction.json +50 -0
  110. package/src/config/scope.access.js +148 -0
  111. package/src/index.d.ts +2 -0
  112. package/src/index.js +2 -0
  113. package/src/listeners/AddDefaultAttachmentConfiguration.js +43 -0
  114. package/src/listeners/DefaultAttachmentConfigurations.json +277 -0
  115. package/src/listeners/DefaultAttachmentTypes.json +523 -0
  116. package/src/listeners/GenerateRequestNumberListener.js +86 -0
  117. package/src/listeners/OnActionCompleteListener.js +95 -0
  118. package/src/listeners/OnCancelAccommodationCardListener.js +86 -0
  119. package/src/listeners/OnReactivateAccommodationCardListener.js +86 -0
  120. package/src/listeners/SendEmailAfterActionStatusChangeListener.js +97 -0
  121. package/src/listeners/SendEmailAfterCardStatusChangeListener.js +138 -0
  122. package/src/listeners/StudentAccommodationCardSaveListener.js +89 -0
  123. package/src/listeners/UpdateStudentAccommodationCardListener.js +69 -0
  124. package/src/listeners/ValidateActionListener.js +347 -0
  125. package/src/listeners/data-localization.js +214 -0
  126. package/src/listeners/lookup-cache-listener.js +89 -0
  127. package/src/models/Accommodation.js +52 -0
  128. package/src/models/AccommodationRequestAction.js +195 -0
  129. package/src/models/AccommodationRequestEvent.js +276 -0
  130. package/src/models/EnableAttachmentModel.js +209 -0
  131. package/src/models/StudentAccommodationCard.js +92 -0
  132. package/src/models/TestAction.d.ts +5 -0
  133. package/src/models/TestAction.js +10 -0
  134. package/src/templates/mail-after-dining-request-status-change/html.ejs +27 -0
@@ -0,0 +1,95 @@
1
+ // eslint-disable-next-line no-unused-vars
2
+ async function beforeSaveAsync(event) {
3
+ const context = event.model.context;
4
+ }
5
+
6
+ async function afterSaveAsync(event) {
7
+ // get context
8
+ // eslint-disable-next-line no-unused-vars
9
+ const context = event.model.context;
10
+ // get current status
11
+ const request = await event.model.where('id').equal(event.target.id)
12
+ .expand({
13
+ name: 'accommodationRequestEvent',
14
+ options: {
15
+ $expand: 'academicYear,academicPeriod',
16
+ }
17
+ }).getItem();
18
+ const actionStatus = request && request.actionStatus && request.actionStatus.alternateName ? request.actionStatus.alternateName : null;
19
+ if ((actionStatus || actionStatus.alternateName) === 'CompletedActionStatus') {
20
+ // set student accommodation card
21
+ const now = new Date();
22
+
23
+ // const now = new Date();
24
+ let academicYear = request && request.accommodationRequestEvent && request.accommodationRequestEvent.academicYear ? request.accommodationRequestEvent.academicYear : null;
25
+ let academicPeriod = request && request.accommodationRequestEvent && request.accommodationRequestEvent.academicPeriod ? request.accommodationRequestEvent.academicPeriod : null;
26
+ let validThrough = request && request.accommodationRequestEvent && request.accommodationRequestEvent.validThrough ? request.accommodationRequestEvent.validThrough : null;
27
+ // get original student
28
+ const student = await context.model('Student').where('id').equal(request.student.id || request.student)
29
+ .expand({
30
+ name: 'department',
31
+ options: {
32
+ $expand: 'currentYear,currentPeriod',
33
+ }
34
+ }).getItem();
35
+ if (student == null) {
36
+ throw new Error(`Student with id ${request.student.id || request.student} not found.`);
37
+ }
38
+
39
+ if (academicYear == null) {
40
+ // get student current academic year
41
+
42
+ academicYear = student && student.department && student.department.currentYear ? student.department.currentYear : null;
43
+ // await event.model.where('id').equal(event.target.id).select('student/department/currentYear').value();
44
+ }
45
+ if (academicPeriod == null) {
46
+ // get student current academic period
47
+ academicPeriod = student && student.department && student.department.currentPeriod ? student.department.currentPeriod : null;
48
+ }
49
+ let cardActionStatus = {};
50
+ if (event.target.accommodation && (Object.keys(event.target.accommodation).length === 0 || event.target.accommodation === '')) {
51
+ // get accommodation valid through date
52
+ cardActionStatus = { alternateName: 'PotentialActionStatus' }
53
+
54
+ } else {
55
+ cardActionStatus = { alternateName: 'CompletedActionStatus' }
56
+ }
57
+
58
+ const StudentAccommodationCard = {
59
+ action: event.target.id,
60
+ student: student,
61
+ academicYear: academicYear,
62
+ academicPeriod: academicPeriod,
63
+ validFrom: now,
64
+ validThrough: validThrough,
65
+ cardStatus: cardActionStatus,
66
+ accommodationRoom: event.target.room || null
67
+ };
68
+ // save student accommodation card
69
+ await context.model('StudentAccommodationCard').silent().save(StudentAccommodationCard);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * @param {DataEventArgs} event
75
+ * @param {Function} callback
76
+ */
77
+ export function beforeSave(event, callback) {
78
+ return beforeSaveAsync(event).then(() => {
79
+ return callback();
80
+ }).catch((err) => {
81
+ return callback(err);
82
+ });
83
+ }
84
+
85
+ /**
86
+ * @param {DataEventArgs} event
87
+ * @param {Function} callback
88
+ */
89
+ export function afterSave(event, callback) {
90
+ return afterSaveAsync(event).then(() => {
91
+ return callback();
92
+ }).catch((err) => {
93
+ return callback(err);
94
+ });
95
+ }
@@ -0,0 +1,86 @@
1
+ import { DataPermissionEventListener, PermissionMask } from "@themost/data";
2
+ import { DataError } from '@themost/common';
3
+ import { promisify } from "util";
4
+
5
+ async function beforeSaveAsync(event) {
6
+ //
7
+ if (event.state !== 2) {
8
+ return;
9
+ }
10
+
11
+ const context = event.model.context;
12
+
13
+ const previous = event.previous;
14
+ if (previous == null) {
15
+ throw new DataError('E_PREVIOUS', 'The previous state of the object cannot be determined');
16
+ }
17
+
18
+ const target = event.target;
19
+
20
+ if (target.active === false && previous.active === true) {
21
+ // get validator listener
22
+ const validator = new DataPermissionEventListener();
23
+ // noinspection JSUnresolvedFunction
24
+ const validateAsync = promisify(validator.validate)
25
+ .bind(validator);
26
+ // validate StudentAccommodationCard/Cancel execute permission
27
+ const validateEvent = {
28
+ model: context.model('StudentAccommodationCard'),
29
+ privilege: 'StudentAccommodationCard/Cancel',
30
+ mask: PermissionMask.Execute,
31
+ target: event.target && event.target.id,
32
+ throwError: true
33
+ }
34
+ await validateAsync(validateEvent);
35
+
36
+ }
37
+ }
38
+
39
+ async function afterSaveAsync(event) {
40
+ if (event.state !== 2) {
41
+ return;
42
+ }
43
+
44
+ const context = event.model.context;
45
+
46
+ const previous = event.previous;
47
+ if (previous == null) {
48
+ throw new DataError('E_PREVIOUS', 'The previous state of the object cannot be determined');
49
+ }
50
+
51
+ const target = event.target;
52
+
53
+ if (target.active === false && previous.active === true) {
54
+ //save
55
+ await context.model('CancelAccommodationCardAction').save({
56
+ accommodationCard: target.id,
57
+ actionStatus: {
58
+ alternateName: 'CompletedActionStatus'
59
+ }
60
+ })
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @param {DataEventArgs} event
66
+ * @param {Function} callback
67
+ */
68
+ export function beforeSave(event, callback) {
69
+ return beforeSaveAsync(event).then(() => {
70
+ return callback();
71
+ }).catch((err) => {
72
+ return callback(err);
73
+ });
74
+ }
75
+
76
+ /**
77
+ * @param {DataEventArgs} event
78
+ * @param {Function} callback
79
+ */
80
+ export function afterSave(event, callback) {
81
+ return afterSaveAsync(event).then(() => {
82
+ return callback();
83
+ }).catch((err) => {
84
+ return callback(err);
85
+ });
86
+ }
@@ -0,0 +1,86 @@
1
+ import { DataPermissionEventListener, PermissionMask } from "@themost/data";
2
+ import { DataError } from '@themost/common';
3
+ import { promisify } from "util";
4
+
5
+ async function beforeSaveAsync(event) {
6
+ //
7
+ if (event.state !== 2) {
8
+ return;
9
+ }
10
+
11
+ const context = event.model.context;
12
+
13
+ const previous = event.previous;
14
+ if (previous == null) {
15
+ throw new DataError('E_PREVIOUS', 'The previous state of the object cannot be determined');
16
+ }
17
+
18
+ const target = event.target;
19
+
20
+ if (target.active === false && previous.active === true) {
21
+ // get validator listener
22
+ const validator = new DataPermissionEventListener();
23
+ // noinspection JSUnresolvedFunction
24
+ const validateAsync = promisify(validator.validate)
25
+ .bind(validator);
26
+ // validate StudentAccommodationCard/Cancel execute permission
27
+ const validateEvent = {
28
+ model: context.model('StudentAccommodationCard'),
29
+ privilege: 'StudentAccommodationCard/Cancel',
30
+ mask: PermissionMask.Execute,
31
+ target: event.target && event.target.id,
32
+ throwError: true
33
+ }
34
+ await validateAsync(validateEvent);
35
+
36
+ }
37
+ }
38
+
39
+ async function afterSaveAsync(event) {
40
+ if (event.state !== 2) {
41
+ return;
42
+ }
43
+
44
+ const context = event.model.context;
45
+
46
+ const previous = event.previous;
47
+ if (previous == null) {
48
+ throw new DataError('E_PREVIOUS', 'The previous state of the object cannot be determined');
49
+ }
50
+
51
+ const target = event.target;
52
+
53
+ if (target.active === false && previous.active === true) {
54
+ //save
55
+ await context.model('CancelAccommodationCardAction').save({
56
+ accommodationCard: target.id,
57
+ actionStatus: {
58
+ alternateName: 'CompletedActionStatus'
59
+ }
60
+ })
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @param {DataEventArgs} event
66
+ * @param {Function} callback
67
+ */
68
+ export function beforeSave(event, callback) {
69
+ return beforeSaveAsync(event).then(() => {
70
+ return callback();
71
+ }).catch((err) => {
72
+ return callback(err);
73
+ });
74
+ }
75
+
76
+ /**
77
+ * @param {DataEventArgs} event
78
+ * @param {Function} callback
79
+ */
80
+ export function afterSave(event, callback) {
81
+ return afterSaveAsync(event).then(() => {
82
+ return callback();
83
+ }).catch((err) => {
84
+ return callback(err);
85
+ });
86
+ }
@@ -0,0 +1,97 @@
1
+ import { getMailer } from '@themost/mailer';
2
+ import { DataError } from '@themost/data';
3
+ import { TraceUtils } from "@themost/common";
4
+ /**
5
+ * @param {DataEventArgs} event
6
+ */
7
+ async function afterSaveAsync(event) {
8
+ if (event.state === 2) {
9
+ const context = event.model.context;
10
+ /**
11
+ * @type {import('@themost/mailer').MailerHelper}
12
+ */
13
+ const mailer = getMailer(context);
14
+
15
+ const actionStatus = await context.model('AccommodationRequestAction')
16
+ .where('id').equal(event.target.id).select('actionStatus/alternateName').value();
17
+ let previousStatus = 'UnknownActionStatus';
18
+ if (event.previous) {
19
+ previousStatus = event.previous.actionStatus.alternateName;
20
+ } else {
21
+ throw new DataError('E_STATE', 'The previous state of an object cannot be determined', null, 'AccommodationRequestAction');
22
+ }
23
+ if (actionStatus === previousStatus) {
24
+ return;
25
+ }
26
+ // get mail template
27
+ const mailTemplate = await context.model('MailConfiguration').where('target').equal('AccommodationRequestActionStatusChange').silent().getItem();
28
+ if (mailTemplate == null) {
29
+ //
30
+ return;
31
+ }
32
+ // get parent action data
33
+ const item = await context.model('AccommodationRequestAction')
34
+ .where('id').equal(event.target.id)
35
+ .expand({
36
+ name: 'student',
37
+ options: {
38
+ $expand: 'person'
39
+ }
40
+ }, 'owner')
41
+ .silent().getItem();
42
+
43
+ const application = await context.model('WebApplication')
44
+ .where('alternateName').equal('students')
45
+ .and('applicationSuite').equal('universis')
46
+ .silent().getItem();
47
+ const config = await context.model('StudentRequestConfiguration')
48
+ .where('additionalType').equal(event.model.name)
49
+ .and('inLanguage').equal(event.target.inLanguage || context.locale)
50
+ .silent().getItem();
51
+
52
+ if (item && application && config) {
53
+
54
+ const email = item.student.person.email;
55
+
56
+ if (email == null || typeof email !== 'string') {
57
+ TraceUtils.warn(`Cannot send email for ${item.student.person.familyName} ${item.student.person.givenName}. Student [${item.student.id}] email does not exist.`);
58
+ return;
59
+ }
60
+ await new Promise((resolve) => {
61
+ mailer.template(mailTemplate.template)
62
+ .subject(mailTemplate.subject)
63
+ .bcc(mailTemplate.bcc || '')
64
+ .to(email)
65
+ .send({
66
+ model: item,
67
+ application: application,
68
+ configuration: config
69
+ }, (err) => {
70
+ if (err) {
71
+ try {
72
+ TraceUtils.error('An error occurred while trying to send an email notification after status change.');
73
+ TraceUtils.error(`Student=${item.student.id}, template=${mailTemplate.template}`);
74
+ TraceUtils.error(err);
75
+ } catch (err1) {
76
+ // do nothing
77
+ }
78
+ return resolve();
79
+ }
80
+ return resolve();
81
+ })
82
+ });
83
+
84
+ }
85
+ }
86
+ }
87
+ /**
88
+ * @param {DataEventArgs} event
89
+ * @param {Function} callback
90
+ */
91
+ export function afterSave(event, callback) {
92
+ return afterSaveAsync(event).then(() => {
93
+ return callback();
94
+ }).catch((err) => {
95
+ return callback(err);
96
+ });
97
+ }
@@ -0,0 +1,138 @@
1
+ import { getMailer } from '@themost/mailer';
2
+ import { DataError } from '@themost/data';
3
+ import { TraceUtils } from "@themost/common";
4
+ /**
5
+ * @param {DataEventArgs} event
6
+ */
7
+ async function afterSaveAsync(event) {
8
+ if (event.state === 2) {
9
+ const context = event.model.context;
10
+ /**
11
+ * @type {import('@themost/mailer').MailerHelper}
12
+ */
13
+ const mailer = getMailer(context);
14
+
15
+ const currentCardStatus = await context
16
+ .model('StudentDiningCard')
17
+ .where('id')
18
+ .equal(event.target.id)
19
+ .select('active')
20
+ .value();
21
+ let previousCardStatus = 'UnknownStatus';
22
+ if (event.previous) {
23
+ previousCardStatus = event.previous.active;
24
+ } else {
25
+ throw new DataError('E_STATE', 'The previous state of an object cannot be determined', null, 'StudentDiningCard');
26
+ }
27
+ if (currentCardStatus === previousCardStatus) {
28
+ return;
29
+ }
30
+
31
+ // get mail template
32
+ const mailTemplate = await context
33
+ .model('MailConfigurations')
34
+ .where('target')
35
+ .equal('DiningCardActiveStatusChange')
36
+ .silent()
37
+ .getItem();
38
+ if (mailTemplate == null) {
39
+ //
40
+ return;
41
+ }
42
+
43
+ //get parent action data
44
+ let item;
45
+ if (typeof event.target.action === 'object' && typeof event.target.action.id === 'number' && Number.isInteger(event.target.action.id) && event.target.action.id > 0) {
46
+ item = await context
47
+ .model('DiningRequestAction')
48
+ .where('id')
49
+ .equal(event.target.action.id)
50
+ .expand({
51
+ name: 'student',
52
+ options: {
53
+ $expand: 'person'
54
+ }
55
+ })
56
+ .silent()
57
+ .getItem();
58
+
59
+ } else if (typeof event.target.action === 'number' && Number.isInteger(event.target.action) && event.target.action > 0) {
60
+ item = await context
61
+ .model('DiningRequestAction')
62
+ .where('id')
63
+ .equal(event.target.action)
64
+ .expand({
65
+ name: 'student',
66
+ options: {
67
+ $expand: 'person'
68
+ }
69
+ })
70
+ .silent()
71
+ .getItem();
72
+ }
73
+
74
+ const application = await context
75
+ .model('WebApplication')
76
+ .where('alternateName')
77
+ .equal('students')
78
+ .and('applicationSuite')
79
+ .equal('universis')
80
+ .silent()
81
+ .getItem();
82
+
83
+ const config = await context
84
+ .model('StudentRequestConfiguration')
85
+ .where('additionalType')
86
+ .equal('DiningRequestAction')
87
+ .and('inLanguage')
88
+ .equal(event.target.inLanguage || context.locale)
89
+ .silent()
90
+ .getItem();
91
+
92
+ if (item && application && config) {
93
+
94
+ const email = item.student.person.email;
95
+
96
+ if (email == null || typeof email !== 'string') {
97
+ TraceUtils.warn(`Cannot send email for ${item.student.person.familyName} ${item.student.person.givenName}. Student [${item.student.id}] email does not exist.`);
98
+ return;
99
+ }
100
+ await new Promise((resolve) => {
101
+ mailer.template(mailTemplate.template)
102
+ .subject(mailTemplate.subject)
103
+ .bcc(mailTemplate.bcc || '')
104
+ .to(email)
105
+ .send({
106
+ model: item,
107
+ application: application,
108
+ configuration: config
109
+ }, (err) => {
110
+ if (err) {
111
+ try {
112
+ TraceUtils.error('An error occurred while trying to send an email notification after status change.');
113
+ TraceUtils.error(`Student=${item.student.id}, template=${mailTemplate.template}`);
114
+ TraceUtils.error(err);
115
+ } catch (err1) {
116
+ // do nothing
117
+ }
118
+ return resolve();
119
+ }
120
+
121
+ return resolve();
122
+ })
123
+ });
124
+
125
+ }
126
+ }
127
+ }
128
+ /**
129
+ * @param {DataEventArgs} event
130
+ * @param {Function} callback
131
+ */
132
+ export function afterSave(event, callback) {
133
+ return afterSaveAsync(event).then(() => {
134
+ return callback();
135
+ }).catch((err) => {
136
+ return callback(err);
137
+ });
138
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @param {DataEventArgs} event
3
+ * @param {Function} callback
4
+ */
5
+ import {DataError} from "@themost/common";
6
+
7
+ export function beforeSave(event, callback) {
8
+ (async () => {
9
+
10
+ // validate student state (on insert or update)
11
+ if (event.state === 1 || event.state === 2) {
12
+ let context = event.model.context;
13
+ /**
14
+ * @type {Student|DataObject|*}
15
+ */
16
+ const student = context.model('Student').convert(event.target.student);
17
+ // const isActive = await student.silent().isActive();
18
+ const isActive = await student.is(':active');
19
+ if (!isActive) {
20
+ throw new DataError('ERR_STATUS',
21
+ 'Invalid student status. Student Accommodation Card may be published upon an active student only.'+student
22
+ , null,
23
+ 'Student', 'studentStatus');
24
+ }
25
+
26
+ const studentObject = await context.model('Student').where('id').equal(student.id).silent().flatten().getItem();
27
+
28
+ const academicYear = context.model('AcademicYear').convert(event.target.academicYear).getId();
29
+ if (Number.isInteger(academicYear) === false) {
30
+ throw new DataError('E_VALUE', 'Invalid academic year. Expected number.', null, 'AcademicYear', 'id');
31
+ }
32
+
33
+ const academicYearObject = await context.model('AcademicYear').where('id').equal(academicYear).getItem();
34
+ if (academicYearObject === undefined){
35
+ throw new DataError('E_VALUE', 'Invalid academic year.', null, 'AcademicYear', 'id');
36
+ }
37
+
38
+ if (event.target.academicPeriod != null){
39
+
40
+ const academicPeriod = context.model('AcademicPeriod').convert(event.target.academicPeriod).getId();
41
+ if (Number.isInteger(academicPeriod) === false) {
42
+ throw new DataError('E_VALUE', 'Invalid academic period. Expected number.', null, 'AcademicPeriod', 'id');
43
+ }
44
+
45
+ const academicPeriodObject = await context.model('AcademicPeriod').where('id').equal(academicPeriod).getItem();
46
+ if (academicPeriodObject === undefined){
47
+ throw new DataError('E_VALUE', 'Invalid academic period.', null, 'AcademicPeriod', 'id');
48
+ }
49
+
50
+ }
51
+ }
52
+ })().then( () => {
53
+ return callback();
54
+ }).catch( err => {
55
+ return callback(err);
56
+ });
57
+ }
58
+
59
+
60
+ /**
61
+ * @param {DataEventArgs} event
62
+ * @param {Function} callback
63
+ */
64
+ export function afterSave(event, callback) {
65
+ (async () => {
66
+ //
67
+ let context = event.model.context;
68
+ if (event.state === 1) {
69
+ if (event.target.accommodationRoom && Object.keys(event.target.accommodationRoom).length != 0) {
70
+ // get accommodation valid through date
71
+
72
+ const room = await context.model('AccommodationRoom').where('id').equal(event.target.accommodationRoom.id).getItem();
73
+ if (room === undefined) {
74
+ throw new DataError('E_VALUE', 'Invalid accommodation room.', null, 'AccommodationRoom', 'id');
75
+ }
76
+ let newRoom = room;
77
+ newRoom.currentOccupancy = room.currentOccupancy+1;
78
+ //todo if i can increase occupancy
79
+ await context.model('AccommodationRoom').silent().save(newRoom);
80
+ }
81
+ }
82
+
83
+
84
+ })().then(() => {
85
+ return callback();
86
+ }).catch(err => {
87
+ return callback(err);
88
+ });
89
+ }
@@ -0,0 +1,69 @@
1
+ import { DataError } from '@themost/common';
2
+
3
+ async function afterSaveAsync(event) {
4
+ //
5
+ if (event.state !== 2) {
6
+ return;
7
+ }
8
+
9
+ const context = event.model.context;
10
+
11
+ const previous = event.previous;
12
+ if (previous == null) {
13
+ throw new DataError('E_PREVIOUS', 'The previous state of the object cannot be determined');
14
+ }
15
+
16
+
17
+ const previousStudentStatus = event.previous.studentStatus;
18
+ if (previousStudentStatus.alternateName === 'active' && event.target.studentStatus && event.target.studentStatus.alternateName != 'active') {
19
+
20
+ // find StudentAccommodationCard
21
+ const StudentAccommodationCard = await context.model('StudentAccommodationCards').where('student/id').equal(event.target.id).select('id', 'active', 'action', 'student', 'academicPeriod', 'academicYear')
22
+ .flatten().silent().getItem();
23
+
24
+ if (StudentAccommodationCard == null) {
25
+ return;
26
+ }
27
+
28
+ if (StudentAccommodationCard.active === false) {
29
+ return;
30
+ }
31
+
32
+ if (StudentAccommodationCard.active === true) {
33
+
34
+ StudentAccommodationCard.active = false
35
+ //save StudentAccommodationCard
36
+ await context.model('StudentAccommodationCard').save(StudentAccommodationCard);
37
+ }
38
+ }
39
+
40
+ }
41
+
42
+ // eslint-disable-next-line no-unused-vars
43
+ async function beforeSaveAsync(event) {
44
+ //
45
+ }
46
+
47
+ /**
48
+ * @param {DataEventArgs} event
49
+ * @param {Function} callback
50
+ */
51
+ export function beforeSave(event, callback) {
52
+ return beforeSaveAsync(event).then(() => {
53
+ return callback();
54
+ }).catch((err) => {
55
+ return callback(err);
56
+ });
57
+ }
58
+
59
+ /**
60
+ * @param {DataEventArgs} event
61
+ * @param {Function} callback
62
+ */
63
+ export function afterSave(event, callback) {
64
+ return afterSaveAsync(event).then(() => {
65
+ return callback();
66
+ }).catch((err) => {
67
+ return callback(err);
68
+ });
69
+ }