UNPKG

@universis/dining

Version:

Universis api for dining

194 lines (164 loc) 8.08 kB
import {DataObject, EdmMapping, EdmType} from '@themost/data'; import {Args, DataError, DataNotFoundError, TraceUtils} from "@themost/common" import moment from 'moment'; /** * @class * @property {number} id * @property {number} serialNumber * @property {boolean} active * @property {string} cancelReason * @property {string} notes * @property {DiningRequestAction|any} action * @property {AcademicYear|any} academicYear * @property {AcademicPeriod|any} academicPeriod * @property {Date} dateCreated * @property {Date} dateModified * @property {Date} validFrom * @property {Date} validThrough * @property {User|any} student */ @EdmMapping.entityType('StudentDiningCard') class StudentDiningCard extends DataObject { /** * @constructor */ constructor() { super(); } /** * POST StudentDiningCards/:id/Cancel */ @EdmMapping.param('data', 'Object', false, true) @EdmMapping.action('cancel', 'StudentDiningCard') async cancel(data) { if (!data.cancelReason) { throw new DataError('E_CANCEL_REASON', 'Cancel Reason should be provided'); } await this.context.executeInTransactionAsync(async () => { // find StudentDiningCard from id const studentDiningCard = await this.context.model('StudentDiningCard') .where('id') .equal(this.getId()) .select('id', 'active', 'action', 'student', 'academicPeriod', 'academicYear') .flatten() .getItem(); // validate existance and permission if (studentDiningCard == null) { throw new DataNotFoundError('The specified Student Dining Card cannot be found or is inaccessible'); } // studentDiningCard already cancelled throw error if (studentDiningCard.active === false) { throw new DataError('E_ACTIVE', 'The specified Student Dining Card is already cancelled') } //validate DiningRequestAction if (studentDiningCard.action == null) { throw new DataError('E_ACTION', 'The Student Dining Card is not linked to a Dining Request Action') } // cancel studentDiningCard studentDiningCard.active = false; studentDiningCard.cancelReason = data.cancelReason; studentDiningCard.dateCancelled = new Date(); await this.context.model('StudentDiningCard').save(studentDiningCard); const action = await this.context.model('DiningRequestAction').where('id').equal(studentDiningCard.action).select('id', 'actionStatus/alternateName as requestStatus').getItem(); //validate DiningRequestAction if (action == null) { throw new DataError('E_ACTION', 'The specified DiningRequestAction cannot be found or is inaccessible') } if (action.requestStatus !== 'CompletedActionStatus') { throw new DataError('E_ACTION', 'The specified DiningRequestAction is not in Completed state') } action.actionStatus = { alternateName: "ActiveActionStatus" } delete action.requestStatus; await this.context.model('DiningRequestAction').save(action); }); } /** * POST StudentDiningCards/analytics */ @EdmMapping.param('data', 'Object', false, true) @EdmMapping.action('analytics', EdmType.CollectionOf('StudentDiningCard')) static async analytics(context, data) { Args.notEmpty(data, 'Data'); Args.notEmpty(data.validFrom, 'Valid from'); Args.notEmpty(data.validThrough, 'Valid through'); const validFrom = moment(new Date(data.validFrom)).startOf('day').toDate(); // get only date format const validThrough = moment(new Date(data.validThrough)).endOf('day').toDate(); // get only date format const model = context.model('StudentDiningCard'); const queryCards = model.where('date(validThrough)').greaterOrEqual(validFrom).and('date(validFrom)').lowerOrEqual(validThrough); if (data.department) { const localDepartment = await context.model('LocalDepartment').where('id').equal(data.department).getItem(); if (localDepartment == null) { throw new DataNotFoundError('Department not found or is inaccessible.', null, 'LocalDepartment'); } queryCards.and('student/department').equal(data.department); } if (data.location) { Args.notNumber(data.location, 'Location'); const location = await context.model('DiningPlace').where('id').equal(data.location).getItem(); if (location == null) { throw new DataNotFoundError('Location not found or is inaccessible.', null, 'DiningPlace'); } queryCards.and('location').equal(data.location); } const cards = await queryCards.getAllItems(); const dates = enumerateDaysBetweenDates(validFrom, validThrough); let previousActive = 0; for (let i = 0; i < dates.length; i++) { const checkDate = dates[i].date; dates[i].active = cards.filter(x => { const startDate = moment(new Date(x.validFrom)).startOf('day').toDate(); let endDate = x.dateCancelled || x.validThrough; endDate = moment(new Date(endDate)).startOf('day').toDate(); return moment(endDate) >= moment(checkDate) && moment(startDate) <= moment(checkDate); }).length; // Delta is a commonly used term in mathematics and science to represent the difference or change between two values. dates[i].delta = dates[i].active - previousActive; previousActive = dates[i].active; } return dates; } /** * POST StudentDiningCards/CancelExpired */ @EdmMapping.param('data', 'Object', false, true) @EdmMapping.action('cancelExpired', EdmType.CollectionOf('Object')) static async cancelExpired(context, data) { const translateService = context.application.getStrategy(function TranslateService() { }); const todayDate = moment(new Date()).startOf('day').toDate(); // if there are find active diningCards that have expired const cardsToCancel = await context.model('StudentDiningCards') .where('active') .equal(true) .and('validThrough') .lowerThan(todayDate) .silent() .getAllItems(); // if there are, set active to false, set system cancelReason and save if (Array.isArray(cardsToCancel)) { if (cardsToCancel.length > 0) { const cancelReason = data.cancelReason || translateService.translate('StudentDiningCardSystemCancelReasonDiningRequestEventExpired'); cardsToCancel.map((el) => { el.active = false; el.cancelReason = cancelReason; el.dateCancelled = new Date(); return el; }); await context.model('StudentDiningCard').silent().save(cardsToCancel); } TraceUtils.log("Dining: Automatically Canceled " + cardsToCancel.length + " StudentDiningCards"); return { "totalCancelled": cardsToCancel.length }; } } } function enumerateDaysBetweenDates (startDate, endDate){ let firstDate = moment(startDate).format('YYYY-MM-DD'); const dates = []; while(moment(firstDate) <= moment(endDate)){ dates.push({date:firstDate, active:0}); firstDate = moment(firstDate).add(1, 'days').format("YYYY-MM-DD"); } return dates; } module.exports = StudentDiningCard;