From c1f3f423686a3706ba101f13379eb5c4be7fa761 Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Wed, 25 Dec 2019 16:41:05 +0100 Subject: [PATCH 1/3] match unlock entry before first reservation in a block --- services/doorLock/doorLock.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/services/doorLock/doorLock.js b/services/doorLock/doorLock.js index 1171261..c50b2cd 100644 --- a/services/doorLock/doorLock.js +++ b/services/doorLock/doorLock.js @@ -19,7 +19,7 @@ const { const { fetchAllMembers } = require('../officeRnD/members'); const { getMappingsFromDatabase } = require('../officeRnD/resources'); -const { getFirstReservationInBlock } = require('../officeRnD/bookings'); +const { getFirstReservationInBlock, getFirstPreviousBooking } = require('../officeRnD/bookings'); const extractMappingFromFileName = (fileName) => { const contentBetweenBracketsRegex = /\[(.*?)\]/; @@ -425,11 +425,25 @@ const getLastEntryForReservation = (reservation) => { const order = [['timestamp', 'DESC']]; db.doorLockEvent.findAll({where: filters, order}) - .then((entries) => { + .then(async(entries) => { if (entries && entries.length > 0){ resolve(entries[0]); } else { - resolve (undefined); + //No entry found in this block of reservations, now check if there is unlock entry for the first reservation in block, before reservation start time + + try { + const firstPreviousBookingBeforeFirstInBlock = await getFirstPreviousBooking(firstReservationInBlock); + const unlockEntryForFirstInBlock = await getUnlockEntryForReservation(firstReservationInBlock, firstPreviousBookingBeforeFirstInBlock); + + if (unlockEntryForFirstInBlock){ + resolve(unlockEntryForFirstInBlock); + }else{ + resolve(undefined); + } + + }catch (e) { + reject(e); + } } }) .catch((error) => reject(error)); From 87d7193bb91f5eac1028863e53c068fe34640ed7 Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Thu, 26 Dec 2019 02:30:03 +0100 Subject: [PATCH 2/3] add method for finding last reservation in a block --- services/officeRnD/bookings.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/services/officeRnD/bookings.js b/services/officeRnD/bookings.js index 35b4fa5..5d390a6 100644 --- a/services/officeRnD/bookings.js +++ b/services/officeRnD/bookings.js @@ -244,6 +244,32 @@ const getFirstReservationInBlock = (reservation) => { }); }; +const getLastReservationInBlock = async (reservation) => { + const { resourceId, memberId, end } = reservation; + + const toTimestamp = moment.utc(end).add(MAX_BACK_TO_BACK_DIFFERENCE).toISOString(); + const fromTimestamp = end; + + const filters = { + resourceId, + memberId, + start: { + [Op.and]: [ + {[Op.gte]: fromTimestamp}, + {[Op.lte]: toTimestamp} + ] + } + }; + + const nextReservation = await db.bookingReservation.findOne({where: filters}); + if (!nextReservation) { + return reservation; + } else { + return getLastReservationInBlock(nextReservation); + } + +}; + const writeBookingReservation = (bookingReservation) => { const { reservationId, memberId, officeId, resourceId, start, end, timezone, canceled, hourlyRate } = bookingReservation; const bookingReservationForDB = { @@ -369,5 +395,6 @@ module.exports = { getFirstNextBooking, getFirstPreviousBooking, getFirstReservationInBlock, + getLastReservationInBlock, bulkWriteReservationsWithChangesTracking, }; From b2450faa0cb7aa574d4f2904cbcdd18e82f840ba Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Thu, 26 Dec 2019 02:31:40 +0100 Subject: [PATCH 3/3] add special check for unscheduled use in brake between reservations --- services/integration/doorLockCharges.js | 172 ++++++++++++++++++------ 1 file changed, 129 insertions(+), 43 deletions(-) diff --git a/services/integration/doorLockCharges.js b/services/integration/doorLockCharges.js index cdefd66..d331a37 100644 --- a/services/integration/doorLockCharges.js +++ b/services/integration/doorLockCharges.js @@ -15,7 +15,7 @@ const { UI_TIMEZONE } = require('../../constants/constants'); const { getUnlockEntryForReservation, getLockEntryForReservation, getEntriesBetween, getLastEntryForReservation } = require('../doorLock/doorLock'); -const { getAllFinishedBookings, getFirstPreviousBooking, getFirstNextBooking } = require('../officeRnD/bookings'); +const { getAllFinishedBookings, getFirstPreviousBooking, getFirstNextBooking, getLastReservationInBlock } = require('../officeRnD/bookings'); const getSortedIncidentsForMember = (memberId) => { const attributes = ['bookingStart', 'incidentLevel', 'incidentLevelPrice', 'unlockTimestamp']; @@ -368,7 +368,7 @@ const getIncidentData = (reservation) => { const { resourceId } = currentReservation; // const reservationMoment = moment.tz(currentReservation.start, currentReservation.timezone); - // if (currentReservation.memberId === '5ce785af422bdd00967fb781' && reservationMoment.isAfter('2019-11-23 00:00:16+00')) { + // if (currentReservation.memberId === '5d240cd34a3efa00882d9526') { // console.log('\r\n\r\n==== ANALYSE RESERVATION [GET INCIDENT DATA] ==== '); // console.log('\tStart : ', reservationMoment.format('DD.MM, HH:mm')); // console.log('\tEnd : ', moment.tz(currentReservation.end, currentReservation.timezone).format('DD.MM, HH:mm')); @@ -474,7 +474,89 @@ const getIncidentData = (reservation) => { // console.log('\tThere is res after : ', nextReservationIsBackToBack); // } let forgotToLockAsyncCheck; + let asyncUnscheduledUseTest = []; if (!lockEntry && !nextReservationIsBackToBack){ + + // Special check + + const checkForUnscheduledUseInBrakeBetweenReservations = async () => { + try { + if (nextReservation) { + const lastReservationInBlockAfterBrake = await getLastReservationInBlock(nextReservation); + + const fromTimestamp = nextReservation.start; + const toTimestamp = lastReservationInBlockAfterBrake.end; + + const entriesInBlock = await getEntriesBetween(fromTimestamp, toTimestamp, reservation.resourceId); + + // const reservationMoment = moment.tz(reservation.start, reservation.timezone); + // if (reservation.memberId === '5d240cd34a3efa00882d9526') { + // console.log('\r\n\r\n==== ANALYSE RESERVATION [GET INCIDENT DATA] ==== '); + // console.log('\tStart : ', reservationMoment.format('DD.MM, HH:mm')); + // console.log('\tEnd : ', moment.tz(reservation.end, reservation.timezone).format('DD.MM, HH:mm')); + // console.log('\t----------------------------------'); + // console.log('\tLast reservation in block after brake :'); + // console.log('\t\tStart : ', moment.tz(lastReservationInBlockAfterBrake.start, UI_TIMEZONE).format('DD.MM, HH:mm')); + // console.log('\t\tEnd : ', moment.tz(lastReservationInBlockAfterBrake.end, UI_TIMEZONE).format('DD.MM, HH:mm')); + // console.log('\tSearch entries : '); + // console.log('\t\tFrom :', moment.tz(fromTimestamp, UI_TIMEZONE).format('DD.MM, HH:mm')); + // console.log('\t\tTo :', moment.tz(toTimestamp, UI_TIMEZONE).format('DD.MM, HH:mm')); + // console.log('\tFirst entry : '); + // } + + const addStandaloneUnscheduledIncident = () => { + + const unlockMoment = reservation.end ? moment.utc(reservation.end) : null; + const lockMoment = nextReservation.start ? moment.utc(nextReservation.start) : null; + + if (unlockMoment && lockMoment) { + 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_STANDALONE, + reservation: emptyReservation, + unlockTimestamp: reservation.end, + lockTimestamp: nextReservation.start, + memberId: reservation.memberId, + resourceId: reservation.resourceId, + chargePrice: UNSCHEDULED_CHARGE_PRICE, + timeIntervalsToCharge, + totalChargeFee, + }); + } + } + }; + + if (Array.isArray(entriesInBlock) && entriesInBlock.length > 0) { + const firstEntry = entriesInBlock[0]; + // console.log('\t\tTimestamp : ', moment.tz(firstEntry.timestamp, UI_TIMEZONE).format('DD.MM, HH:mm')); + // console.log('\t\tEvent : ', firstEntry.event); + if (firstEntry && firstEntry.event && + firstEntry.memberId === reservation.memberId && + firstEntry.event === doorLockEvents.USER_LOCKED) { + + addStandaloneUnscheduledIncident(); + } + } else { + const reservationAfterLastReservationInBlock = await getFirstNextBooking(nextReservation); + + if (reservationAfterLastReservationInBlock) { + const lastReservationLockEntry = await getLockEntryForReservation(lastReservationInBlockAfterBrake, reservationAfterLastReservationInBlock); + if (lastReservationLockEntry) { + addStandaloneUnscheduledIncident(); + } + } + } + } + }catch (e) { + console.log('ERROR while checking for unscheduled use in brake between reservations '); + console.log(e); + } + }; + + if (unlockEntry){ // if (currentReservation.memberId === '5ce785af422bdd00967fb781' && reservationMoment.isAfter('2019-12-01 00:00:16+00')) { // console.log('\tIncident : YES [#1]'); @@ -486,6 +568,8 @@ const getIncidentData = (reservation) => { resourceId: unlockEntry.resourceId, reservation: reservation && reservation.dataValues ? reservation.dataValues : emptyReservation, }); + + asyncUnscheduledUseTest.push(checkForUnscheduledUseInBrakeBetweenReservations()); } else { // No lock entry, no unlock entry and no reservation after this one // This is either : @@ -501,17 +585,18 @@ const getIncidentData = (reservation) => { forgotToLockAsyncCheck = getLastEntryForReservation(reservation); forgotToLockAsyncCheck .then((lastEntry) => { - if (lastEntry && lastEntry.event === doorLockEvents.USER_UNLOCKED){ - // if (currentReservation.memberId === '5ce785af422bdd00967fb781' && reservationMoment.isAfter('2019-12-01 00:00:16+00')) { - // console.log('\tIncident : YES [#2]'); - // } - incidents.push({ - incidentType: incidentType.UNLOCKED_INCIDENT_RELATED_WITH_RESERVATION, - unlockTimestamp: lastEntry.timestamp, - memberId: lastEntry.memberId, - resourceId: lastEntry.resourceId, - reservation: reservation && reservation.dataValues ? reservation.dataValues : emptyReservation, - }); + if (lastEntry) { + if (lastEntry && lastEntry.event === doorLockEvents.USER_UNLOCKED) { + incidents.push({ + incidentType: incidentType.UNLOCKED_INCIDENT_RELATED_WITH_RESERVATION, + unlockTimestamp: lastEntry.timestamp, + memberId: lastEntry.memberId, + resourceId: lastEntry.resourceId, + reservation: reservation && reservation.dataValues ? reservation.dataValues : emptyReservation, + }); + + asyncUnscheduledUseTest.push(checkForUnscheduledUseInBrakeBetweenReservations()); + } } }) .catch((error) => reject(error)); @@ -539,35 +624,36 @@ const getIncidentData = (reservation) => { const previousReservationUnlockEntry = previousReservationResults.unlockEntry; //Special check for bookings with break between - if (previousReservation && - !previousReservationIsBackToBack && - previousReservation.memberId === currentReservation.memberId && - previousReservationUnlockEntry && !previousReservationLockEntry && - !unlockEntry && lockEntry //current reservation unlock / lock entries - ) { - - const unlockMoment = previousReservation.end ? moment.utc(previousReservation.end) : null; - const lockMoment = currentReservation.start ? moment.utc(currentReservation.start) : null; - - if (unlockMoment && lockMoment){ - 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_STANDALONE, - reservation: emptyReservation, - unlockTimestamp: previousReservation.end, - lockTimestamp: currentReservation.start, - memberId: currentReservation.memberId, - resourceId, - chargePrice: UNSCHEDULED_CHARGE_PRICE, - timeIntervalsToCharge, - totalChargeFee, - }); - } - } - } + // Check this for duplication, previous special check in step 3. can catch this scenario + // if (previousReservation && + // !previousReservationIsBackToBack && + // previousReservation.memberId === currentReservation.memberId && + // previousReservationUnlockEntry && !previousReservationLockEntry && + // !unlockEntry && lockEntry //current reservation unlock / lock entries + // ) { + // + // const unlockMoment = previousReservation.end ? moment.utc(previousReservation.end) : null; + // const lockMoment = currentReservation.start ? moment.utc(currentReservation.start) : null; + // + // if (unlockMoment && lockMoment){ + // 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_STANDALONE, + // reservation: emptyReservation, + // unlockTimestamp: previousReservation.end, + // lockTimestamp: currentReservation.start, + // memberId: currentReservation.memberId, + // resourceId, + // chargePrice: UNSCHEDULED_CHARGE_PRICE, + // timeIntervalsToCharge, + // totalChargeFee, + // }); + // } + // } + // } fromTimestamp = previousReservationLockEntry && previousReservationLockEntry.timestamp ? previousReservationLockEntry.timestamp : previousReservation.end; @@ -588,7 +674,7 @@ const getIncidentData = (reservation) => { } //Now wait for "forgotToLockAsyncCheck", and possible "getEntriesBetween" to finish - Promise.all([forgotToLockAsyncCheck, getEntriesAsyncCheck]) + Promise.all([forgotToLockAsyncCheck, getEntriesAsyncCheck, asyncUnscheduledUseTest]) .then((asyncActionResults) => { const entriesBetween = asyncActionResults[1]; if (Array.isArray(entriesBetween)){