Files
web/packages/booking-flow/lib/contexts/SelectRate/getTotalPrice.ts
Bianca Widstam 9175331e4d Merged in fix/BOOK-499-striketrough-price-total (pull request #3122)
fix(BOOK-499): fix total price strikethrough rate

* fix(BOOK-499): fix total price strikethrough rate


Approved-by: Erik Tiekstra
2025-11-11 14:05:25 +00:00

300 lines
8.6 KiB
TypeScript

import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { calculateRegularPrice } from "../../utils/calculateRegularPrice"
import { sumPackages, sumPackagesRequestedPrice } from "../../utils/SelectRate"
import type { RedemptionProduct } from "@scandic-hotels/trpc/types/roomAvailability"
import type { Price } from "../../types/price"
import type { AvailabilityWithRoomInfo, Rate, RoomPackage } from "./types"
type SelectedRate = {
roomConfiguration: AvailabilityWithRoomInfo | null
rate: Rate | undefined
}
export function getTotalPrice({
selectedRates,
isMember,
addAdditionalCost = true,
pointsCurrency,
}: {
selectedRates: Array<SelectedRate | null>
isMember: boolean
addAdditionalCost?: boolean
pointsCurrency?: CurrencyEnum
}): Price | null {
const mainRoom = selectedRates[0]
const mainRoomRate = mainRoom?.rate
const summaryArray = selectedRates.filter(
(x): x is OneLevelNonNullable<SelectedRate> => !!x
)
if (
summaryArray.some((room) => room.rate && "corporateCheque" in room.rate)
) {
return calculateCorporateChequePrice(summaryArray, addAdditionalCost)
}
if (!mainRoomRate) {
return calculateTotalPrice(summaryArray, isMember, addAdditionalCost)
}
// 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,
addAdditionalCost,
pointsCurrency
)
}
if ("voucher" in mainRoomRate) {
const voucherPrice = calculateVoucherPrice(summaryArray, addAdditionalCost)
return voucherPrice
}
return calculateTotalPrice(summaryArray, isMember, addAdditionalCost)
}
function calculateTotalPrice(
selectedRateSummary: OneLevelNonNullable<SelectedRate>[],
isMember: boolean,
addAdditionalCost: boolean
) {
const totalPrice = 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 && isMember && room.rate.member
const rate = useMemberRate ? room.rate.member : room.rate.public
const publicRate = room.rate.public
const memberRate = room.rate.member
if (!rate) {
return total
}
const packagesPrice = addAdditionalCost
? sumPackages(room.roomConfiguration?.selectedPackages)
: { price: 0, currency: undefined }
const packagesRequestedPrice = addAdditionalCost
? sumPackagesRequestedPrice(room.roomConfiguration?.selectedPackages)
: { price: 0, currency: undefined }
total.local.currency = rate.localPrice.currency
total.local.price =
total.local.price + rate.localPrice.pricePerStay + packagesPrice.price
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 +
packagesRequestedPrice.price
if (rate.requestedPrice.regularPricePerStay) {
total.requested.regularPrice =
(total.requested.regularPrice || 0) +
rate.requestedPrice.regularPricePerStay +
packagesRequestedPrice.price
}
}
return calculateRegularPrice({
total,
useMemberRate: !!useMemberRate,
regularMemberPrice: memberRate
? {
pricePerStay: memberRate.localPrice.pricePerStay,
regularPricePerStay: memberRate.localPrice.regularPricePerStay,
}
: undefined,
regularPublicPrice: publicRate
? {
pricePerStay: publicRate.localPrice.pricePerStay,
regularPricePerStay: publicRate.localPrice.regularPricePerStay,
}
: undefined,
additionalCost: packagesPrice.price,
})
},
{
local: {
currency: CurrencyEnum.Unknown,
price: 0,
regularPrice: undefined,
},
requested: undefined,
}
)
if (
totalPrice.local.regularPrice &&
totalPrice.local.price >= totalPrice.local.regularPrice
) {
totalPrice.local.regularPrice = undefined
}
return totalPrice
}
function calculateRedemptionTotalPrice(
redemption: RedemptionProduct["redemption"],
packages: RoomPackage[] | null,
addAdditonalCost: boolean,
pointsCurrency?: CurrencyEnum
) {
const pkgsSum = addAdditonalCost
? sumPackages(packages)
: { price: 0, currency: undefined }
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: pointsCurrency ?? CurrencyEnum.POINTS,
price: redemption.localPrice.pointsPerStay,
},
}
}
function calculateVoucherPrice(
selectedRateSummary: OneLevelNonNullable<SelectedRate>[],
addAdditionalPrice?: boolean
) {
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 = addAdditionalPrice
? sumPackages(room.roomConfiguration?.selectedPackages)
: { price: 0, currency: undefined }
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,
regularPrice: undefined,
},
requested: undefined,
}
)
}
type OneLevelNonNullable<T> = {
[K in keyof T]-?: NonNullable<T[K]>
}
function calculateCorporateChequePrice(
selectedRates: OneLevelNonNullable<SelectedRate>[],
addAdditionalCost?: boolean
) {
return selectedRates.reduce<Price>(
(total, room) => {
if (!(room.rate && "corporateCheque" in room.rate)) {
return total
}
const rate = room.rate.corporateCheque
const pkgsSum = addAdditionalCost
? sumPackages(room.roomConfiguration?.selectedPackages)
: { price: 0, currency: undefined }
const packagesRequestedPrice = addAdditionalCost
? sumPackagesRequestedPrice(room.roomConfiguration?.selectedPackages)
: { price: 0, currency: undefined }
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 +
packagesRequestedPrice.price
} else if (packagesRequestedPrice.price) {
total.local.additionalPrice =
(total.local.additionalPrice || 0) + packagesRequestedPrice.price
}
if (rate.requestedPrice.currency) {
total.requested.additionalPriceCurrency = rate.requestedPrice.currency
}
}
return total
},
{
local: {
currency: CurrencyEnum.CC,
price: 0,
},
requested: undefined,
}
)
}