'use strict'; const moment = require('moment-timezone'); const db = require('../../models/index'); const Op = require('sequelize').Op; const { UI_TIMEZONE, BOOKING_CHANGE_PERCENTAGE_CHARGE, CHARGE_BOOKING_CHANGE_UNDER_TIME, ALLOWED_BOOKING_CANCELLATION_TIME, incidentType } = require('../../constants/constants'); const bulkWriteBookingChangeIncidents = (incidents) => { return new Promise((resolve, reject) => { const asyncJobs = []; incidents.forEach((incident) => { asyncJobs.push(db.bookingChangeIncident.findOrCreate({where: incident, defaults: incident})); }); Promise.all(asyncJobs) .then(() => { resolve(); }) .catch((error) => reject(error)); }); }; const chargeBookingChanges = (changes) => { return new Promise((resolve, reject) => { if (Array.isArray(changes)){ const incidents = []; changes.forEach((change) => { const { oldReservation, newReservation } = change; if (oldReservation && newReservation){ const oldResourceId = oldReservation.resourceId; const oldStart = oldReservation.start ? moment.utc(oldReservation.start) : null; const oldEnd = oldReservation.end ? moment.utc(oldReservation.end) : null; const newStart = newReservation.start ? moment.utc(newReservation.start) : null; const newEnd = newReservation.end ? moment.utc(newReservation.end) : null; const reservationCreationTimestamp = newReservation.createdAt ? moment.utc(newReservation.createdAt) : null; const reservationTimezone = newReservation.timezone ? newReservation.timezone : UI_TIMEZONE; const reservationHourlyRate = oldReservation.hourlyRate ? oldReservation.hourlyRate : newReservation.hourlyRate; const canceled = newReservation.canceled; if (oldStart && oldEnd && newStart && newEnd && reservationHourlyRate){ const oldReservationLength = oldEnd.diff(oldStart, 'hours', true); const newReservationLength = newEnd.diff(newStart, 'hours', true); const differenceFromNow = oldStart.diff(moment.utc(), 'minutes'); if (differenceFromNow < CHARGE_BOOKING_CHANGE_UNDER_TIME){ const { reservationId, memberId, resourceId } = newReservation; if (!canceled) { // Check if new reservation is on same day const sameDay = oldStart.tz(reservationTimezone).isSame(newStart.tz(reservationTimezone), 'day'); if (sameDay) { // Reservation moved in same day // Check if member shortened the reservation if (newReservationLength < oldReservationLength) { const differenceInLength = oldReservationLength - newReservationLength; const chargeFee = differenceInLength * reservationHourlyRate * BOOKING_CHANGE_PERCENTAGE_CHARGE / 100; const incident = { reservationId, memberId, oldResourceId: oldResourceId || resourceId, newResourceId: resourceId, oldBookingStart: oldReservation.start, oldBookingEnd: oldReservation.end, newBookingStart: newReservation.start, newBookingEnd: newReservation.end, incidentType: incidentType.BOOKING_SHORTENED, chargeFee, }; incidents.push(incident); } } else { // Reservation moved to another day // Add cancellation charge const chargeFee = oldReservationLength * reservationHourlyRate * BOOKING_CHANGE_PERCENTAGE_CHARGE / 100; const incident = { reservationId, memberId, oldResourceId: oldResourceId || resourceId, newResourceId: resourceId, oldBookingStart: oldReservation.start, oldBookingEnd: oldReservation.end, newBookingStart: newReservation.start, newBookingEnd: newReservation.end, incidentType: incidentType.BOOKING_MOVED_TO_ANOTHER_DAY, chargeFee, }; incidents.push(incident); } }else{ const differenceFromCreation = moment.utc().diff(reservationCreationTimestamp, 'minutes'); if (differenceFromCreation > ALLOWED_BOOKING_CANCELLATION_TIME){ const chargeFee = reservationHourlyRate * oldReservationLength * BOOKING_CHANGE_PERCENTAGE_CHARGE / 100; const incident = { reservationId, memberId, oldResourceId: oldResourceId || resourceId, newResourceId: null, oldBookingStart: oldReservation.start, oldBookingEnd: oldReservation.end, newBookingStart: null, newBookingEnd: null, incidentType: incidentType.BOOKING_CANCELED_LATE, chargeFee, }; incidents.push(incident); } } } } } }); resolve(bulkWriteBookingChangeIncidents(incidents)); }else{ reject('Input argument is not an array !'); } }); }; const getChargedCanceledReservations = (reservationIds) => { const filters = { reservationId: { [Op.in]: reservationIds, }, incidentType: incidentType.BOOKING_CANCELED_LATE, }; const attributes = ['memberId', 'oldBookingStart', 'oldBookingEnd']; return db.bookingChangeIncident.findAll({attributes, where: filters}); }; module.exports = { chargeBookingChanges, getChargedCanceledReservations, };