From 930915cb9570df72f4cd7425b544d36877a06327 Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Wed, 14 Aug 2019 21:58:32 +0200 Subject: [PATCH 1/2] reuse incidents data to calculate discount --- services/integration/invoiceIntegration.js | 88 ++++++++++------------ 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/services/integration/invoiceIntegration.js b/services/integration/invoiceIntegration.js index 21f81d1..9aa6526 100644 --- a/services/integration/invoiceIntegration.js +++ b/services/integration/invoiceIntegration.js @@ -9,7 +9,6 @@ const { DEFAULT_DATE_FORMAT, UI_TIMEZONE, incidentTypeExplanations, incidentType const { getResourceMappings } = require('../officeRnD/resources'); const { fetchAllMembers } = require('../officeRnD/members'); const { fetchAllMembershipsAsMap } = require('../officeRnD/memberships'); -const { getChargedCanceledReservations } = require('../integration/bookingChangeCharges'); const { discounts, DISCOUNT_PLANS } = require('../../constants/constants'); const createFeeFromIncident = (incident) => { @@ -301,11 +300,35 @@ const getMembersFeesForDateRange = (dateRange, memberIds) => { }; }); - const reservationIdsForAdditionalData = []; + const memberIdTeamMappings = {}; + membersList.forEach((member) => { + memberIdTeamMappings[member.memberId] = member.teamId; + }); - const allActiveBookings = []; + const allFees = []; + + allIncidents.forEach((incident) => { + const { memberId, oldBookingStartRaw, oldBookingEndRaw, totalChargeFee } = incident; + const incidentTypeNumber = incident.incidentType; + + if ( incidentTypeNumber === incidentType.BOOKING_CANCELED_LATE){ + const startMoment = moment.utc(oldBookingStartRaw); + const endMoment = moment.utc(oldBookingEndRaw); + + if (startMoment.isValid() && endMoment.isValid()) { + const bookingLength = endMoment.diff(startMoment, 'hours', true); + + // membersMap[memberId].bookingData.totalBookedHours += bookingLength; + // "booked hours" is counted in canceled booking section + membersMap[memberId].bookingData.totalChargedHours += bookingLength; + membersMap[memberId].bookingData.totalBookingChargedFee += totalChargeFee; + } + } + + allFees.push(createFeeFromIncident(incident)); + }); allBookings.forEach((booking) => { - const {reservationId, memberId, start, end, timezone, canceled, hourlyRate} = booking.get(); + const {memberId, start, end, timezone, hourlyRate, canceled } = booking.get(); const startMoment = moment.tz(start, timezone); const endMoment = moment.tz(end, timezone); @@ -318,59 +341,30 @@ const getMembersFeesForDateRange = (dateRange, memberIds) => { membersMap[memberId].bookingData.totalBookedHours += bookingLength; - if (canceled) { - reservationIdsForAdditionalData.push(reservationId); - } else { - allActiveBookings.push(booking); + if (!canceled){ membersMap[memberId].bookingData.totalChargedHours += bookingLength; - const bookingFee = bookingLength * hourlyRate; membersMap[memberId].bookingData.totalBookingChargedFee += bookingFee; + + allFees.push(createFeeFromBooking(booking, resourceMappings)); } } }); - getChargedCanceledReservations(reservationIdsForAdditionalData) - .then((incidents) => { - incidents.forEach((incident) => { - const {memberId, oldBookingStart, oldBookingEnd, chargeFee} = incident.get(); + //add discount + memberIds.forEach((memberId) => { + const discountFee = createNegativeFeeForDiscount(membersMap[memberId], dateRange); + if (discountFee){ + allFees.push(discountFee); + } + }); - const startMoment = moment.tz(oldBookingStart, UI_TIMEZONE); - const endMoment = moment.tz(oldBookingEnd, UI_TIMEZONE); + allFees.forEach((fee) => { + fee.team = memberIdTeamMappings[fee.member] || null; + }); - if (startMoment.isValid() && endMoment.isValid()) { - const bookingLength = endMoment.diff(startMoment, 'hours', true); + resolve(allFees); - membersMap[memberId].bookingData.totalChargedHours += bookingLength; - membersMap[memberId].bookingData.totalBookingChargedFee += chargeFee; - } - }); - - const memberIdTeamMappings = {}; - membersList.forEach((member) => { - memberIdTeamMappings[member.memberId] = member.teamId; - }); - - const allFees = []; - - allIncidents.forEach((incident) => allFees.push(createFeeFromIncident(incident))); - allActiveBookings.forEach((booking) => allFees.push(createFeeFromBooking(booking, resourceMappings))); - - //add discount - memberIds.forEach((memberId) => { - const discountFee = createNegativeFeeForDiscount(membersMap[memberId], dateRange); - if (discountFee){ - allFees.push(discountFee); - } - }); - - allFees.forEach((fee) => { - fee.team = memberIdTeamMappings[fee.member] || null; - }); - - resolve(allFees); - }) - .catch((error) => reject(error)); }) .catch((error) => { console.log(error); From ed9a3bf9492c16440275b355dafd2d1da50d3f9d Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Thu, 15 Aug 2019 10:00:09 +0200 Subject: [PATCH 2/2] include overuse / unscheduled use in discount --- services/integration/invoiceIntegration.js | 93 ++++++++++++++++++---- 1 file changed, 78 insertions(+), 15 deletions(-) diff --git a/services/integration/invoiceIntegration.js b/services/integration/invoiceIntegration.js index 9aa6526..4c63322 100644 --- a/services/integration/invoiceIntegration.js +++ b/services/integration/invoiceIntegration.js @@ -308,24 +308,87 @@ const getMembersFeesForDateRange = (dateRange, memberIds) => { const allFees = []; allIncidents.forEach((incident) => { - const { memberId, oldBookingStartRaw, oldBookingEndRaw, totalChargeFee } = incident; + allFees.push(createFeeFromIncident(incident)); + + const incidentsValuableForDiscountCalculation = [ + incidentType.UNSCHEDULED_INCIDENT_BEFORE_RESERVATION, + incidentType.UNSCHEDULED_INCIDENT_AFTER_RESERVATION, + incidentType.UNSCHEDULED_INCIDENT_STANDALONE, + incidentType.BOOKING_SHORTENED, + incidentType.BOOKING_CANCELED_LATE + ]; + const incidentTypeNumber = incident.incidentType; - - if ( incidentTypeNumber === incidentType.BOOKING_CANCELED_LATE){ - const startMoment = moment.utc(oldBookingStartRaw); - const endMoment = moment.utc(oldBookingEndRaw); - - if (startMoment.isValid() && endMoment.isValid()) { - const bookingLength = endMoment.diff(startMoment, 'hours', true); - - // membersMap[memberId].bookingData.totalBookedHours += bookingLength; - // "booked hours" is counted in canceled booking section - membersMap[memberId].bookingData.totalChargedHours += bookingLength; - membersMap[memberId].bookingData.totalBookingChargedFee += totalChargeFee; - } + if (incidentsValuableForDiscountCalculation.indexOf(incidentTypeNumber) === -1){ + return; } - allFees.push(createFeeFromIncident(incident)); + const { + memberId, + oldBookingStartRaw, + oldBookingEndRaw, + newBookingStartRaw, + newBookingEndRaw, + unlockTimestampRaw, + lockTimestampRaw, + bookingStartRaw, + bookingEndRaw, + totalChargeFee + } = incident; + + let chargedBookingLength = 0; + + switch (incidentTypeNumber){ + case incidentType.UNSCHEDULED_INCIDENT_BEFORE_RESERVATION: + const unlockMoment = moment.utc(unlockTimestampRaw); + const bookingStartMoment =moment.utc(bookingStartRaw); + if (unlockMoment.isValid() && bookingStartMoment.isValid()){ + chargedBookingLength = bookingStartMoment.diff(unlockMoment, 'hours', true); + } + break; + case incidentType.UNSCHEDULED_INCIDENT_AFTER_RESERVATION: + const lockMoment = moment.utc(lockTimestampRaw); + const bookingEndMoment =moment.utc(bookingEndRaw); + if (lockMoment.isValid() && bookingEndMoment.isValid()){ + chargedBookingLength = lockMoment.diff(bookingEndMoment, 'hours', true); + } + break; + case incidentType.UNSCHEDULED_INCIDENT_STANDALONE: + const unlockMomentStandalone = moment.utc(unlockTimestampRaw); + const lockMomentStandalone = moment.utc(lockTimestampRaw); + if (unlockMomentStandalone.isValid() && lockMomentStandalone.isValid()){ + chargedBookingLength = lockMomentStandalone.diff(unlockMomentStandalone, 'hours', true); + } + break; + case incidentType.BOOKING_SHORTENED: + const oldBookingStartMoment = moment.utc(oldBookingStartRaw); + const oldBookingEndMoment = moment.utc(oldBookingEndRaw); + const newBookingStartMoment = moment.utc(newBookingStartRaw); + const newBookingEndMoment = moment.utc(newBookingEndRaw); + + if (oldBookingStartMoment.isValid() && oldBookingEndMoment.isValid() && newBookingStartMoment.isValid() && newBookingEndMoment.isValid()){ + const oldBookingLength = oldBookingEndMoment.diff(oldBookingStartMoment, 'hours', true); + const newBookingLength = newBookingEndMoment.diff(newBookingStartMoment, 'hours', true); + + chargedBookingLength = Math.abs(oldBookingLength - newBookingLength); + } + break; + case incidentType.BOOKING_CANCELED_LATE: + const startMoment = moment.utc(oldBookingStartRaw); + const endMoment = moment.utc(oldBookingEndRaw); + + if (startMoment.isValid() && endMoment.isValid()) { + chargedBookingLength = endMoment.diff(startMoment, 'hours', true); + + // membersMap[memberId].bookingData.totalBookedHours += bookingLength; + // "booked hours" is counted in canceled booking section + } + + break; + } + + membersMap[memberId].bookingData.totalChargedHours += chargedBookingLength; + membersMap[memberId].bookingData.totalBookingChargedFee += totalChargeFee; }); allBookings.forEach((booking) => { const {memberId, start, end, timezone, hourlyRate, canceled } = booking.get();