Files
web/packages/booking-flow/lib/contexts/SelectRate/getTotalPrice.ts
Hrishikesh Vaipurkar 0a4bf40a15 Merged in chore/SW-3321-move-selectratecontext-to- (pull request #2729)
chore(SW-3321): Moved Select rate context to booking-flow package

* chore(SW-3321): Moved Select rate context to booking-flow package

* chore(SW-3321): Optimised code


Approved-by: Joakim Jäderberg
2025-09-02 07:40:01 +00:00

270 lines
7.2 KiB
TypeScript

import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { sumPackages } from "../../utils/SelectRate"
import type { RedemptionProduct } from "@scandic-hotels/trpc/types/roomAvailability"
import type { AvailabilityWithRoomInfo, Rate, RoomPackage } from "./types"
type TPrice = {
additionalPrice?: number
additionalPriceCurrency?: CurrencyEnum
currency: CurrencyEnum
price: number
regularPrice?: number
}
export type Price = {
requested?: TPrice
local: TPrice
}
type SelectedRate = {
roomConfiguration: AvailabilityWithRoomInfo | null
rate: Rate | undefined
}
export function getTotalPrice({
selectedRates,
useMemberPrices,
}: {
selectedRates: Array<SelectedRate | null>
useMemberPrices: boolean
}): Price | null {
const mainRoom = selectedRates[0]
const mainRoomRate = mainRoom?.rate
const summaryArray = selectedRates.filter(
(x): x is OneLevelNonNullable<SelectedRate> => !!x
)
if (summaryArray.some((rate) => "corporateCheque" in rate)) {
return calculateCorporateChequePrice(summaryArray)
}
if (!mainRoomRate) {
return calculateTotalPrice(summaryArray, useMemberPrices)
}
// In case of reward night (redemption) or voucher only single room booking is supported by business rules
if ("redemption" in mainRoomRate) {
return calculateRedemptionTotalPrice(
mainRoomRate.redemption,
mainRoom.roomConfiguration?.selectedPackages.filter(
(pkg) => "localPrice" in pkg
) ?? null
)
}
if ("voucher" in mainRoomRate) {
const voucherPrice = calculateVoucherPrice(summaryArray)
return voucherPrice
}
return calculateTotalPrice(summaryArray, useMemberPrices)
}
function calculateTotalPrice(
selectedRateSummary: OneLevelNonNullable<SelectedRate>[],
useMemberPrices: boolean
) {
return selectedRateSummary.reduce<Price>(
(total, room, idx) => {
if (!room.rate || !("member" in room.rate) || !("public" in room.rate)) {
return total
}
const roomNr = idx + 1
const isMainRoom = roomNr === 1
const useMemberRate = isMainRoom && useMemberPrices && room.rate.member
const rate = useMemberRate ? room.rate.member : room.rate.public
if (!rate) {
return total
}
const packagesPrice = room.roomConfiguration?.selectedPackages.reduce(
(total, pkg) => {
total.local = total.local + pkg.localPrice.totalPrice
if (pkg.requestedPrice.totalPrice) {
total.requested = total.requested + pkg.requestedPrice.totalPrice
}
return total
},
{ local: 0, requested: 0 }
)
total.local.currency = rate.localPrice.currency
total.local.price =
total.local.price + rate.localPrice.pricePerStay + packagesPrice.local
if (rate.localPrice.regularPricePerStay) {
total.local.regularPrice =
(total.local.regularPrice || 0) +
rate.localPrice.regularPricePerStay +
packagesPrice.local
}
if (rate.requestedPrice) {
if (!total.requested) {
total.requested = {
currency: rate.requestedPrice.currency,
price: 0,
}
}
if (!total.requested.currency) {
total.requested.currency = rate.requestedPrice.currency
}
total.requested.price =
total.requested.price +
rate.requestedPrice.pricePerStay +
packagesPrice.requested
if (rate.requestedPrice.regularPricePerStay) {
total.requested.regularPrice =
(total.requested.regularPrice || 0) +
rate.requestedPrice.regularPricePerStay +
packagesPrice.requested
}
}
return total
},
{
local: {
currency: CurrencyEnum.Unknown,
price: 0,
regularPrice: undefined,
},
requested: undefined,
}
)
}
function calculateRedemptionTotalPrice(
redemption: RedemptionProduct["redemption"],
packages: RoomPackage[] | null
) {
const pkgsSum = sumPackages(packages)
let additionalPrice
if (redemption.localPrice.additionalPricePerStay) {
additionalPrice =
redemption.localPrice.additionalPricePerStay + pkgsSum.price
} else if (pkgsSum.price) {
additionalPrice = pkgsSum.price
}
let additionalPriceCurrency
if (redemption.localPrice.currency) {
additionalPriceCurrency = redemption.localPrice.currency
} else if (pkgsSum.currency) {
additionalPriceCurrency = pkgsSum.currency
}
return {
local: {
additionalPrice,
additionalPriceCurrency,
currency: CurrencyEnum.POINTS,
price: redemption.localPrice.pointsPerStay,
},
}
}
function calculateVoucherPrice(
selectedRateSummary: OneLevelNonNullable<SelectedRate>[]
) {
return selectedRateSummary.reduce<Price>(
(total, room) => {
if (!("voucher" in room.rate)) {
return total
}
const rate = room.rate.voucher
total.local.price = total.local.price + rate.numberOfVouchers
const pkgsSum = sumPackages(room.roomConfiguration?.selectedPackages)
if (pkgsSum.price && pkgsSum.currency) {
total.local.additionalPrice =
(total.local.additionalPrice || 0) + pkgsSum.price
total.local.additionalPriceCurrency = pkgsSum.currency
}
return total
},
{
local: {
currency: CurrencyEnum.Voucher,
price: 0,
},
requested: undefined,
}
)
}
type OneLevelNonNullable<T> = {
[K in keyof T]-?: NonNullable<T[K]>
}
export function calculateCorporateChequePrice(
selectedRates: OneLevelNonNullable<SelectedRate>[]
) {
return selectedRates.reduce<Price>(
(total, room) => {
if (!("corporateCheque" in room.rate)) {
return total
}
const rate = room.rate.corporateCheque
const pkgsSum = sumPackages(
selectedRates.flatMap((x) => x.roomConfiguration?.selectedPackages)
)
total.local.price = total.local.price + rate.localPrice.numberOfCheques
if (rate.localPrice.additionalPricePerStay) {
total.local.additionalPrice =
(total.local.additionalPrice || 0) +
rate.localPrice.additionalPricePerStay +
pkgsSum.price
} else if (pkgsSum.price) {
total.local.additionalPrice =
(total.local.additionalPrice || 0) + pkgsSum.price
}
if (rate.localPrice.currency) {
total.local.additionalPriceCurrency = rate.localPrice.currency
}
if (rate.requestedPrice) {
if (!total.requested) {
total.requested = {
currency: CurrencyEnum.CC,
price: 0,
}
}
total.requested.price =
total.requested.price + rate.requestedPrice.numberOfCheques
if (rate.requestedPrice.additionalPricePerStay) {
total.requested.additionalPrice =
(total.requested.additionalPrice || 0) +
rate.requestedPrice.additionalPricePerStay
}
if (rate.requestedPrice.currency) {
total.requested.additionalPriceCurrency = rate.requestedPrice.currency
}
}
return total
},
{
local: {
currency: CurrencyEnum.CC,
price: 0,
},
requested: undefined,
}
)
}