Files
old-psihologija/services/officeRnD/bookings.js

326 lines
13 KiB
JavaScript

'use strict';
const db = require('../../models/index');
const moment = require('moment-timezone');
const Op = require('sequelize').Op;
const { API } = require('../../helpers/api');
const { officeRnDAPIErrors, MAX_BACK_TO_BACK_DIFFERENCE } = require('../../constants/constants');
const fetchAllBookings = () => {
return new Promise((resolve, reject) => {
API.get('/bookings')
.then((result) => {
const cleanedBookingReservations = [];
const bookingData = result && result.data ? result.data : [];
bookingData.forEach((fullBookingEntry) => {
const fees = fullBookingEntry && fullBookingEntry.fees ? fullBookingEntry.fees : [];
const startMoment = fullBookingEntry && fullBookingEntry.start && fullBookingEntry.start.dateTime ?
moment.utc(fullBookingEntry.start.dateTime) : null;
const endMoment = fullBookingEntry && fullBookingEntry.end && fullBookingEntry.end.dateTime ?
moment.utc(fullBookingEntry.end.dateTime) : null;
// console.log('\r\n\r\nStart : ', startMoment.clone().tz(fullBookingEntry.timezone).format('DD.MM. HH:mm'), '[', startMoment.toISOString(),']');
// console.log('End : ', endMoment.clone().tz(fullBookingEntry.timezone).format('DD.MM. HH:mm'), '[', endMoment.toISOString(), ']');
// console.log('Fees : ');
fees.forEach((feeElement, index) => {
const fee = feeElement.fee ? feeElement.fee : null;
const dateMoment = feeElement.date ? moment.utc(feeElement.date) : null;
const feeId = fee && fee['_id'] ? fee['_id'] : '0';
const hourlyRate = fee && fee.price ? fee.price : 0;
if (startMoment && endMoment && dateMoment){
// console.log('\tOriginal date : ', dateMoment.format('DD.MM'));
const yearPart = dateMoment.year();
const monthPart = dateMoment.month();
const dayPart = dateMoment.date();
// console.log('\t\tYear part : ', yearPart);
// console.log('\t\tMonth part: ', monthPart);
// console.log('\t\tDay part : ', dayPart);
const newStartMoment = startMoment.clone().tz(fullBookingEntry.timezone).year(yearPart).month(monthPart).date(dayPart);
const newEndMoment = endMoment.clone().tz(fullBookingEntry.timezone).year(yearPart).month(monthPart).date(dayPart);
// console.log('\tNew start : ', newStartMoment.format('DD.MM. HH:mm'), '[', newStartMoment.toISOString(), ']');
// console.log('\tNew end : ', newEndMoment.format('DD.MM. HH:mm'), '[', newEndMoment.toISOString(), ']');
// console.log('\t----------------------------');
cleanedBookingReservations.push({
reservationId: `${fullBookingEntry['_id']}-${index}`,
memberId: fullBookingEntry.member,
officeId: fullBookingEntry.office,
resourceId: fullBookingEntry.resourceId,
start: newStartMoment.toISOString(),
end: newEndMoment.toISOString(),
timezone: fullBookingEntry.timezone,
canceled: fullBookingEntry.canceled || false,
hourlyRate,
});
}
});
if (fees.length === 0){
cleanedBookingReservations.push({
reservationId: `${fullBookingEntry['_id']}-0`,
memberId: fullBookingEntry.member,
officeId: fullBookingEntry.office,
resourceId: fullBookingEntry.resourceId,
start: startMoment.toISOString(),
end: endMoment.toISOString(),
timezone: fullBookingEntry.timezone,
canceled: fullBookingEntry.canceled || false,
hourlyRate: 0,
});
}
});
resolve(cleanedBookingReservations);
})
.catch((error) => {
console.log(officeRnDAPIErrors.FAILED_TO_FETCH_BOOKINGS);
console.log('Details : ', error);
reject(officeRnDAPIErrors.FAILED_TO_FETCH_BOOKINGS);
});
});
};
const getAllFinishedBookings = () => {
const attributes = ['reservationId', 'memberId', 'resourceId', 'start', 'end', 'timezone'];
const filters = {
canceled: false,
end: {
[Op.lt]: moment.utc().toISOString()
}
};
return db.bookingReservation.findAll({
attributes,
where: filters,
order: [
['start', 'ASC'],
]
})
};
const getFirstNextBooking = (reservation) => {
return new Promise ((resolve, reject) => {
const { resourceId, start } = reservation;
const attributes = ['reservationId', 'memberId', 'resourceId', 'start', 'end', 'timezone'];
const filters = {
canceled: false,
start: {
[Op.gt]: start
},
resourceId,
};
const order = [['start', 'ASC']];
db.bookingReservation.findAll({
attributes,
where: filters,
order,
})
.then((reservations) => {
if (reservations && reservations[0]){
resolve(reservations[0]);
}else{
resolve(undefined);
}
})
.catch((error) => reject(error));
});
};
const getFirstPreviousBooking = (reservation) => {
return new Promise ((resolve, reject) => {
const { resourceId, start } = reservation;
const attributes = ['reservationId', 'memberId', 'resourceId', 'start', 'end', 'timezone'];
const filters = {
canceled: false,
end: {
[Op.lte]: start
},
resourceId,
};
const order = [['end', 'DESC']];
db.bookingReservation.findAll({
attributes,
where: filters,
order,
})
.then((reservations) => {
if (reservations && reservations[0]){
resolve(reservations[0]);
}else{
resolve(undefined);
}
})
.catch((error) => reject(error));
});
};
const getFirstReservationInBlock = (reservation) => {
return new Promise ((resolve, reject) => {
const { resourceId, memberId, start } = reservation;
const fromTimestamp = moment.utc(start).subtract(MAX_BACK_TO_BACK_DIFFERENCE).toISOString();
const toTimestamp = start;
const filters = {
resourceId,
memberId,
end: {
[Op.and]: [
{[Op.gte]: fromTimestamp},
{[Op.lte]: toTimestamp}
]
}
};
db.bookingReservation.findOne({where: filters})
.then((previousReservation) => {
if (!previousReservation) {
resolve(reservation);
} else {
resolve(getFirstReservationInBlock(previousReservation));
}
})
.catch((error) => reject(error));
});
};
const writeBookingReservation = (bookingReservation) => {
const { reservationId, memberId, officeId, resourceId, start, end, timezone, canceled, hourlyRate } = bookingReservation;
const bookingReservationForDB = {
reservationId,
memberId,
officeId,
resourceId,
start,
end,
timezone,
canceled,
hourlyRate,
};
return db.bookingReservation.findOrCreate({where: {...bookingReservationForDB}, defaults: {...bookingReservationForDB}});
};
const bulkWriteReservationsWithChangesTracking = (reservations, resourcesMap) => {
return new Promise ((resolve, reject) => {
const changes = [];
const asyncJobs = [];
db.bookingReservation.addHook('beforeUpdate', 'updateHook', (instance) => {
const changedKeys = instance.changed();
const previous = instance.previous();
const lookupKeys = ['start', 'end', 'resourceId', 'canceled'];
let realChange = false;
lookupKeys.forEach((key) => {
if ((changedKeys.indexOf(key) !== -1) &&
(JSON.stringify(previous[key]) !== JSON.stringify(instance[key]))){
realChange = true;
}
});
const previousResourceId = instance.previous('resourceId');
const currentResourceId = instance.resourceId;
const resourceId = currentResourceId ? currentResourceId : previousResourceId;
if (instance.hourlyRate === 0 || isNaN(instance.hourlyRate)){
if (parseFloat(instance.previous('hourlyRate') > 0)) {
instance.setDataValue('hourlyRate', instance.previous('hourlyRate'));
}else{
//Determine if we should apply weekend price or work day price
const newStartWeekDay = moment.utc(instance.start).isoWeekday();
const isWeekend = newStartWeekDay > 5; //6 - Saturday, 7 - Sunday
let hourlyRate;
if (isWeekend){
hourlyRate = resourceId ? resourcesMap[resourceId].price.weekendPrice : 0;
}else{
hourlyRate = resourceId ? resourcesMap[resourceId].price.price : 0;
}
instance.setDataValue('hourlyRate', hourlyRate);
}
}
if (realChange){
changes.push({
oldReservation: previous,
newReservation: instance.get(),
});
}
});
const newReservations = [];
const asyncReservationUpdate = (reservation) => {
return new Promise((resolve, reject) => {
db.bookingReservation.update(reservation, {
where: {
reservationId: reservation.reservationId,
},
returning: true,
individualHooks: true,
})
.then(([updateCount, updatedInstances]) => {
try {
if (updateCount === 0) {
const oldReservation = {
start: null,
end: null,
resourceId: null,
};
changes.push({
oldReservation,
newReservation: reservation,
});
newReservations.push(reservation);
}
resolve();
}catch (e) {
console.log('CATCH E : ', e);
reject(e);
}
})
.catch((error) => {
console.log('Error updating');
console.log(error);
reject(error);
});
});
};
reservations.forEach((reservation) => asyncJobs.push(asyncReservationUpdate(reservation)));
Promise.all(asyncJobs)
.then(() => {
db.bookingReservation.removeHook('updateHook');
db.bookingReservation.bulkCreate(newReservations)
.then(() => resolve(changes))
.catch((error) => reject(error));
})
.catch((error) => reject(error));
});
};
module.exports = {
fetchAllBookings,
writeBookingReservation,
getAllFinishedBookings,
getFirstNextBooking,
getFirstPreviousBooking,
getFirstReservationInBlock,
bulkWriteReservationsWithChangesTracking,
};