add negative fee for discount
This commit is contained in:
@@ -107,6 +107,17 @@ const BOOKING_CHANGE_PERCENTAGE_CHARGE = parseInt(process.env.BOOKING_CHANGE_PER
|
||||
const CHARGE_BOOKING_CHANGE_UNDER_TIME = parseInt(process.env.CHARGE_BOOKING_CHANGE_UNDER_TIME) || 1430;
|
||||
const ALLOWED_BOOKING_CANCELLATION_TIME = parseInt(process.env.ALLOWED_BOOKING_CANCELLATION_TIME) || 30;
|
||||
|
||||
const discounts = {
|
||||
LEVEL_1:{
|
||||
hoursRequired: parseInt(process.env.DISCOUNT_LEVEL_1_HOURS) || 10,
|
||||
percentage: parseInt(process.env.DISCOUNT_LEVEL_1_PERCENTAGE) || 5,
|
||||
},
|
||||
LEVEL_2:{
|
||||
hoursRequired: parseInt(process.env.DISCOUNT_LEVEL_2_HOURS) || 40,
|
||||
percentage: parseInt(process.env.DISCOUNT_LEVEL_2_PERCENTAGE) || 10,
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
VALID_CSV_HEADERS,
|
||||
USER_ENTRY_EVENT,
|
||||
@@ -127,4 +138,5 @@ module.exports = {
|
||||
BOOKING_CHANGE_PERCENTAGE_CHARGE,
|
||||
CHARGE_BOOKING_CHANGE_UNDER_TIME,
|
||||
ALLOWED_BOOKING_CANCELLATION_TIME,
|
||||
discounts,
|
||||
};
|
||||
|
||||
@@ -26,6 +26,11 @@ ALLOWED_BOOKING_CANCELLATION_TIME=Time from creation (in minutes) in which cance
|
||||
|
||||
SEQUELIZE_LOGGING=0 - false, 1 - true (console logging)
|
||||
|
||||
DISCOUNT_LEVEL_1_HOURS=Hours requred to apply DISCOUNT_LEVEL_1_PERCENTAGE discount
|
||||
DISCOUNT_LEVEL_1_PERCENTAGE=Discount to apply in percentage, if DISCOUNT_LEVEL_1_HOURS of billable hours is booked
|
||||
DISCOUNT_LEVEL_2_HOURS=Hours requred to apply DISCOUNT_LEVEL_2_PERCENTAGE discount
|
||||
DISCOUNT_LEVEL_2_PERCENTAGE=Discount to apply in percentage, if DISCOUNT_LEVEL_2_HOURS of billable hours is booked
|
||||
|
||||
#More about pool option : http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html
|
||||
DB_POOL_MAX_CONNECTIONS=Maximum number of connection in pool (ex. 18)
|
||||
DB_POOL_ACQUIRE=The maximum time, in milliseconds, that pool will try to get connection before throwing error (ex. 120000)
|
||||
|
||||
@@ -142,7 +142,7 @@ const getChargedCanceledReservations = (reservationIds) => {
|
||||
incidentType: incidentType.BOOKING_CANCELED_LATE,
|
||||
};
|
||||
|
||||
const attributes = ['memberId', 'oldBookingStart', 'oldBookingEnd'];
|
||||
const attributes = ['memberId', 'oldBookingStart', 'oldBookingEnd', 'chargeFee'];
|
||||
|
||||
return db.bookingChangeIncident.findAll({attributes, where: filters});
|
||||
};
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
const moment = require('moment-timezone');
|
||||
|
||||
const { getAllIncidents } = require('./reports');
|
||||
const { getActiveBookingsForMembersInDateRange } = require('./bookings');
|
||||
const { getAllBookingsForMembersInDateRange } = require('./bookings');
|
||||
|
||||
const { DEFAULT_DATE_FORMAT, UI_TIMEZONE, incidentTypeExplanations, incidentType, unlockedIncidentLevelsPrices } = require('../../constants/constants');
|
||||
const { getResourceMappings } = require('../officeRnD/resources');
|
||||
const { fetchAllMembers } = require('../officeRnD/members');
|
||||
const { fetchAllMembershipsAsMap } = require('../officeRnD/memberships');
|
||||
const { getChargedCanceledReservations } = require('../integration/bookingChangeCharges');
|
||||
const { discounts } = require('../../constants/constants');
|
||||
|
||||
const createFeeFromIncident = (incident) => {
|
||||
const {
|
||||
@@ -222,33 +225,138 @@ const createFeeFromBooking = (booking, resourceMappings) => {
|
||||
}
|
||||
};
|
||||
|
||||
const createNegativeFeeForDiscount = (memberData) => {
|
||||
const { bookingData, member, membershipFee } = memberData;
|
||||
const { totalBookedHours, totalChargedHours, totalBookingChargedFee } = bookingData;
|
||||
const { memberId, officeId } = member;
|
||||
|
||||
const totalChargeFee = membershipFee + totalBookingChargedFee;
|
||||
|
||||
let discount = 0;
|
||||
let discountPercentage = 0;
|
||||
|
||||
if (totalChargedHours >= discounts.LEVEL_2.hoursRequired){
|
||||
discountPercentage = discounts.LEVEL_2.percentage;
|
||||
const discountRate = discountPercentage / 100;
|
||||
discount = totalChargeFee * discountRate;
|
||||
}else if (totalChargedHours >= discounts.LEVEL_1.hoursRequired){
|
||||
discountPercentage = discounts.LEVEL_1.percentage;
|
||||
const discountRate = discountPercentage / 100;
|
||||
console.log(discountRate);
|
||||
discount = totalChargeFee * discountRate;
|
||||
}else{
|
||||
discountPercentage = 0;
|
||||
discount = 0;
|
||||
}
|
||||
|
||||
const formattedName = `[Discount] Total booked : ${totalBookedHours.toFixed(2)} hrs, Total charged : ${totalChargedHours.toFixed(2)} hrs, Discount : ${discountPercentage} %`;
|
||||
|
||||
return {
|
||||
name: formattedName,
|
||||
price: -discount.toFixed(2),
|
||||
quantity: 1,
|
||||
date: moment.tz(UI_TIMEZONE).format(),
|
||||
member: memberId,
|
||||
team: null,
|
||||
office: officeId,
|
||||
isPersonal: false,
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const getMembersFeesForDateRange = (dateRange, memberIds) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const collectData = [getAllIncidents(dateRange, memberIds), getActiveBookingsForMembersInDateRange(dateRange, memberIds), getResourceMappings(), fetchAllMembers()];
|
||||
|
||||
const collectData = [getAllIncidents(dateRange, memberIds), getAllBookingsForMembersInDateRange(dateRange, memberIds), getResourceMappings(), fetchAllMembers(), fetchAllMembershipsAsMap()];
|
||||
|
||||
Promise.all(collectData)
|
||||
.then((result) => {
|
||||
const allIncidents = result[0];
|
||||
const allActiveBookings = result[1];
|
||||
const allBookings = result[1];
|
||||
const resourceMappings = result[2];
|
||||
const membersList = result[3];
|
||||
const membershipsMap = result[4];
|
||||
|
||||
const membersMap = {};
|
||||
const oneMemberObject = {
|
||||
totalBookedHours: 0,
|
||||
totalChargedHours: 0,
|
||||
totalBookingChargedFee: 0,
|
||||
};
|
||||
|
||||
const memberIdTeamMappings = {};
|
||||
membersList.forEach((member) => {
|
||||
memberIdTeamMappings[member.memberId] = member.teamId;
|
||||
membersMap[member.memberId] = {
|
||||
member,
|
||||
bookingData: Object.assign({}, oneMemberObject),
|
||||
membershipFee: membershipsMap[member.memberId] || 0,
|
||||
};
|
||||
});
|
||||
|
||||
const allFees = [];
|
||||
const reservationIdsForAdditionalData = [];
|
||||
|
||||
allIncidents.forEach((incident) => allFees.push(createFeeFromIncident(incident)));
|
||||
allActiveBookings.forEach((booking) => allFees.push(createFeeFromBooking(booking, resourceMappings)));
|
||||
const allActiveBookings = [];
|
||||
allBookings.forEach((booking) => {
|
||||
const {reservationId, memberId, start, end, timezone, canceled, hourlyRate} = booking.get();
|
||||
const startMoment = moment.tz(start, timezone);
|
||||
const endMoment = moment.tz(end, timezone);
|
||||
|
||||
allFees.forEach((fee) => {
|
||||
fee.team = memberIdTeamMappings[fee.member] || null;
|
||||
if (startMoment.isValid() && endMoment.isValid()) {
|
||||
const bookingLength = endMoment.diff(startMoment, 'hours', true);
|
||||
|
||||
if (!membersMap[memberId] || !membersMap[memberId].bookingData) {
|
||||
membersMap[memberId].bookingData = Object.assign({}, oneMemberObject);
|
||||
}
|
||||
|
||||
membersMap[memberId].bookingData.totalBookedHours += bookingLength;
|
||||
|
||||
if (canceled) {
|
||||
reservationIdsForAdditionalData.push(reservationId);
|
||||
} else {
|
||||
membersMap[memberId].bookingData.totalChargedHours += bookingLength;
|
||||
|
||||
const bookingFee = bookingLength * hourlyRate;
|
||||
membersMap[memberId].bookingData.totalBookingChargedFee += bookingFee;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
resolve(allFees);
|
||||
getChargedCanceledReservations(reservationIdsForAdditionalData)
|
||||
.then((incidents) => {
|
||||
incidents.forEach((incident) => {
|
||||
const {memberId, oldBookingStart, oldBookingEnd, chargeFee} = incident.get();
|
||||
|
||||
const startMoment = moment.tz(oldBookingStart, UI_TIMEZONE);
|
||||
const endMoment = moment.tz(oldBookingEnd, UI_TIMEZONE);
|
||||
|
||||
if (startMoment.isValid() && endMoment.isValid()) {
|
||||
const bookingLength = endMoment.diff(startMoment, 'hours', true);
|
||||
|
||||
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) => {
|
||||
allFees.push(createNegativeFeeForDiscount(membersMap[memberId]));
|
||||
});
|
||||
|
||||
allFees.forEach((fee) => {
|
||||
fee.team = memberIdTeamMappings[fee.member] || null;
|
||||
});
|
||||
|
||||
resolve(allFees);
|
||||
})
|
||||
.catch((error) => reject(error));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
|
||||
@@ -14,6 +14,7 @@ const fetchAllMembers = () => {
|
||||
memberId: member['_id'],
|
||||
teamId: member.team,
|
||||
active: member.status === 'active',
|
||||
officeId: member.office,
|
||||
});
|
||||
});
|
||||
cleanedResult.sort((member1, member2) => (member1.name > member2.name) ? 1 : -1 );
|
||||
|
||||
27
services/officeRnD/memberships.js
Normal file
27
services/officeRnD/memberships.js
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const { API } = require('../../helpers/api');
|
||||
|
||||
const fetchAllMembershipsAsMap = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
API.get('/memberships')
|
||||
.then((result) => {
|
||||
const membershipsMap = {};
|
||||
const memberships = result.data || [];
|
||||
memberships.forEach((membership) => {
|
||||
const { price, member } = membership;
|
||||
if (!membershipsMap[member]) {
|
||||
membershipsMap[member] = price;
|
||||
}
|
||||
});
|
||||
resolve(membershipsMap);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
fetchAllMembershipsAsMap,
|
||||
};
|
||||
Reference in New Issue
Block a user