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, }: { selectedRates: Array isMember: boolean addAdditionalCost?: boolean }): Price | null { const mainRoom = selectedRates[0] const mainRoomRate = mainRoom?.rate const summaryArray = selectedRates.filter( (x): x is OneLevelNonNullable => !!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 ) } if ("voucher" in mainRoomRate) { const voucherPrice = calculateVoucherPrice(summaryArray, addAdditionalCost) return voucherPrice } return calculateTotalPrice(summaryArray, isMember, addAdditionalCost) } function calculateTotalPrice( selectedRateSummary: OneLevelNonNullable[], isMember: boolean, addAdditionalCost: boolean ) { const totalPrice = selectedRateSummary.reduce( (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.pricePerNight, regularPricePerStay: memberRate.localPrice.regularPricePerStay, } : undefined, regularPublicPrice: publicRate ? { pricePerStay: publicRate.localPrice.pricePerNight, 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 ) { 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: CurrencyEnum.POINTS, price: redemption.localPrice.pointsPerStay, }, } } function calculateVoucherPrice( selectedRateSummary: OneLevelNonNullable[], addAdditionalPrice?: boolean ) { return selectedRateSummary.reduce( (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 = { [K in keyof T]-?: NonNullable } function calculateCorporateChequePrice( selectedRates: OneLevelNonNullable[], addAdditionalCost?: boolean ) { return selectedRates.reduce( (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, } ) }