Merged in feat/refactor-enter-details-price-calculation (pull request #3183)
feat: Refactor enter details price calculation * Refactor getTotalPrice and child functions * Move price calculations from helper file to specific file Approved-by: Linus Flood
This commit is contained in:
@@ -16,10 +16,10 @@ import {
|
|||||||
import { EnterDetailsStepEnum } from "../../stores/enter-details/enterDetailsStep"
|
import { EnterDetailsStepEnum } from "../../stores/enter-details/enterDetailsStep"
|
||||||
import {
|
import {
|
||||||
clearSessionStorage,
|
clearSessionStorage,
|
||||||
getTotalPrice,
|
|
||||||
readFromSessionStorage,
|
readFromSessionStorage,
|
||||||
writeToSessionStorage,
|
writeToSessionStorage,
|
||||||
} from "../../stores/enter-details/helpers"
|
} from "../../stores/enter-details/helpers"
|
||||||
|
import { getTotalPrice } from "../../stores/enter-details/priceCalculations"
|
||||||
import { isSameBooking } from "../../utils/isSameBooking"
|
import { isSameBooking } from "../../utils/isSameBooking"
|
||||||
|
|
||||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
import { parsePhoneNumberFromString } from "libphonenumber-js"
|
import { parsePhoneNumberFromString } from "libphonenumber-js"
|
||||||
|
|
||||||
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
|
||||||
import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType"
|
|
||||||
import { logger } from "@scandic-hotels/common/logger"
|
import { logger } from "@scandic-hotels/common/logger"
|
||||||
|
|
||||||
import { calculateRegularPrice } from "../../utils/calculateRegularPrice"
|
|
||||||
import { sumPackages, sumPackagesRequestedPrice } from "../../utils/SelectRate"
|
|
||||||
import { detailsStorageName } from "."
|
import { detailsStorageName } from "."
|
||||||
|
|
||||||
import type { Product } from "@scandic-hotels/trpc/types/roomAvailability"
|
|
||||||
import type { User } from "@scandic-hotels/trpc/types/user"
|
import type { User } from "@scandic-hotels/trpc/types/user"
|
||||||
|
|
||||||
import type { Price } from "../../types/price"
|
|
||||||
import type { PersistedState, RoomState } from "./types"
|
import type { PersistedState, RoomState } from "./types"
|
||||||
|
|
||||||
export function extractGuestFromUser(user: User) {
|
export function extractGuestFromUser(user: User) {
|
||||||
@@ -34,191 +28,6 @@ export function extractGuestFromUser(user: User) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(...nums: (number | string | undefined)[]) {
|
|
||||||
return nums.reduce((total: number, num) => {
|
|
||||||
if (typeof num === "undefined") {
|
|
||||||
num = 0
|
|
||||||
}
|
|
||||||
total = total + parseInt(`${num}`)
|
|
||||||
return total
|
|
||||||
}, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRoomPrice(
|
|
||||||
roomRate: Product,
|
|
||||||
isMember: boolean,
|
|
||||||
pointsCurrency?: CurrencyEnum
|
|
||||||
) {
|
|
||||||
if (isMember && "member" in roomRate && roomRate.member) {
|
|
||||||
let publicRate
|
|
||||||
if (
|
|
||||||
"public" in roomRate &&
|
|
||||||
roomRate.public?.rateType === RateTypeEnum.Regular
|
|
||||||
) {
|
|
||||||
publicRate = roomRate.public
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
perNight: {
|
|
||||||
requested: roomRate.member.requestedPrice
|
|
||||||
? {
|
|
||||||
currency: roomRate.member.requestedPrice.currency,
|
|
||||||
price: roomRate.member.requestedPrice.pricePerNight,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
local: {
|
|
||||||
currency: roomRate.member.localPrice.currency,
|
|
||||||
price: roomRate.member.localPrice.pricePerNight,
|
|
||||||
regularPrice:
|
|
||||||
publicRate?.localPrice.pricePerStay ||
|
|
||||||
roomRate.member.localPrice.regularPricePerNight,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perStay: {
|
|
||||||
requested: roomRate.member.requestedPrice
|
|
||||||
? {
|
|
||||||
currency: roomRate.member.requestedPrice.currency,
|
|
||||||
price: roomRate.member.requestedPrice.pricePerStay,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
local: {
|
|
||||||
currency: roomRate.member.localPrice.currency,
|
|
||||||
price: roomRate.member.localPrice.pricePerStay,
|
|
||||||
regularPrice:
|
|
||||||
publicRate?.localPrice.pricePerStay ||
|
|
||||||
roomRate.member.localPrice.regularPricePerStay,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("public" in roomRate && roomRate.public) {
|
|
||||||
return {
|
|
||||||
perNight: {
|
|
||||||
requested: roomRate.public.requestedPrice
|
|
||||||
? {
|
|
||||||
currency: roomRate.public.requestedPrice.currency,
|
|
||||||
price: roomRate.public.requestedPrice.pricePerNight,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
local: {
|
|
||||||
currency: roomRate.public.localPrice.currency,
|
|
||||||
price: roomRate.public.localPrice.pricePerNight,
|
|
||||||
regularPrice: roomRate.public.localPrice.regularPricePerNight,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perStay: {
|
|
||||||
requested: roomRate.public.requestedPrice
|
|
||||||
? {
|
|
||||||
currency: roomRate.public.requestedPrice.currency,
|
|
||||||
price: roomRate.public.requestedPrice.pricePerStay,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
local: {
|
|
||||||
currency: roomRate.public.localPrice.currency,
|
|
||||||
price: roomRate.public.localPrice.pricePerStay,
|
|
||||||
regularPrice: roomRate.public.localPrice.regularPricePerStay,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("corporateCheque" in roomRate) {
|
|
||||||
return {
|
|
||||||
perNight: {
|
|
||||||
requested: roomRate.corporateCheque.requestedPrice
|
|
||||||
? {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: roomRate.corporateCheque.requestedPrice.numberOfCheques,
|
|
||||||
additionalPrice:
|
|
||||||
roomRate.corporateCheque.requestedPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
roomRate.corporateCheque.requestedPrice.currency ?? undefined,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: roomRate.corporateCheque.localPrice.numberOfCheques,
|
|
||||||
additionalPrice:
|
|
||||||
roomRate.corporateCheque.localPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
roomRate.corporateCheque.localPrice.currency ?? undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perStay: {
|
|
||||||
requested: roomRate.corporateCheque.requestedPrice
|
|
||||||
? {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: roomRate.corporateCheque.requestedPrice.numberOfCheques,
|
|
||||||
additionalPrice:
|
|
||||||
roomRate.corporateCheque.requestedPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
roomRate.corporateCheque.requestedPrice.currency ?? undefined,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: roomRate.corporateCheque.localPrice.numberOfCheques,
|
|
||||||
additionalPrice:
|
|
||||||
roomRate.corporateCheque.localPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
roomRate.corporateCheque.localPrice.currency ?? undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("voucher" in roomRate) {
|
|
||||||
return {
|
|
||||||
perNight: {
|
|
||||||
requested: undefined,
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Voucher,
|
|
||||||
price: roomRate.voucher.numberOfVouchers,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perStay: {
|
|
||||||
requested: undefined,
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Voucher,
|
|
||||||
price: roomRate.voucher.numberOfVouchers,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("redemption" in roomRate) {
|
|
||||||
return {
|
|
||||||
// ToDo Handle perNight as undefined
|
|
||||||
perNight: {
|
|
||||||
requested: undefined,
|
|
||||||
local: {
|
|
||||||
currency: pointsCurrency ?? CurrencyEnum.POINTS,
|
|
||||||
price: roomRate.redemption.localPrice.pointsPerStay,
|
|
||||||
additionalPrice:
|
|
||||||
roomRate.redemption.localPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
roomRate.redemption.localPrice.currency ?? undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perStay: {
|
|
||||||
requested: undefined,
|
|
||||||
local: {
|
|
||||||
currency: pointsCurrency ?? CurrencyEnum.POINTS,
|
|
||||||
price: roomRate.redemption.localPrice.pointsPerStay,
|
|
||||||
additionalPrice:
|
|
||||||
roomRate.redemption.localPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
roomRate.redemption.localPrice.currency ?? undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(
|
|
||||||
`Unable to calculate RoomPrice since user is neither a member or memberRate is missing, or publicRate is missing`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const checkRoomProgress = (steps: RoomState["steps"]) => {
|
export const checkRoomProgress = (steps: RoomState["steps"]) => {
|
||||||
return Object.values(steps)
|
return Object.values(steps)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
@@ -267,430 +76,3 @@ export function clearSessionStorage() {
|
|||||||
}
|
}
|
||||||
sessionStorage.removeItem(detailsStorageName)
|
sessionStorage.removeItem(detailsStorageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAdditionalPrice(
|
|
||||||
total: {
|
|
||||||
local: {
|
|
||||||
additionalPrice?: number
|
|
||||||
additionalPriceCurrency?: CurrencyEnum
|
|
||||||
}
|
|
||||||
},
|
|
||||||
adults: number,
|
|
||||||
breakfast:
|
|
||||||
| { localPrice: { price: number; currency?: CurrencyEnum } }
|
|
||||||
| false
|
|
||||||
| undefined,
|
|
||||||
nights: number,
|
|
||||||
packages:
|
|
||||||
| { localPrice: { totalPrice: number; currency?: CurrencyEnum } }[]
|
|
||||||
| null
|
|
||||||
| undefined,
|
|
||||||
additionalPrice = 0,
|
|
||||||
additionalPriceCurrency?: CurrencyEnum | null | undefined
|
|
||||||
) {
|
|
||||||
const breakfastLocalPrice =
|
|
||||||
(breakfast ? breakfast.localPrice.price : 0) * nights * adults
|
|
||||||
const pkgsSum = sumPackages(packages || [])
|
|
||||||
|
|
||||||
total.local.additionalPrice = add(
|
|
||||||
total.local.additionalPrice,
|
|
||||||
additionalPrice,
|
|
||||||
breakfastLocalPrice,
|
|
||||||
pkgsSum.price
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!total.local.additionalPriceCurrency) {
|
|
||||||
if (additionalPriceCurrency) {
|
|
||||||
total.local.additionalPriceCurrency = additionalPriceCurrency
|
|
||||||
} else if (breakfast && breakfast.localPrice.currency) {
|
|
||||||
total.local.additionalPriceCurrency = breakfast.localPrice.currency
|
|
||||||
} else if (pkgsSum.currency) {
|
|
||||||
total.local.additionalPriceCurrency = pkgsSum.currency
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRequestedAdditionalPrice(
|
|
||||||
total: Price,
|
|
||||||
adults: number,
|
|
||||||
breakfast:
|
|
||||||
| {
|
|
||||||
requestedPrice?: { price: number; currency?: CurrencyEnum }
|
|
||||||
}
|
|
||||||
| false
|
|
||||||
| undefined,
|
|
||||||
nights: number,
|
|
||||||
packages:
|
|
||||||
| { requestedPrice: { totalPrice: number; currency?: CurrencyEnum } }[]
|
|
||||||
| null
|
|
||||||
| undefined,
|
|
||||||
cheques: number,
|
|
||||||
additionalPrice = 0,
|
|
||||||
additionalPriceCurrency: CurrencyEnum | null | undefined
|
|
||||||
) {
|
|
||||||
if (!total.requested) {
|
|
||||||
total.requested = {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total.requested.price = add(total.requested.price, cheques)
|
|
||||||
|
|
||||||
const breakfastRequestedPrice =
|
|
||||||
(breakfast ? breakfast.requestedPrice?.price || 0 : 0) * nights * adults
|
|
||||||
const pkgsSumRequested = sumPackagesRequestedPrice(packages)
|
|
||||||
|
|
||||||
total.requested.additionalPrice = add(
|
|
||||||
total.requested.additionalPrice,
|
|
||||||
additionalPrice,
|
|
||||||
breakfastRequestedPrice,
|
|
||||||
pkgsSumRequested.price
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!total.requested.additionalPriceCurrency) {
|
|
||||||
if (additionalPriceCurrency) {
|
|
||||||
total.requested.additionalPriceCurrency = additionalPriceCurrency
|
|
||||||
} else if (pkgsSumRequested.currency) {
|
|
||||||
total.requested.additionalPriceCurrency = pkgsSumRequested.currency
|
|
||||||
} else if (breakfast && breakfast.requestedPrice) {
|
|
||||||
total.requested.additionalPriceCurrency =
|
|
||||||
breakfast.requestedPrice.currency
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CorporateCheckRoom = PriceCalculationRoom & {
|
|
||||||
roomRate: {
|
|
||||||
corporateCheque: {
|
|
||||||
localPrice: {
|
|
||||||
numberOfCheques: number
|
|
||||||
additionalPricePerStay: number
|
|
||||||
currency?: CurrencyEnum
|
|
||||||
}
|
|
||||||
requestedPrice?: {
|
|
||||||
numberOfCheques: number
|
|
||||||
additionalPricePerStay: number
|
|
||||||
currency?: CurrencyEnum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCorporateChequePrice(
|
|
||||||
rooms: PriceCalculationRoom[],
|
|
||||||
nights: number
|
|
||||||
) {
|
|
||||||
return rooms
|
|
||||||
.filter(
|
|
||||||
(room): room is CorporateCheckRoom => "corporateCheque" in room.roomRate
|
|
||||||
)
|
|
||||||
.reduce<Price>(
|
|
||||||
(total, room) => {
|
|
||||||
const corporateCheque = room.roomRate.corporateCheque
|
|
||||||
|
|
||||||
total.local.price = add(
|
|
||||||
total.local.price,
|
|
||||||
corporateCheque.localPrice.numberOfCheques
|
|
||||||
)
|
|
||||||
|
|
||||||
getAdditionalPrice(
|
|
||||||
total,
|
|
||||||
room.adults,
|
|
||||||
room.breakfast,
|
|
||||||
nights,
|
|
||||||
room.roomFeatures,
|
|
||||||
corporateCheque.localPrice.additionalPricePerStay,
|
|
||||||
corporateCheque.localPrice.currency
|
|
||||||
)
|
|
||||||
|
|
||||||
if (corporateCheque.requestedPrice) {
|
|
||||||
getRequestedAdditionalPrice(
|
|
||||||
total,
|
|
||||||
room.adults,
|
|
||||||
room.breakfast,
|
|
||||||
nights,
|
|
||||||
room.roomFeatures,
|
|
||||||
corporateCheque.requestedPrice.numberOfCheques,
|
|
||||||
corporateCheque.requestedPrice?.additionalPricePerStay,
|
|
||||||
corporateCheque.requestedPrice?.currency
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return total
|
|
||||||
},
|
|
||||||
{
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type VoucherRoom = PriceCalculationRoom & {
|
|
||||||
roomRate: {
|
|
||||||
voucher: {
|
|
||||||
numberOfVouchers: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getVoucherPrice(rooms: PriceCalculationRoom[], nights: number) {
|
|
||||||
return rooms
|
|
||||||
.filter((room): room is VoucherRoom => "voucher" in room.roomRate)
|
|
||||||
.reduce<Price>(
|
|
||||||
(total, room) => {
|
|
||||||
const voucher = room.roomRate.voucher
|
|
||||||
|
|
||||||
total.local.price = add(total.local.price, voucher.numberOfVouchers)
|
|
||||||
|
|
||||||
getAdditionalPrice(
|
|
||||||
total,
|
|
||||||
room.adults,
|
|
||||||
room.breakfast,
|
|
||||||
nights,
|
|
||||||
room.roomFeatures
|
|
||||||
)
|
|
||||||
|
|
||||||
return total
|
|
||||||
},
|
|
||||||
{
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Voucher,
|
|
||||||
price: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type PriceCalculationRoom = {
|
|
||||||
adults: number
|
|
||||||
breakfast:
|
|
||||||
| {
|
|
||||||
localPrice: { price: number; currency?: CurrencyEnum }
|
|
||||||
requestedPrice?: { price: number; currency?: CurrencyEnum }
|
|
||||||
}
|
|
||||||
| false
|
|
||||||
| undefined
|
|
||||||
roomFeatures:
|
|
||||||
| {
|
|
||||||
localPrice: { totalPrice: number; currency?: CurrencyEnum }
|
|
||||||
requestedPrice: { totalPrice: number; currency?: CurrencyEnum }
|
|
||||||
}[]
|
|
||||||
| null
|
|
||||||
| undefined
|
|
||||||
// We don't care about roomRate unless it's RedemptionProduct
|
|
||||||
roomRate: object
|
|
||||||
}
|
|
||||||
type RedemptionRoom = PriceCalculationRoom & {
|
|
||||||
roomRate: {
|
|
||||||
redemption: {
|
|
||||||
localPrice: {
|
|
||||||
pointsPerStay: number
|
|
||||||
additionalPricePerStay: number
|
|
||||||
currency?: CurrencyEnum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRedemptionPrice(
|
|
||||||
rooms: PriceCalculationRoom[],
|
|
||||||
nights: number,
|
|
||||||
pointsCurrency?: CurrencyEnum
|
|
||||||
) {
|
|
||||||
return rooms
|
|
||||||
.filter((room): room is RedemptionRoom => "redemption" in room.roomRate)
|
|
||||||
.reduce<Price>(
|
|
||||||
(total, room) => {
|
|
||||||
const redemption = room.roomRate.redemption
|
|
||||||
|
|
||||||
total.local.price = add(
|
|
||||||
total.local.price,
|
|
||||||
redemption.localPrice.pointsPerStay
|
|
||||||
)
|
|
||||||
|
|
||||||
getAdditionalPrice(
|
|
||||||
total,
|
|
||||||
room.adults,
|
|
||||||
room.breakfast,
|
|
||||||
nights,
|
|
||||||
room.roomFeatures,
|
|
||||||
redemption.localPrice.additionalPricePerStay,
|
|
||||||
redemption.localPrice.currency
|
|
||||||
)
|
|
||||||
|
|
||||||
return total
|
|
||||||
},
|
|
||||||
{
|
|
||||||
local: {
|
|
||||||
currency: pointsCurrency ?? CurrencyEnum.POINTS,
|
|
||||||
price: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type RegularPriceCalculationRoom = PriceCalculationRoom & {
|
|
||||||
guest: {
|
|
||||||
join: boolean
|
|
||||||
membershipNo?: string | null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type RegularRoomLocalPrice = {
|
|
||||||
price: number
|
|
||||||
currency: CurrencyEnum
|
|
||||||
pricePerStay: number
|
|
||||||
pricePerNight: number
|
|
||||||
regularPricePerStay: number
|
|
||||||
}
|
|
||||||
type RegularRoomRequestedPrice = {
|
|
||||||
price: number
|
|
||||||
currency: CurrencyEnum
|
|
||||||
pricePerStay: number
|
|
||||||
}
|
|
||||||
type GetRegularPriceRoom = RegularPriceCalculationRoom & {
|
|
||||||
roomRate: {
|
|
||||||
member: {
|
|
||||||
localPrice: RegularRoomLocalPrice
|
|
||||||
requestedPrice: RegularRoomRequestedPrice
|
|
||||||
}
|
|
||||||
public: {
|
|
||||||
localPrice: RegularRoomLocalPrice
|
|
||||||
requestedPrice: RegularRoomRequestedPrice
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRegularPrice(
|
|
||||||
rooms: RegularPriceCalculationRoom[],
|
|
||||||
isMember: boolean,
|
|
||||||
nights: number
|
|
||||||
) {
|
|
||||||
const totalPrice = rooms
|
|
||||||
.filter(
|
|
||||||
(room): room is GetRegularPriceRoom =>
|
|
||||||
"member" in room.roomRate || "public" in room.roomRate
|
|
||||||
)
|
|
||||||
.reduce<Price>(
|
|
||||||
(total, room, idx) => {
|
|
||||||
const isMainRoomAndMember = idx === 0 && isMember
|
|
||||||
const join = Boolean(room.guest.join || room.guest.membershipNo)
|
|
||||||
const memberRate = "member" in room.roomRate && room.roomRate.member
|
|
||||||
const publicRate = "public" in room.roomRate && room.roomRate.public
|
|
||||||
const useMemberRate = (isMainRoomAndMember || join) && memberRate
|
|
||||||
|
|
||||||
const rate = useMemberRate ? memberRate : publicRate
|
|
||||||
|
|
||||||
if (!rate) {
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
|
|
||||||
const breakfastLocalPrice =
|
|
||||||
(room.breakfast ? room.breakfast.localPrice.price || 0 : 0) *
|
|
||||||
nights *
|
|
||||||
room.adults
|
|
||||||
const pkgsSum = sumPackages(room.roomFeatures || [])
|
|
||||||
const additionalCost = breakfastLocalPrice + pkgsSum.price
|
|
||||||
|
|
||||||
total.local.currency = rate.localPrice.currency
|
|
||||||
total.local.price = add(
|
|
||||||
total.local.price,
|
|
||||||
rate.localPrice.pricePerStay,
|
|
||||||
additionalCost
|
|
||||||
)
|
|
||||||
|
|
||||||
if (rate.requestedPrice) {
|
|
||||||
if (!total.requested) {
|
|
||||||
total.requested = {
|
|
||||||
currency: rate.requestedPrice.currency,
|
|
||||||
price: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const breakfastRequestedPrice =
|
|
||||||
(room.breakfast ? (room.breakfast.requestedPrice?.price ?? 0) : 0) *
|
|
||||||
nights *
|
|
||||||
room.adults
|
|
||||||
const pkgsSumRequested = sumPackagesRequestedPrice(room.roomFeatures)
|
|
||||||
|
|
||||||
total.requested.price = add(
|
|
||||||
total.requested.price,
|
|
||||||
rate.requestedPrice.pricePerStay,
|
|
||||||
breakfastRequestedPrice,
|
|
||||||
pkgsSumRequested.price
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return calculateRegularPrice({
|
|
||||||
total,
|
|
||||||
useMemberRate: !!useMemberRate,
|
|
||||||
regularMemberPrice: memberRate
|
|
||||||
? {
|
|
||||||
pricePerStay: memberRate.localPrice.pricePerNight,
|
|
||||||
regularPricePerStay: memberRate.localPrice.regularPricePerStay,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
regularPublicPrice: publicRate
|
|
||||||
? {
|
|
||||||
pricePerStay: publicRate.localPrice.pricePerNight,
|
|
||||||
regularPricePerStay: publicRate.localPrice.regularPricePerStay,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
additionalCost,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Unknown,
|
|
||||||
price: 0,
|
|
||||||
regularPrice: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
|
||||||
totalPrice.local.regularPrice &&
|
|
||||||
totalPrice.local.price >= totalPrice.local.regularPrice
|
|
||||||
) {
|
|
||||||
totalPrice.local.regularPrice = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return totalPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
type TRoom = Pick<
|
|
||||||
RoomState["room"],
|
|
||||||
"adults" | "breakfast" | "guest" | "roomFeatures" | "roomRate"
|
|
||||||
>
|
|
||||||
|
|
||||||
export function getTotalPrice(
|
|
||||||
rooms: TRoom[],
|
|
||||||
isMember: boolean,
|
|
||||||
nights: number,
|
|
||||||
pointsCurrency?: CurrencyEnum
|
|
||||||
) {
|
|
||||||
const hasCorpChqRates = rooms.some(
|
|
||||||
(room) => "corporateCheque" in room.roomRate
|
|
||||||
)
|
|
||||||
if (hasCorpChqRates) {
|
|
||||||
return getCorporateChequePrice(rooms, nights)
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasRedemptionRates = rooms.some((room) => "redemption" in room.roomRate)
|
|
||||||
if (hasRedemptionRates) {
|
|
||||||
return getRedemptionPrice(rooms, nights, pointsCurrency)
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasVoucherRates = rooms.some((room) => "voucher" in room.roomRate)
|
|
||||||
if (hasVoucherRates) {
|
|
||||||
return getVoucherPrice(rooms, nights)
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRegularPrice(rooms, isMember, nights)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ import { EnterDetailsStepEnum } from "./enterDetailsStep"
|
|||||||
import {
|
import {
|
||||||
checkRoomProgress,
|
checkRoomProgress,
|
||||||
extractGuestFromUser,
|
extractGuestFromUser,
|
||||||
getRoomPrice,
|
|
||||||
getTotalPrice,
|
|
||||||
writeToSessionStorage,
|
writeToSessionStorage,
|
||||||
} from "./helpers"
|
} from "./helpers"
|
||||||
|
import { getRoomPrice, getTotalPrice } from "./priceCalculations"
|
||||||
|
|
||||||
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
||||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
getRequestedAdditionalPrice,
|
getRequestedAdditionalPrice,
|
||||||
getTotalPrice,
|
getTotalPrice,
|
||||||
getVoucherPrice,
|
getVoucherPrice,
|
||||||
} from "./helpers"
|
} from "./priceCalculations"
|
||||||
|
|
||||||
type GetAdditionalPriceParams = Parameters<typeof getAdditionalPrice>
|
type GetAdditionalPriceParams = Parameters<typeof getAdditionalPrice>
|
||||||
describe("getAdditionalPrice", () => {
|
describe("getAdditionalPrice", () => {
|
||||||
@@ -920,48 +920,6 @@ describe("getCorporateChequePrice", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("does not return price for rooms without corporateCheque", () => {
|
|
||||||
const nights = 2
|
|
||||||
const rooms: GetCorporateChequePriceParams[0] = [
|
|
||||||
{
|
|
||||||
adults: 1,
|
|
||||||
breakfast: false,
|
|
||||||
roomFeatures: [],
|
|
||||||
roomRate: {
|
|
||||||
public: {
|
|
||||||
localPrice: {
|
|
||||||
pricePerStay: 500,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
adults: 1,
|
|
||||||
breakfast: false,
|
|
||||||
roomFeatures: [],
|
|
||||||
roomRate: {
|
|
||||||
corporateCheque: {
|
|
||||||
localPrice: {
|
|
||||||
numberOfCheques: 3,
|
|
||||||
additionalPricePerStay: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const result = getCorporateChequePrice(rooms, nights)
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
local: {
|
|
||||||
price: 3,
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
additionalPrice: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("calculates combined price with breakfast and room features", () => {
|
it("calculates combined price with breakfast and room features", () => {
|
||||||
const nights = 3
|
const nights = 3
|
||||||
const rooms: GetCorporateChequePriceParams[0] = [
|
const rooms: GetCorporateChequePriceParams[0] = [
|
||||||
@@ -1167,49 +1125,6 @@ describe("getRedemptionPrice", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("does not return price for room without redemption", () => {
|
|
||||||
const nights = 3
|
|
||||||
const result = getRedemptionPrice(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
adults: 1,
|
|
||||||
breakfast: false,
|
|
||||||
roomFeatures: [],
|
|
||||||
roomRate: {
|
|
||||||
public: {
|
|
||||||
price: 150,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
adults: 1,
|
|
||||||
breakfast: false,
|
|
||||||
roomFeatures: [],
|
|
||||||
roomRate: {
|
|
||||||
redemption: {
|
|
||||||
localPrice: {
|
|
||||||
pointsPerStay: 150,
|
|
||||||
currency: CurrencyEnum.POINTS,
|
|
||||||
additionalPricePerStay: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
nights
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
local: {
|
|
||||||
price: 150,
|
|
||||||
currency: CurrencyEnum.POINTS,
|
|
||||||
additionalPrice: 0,
|
|
||||||
additionalPriceCurrency: CurrencyEnum.POINTS,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("returns price and additionalPrice for single room with room features", () => {
|
it("returns price and additionalPrice for single room with room features", () => {
|
||||||
const nights = 2
|
const nights = 2
|
||||||
const result = getRedemptionPrice(
|
const result = getRedemptionPrice(
|
||||||
@@ -1352,48 +1267,6 @@ describe("getVoucherPrice", () => {
|
|||||||
requested: undefined,
|
requested: undefined,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("does not return price for room without voucher", () => {
|
|
||||||
const nights = 3
|
|
||||||
const result = getVoucherPrice(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
adults: 1,
|
|
||||||
breakfast: false,
|
|
||||||
roomFeatures: [],
|
|
||||||
roomRate: {
|
|
||||||
redemption: {
|
|
||||||
localPrice: {
|
|
||||||
pointsPerStay: 150,
|
|
||||||
currency: CurrencyEnum.POINTS,
|
|
||||||
additionalPricePerStay: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
adults: 1,
|
|
||||||
breakfast: false,
|
|
||||||
roomFeatures: [],
|
|
||||||
roomRate: {
|
|
||||||
voucher: {
|
|
||||||
numberOfVouchers: 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
nights
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
local: {
|
|
||||||
price: 2,
|
|
||||||
currency: CurrencyEnum.Voucher,
|
|
||||||
additionalPrice: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("getRegularPrice", () => {
|
describe("getRegularPrice", () => {
|
||||||
@@ -1412,34 +1285,6 @@ describe("getRegularPrice", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns price 0 for rooms without public or member rate", () => {
|
|
||||||
const isMember = false
|
|
||||||
const nights = 1
|
|
||||||
const guest = { join: false }
|
|
||||||
const result = getRegularPrice(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
adults: 1,
|
|
||||||
breakfast: false,
|
|
||||||
guest,
|
|
||||||
roomFeatures: [],
|
|
||||||
roomRate: {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
isMember,
|
|
||||||
nights
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Unknown,
|
|
||||||
price: 0,
|
|
||||||
regularPrice: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("calculates regular price for non-member", () => {
|
it("calculates regular price for non-member", () => {
|
||||||
const isMember = false
|
const isMember = false
|
||||||
const nights = 2
|
const nights = 2
|
||||||
@@ -1455,6 +1300,7 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 100,
|
pricePerNight: 100,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 100,
|
regularPricePerStay: 100,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1462,6 +1308,7 @@ describe("getRegularPrice", () => {
|
|||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 50,
|
pricePerNight: 50,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 50,
|
regularPricePerStay: 50,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1498,6 +1345,7 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 100,
|
pricePerNight: 100,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 100,
|
regularPricePerStay: 100,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1505,6 +1353,7 @@ describe("getRegularPrice", () => {
|
|||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 50,
|
pricePerNight: 50,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 50,
|
regularPricePerStay: 50,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1541,10 +1390,12 @@ describe("getRegularPrice", () => {
|
|||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 50,
|
pricePerNight: 50,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 50,
|
regularPricePerStay: 50,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
public: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -1577,10 +1428,12 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 50,
|
pricePerNight: 50,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 50,
|
regularPricePerStay: 50,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
member: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -1613,6 +1466,7 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 100,
|
pricePerNight: 100,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 100,
|
regularPricePerStay: 100,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1620,6 +1474,7 @@ describe("getRegularPrice", () => {
|
|||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 50,
|
pricePerNight: 50,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 50,
|
regularPricePerStay: 50,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1665,6 +1520,7 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 100,
|
pricePerNight: 100,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 100,
|
regularPricePerStay: 100,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1672,6 +1528,7 @@ describe("getRegularPrice", () => {
|
|||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 50,
|
pricePerNight: 50,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 50,
|
regularPricePerStay: 50,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1713,10 +1570,12 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 0,
|
pricePerNight: 0,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 0,
|
regularPricePerStay: 0,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
member: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -1757,15 +1616,16 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 100,
|
pricePerNight: 100,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 100,
|
regularPricePerStay: 100,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
requestedPrice: {
|
requestedPrice: {
|
||||||
currency: CurrencyEnum.EUR,
|
currency: CurrencyEnum.EUR,
|
||||||
pricePerNight: 10,
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 10,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
member: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -1800,6 +1660,7 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 100,
|
pricePerNight: 100,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 100,
|
regularPricePerStay: 100,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1807,6 +1668,7 @@ describe("getRegularPrice", () => {
|
|||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 50,
|
pricePerNight: 50,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 50,
|
regularPricePerStay: 50,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1822,6 +1684,7 @@ describe("getRegularPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 75,
|
pricePerNight: 75,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 75,
|
regularPricePerStay: 75,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1829,6 +1692,7 @@ describe("getRegularPrice", () => {
|
|||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 30,
|
pricePerNight: 30,
|
||||||
|
pricePerStay: 0,
|
||||||
regularPricePerStay: 30,
|
regularPricePerStay: 30,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
},
|
},
|
||||||
@@ -1849,6 +1713,36 @@ describe("getRegularPrice", () => {
|
|||||||
requested: undefined,
|
requested: undefined,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("returns unknown price for room without public and member rate", () => {
|
||||||
|
const isMember = false
|
||||||
|
const nights = 1
|
||||||
|
const result = getRegularPrice(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
adults: 1,
|
||||||
|
breakfast: false,
|
||||||
|
roomFeatures: [],
|
||||||
|
guest: { join: false },
|
||||||
|
roomRate: {
|
||||||
|
public: null,
|
||||||
|
member: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isMember,
|
||||||
|
nights
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.Unknown,
|
||||||
|
price: 0,
|
||||||
|
regularPrice: 0,
|
||||||
|
},
|
||||||
|
requested: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
type TotalPriceRooms = Parameters<typeof getTotalPrice>[0]
|
type TotalPriceRooms = Parameters<typeof getTotalPrice>[0]
|
||||||
@@ -1868,15 +1762,8 @@ describe("getTotalPrice", () => {
|
|||||||
numberOfCheques: 3,
|
numberOfCheques: 3,
|
||||||
additionalPricePerStay: 0,
|
additionalPricePerStay: 0,
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
bookingCode: {} as never,
|
|
||||||
rateDefinition: {} as never,
|
|
||||||
rate: {} as never,
|
|
||||||
rateDefinitionMember: {} as never,
|
|
||||||
},
|
},
|
||||||
guest: {} as never,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
adults: 1,
|
adults: 1,
|
||||||
@@ -1886,33 +1773,21 @@ describe("getTotalPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerStay: 500,
|
pricePerStay: 500,
|
||||||
|
pricePerNight: 500,
|
||||||
|
regularPricePerStay: 500,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
omnibusPricePerNight: {} as never,
|
|
||||||
pricePerNight: {} as never,
|
|
||||||
regularPricePerNight: {} as never,
|
|
||||||
regularPricePerStay: {} as never,
|
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 30,
|
pricePerNight: 30,
|
||||||
|
pricePerStay: 30,
|
||||||
regularPricePerStay: 30,
|
regularPricePerStay: 30,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
omnibusPricePerNight: {} as never,
|
|
||||||
pricePerStay: {} as never,
|
|
||||||
regularPricePerNight: {} as never,
|
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
bookingCode: {} as never,
|
|
||||||
rateDefinition: {} as never,
|
|
||||||
rate: {} as never,
|
|
||||||
rateDefinitionMember: {} as never,
|
|
||||||
},
|
},
|
||||||
guest: {} as never,
|
guest: { join: false },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1941,20 +1816,11 @@ describe("getTotalPrice", () => {
|
|||||||
redemption: {
|
redemption: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pointsPerStay: 100,
|
pointsPerStay: 100,
|
||||||
pointsPerNight: 100,
|
|
||||||
currency: CurrencyEnum.POINTS,
|
currency: CurrencyEnum.POINTS,
|
||||||
additionalPricePerStay: 0,
|
additionalPricePerStay: 0,
|
||||||
},
|
},
|
||||||
hasEnoughPoints: {} as never,
|
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
bookingCode: {} as never,
|
|
||||||
rateDefinition: {} as never,
|
|
||||||
rate: {} as never,
|
|
||||||
rateDefinitionMember: {} as never,
|
|
||||||
},
|
},
|
||||||
guest: {} as never,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
adults: 1,
|
adults: 1,
|
||||||
@@ -1964,33 +1830,21 @@ describe("getTotalPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerStay: 500,
|
pricePerStay: 500,
|
||||||
|
pricePerNight: 500,
|
||||||
|
regularPricePerStay: 500,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
omnibusPricePerNight: {} as never,
|
|
||||||
pricePerNight: {} as never,
|
|
||||||
regularPricePerNight: {} as never,
|
|
||||||
regularPricePerStay: {} as never,
|
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 30,
|
pricePerNight: 30,
|
||||||
|
pricePerStay: 30,
|
||||||
regularPricePerStay: 30,
|
regularPricePerStay: 30,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
omnibusPricePerNight: {} as never,
|
|
||||||
pricePerStay: {} as never,
|
|
||||||
regularPricePerNight: {} as never,
|
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
bookingCode: {} as never,
|
|
||||||
rateDefinition: {} as never,
|
|
||||||
rate: {} as never,
|
|
||||||
rateDefinitionMember: {} as never,
|
|
||||||
},
|
},
|
||||||
guest: {} as never,
|
guest: { join: false },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2018,15 +1872,8 @@ describe("getTotalPrice", () => {
|
|||||||
roomRate: {
|
roomRate: {
|
||||||
voucher: {
|
voucher: {
|
||||||
numberOfVouchers: 1,
|
numberOfVouchers: 1,
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
bookingCode: {} as never,
|
|
||||||
rateDefinition: {} as never,
|
|
||||||
rate: {} as never,
|
|
||||||
rateDefinitionMember: {} as never,
|
|
||||||
},
|
},
|
||||||
guest: {} as never,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
adults: 1,
|
adults: 1,
|
||||||
@@ -2036,33 +1883,21 @@ describe("getTotalPrice", () => {
|
|||||||
public: {
|
public: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerStay: 500,
|
pricePerStay: 500,
|
||||||
|
pricePerNight: 500,
|
||||||
|
regularPricePerStay: 500,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
omnibusPricePerNight: {} as never,
|
|
||||||
pricePerNight: {} as never,
|
|
||||||
regularPricePerNight: {} as never,
|
|
||||||
regularPricePerStay: {} as never,
|
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerNight: 30,
|
pricePerNight: 30,
|
||||||
|
pricePerStay: 30,
|
||||||
regularPricePerStay: 30,
|
regularPricePerStay: 30,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
omnibusPricePerNight: {} as never,
|
|
||||||
pricePerStay: {} as never,
|
|
||||||
regularPricePerNight: {} as never,
|
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
bookingCode: {} as never,
|
|
||||||
rateDefinition: {} as never,
|
|
||||||
rate: {} as never,
|
|
||||||
rateDefinitionMember: {} as never,
|
|
||||||
},
|
},
|
||||||
guest: {} as never,
|
guest: { join: false },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2092,31 +1927,19 @@ describe("getTotalPrice", () => {
|
|||||||
pricePerStay: 500,
|
pricePerStay: 500,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
regularPricePerStay: 500,
|
regularPricePerStay: 500,
|
||||||
omnibusPricePerNight: {} as never,
|
pricePerNight: 500,
|
||||||
pricePerNight: {} as never,
|
|
||||||
regularPricePerNight: {} as never,
|
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
localPrice: {
|
localPrice: {
|
||||||
pricePerStay: 30,
|
pricePerStay: 30,
|
||||||
currency: CurrencyEnum.SEK,
|
currency: CurrencyEnum.SEK,
|
||||||
regularPricePerStay: 30,
|
regularPricePerStay: 30,
|
||||||
omnibusPricePerNight: {} as never,
|
pricePerNight: 30,
|
||||||
pricePerNight: {} as never,
|
|
||||||
regularPricePerNight: {} as never,
|
|
||||||
},
|
},
|
||||||
rateCode: {} as never,
|
|
||||||
rateType: {} as never,
|
|
||||||
},
|
},
|
||||||
bookingCode: {} as never,
|
|
||||||
rateDefinition: {} as never,
|
|
||||||
rate: {} as never,
|
|
||||||
rateDefinitionMember: {} as never,
|
|
||||||
},
|
},
|
||||||
guest: { join: false } as never,
|
guest: { join: false },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2131,4 +1954,64 @@ describe("getTotalPrice", () => {
|
|||||||
requested: undefined,
|
requested: undefined,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("returns regular price for room with only public rate", () => {
|
||||||
|
const nights = 1
|
||||||
|
const isMember = false
|
||||||
|
const rooms: TotalPriceRooms = [
|
||||||
|
{
|
||||||
|
adults: 1,
|
||||||
|
breakfast: false,
|
||||||
|
roomFeatures: [],
|
||||||
|
roomRate: {
|
||||||
|
public: {
|
||||||
|
localPrice: {
|
||||||
|
pricePerStay: 500,
|
||||||
|
currency: CurrencyEnum.SEK,
|
||||||
|
regularPricePerStay: 500,
|
||||||
|
pricePerNight: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
member: null,
|
||||||
|
},
|
||||||
|
guest: { join: false },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const totalPrice = getTotalPrice(rooms, isMember, nights)
|
||||||
|
|
||||||
|
expect(totalPrice).toEqual({
|
||||||
|
local: {
|
||||||
|
price: 500,
|
||||||
|
regularPrice: 0,
|
||||||
|
currency: CurrencyEnum.SEK,
|
||||||
|
},
|
||||||
|
requested: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns unknown price for unknown room type", () => {
|
||||||
|
const nights = 1
|
||||||
|
const isMember = false
|
||||||
|
const rooms: TotalPriceRooms = [
|
||||||
|
{
|
||||||
|
adults: 1,
|
||||||
|
breakfast: false,
|
||||||
|
roomFeatures: [],
|
||||||
|
roomRate: {},
|
||||||
|
guest: { join: false },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const totalPrice = getTotalPrice(rooms, isMember, nights)
|
||||||
|
|
||||||
|
expect(totalPrice).toEqual({
|
||||||
|
local: {
|
||||||
|
price: 0,
|
||||||
|
currency: CurrencyEnum.Unknown,
|
||||||
|
regularPrice: 0,
|
||||||
|
},
|
||||||
|
requested: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,626 @@
|
|||||||
|
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
||||||
|
import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType"
|
||||||
|
import { logger } from "@scandic-hotels/common/logger"
|
||||||
|
|
||||||
|
import { calculateRegularPrice } from "../../utils/calculateRegularPrice"
|
||||||
|
import { sumPackages, sumPackagesRequestedPrice } from "../../utils/SelectRate"
|
||||||
|
|
||||||
|
import type { Product } from "@scandic-hotels/trpc/types/roomAvailability"
|
||||||
|
|
||||||
|
import type { Price } from "../../types/price"
|
||||||
|
|
||||||
|
function add(...nums: (number | string | undefined)[]) {
|
||||||
|
return nums.reduce((total: number, num) => {
|
||||||
|
if (typeof num === "undefined") {
|
||||||
|
num = 0
|
||||||
|
}
|
||||||
|
total = total + parseInt(`${num}`)
|
||||||
|
return total
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoomPrice(
|
||||||
|
roomRate: Product,
|
||||||
|
isMember: boolean,
|
||||||
|
pointsCurrency?: CurrencyEnum
|
||||||
|
) {
|
||||||
|
if (isMember && "member" in roomRate && roomRate.member) {
|
||||||
|
let publicRate
|
||||||
|
if (
|
||||||
|
"public" in roomRate &&
|
||||||
|
roomRate.public?.rateType === RateTypeEnum.Regular
|
||||||
|
) {
|
||||||
|
publicRate = roomRate.public
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
perNight: {
|
||||||
|
requested: roomRate.member.requestedPrice
|
||||||
|
? {
|
||||||
|
currency: roomRate.member.requestedPrice.currency,
|
||||||
|
price: roomRate.member.requestedPrice.pricePerNight,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
local: {
|
||||||
|
currency: roomRate.member.localPrice.currency,
|
||||||
|
price: roomRate.member.localPrice.pricePerNight,
|
||||||
|
regularPrice:
|
||||||
|
publicRate?.localPrice.pricePerStay ||
|
||||||
|
roomRate.member.localPrice.regularPricePerNight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
perStay: {
|
||||||
|
requested: roomRate.member.requestedPrice
|
||||||
|
? {
|
||||||
|
currency: roomRate.member.requestedPrice.currency,
|
||||||
|
price: roomRate.member.requestedPrice.pricePerStay,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
local: {
|
||||||
|
currency: roomRate.member.localPrice.currency,
|
||||||
|
price: roomRate.member.localPrice.pricePerStay,
|
||||||
|
regularPrice:
|
||||||
|
publicRate?.localPrice.pricePerStay ||
|
||||||
|
roomRate.member.localPrice.regularPricePerStay,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("public" in roomRate && roomRate.public) {
|
||||||
|
return {
|
||||||
|
perNight: {
|
||||||
|
requested: roomRate.public.requestedPrice
|
||||||
|
? {
|
||||||
|
currency: roomRate.public.requestedPrice.currency,
|
||||||
|
price: roomRate.public.requestedPrice.pricePerNight,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
local: {
|
||||||
|
currency: roomRate.public.localPrice.currency,
|
||||||
|
price: roomRate.public.localPrice.pricePerNight,
|
||||||
|
regularPrice: roomRate.public.localPrice.regularPricePerNight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
perStay: {
|
||||||
|
requested: roomRate.public.requestedPrice
|
||||||
|
? {
|
||||||
|
currency: roomRate.public.requestedPrice.currency,
|
||||||
|
price: roomRate.public.requestedPrice.pricePerStay,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
local: {
|
||||||
|
currency: roomRate.public.localPrice.currency,
|
||||||
|
price: roomRate.public.localPrice.pricePerStay,
|
||||||
|
regularPrice: roomRate.public.localPrice.regularPricePerStay,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("corporateCheque" in roomRate) {
|
||||||
|
return {
|
||||||
|
perNight: {
|
||||||
|
requested: roomRate.corporateCheque.requestedPrice
|
||||||
|
? {
|
||||||
|
currency: CurrencyEnum.CC,
|
||||||
|
price: roomRate.corporateCheque.requestedPrice.numberOfCheques,
|
||||||
|
additionalPrice:
|
||||||
|
roomRate.corporateCheque.requestedPrice.additionalPricePerStay,
|
||||||
|
additionalPriceCurrency:
|
||||||
|
roomRate.corporateCheque.requestedPrice.currency ?? undefined,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.CC,
|
||||||
|
price: roomRate.corporateCheque.localPrice.numberOfCheques,
|
||||||
|
additionalPrice:
|
||||||
|
roomRate.corporateCheque.localPrice.additionalPricePerStay,
|
||||||
|
additionalPriceCurrency:
|
||||||
|
roomRate.corporateCheque.localPrice.currency ?? undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
perStay: {
|
||||||
|
requested: roomRate.corporateCheque.requestedPrice
|
||||||
|
? {
|
||||||
|
currency: CurrencyEnum.CC,
|
||||||
|
price: roomRate.corporateCheque.requestedPrice.numberOfCheques,
|
||||||
|
additionalPrice:
|
||||||
|
roomRate.corporateCheque.requestedPrice.additionalPricePerStay,
|
||||||
|
additionalPriceCurrency:
|
||||||
|
roomRate.corporateCheque.requestedPrice.currency ?? undefined,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.CC,
|
||||||
|
price: roomRate.corporateCheque.localPrice.numberOfCheques,
|
||||||
|
additionalPrice:
|
||||||
|
roomRate.corporateCheque.localPrice.additionalPricePerStay,
|
||||||
|
additionalPriceCurrency:
|
||||||
|
roomRate.corporateCheque.localPrice.currency ?? undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("voucher" in roomRate) {
|
||||||
|
return {
|
||||||
|
perNight: {
|
||||||
|
requested: undefined,
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.Voucher,
|
||||||
|
price: roomRate.voucher.numberOfVouchers,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
perStay: {
|
||||||
|
requested: undefined,
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.Voucher,
|
||||||
|
price: roomRate.voucher.numberOfVouchers,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("redemption" in roomRate) {
|
||||||
|
return {
|
||||||
|
// ToDo Handle perNight as undefined
|
||||||
|
perNight: {
|
||||||
|
requested: undefined,
|
||||||
|
local: {
|
||||||
|
currency: pointsCurrency ?? CurrencyEnum.POINTS,
|
||||||
|
price: roomRate.redemption.localPrice.pointsPerStay,
|
||||||
|
additionalPrice:
|
||||||
|
roomRate.redemption.localPrice.additionalPricePerStay,
|
||||||
|
additionalPriceCurrency:
|
||||||
|
roomRate.redemption.localPrice.currency ?? undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
perStay: {
|
||||||
|
requested: undefined,
|
||||||
|
local: {
|
||||||
|
currency: pointsCurrency ?? CurrencyEnum.POINTS,
|
||||||
|
price: roomRate.redemption.localPrice.pointsPerStay,
|
||||||
|
additionalPrice:
|
||||||
|
roomRate.redemption.localPrice.additionalPricePerStay,
|
||||||
|
additionalPriceCurrency:
|
||||||
|
roomRate.redemption.localPrice.currency ?? undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`Unable to calculate RoomPrice since user is neither a member or memberRate is missing, or publicRate is missing`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAdditionalPrice(
|
||||||
|
total: {
|
||||||
|
local: {
|
||||||
|
additionalPrice?: number
|
||||||
|
additionalPriceCurrency?: CurrencyEnum
|
||||||
|
}
|
||||||
|
},
|
||||||
|
adults: number,
|
||||||
|
breakfast:
|
||||||
|
| { localPrice: { price: number; currency?: CurrencyEnum } }
|
||||||
|
| false
|
||||||
|
| undefined,
|
||||||
|
nights: number,
|
||||||
|
packages:
|
||||||
|
| { localPrice: { totalPrice: number; currency?: CurrencyEnum } }[]
|
||||||
|
| null
|
||||||
|
| undefined,
|
||||||
|
additionalPrice = 0,
|
||||||
|
additionalPriceCurrency?: CurrencyEnum | null | undefined
|
||||||
|
) {
|
||||||
|
const breakfastLocalPrice =
|
||||||
|
(breakfast ? breakfast.localPrice.price : 0) * nights * adults
|
||||||
|
const pkgsSum = sumPackages(packages || [])
|
||||||
|
|
||||||
|
total.local.additionalPrice = add(
|
||||||
|
total.local.additionalPrice,
|
||||||
|
additionalPrice,
|
||||||
|
breakfastLocalPrice,
|
||||||
|
pkgsSum.price
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!total.local.additionalPriceCurrency) {
|
||||||
|
if (additionalPriceCurrency) {
|
||||||
|
total.local.additionalPriceCurrency = additionalPriceCurrency
|
||||||
|
} else if (breakfast && breakfast.localPrice.currency) {
|
||||||
|
total.local.additionalPriceCurrency = breakfast.localPrice.currency
|
||||||
|
} else if (pkgsSum.currency) {
|
||||||
|
total.local.additionalPriceCurrency = pkgsSum.currency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRequestedAdditionalPrice(
|
||||||
|
total: Price,
|
||||||
|
adults: number,
|
||||||
|
breakfast:
|
||||||
|
| {
|
||||||
|
requestedPrice?: { price: number; currency?: CurrencyEnum }
|
||||||
|
}
|
||||||
|
| false
|
||||||
|
| undefined,
|
||||||
|
nights: number,
|
||||||
|
packages:
|
||||||
|
| { requestedPrice: { totalPrice: number; currency?: CurrencyEnum } }[]
|
||||||
|
| null
|
||||||
|
| undefined,
|
||||||
|
cheques: number,
|
||||||
|
additionalPrice = 0,
|
||||||
|
additionalPriceCurrency: CurrencyEnum | null | undefined
|
||||||
|
) {
|
||||||
|
if (!total.requested) {
|
||||||
|
total.requested = {
|
||||||
|
currency: CurrencyEnum.CC,
|
||||||
|
price: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total.requested.price = add(total.requested.price, cheques)
|
||||||
|
|
||||||
|
const breakfastRequestedPrice =
|
||||||
|
(breakfast ? breakfast.requestedPrice?.price || 0 : 0) * nights * adults
|
||||||
|
const pkgsSumRequested = sumPackagesRequestedPrice(packages)
|
||||||
|
|
||||||
|
total.requested.additionalPrice = add(
|
||||||
|
total.requested.additionalPrice,
|
||||||
|
additionalPrice,
|
||||||
|
breakfastRequestedPrice,
|
||||||
|
pkgsSumRequested.price
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!total.requested.additionalPriceCurrency) {
|
||||||
|
if (additionalPriceCurrency) {
|
||||||
|
total.requested.additionalPriceCurrency = additionalPriceCurrency
|
||||||
|
} else if (pkgsSumRequested.currency) {
|
||||||
|
total.requested.additionalPriceCurrency = pkgsSumRequested.currency
|
||||||
|
} else if (breakfast && breakfast.requestedPrice) {
|
||||||
|
total.requested.additionalPriceCurrency =
|
||||||
|
breakfast.requestedPrice.currency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type BasePriceCalculationRoom = {
|
||||||
|
adults: number
|
||||||
|
breakfast:
|
||||||
|
| {
|
||||||
|
localPrice: { price: number; currency?: CurrencyEnum }
|
||||||
|
requestedPrice?: { price: number; currency?: CurrencyEnum }
|
||||||
|
}
|
||||||
|
| false
|
||||||
|
| undefined
|
||||||
|
roomFeatures:
|
||||||
|
| {
|
||||||
|
localPrice: { totalPrice: number; currency?: CurrencyEnum }
|
||||||
|
requestedPrice: { totalPrice: number; currency?: CurrencyEnum }
|
||||||
|
}[]
|
||||||
|
| null
|
||||||
|
| undefined
|
||||||
|
// We don't care about what type of roomRate it is yet
|
||||||
|
roomRate: object
|
||||||
|
}
|
||||||
|
|
||||||
|
type CorporateCheckRoom = BasePriceCalculationRoom & {
|
||||||
|
roomRate: {
|
||||||
|
corporateCheque: {
|
||||||
|
localPrice: {
|
||||||
|
numberOfCheques: number
|
||||||
|
additionalPricePerStay: number
|
||||||
|
currency?: CurrencyEnum
|
||||||
|
}
|
||||||
|
requestedPrice?: {
|
||||||
|
numberOfCheques: number
|
||||||
|
additionalPricePerStay: number
|
||||||
|
currency?: CurrencyEnum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function getCorporateChequePrice(
|
||||||
|
rooms: CorporateCheckRoom[],
|
||||||
|
nights: number
|
||||||
|
) {
|
||||||
|
return rooms.reduce<Price>(
|
||||||
|
(total, room) => {
|
||||||
|
const corporateCheque = room.roomRate.corporateCheque
|
||||||
|
|
||||||
|
total.local.price = add(
|
||||||
|
total.local.price,
|
||||||
|
corporateCheque.localPrice.numberOfCheques
|
||||||
|
)
|
||||||
|
|
||||||
|
getAdditionalPrice(
|
||||||
|
total,
|
||||||
|
room.adults,
|
||||||
|
room.breakfast,
|
||||||
|
nights,
|
||||||
|
room.roomFeatures,
|
||||||
|
corporateCheque.localPrice.additionalPricePerStay,
|
||||||
|
corporateCheque.localPrice.currency
|
||||||
|
)
|
||||||
|
|
||||||
|
if (corporateCheque.requestedPrice) {
|
||||||
|
getRequestedAdditionalPrice(
|
||||||
|
total,
|
||||||
|
room.adults,
|
||||||
|
room.breakfast,
|
||||||
|
nights,
|
||||||
|
room.roomFeatures,
|
||||||
|
corporateCheque.requestedPrice.numberOfCheques,
|
||||||
|
corporateCheque.requestedPrice?.additionalPricePerStay,
|
||||||
|
corporateCheque.requestedPrice?.currency
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return total
|
||||||
|
},
|
||||||
|
{
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.CC,
|
||||||
|
price: 0,
|
||||||
|
},
|
||||||
|
requested: undefined,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type VoucherRoom = BasePriceCalculationRoom & {
|
||||||
|
roomRate: {
|
||||||
|
voucher: {
|
||||||
|
numberOfVouchers: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function getVoucherPrice(rooms: VoucherRoom[], nights: number) {
|
||||||
|
return rooms.reduce<Price>(
|
||||||
|
(total, room) => {
|
||||||
|
const voucher = room.roomRate.voucher
|
||||||
|
|
||||||
|
total.local.price = add(total.local.price, voucher.numberOfVouchers)
|
||||||
|
|
||||||
|
getAdditionalPrice(
|
||||||
|
total,
|
||||||
|
room.adults,
|
||||||
|
room.breakfast,
|
||||||
|
nights,
|
||||||
|
room.roomFeatures
|
||||||
|
)
|
||||||
|
|
||||||
|
return total
|
||||||
|
},
|
||||||
|
{
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.Voucher,
|
||||||
|
price: 0,
|
||||||
|
},
|
||||||
|
requested: undefined,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RedemptionRoom = BasePriceCalculationRoom & {
|
||||||
|
roomRate: {
|
||||||
|
redemption: {
|
||||||
|
localPrice: {
|
||||||
|
pointsPerStay: number
|
||||||
|
additionalPricePerStay: number
|
||||||
|
currency?: CurrencyEnum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRedemptionPrice(
|
||||||
|
rooms: RedemptionRoom[],
|
||||||
|
nights: number,
|
||||||
|
pointsCurrency?: CurrencyEnum
|
||||||
|
) {
|
||||||
|
return rooms.reduce<Price>(
|
||||||
|
(total, room) => {
|
||||||
|
const redemption = room.roomRate.redemption
|
||||||
|
|
||||||
|
total.local.price = add(
|
||||||
|
total.local.price,
|
||||||
|
redemption.localPrice.pointsPerStay
|
||||||
|
)
|
||||||
|
|
||||||
|
getAdditionalPrice(
|
||||||
|
total,
|
||||||
|
room.adults,
|
||||||
|
room.breakfast,
|
||||||
|
nights,
|
||||||
|
room.roomFeatures,
|
||||||
|
redemption.localPrice.additionalPricePerStay,
|
||||||
|
redemption.localPrice.currency
|
||||||
|
)
|
||||||
|
|
||||||
|
return total
|
||||||
|
},
|
||||||
|
{
|
||||||
|
local: {
|
||||||
|
currency: pointsCurrency ?? CurrencyEnum.POINTS,
|
||||||
|
price: 0,
|
||||||
|
},
|
||||||
|
requested: undefined,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegularPriceCalculationRoom = BasePriceCalculationRoom & {
|
||||||
|
guest: {
|
||||||
|
join: boolean
|
||||||
|
membershipNo?: string | null
|
||||||
|
}
|
||||||
|
roomRate: {
|
||||||
|
member?: {
|
||||||
|
localPrice: RegularRoomLocalPrice
|
||||||
|
requestedPrice?: RegularRoomRequestedPrice | null
|
||||||
|
} | null
|
||||||
|
public?: {
|
||||||
|
localPrice: RegularRoomLocalPrice
|
||||||
|
requestedPrice?: RegularRoomRequestedPrice | null
|
||||||
|
} | null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type RegularRoomLocalPrice = {
|
||||||
|
currency: CurrencyEnum
|
||||||
|
pricePerStay: number
|
||||||
|
pricePerNight: number
|
||||||
|
regularPricePerStay: number
|
||||||
|
}
|
||||||
|
type RegularRoomRequestedPrice = {
|
||||||
|
currency: CurrencyEnum
|
||||||
|
pricePerStay: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRegularPrice(
|
||||||
|
rooms: RegularPriceCalculationRoom[],
|
||||||
|
isMember: boolean,
|
||||||
|
nights: number
|
||||||
|
) {
|
||||||
|
const totalPrice = rooms.reduce<Price>(
|
||||||
|
(total, room, idx) => {
|
||||||
|
const isMainRoomAndMember = idx === 0 && isMember
|
||||||
|
const join = Boolean(room.guest.join || room.guest.membershipNo)
|
||||||
|
const memberRate = room.roomRate.member
|
||||||
|
const publicRate = room.roomRate.public
|
||||||
|
const useMemberRate = (isMainRoomAndMember || join) && memberRate
|
||||||
|
|
||||||
|
const rate = useMemberRate ? memberRate : publicRate
|
||||||
|
|
||||||
|
if (!rate) {
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
const breakfastLocalPrice =
|
||||||
|
(room.breakfast ? room.breakfast.localPrice.price || 0 : 0) *
|
||||||
|
nights *
|
||||||
|
room.adults
|
||||||
|
const pkgsSum = sumPackages(room.roomFeatures || [])
|
||||||
|
const additionalCost = breakfastLocalPrice + pkgsSum.price
|
||||||
|
|
||||||
|
total.local.currency = rate.localPrice.currency
|
||||||
|
total.local.price = add(
|
||||||
|
total.local.price,
|
||||||
|
rate.localPrice.pricePerStay,
|
||||||
|
additionalCost
|
||||||
|
)
|
||||||
|
|
||||||
|
if (rate.requestedPrice) {
|
||||||
|
if (!total.requested) {
|
||||||
|
total.requested = {
|
||||||
|
currency: rate.requestedPrice.currency,
|
||||||
|
price: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const breakfastRequestedPrice =
|
||||||
|
(room.breakfast ? (room.breakfast.requestedPrice?.price ?? 0) : 0) *
|
||||||
|
nights *
|
||||||
|
room.adults
|
||||||
|
const pkgsSumRequested = sumPackagesRequestedPrice(room.roomFeatures)
|
||||||
|
|
||||||
|
total.requested.price = add(
|
||||||
|
total.requested.price,
|
||||||
|
rate.requestedPrice.pricePerStay,
|
||||||
|
breakfastRequestedPrice,
|
||||||
|
pkgsSumRequested.price
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return calculateRegularPrice({
|
||||||
|
total,
|
||||||
|
useMemberRate: !!useMemberRate,
|
||||||
|
regularMemberPrice: memberRate
|
||||||
|
? {
|
||||||
|
pricePerStay: memberRate.localPrice.pricePerNight,
|
||||||
|
regularPricePerStay: memberRate.localPrice.regularPricePerStay,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
regularPublicPrice: publicRate
|
||||||
|
? {
|
||||||
|
pricePerStay: publicRate.localPrice.pricePerNight,
|
||||||
|
regularPricePerStay: publicRate.localPrice.regularPricePerStay,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
additionalCost,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.Unknown,
|
||||||
|
price: 0,
|
||||||
|
regularPrice: 0,
|
||||||
|
},
|
||||||
|
requested: undefined,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
totalPrice.local.regularPrice &&
|
||||||
|
totalPrice.local.price >= totalPrice.local.regularPrice
|
||||||
|
) {
|
||||||
|
totalPrice.local.regularPrice = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTotalPrice(
|
||||||
|
rooms: (
|
||||||
|
| RegularPriceCalculationRoom
|
||||||
|
| CorporateCheckRoom
|
||||||
|
| RedemptionRoom
|
||||||
|
| VoucherRoom
|
||||||
|
)[],
|
||||||
|
isMember: boolean,
|
||||||
|
nights: number,
|
||||||
|
pointsCurrency?: CurrencyEnum
|
||||||
|
) {
|
||||||
|
const corporateChequeRooms = rooms.filter(
|
||||||
|
(x): x is CorporateCheckRoom => "corporateCheque" in x.roomRate
|
||||||
|
)
|
||||||
|
if (corporateChequeRooms.length > 0) {
|
||||||
|
return getCorporateChequePrice(corporateChequeRooms, nights)
|
||||||
|
}
|
||||||
|
|
||||||
|
const redemptionRooms = rooms.filter(
|
||||||
|
(x): x is RedemptionRoom => "redemption" in x.roomRate
|
||||||
|
)
|
||||||
|
if (redemptionRooms.length > 0) {
|
||||||
|
return getRedemptionPrice(redemptionRooms, nights, pointsCurrency)
|
||||||
|
}
|
||||||
|
|
||||||
|
const voucherRooms = rooms.filter(
|
||||||
|
(x): x is VoucherRoom => "voucher" in x.roomRate
|
||||||
|
)
|
||||||
|
if (voucherRooms.length > 0) {
|
||||||
|
return getVoucherPrice(voucherRooms, nights)
|
||||||
|
}
|
||||||
|
|
||||||
|
const regularRooms = rooms.filter(
|
||||||
|
(x): x is RegularPriceCalculationRoom =>
|
||||||
|
"member" in x.roomRate || "public" in x.roomRate
|
||||||
|
)
|
||||||
|
if (regularRooms.length > 0) {
|
||||||
|
return getRegularPrice(regularRooms, isMember, nights)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.warn(
|
||||||
|
"Unable to determine room type for price calculation, return zero price"
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
local: {
|
||||||
|
currency: CurrencyEnum.Unknown,
|
||||||
|
price: 0,
|
||||||
|
regularPrice: 0,
|
||||||
|
},
|
||||||
|
requested: undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user