Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(taxes_and_fees): update a logic of calculation taxes and fees #40

Merged
merged 7 commits into from
Oct 29, 2021
3 changes: 2 additions & 1 deletion compiled/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ module.exports = {
vendor: require('./vendor'),
flights: require('./flights'),
offer: require('./offer'),
currency: require('./currency')
currency: require('./currency'),
occupancy: require('./occupancy')
};
89 changes: 89 additions & 0 deletions compiled/occupancy/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"use strict";

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

var match = function match(occupancy) {
return !(occupancy.match(/^[0-9]{1,2}-[0-9]{1,2}-[0-9]{1,2}?$/gi) == null) || !(occupancy.match(/^[0-9]{1,2}(-[0-9]{1,2}?(,[0-9]{1,2})*)?$/ig) == null);
};

var parse = function parse(occupancy) {
if (occupancy.match(/^[0-9]{1,2}(-[0-9]{1,2}?(,[0-9]{1,2})*)?$/ig)) {
var _occupancy$split = occupancy.split('-'),
_occupancy$split2 = _slicedToArray(_occupancy$split, 2),
adults = _occupancy$split2[0],
ages = _occupancy$split2[1];

var children = 0;
var childrenAges = [];

if (ages) {
childrenAges = ages.split(',').map(function (x) {
return Number(x);
});
children = childrenAges.length;
}

return {
adults: Number(adults),
children: Number(children),
infants: 0,
childrenAges: childrenAges
};
} else {
var _occupancy$split3 = occupancy.split('-'),
_occupancy$split4 = _slicedToArray(_occupancy$split3, 3),
_adults = _occupancy$split4[0],
_children = _occupancy$split4[1],
infants = _occupancy$split4[2];

return {
adults: Number(_adults),
children: Number(_children),
infants: Number(infants),
childrenAges: []
};
}
};

var toString = function toString(occupancy) {
if (occupancy.childrenAges && occupancy.childrenAges.length) {
return "".concat(occupancy.adults, "-").concat(occupancy.childrenAges.join(','));
} else {
return "".concat(occupancy.adults, "-").concat(occupancy.children, "-").concat(occupancy.infants);
}
};

var get = function get(occupancy) {
var occupancies = [];

if (typeof occupancy === 'string') {
if (occupancy.split(',').every(function (occupancy) {
return !!occupancy.match(/^[0-9]{1,2}-[0-9]{1,2}-[0-9]{1,2}?$/gi);
})) {
occupancies = occupancy.split(',').map(parse);
} else {
occupancies = [occupancy].map(parse);
}
} else {
occupancies = occupancy.map(parse);
}

return occupancies;
};

module.exports = {
parse: parse,
get: get,
match: match,
toString: toString
};
93 changes: 85 additions & 8 deletions compiled/offer/pricing.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,95 @@
"use strict";

var calculateTaxAmount = function calculateTaxAmount(_ref) {
var price = _ref.price,
taxesAndFees = _ref.taxesAndFees,
numberOfNights = _ref.numberOfNights;
var countOfMembers = function countOfMembers(occupancies) {
return (occupancies || []).reduce(function (acc, occupancy) {
return acc + occupancy.adults + (occupancy.children || 0) + (occupancy.infants || 0);
}, 0) || 2;
};

var perNight = function perNight(_ref) {
var total = _ref.total,
unit = _ref.unit,
value = _ref.value,
nights = _ref.nights,
perPerson = _ref.perPerson,
occupancies = _ref.occupancies;
var members = perPerson ? countOfMembers(occupancies) : 1;

if (unit === 'percentage') {
return total / 100 * value * members;
} else {
return value * nights * members;
}
};

var perStay = function perStay(_ref2) {
var total = _ref2.total,
unit = _ref2.unit,
value = _ref2.value,
perPerson = _ref2.perPerson,
occupancies = _ref2.occupancies;
var members = perPerson ? countOfMembers(occupancies) : 1;

if (unit === 'percentage') {
return total / 100 * value * members;
} else {
return value * members;
}
};
/**
* Extract and validate the offer and offer package for an order
*
* interface TaxesAndFees {
* name: string;
* unit: "percentage" | "amount";
* type: "night" | "stay";
* per_person: boolean;
* value: number;
* }
*
* interface Occupants {
* adults: number;
* children?: number;
* infants?: number;
* childrenAge?: Array<number>;
* }
*
* @param {object} params - All params
* @param {number} params.total - The total amount of booking period
* @param {Array<TaxesAndFees>} params.taxesAndFees - The orders currency code
* @param {number} params.nights - The number of nights
* @param {Array<Occupants>} params.occupancies - The occupancies
* @returns {number} Sum of taxes and fees
*/


var calculateTaxAmount = function calculateTaxAmount(_ref3) {
var total = _ref3.total,
taxesAndFees = _ref3.taxesAndFees,
nights = _ref3.nights,
occupancies = _ref3.occupancies;

if (taxesAndFees && price) {
if (taxesAndFees && total) {
return Math.floor(taxesAndFees.reduce(function (acc, item) {
var tax = 0;

if (item.unit === 'percentage') {
tax = price / 100 * item.value;
if (item.type === 'stay') {
tax = perStay({
total: total,
unit: item.unit,
value: item.value,
perPerson: item.per_person,
occupancies: occupancies
});
} else {
tax = item.value * numberOfNights;
tax = perNight({
total: total,
unit: item.unit,
value: item.value,
nights: nights,
perPerson: item.per_person,
occupancies: occupancies
});
}

return acc + tax;
Expand Down
17 changes: 16 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,17 @@ declare module "@luxuryescapes/lib-global" {
interface TaxesAndFees {
name: string;
unit: "percentage" | "amount";
type: "night" | "stay";
per_person: boolean;
value: number;
}

interface Occupants {
adults: number;
children?: number;
infants?: number;
childrenAge?: Array<number>;
}

export type LeHotelOfferType =
| "hotel"
Expand Down Expand Up @@ -52,9 +61,15 @@ declare module "@luxuryescapes/lib-global" {
getFromPackages: (packages: Array<object>, offerType: string, holidayTypes: Array<string>) => string;
};
pricing: {
calculateTaxAmount: ({ price, taxesAndFees, numberOfNights }: { price: number, taxesAndFees: TaxesAndFees[], numberOfNights: number }) => number;
calculateTaxAmount: ({ total, taxesAndFees, nights, occupancies }: { total: number, taxesAndFees: TaxesAndFees[], nights: number, occupancies?: Occupants[] }) => number;
};
};
const occupancy: {
get: (occupancy: string | string[]) => Occupants[];
parse: (occupancy: string) => Occupants;
match: (occupancy: string) => boolean;
toString: (occupancy: Occupants) => string;
};
const currency: {
addDollarType: (
formattedAmount: string,
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ module.exports = {
flights: require('./flights'),
offer: require('./offer'),
currency: require('./currency'),
occupancy: require('./occupancy'),
}
62 changes: 62 additions & 0 deletions src/occupancy/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const match = occupancy => !(occupancy.match(/^[0-9]{1,2}-[0-9]{1,2}-[0-9]{1,2}?$/gi) == null) ||
!(occupancy.match(/^[0-9]{1,2}(-[0-9]{1,2}?(,[0-9]{1,2})*)?$/ig) == null)

const parse = (occupancy) => {
if (occupancy.match(/^[0-9]{1,2}(-[0-9]{1,2}?(,[0-9]{1,2})*)?$/ig)) {
const [adults, ages] = occupancy.split('-')
let children = 0
let childrenAges = []

if (ages) {
childrenAges = ages.split(',').map(x => Number(x))
children = childrenAges.length
}

return {
adults: Number(adults),
children: Number(children),
infants: 0,
childrenAges,
}
} else {
const [adults, children, infants] = occupancy.split('-')

return {
adults: Number(adults),
children: Number(children),
infants: Number(infants),
childrenAges: [],
}
}
}

const toString = occupancy => {
if (occupancy.childrenAges && occupancy.childrenAges.length) {
return `${occupancy.adults}-${occupancy.childrenAges.join(',')}`
} else {
return `${occupancy.adults}-${occupancy.children}-${occupancy.infants}`
}
}

const get = occupancy => {
let occupancies = []

if (typeof occupancy === 'string') {
if (occupancy.split(',').every(occupancy => !!occupancy.match(/^[0-9]{1,2}-[0-9]{1,2}-[0-9]{1,2}?$/gi))) {
occupancies = occupancy.split(',').map(parse)
} else {
occupancies = [occupancy].map(parse)
}
} else {
occupancies = occupancy.map(parse)
}

return occupancies
}

module.exports = {
parse: parse,
get: get,
match: match,
toString: toString,
}
62 changes: 57 additions & 5 deletions src/offer/pricing.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,64 @@
const calculateTaxAmount = ({ price, taxesAndFees, numberOfNights }) => {
if (taxesAndFees && price) {
const countOfMembers = (occupancies) => {
return (occupancies || []).reduce((acc, occupancy) => {
return acc + occupancy.adults + (occupancy.children || 0) + (occupancy.infants || 0)
}, 0) || 2
}

const perNight = ({ total, unit, value, nights, perPerson, occupancies }) => {
const members = perPerson ? countOfMembers(occupancies) : 1

if (unit === 'percentage') {
return ((total / 100) * value) * members
} else {
return (value * nights) * members
}
}

const perStay = ({ total, unit, value, perPerson, occupancies }) => {
const members = perPerson ? countOfMembers(occupancies) : 1

if (unit === 'percentage') {
return ((total / 100) * value) * members
} else {
return value * members
}
}

/**
* Extract and validate the offer and offer package for an order
*
* interface TaxesAndFees {
* name: string;
* unit: "percentage" | "amount";
* type: "night" | "stay";
* per_person: boolean;
* value: number;
* }
*
* interface Occupants {
* adults: number;
* children?: number;
* infants?: number;
* childrenAge?: Array<number>;
* }
*
* @param {object} params - All params
* @param {number} params.total - The total amount of booking period
* @param {Array<TaxesAndFees>} params.taxesAndFees - The orders currency code
* @param {number} params.nights - The number of nights
* @param {Array<Occupants>} params.occupancies - The occupancies
* @returns {number} Sum of taxes and fees
*/
const calculateTaxAmount = ({ total, taxesAndFees, nights, occupancies }) => {
if (taxesAndFees && total) {
return Math.floor(
taxesAndFees.reduce((acc, item) => {
let tax = 0
if (item.unit === 'percentage') {
tax = (price / 100) * item.value

if (item.type === 'stay') {
tax = perStay({ total, unit: item.unit, value: item.value, perPerson: item.per_person, occupancies })
} else {
tax = item.value * numberOfNights
tax = perNight({ total, unit: item.unit, value: item.value, nights, perPerson: item.per_person, occupancies })
}

return acc + tax
Expand Down
Loading