Fix bugs with dor lock charges
This commit is contained in:
@@ -3,9 +3,9 @@
|
||||
const moment = require('moment-timezone');
|
||||
const db = require('../../models/index');
|
||||
|
||||
const { incidentType, unlockedIncidentLevelsPrices, UNSCHEDULED_CHARGE_PRICE, MAX_BACK_TO_BACK_DIFFERENCE, UNSCHEDULED_TIME_RESOLUTION } = require('../../constants/constants');
|
||||
const { getUnlockEntryForReservation, getLockEntryForReservation } = require('../doorLock/doorLock');
|
||||
const { getAllFinishedBookings, getFirstReservationInBlock, getFirstPreviousBooking, getFirstNextBooking } = require('../officeRnD/bookings');
|
||||
const { doorLockEvents, incidentType, unlockedIncidentLevelsPrices, UNSCHEDULED_CHARGE_PRICE, MAX_BACK_TO_BACK_DIFFERENCE, UNSCHEDULED_TIME_RESOLUTION } = require('../../constants/constants');
|
||||
const { getUnlockEntryForReservation, getLockEntryForReservation, getEntriesBetween, getLastEntryForReservation } = require('../doorLock/doorLock');
|
||||
const { getAllFinishedBookings, getFirstPreviousBooking, getFirstNextBooking } = require('../officeRnD/bookings');
|
||||
|
||||
const getSortedIncidentsForMember = (memberId) => {
|
||||
const attributes = ['bookingStart', 'incidentLevel', 'incidentLevelPrice'];
|
||||
@@ -169,45 +169,6 @@ const setUnlockedIncidentsLevel = (incidentReservations) => {
|
||||
});
|
||||
};
|
||||
|
||||
const getUnlockEntryForBlockReservations = (lastReservation, firstReservation) => {
|
||||
return new Promise ((resolve, reject) => {
|
||||
analyseReservation(firstReservation)
|
||||
.then((result) => {
|
||||
const reservationBeforeFirstReservationInBlock = result.previousReservation;
|
||||
const unlockEntryForFirstReservation = result.unlockEntry;
|
||||
|
||||
if (unlockEntryForFirstReservation){
|
||||
resolve(unlockEntryForFirstReservation);
|
||||
}else{
|
||||
const fromTimestamp = reservationBeforeFirstReservationInBlock ?
|
||||
reservationBeforeFirstReservationInBlock.end :
|
||||
moment.utc(firstReservation.start).tz(UI_TIMEZONE).startOf('Day').toISOString();
|
||||
const toTimestamp = lastReservation.end;
|
||||
const { memberId, reservationId } = lastReservation;
|
||||
|
||||
const filters = {
|
||||
memberId,
|
||||
reservationId,
|
||||
event: doorLockEvents.USER_UNLOCKED,
|
||||
timestamp: {
|
||||
[Op.and]: [
|
||||
{[Op.gt]: fromTimestamp},
|
||||
{[Op.lte]: toTimestamp}
|
||||
]
|
||||
},
|
||||
};
|
||||
|
||||
db.doorLockEvent.findOne({where: filters})
|
||||
.then((anyUnlockEntryInBlock) => {
|
||||
resolve(anyUnlockEntryInBlock);
|
||||
})
|
||||
.catch((error) => reject(error));
|
||||
}
|
||||
})
|
||||
.catch((error) => reject(error));
|
||||
});
|
||||
};
|
||||
|
||||
const analyseReservation = (reservation) => {
|
||||
return new Promise ((resolve, reject) => {
|
||||
const getNearBookingsAsync = [
|
||||
@@ -223,7 +184,7 @@ const analyseReservation = (reservation) => {
|
||||
];
|
||||
|
||||
Promise.all(getRelatedDoorLockEntriesAsync)
|
||||
.then(([unlockEntry, lockEntry]) => {
|
||||
.then(([unlockEntry, lockEntry, entriesBetween]) => {
|
||||
const currentReservationStart = moment.utc(reservation.start);
|
||||
const currentReservationEnd = moment.utc(reservation.end);
|
||||
|
||||
@@ -288,20 +249,6 @@ const analyseReservation = (reservation) => {
|
||||
});
|
||||
};
|
||||
|
||||
const checkIfMemberEverEntered = (reservation) => {
|
||||
return new Promise ((resolve, reject) => {
|
||||
getFirstReservationInBlock(reservation)
|
||||
.then((firstReservationInBlock) => {
|
||||
getUnlockEntryForBlockReservations(reservation, firstReservationInBlock)
|
||||
.then((unlockEntry) => {
|
||||
resolve(!!unlockEntry);
|
||||
})
|
||||
.catch((error) => reject(error));
|
||||
})
|
||||
.catch((error) => reject(error));
|
||||
});
|
||||
};
|
||||
|
||||
const getIncidentData = (reservation) => {
|
||||
return new Promise ((resolve, reject) => {
|
||||
analyseReservation(reservation)
|
||||
@@ -326,6 +273,113 @@ const getIncidentData = (reservation) => {
|
||||
timeIntervalsToChargeAfter,
|
||||
} = result;
|
||||
const incidents = [];
|
||||
const incidentsAsyncJobs = [];
|
||||
const { resourceId } = currentReservation;
|
||||
|
||||
// 0a. Check for unscheduled use between current and previous reservation
|
||||
const analysePreviousJob = [];
|
||||
if (previousReservation && !previousReservationIsBackToBack){
|
||||
analysePreviousJob.push(analyseReservation(previousReservation));
|
||||
}else {
|
||||
analysePreviousJob.push(undefined);
|
||||
}
|
||||
|
||||
incidentsAsyncJobs.push(
|
||||
Promise.all(analysePreviousJob)
|
||||
.then(([previousReservationResults]) => {
|
||||
let fromTimestamp;
|
||||
let toTimestamp;
|
||||
|
||||
if (previousReservationResults){
|
||||
const previousReservationLockEntry = previousReservationResults.lockEntry;
|
||||
|
||||
fromTimestamp = previousReservationLockEntry && previousReservationLockEntry.timestamp ?
|
||||
previousReservationLockEntry.timestamp : previousReservation.end;
|
||||
toTimestamp = unlockEntry && unlockEntry.timestamp ?
|
||||
unlockEntry.timestamp : reservation.start;
|
||||
}else{
|
||||
fromTimestamp = undefined;
|
||||
toTimestamp = unlockEntry && unlockEntry.timestamp ?
|
||||
unlockEntry.timestamp : reservation.start;
|
||||
}
|
||||
|
||||
incidentsAsyncJobs.push(
|
||||
getEntriesBetween(fromTimestamp, toTimestamp, resourceId)
|
||||
.then((entriesBetween) => {
|
||||
incidentsAsyncJobs.push(
|
||||
new Promise((resolve, reject) => {
|
||||
let pairUnlockEntry = null;
|
||||
let pairLockEntry = null;
|
||||
|
||||
entriesBetween.forEach((entry) => {
|
||||
if (entry && entry.event){
|
||||
switch(entry.event){
|
||||
case doorLockEvents.USER_UNLOCKED:
|
||||
if (!pairUnlockEntry){
|
||||
pairUnlockEntry = entry;
|
||||
}else{
|
||||
const virtualReservation = {
|
||||
reservationId: '',
|
||||
start: pairUnlockEntry.timestamp,
|
||||
end: pairUnlockEntry.timestamp,
|
||||
memberId: pairUnlockEntry.memberId,
|
||||
resourceId,
|
||||
};
|
||||
|
||||
incidents.push({
|
||||
incidentType: incidentType.UNLOCKED_INCIDENT,
|
||||
reservation: virtualReservation,
|
||||
});
|
||||
|
||||
pairLockEntry = null;
|
||||
pairUnlockEntry = entry;
|
||||
}
|
||||
break;
|
||||
case doorLockEvents.USER_LOCKED:
|
||||
if (pairUnlockEntry && !pairLockEntry){
|
||||
pairLockEntry = entry;
|
||||
const virtualReservation = {
|
||||
reservationId: '',
|
||||
start: pairUnlockEntry.timestamp,
|
||||
end: pairLockEntry.timestamp,
|
||||
memberId: pairUnlockEntry.memberId,
|
||||
resourceId,
|
||||
};
|
||||
const unlockMoment = moment.utc(pairUnlockEntry.timestamp);
|
||||
const lockMoment = moment.utc(pairLockEntry.timestamp);
|
||||
const timeDifference = lockMoment.diff(unlockMoment, 'minutes');
|
||||
const timeIntervalsToCharge = Math.floor(timeDifference / UNSCHEDULED_TIME_RESOLUTION);
|
||||
const totalChargeFee = timeIntervalsToCharge * UNSCHEDULED_CHARGE_PRICE;
|
||||
if (timeIntervalsToCharge > 0){
|
||||
incidents.push({
|
||||
incidentType: incidentType.UNSCHEDULED_INCIDENT,
|
||||
reservation: virtualReservation,
|
||||
doorLockEntry: pairLockEntry,
|
||||
chargePrice: UNSCHEDULED_CHARGE_PRICE,
|
||||
timeIntervalsToCharge,
|
||||
totalChargeFee,
|
||||
});
|
||||
}
|
||||
|
||||
pairUnlockEntry = null;
|
||||
pairLockEntry = null;
|
||||
}else{
|
||||
if (!pairUnlockEntry){
|
||||
pairLockEntry = entry;
|
||||
//Only lock entry, ignore now
|
||||
}
|
||||
pairLockEntry = null;
|
||||
pairUnlockEntry = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
resolve(null);
|
||||
}));
|
||||
})
|
||||
.catch((error) => reject(error)));
|
||||
})
|
||||
.catch((error) => reject(error)));
|
||||
|
||||
// 1. Check if member entered before reservation start time
|
||||
if (unlockEntry && chargeBefore && !previousReservationIsBackToBack) {
|
||||
@@ -351,15 +405,45 @@ const getIncidentData = (reservation) => {
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Check if member forgot to lock door
|
||||
if (unlockEntry && !lockEntry && !nextReservationIsBackToBack){
|
||||
incidents.push({
|
||||
incidentType: incidentType.UNLOCKED_INCIDENT,
|
||||
reservation,
|
||||
});
|
||||
// 3. Check if member forgot to lock the door
|
||||
if (!lockEntry && !nextReservationIsBackToBack){
|
||||
if (unlockEntry){
|
||||
incidents.push({
|
||||
incidentType: incidentType.UNLOCKED_INCIDENT,
|
||||
reservation,
|
||||
});
|
||||
} else {
|
||||
// No lock entry, no unlock entry and no reservation after this one
|
||||
// This is either :
|
||||
// 1. Last reservation in block of N reservations
|
||||
// 1a. Member locked before entering this reservation
|
||||
// 1b. Member forgot to lock the door <<< Only this is real incident
|
||||
// 2. One reservation, but member never entered
|
||||
|
||||
if (previousReservationIsBackToBack){
|
||||
// To ensure that this is last reservation in block (there is previous but no next reservation back to back)
|
||||
// Now, just check if member actually locked before in the reservation time
|
||||
incidentsAsyncJobs.push(
|
||||
getLastEntryForReservation(reservation)
|
||||
.then((lastEntry) => {
|
||||
if (lastEntry && lastEntry.event === doorLockEvents.USER_UNLOCKED){
|
||||
incidents.push({
|
||||
incidentType: incidentType.UNLOCKED_INCIDENT,
|
||||
reservation,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => reject(error)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve(incidents);
|
||||
Promise.all(incidentsAsyncJobs)
|
||||
.then(() => {
|
||||
resolve(incidents);
|
||||
})
|
||||
.catch((error) => reject(error));
|
||||
|
||||
})
|
||||
.catch((error) => reject(error));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user