import { CurrencyEnum } from "@scandic-hotels/common/constants/currency" import { sumPackages } from "@/components/HotelReservation/utils" import type { RedemptionProduct } from "@scandic-hotels/trpc/types/roomAvailability" import type { AvailabilityWithRoomInfo, Rate, RoomPackage, } from "@/contexts/SelectRate/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 useMemberPrices: boolean }): Price | null { const mainRoom = selectedRates[0] const mainRoomRate = mainRoom?.rate const summaryArray = selectedRates.filter( (x): x is OneLevelNonNullable => !!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[], useMemberPrices: boolean ) { return 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 && 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[] ) { 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 = 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 = { [K in keyof T]-?: NonNullable } export function calculateCorporateChequePrice( selectedRates: OneLevelNonNullable[] ) { return selectedRates.reduce( (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, } ) }