UNPKG

@universis/dining

Version:

Universis api for dining

276 lines (242 loc) 13.2 kB
import { DataError } from "@themost/common"; import { DataObject, EdmMapping } from "@themost/data"; @EdmMapping.entityType('DiningRequestEvent') class DiningRequestEvent extends DataObject { /** * @constructor */ constructor() { super(); } /** * POST DiningRequestEvents/:id/Remove */ //remove dining request event @EdmMapping.param('data', 'Object', false, true) @EdmMapping.action('remove', 'DiningRequestEvent') async remove(data) { /** * @type {import('@themost/data').DataModel} */ const model = this.getModel(); const item = await model.where('id') .equal(this.getId()) .getItem(); const translateService = this.context.application.getStrategy(function TranslateService() { }); if (item == null) { throw new DataError('E_DINING_REQUEST_EVENT', translateService.translate('The specified DiningRequestEvent cannot be found or is inaccessible.')); } const hasActions = await this.context.model('DiningRequestAction') .where('diningRequestEvent').equal(item.id).count(); if (hasActions) { throw new DataError('E_DINING_REQUESTS_EXISTS', translateService.translate('Cannot remove dining request event. Dining request event is related to requests.'), null, 'DiningRequestEvent'); } return model.silent().remove(item); } /** * POST DiningRequestEvents/:id/Extend */ /** * @returns {DiningRequestEvent} */ //extend dining request event @EdmMapping.param("data", "Object", false, true) @EdmMapping.action('extend', 'DiningRequestEvent') async extend(data) { const model = this.getModel(); const previous = await model.where('id') .equal(this.getId()) .getItem(); const target = data.event; const translateService = this.context.application.getStrategy(function TranslateService() { }); if (previous == null) { throw new DataError('E_DINING_REQUEST_EVENT', translateService.translate('The specified DiningRequestEvent cannot be found or is inaccessible.')); } if (previous.eventStatus && previous.eventStatus.alternateName !== 'EventOpened' && target.eventStatus && target.eventStatus.alternateName !== 'EventOpened') { throw new DataError('E_EVENT_STATUS', translateService.translate('The DiningRequestEvent can only be extended when it is open.')); } if ((target.validThrough && target.validFrom) && target.validThrough < target.validFrom) { throw new DataError('E_DATES', translateService.translate('ValidThrough date cannot be earlier than validFrom date.')); } const today = new Date().toISOString(); if (previous.validThrough && previous.validThrough <= today) { throw new DataError('E_DATES', translateService.translate('The DiningRequestEvent can only be extended if it has not already expired.')); } if (previous.eventStatus && previous.eventStatus.alternateName === 'EventOpened') { const validThroughChange = previous.validThrough && previous.validThrough.toISOString() !== target.validThrough.toISOString(); const endDateChange = previous.endDate && previous.endDate.toISOString() !== target.endDate.toISOString(); if (validThroughChange || endDateChange) { const actionItem = { object: previous.id, currentValidThrough: validThroughChange === true ? previous.validThrough : null, validThrough: validThroughChange === true ? target.validThrough : null, currentEndDate: endDateChange === true ? previous.endDate : null, endDate: endDateChange === true ? target.endDate : null, status: previous.eventStatus, description: validThroughChange === true ? (endDateChange === true ? translateService.translate('END_DATE_VALID_THROUGH_DATE') : translateService.translate('VALID_THROUGH_DATE')) : translateService.translate('END_DATE') }; const action = await this.context.model('UpdateDiningRequestEventAction').save(actionItem); if (action) { return await this.context.model('DiningRequestEvent').save(target).then(async res => { if (res) { const response = res; let sseUser; sseUser = this.context.user || await this.context.model('User'); // check if there are active cards to extend const cards = await this.context.model('StudentDiningCards') .where('student/studentStatus/alternateName').equal('active') .or('student/studentStatus/alternateName').equal('declared') .prepare() .and('active').equal(true) .and('action/diningRequestEvent/id').equal(previous.id) .and('action/actionStatus/alternateName').equal('CompletedActionStatus') .count(); if (validThroughChange === true && cards) { Promise.all([ action, this.handleStudentDiningCards(res, action) ]).then(([actionResult]) => { this.sendSse(sseUser, this.context, actionResult, null); return; }).catch(err => { this.sendSse(sseUser, this.context, action, err); }); } else { action.totalCards = action.totalCardsAffected = 0; action.actionResult = translateService.translate('The process was completed successfully.'); action.actionStatus = { alternateName: 'CompletedActionStatus' }; await this.context.model('UpdateDiningRequestEventAction').save(action); this.sendSse(sseUser, this.context, action, null); } return response; } else { //set action status fail action.actionResult = translateService.translate('Error occured while trying to extend DiningRequestEvent.') action.actionStatus = { alternateName: 'FailedActionStatus' }; await this.context.model('UpdateDiningRequestEventAction').save(action); return false; } }) } } else { return false; } } } sendSse(user, context, updateEventAction, error) { // try to find ServerSentEventService const sse = context.getApplication().getService(function ServerSentEventService() {}); // only if it exists - it is not required if (sse != null) { if (user != null && updateEventAction != null) { // create an event const event = { entitySet: "UpdateDiningRequestEventActions", entityType: "UpdateDiningRequestEventAction", target: { id: updateEventAction.id, object: updateEventAction.object.id || updateEventAction.object, actionResult: updateEventAction.actionResult }, status: { success: true, }, dateCreated: new Date() } if (error) { Object.assign(event, { status: { success: false }, error: { message: error.code || error.message } }) } // and send it to the user that is performing the approval (dining scope) sse.emit(user.name, user.authenticationScope || "dining", event); } } } /** * @returns Promise<ValidationResult[]> */ async handleStudentDiningCards(event, action) { const translateService = this.context.application.getStrategy(function TranslateService() { }); const model = this.getModel(); const eventNext = await model.where('id') .equal(event.id) .getItem(); if (!eventNext) { action.actionResult = translateService.translate('The specified DiningRequestEvent cannot be found or is inaccessible.') action.actionStatus = { alternateName: 'FailedActionStatus' }; await this.context.model('UpdateDiningRequestEventAction').save(action); throw new DataError('E_DINING_REQUEST_EVENT', translateService.translate('The specified DiningRequestEvent cannot be found or is inaccessible.')); } /** * Try to update valid through date of active student dining cards * Do not throw errors, but catch the procedure errors */ let actionItem = action; let cardResults = []; const diningCardsToChange = await this.context.model('StudentDiningCards') .where('student/studentStatus/alternateName').equal('active') .or('student/studentStatus/alternateName').equal('declared') .prepare() .and('active').equal(true) .and('action/diningRequestEvent/id').equal(eventNext.id) .and('action/actionStatus/alternateName').equal('CompletedActionStatus') .expand({ name: 'student', options: { $expand: 'studentStatus' } }) .getItems(); // extend all active diningCards // let index = 0; // debugging purposes for (const item of diningCardsToChange) { try { // update only validThrough date // property student is required // check if studentStatus allows card to be updated (active and declared actionStatus) if (item && item.student && item.student.studentStatus && item.student.studentStatus.alternateName && (item.student.studentStatus.alternateName === 'active' || item.student.studentStatus.alternateName === 'declared')){ const itemNext = { id: item.id, validThrough: eventNext.validThrough, student: item.student }; await this.context.model('StudentDiningCards').save(itemNext); } } catch (err) { // if err catch on cardResults const res = item && item.action && item.action.requestNumber cardResults.push(res) } // index ++; // debugging purposes } // return result try { actionItem.totalCards = diningCardsToChange.length; actionItem.totalCardsAffected = diningCardsToChange.length - cardResults.length; if (cardResults && cardResults.length === 0) { //set action status completed actionItem.actionStatus = { alternateName: 'CompletedActionStatus' }; actionItem.actionResult = translateService.translate('The process was completed successfully.'); } else { //set action status fail actionItem.actionStatus = { alternateName: 'FailedActionStatus' }; actionItem.actionResult = translateService.translate('Error occured while trying to update student dining cards') + '<br>' + cardResults.join("<br>"); } const res = await this.context.model('UpdateDiningRequestEventActions').save(actionItem); } catch (err) { let sseUser; sseUser = this.context.user || await this.context.model('User'); this.sendSse(sseUser, this.context, action, null); throw new DataError('E_UPDATE_ACTION', 'Error occured while trying to update the UpdateDiningRequestEventAction.'); } } } module.exports = DiningRequestEvent;