Merged in chore/refactor-hotel-trpc-routes (pull request #2891)
Chore/refactor hotel trpc routes * chore(SW-3519): refactor trpc hotel routers * chore(SW-3519): refactor trpc hotel routers * refactor * merge * Merge branch 'master' of bitbucket.org:scandic-swap/web into chore/refactor-hotel-trpc-routes Approved-by: Linus Flood
This commit is contained in:
178
packages/trpc/lib/routers/hotels/availability/enterDetails.ts
Normal file
178
packages/trpc/lib/routers/hotels/availability/enterDetails.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||
import { RateEnum } from "@scandic-hotels/common/constants/rate"
|
||||
import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType"
|
||||
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
||||
|
||||
import { SEARCH_TYPE_REDEMPTION } from "../../../constants/booking"
|
||||
import { AvailabilityEnum } from "../../../enums/selectHotel"
|
||||
import { unauthorizedError } from "../../../errors"
|
||||
import { safeProtectedServiceProcedure } from "../../../procedures"
|
||||
import { getVerifiedUser } from "../../user/utils/getVerifiedUser"
|
||||
import { baseBookingSchema, baseRoomSchema, selectedRoomSchema } from "../input"
|
||||
import { getHotel } from "../services/getHotel"
|
||||
import { getRoomsAvailability } from "../services/getRoomsAvailability"
|
||||
import {
|
||||
getBedTypes,
|
||||
getSelectedRoomAvailability,
|
||||
selectRateRedirectURL,
|
||||
} from "../utils"
|
||||
|
||||
import type { Room } from "../../../types/room"
|
||||
|
||||
export type RoomsAvailabilityExtendedInputSchema = z.input<
|
||||
typeof enterDetailsRoomsAvailabilityInputSchema
|
||||
>
|
||||
export const enterDetailsRoomsAvailabilityInputSchema = z.object({
|
||||
booking: baseBookingSchema.extend({
|
||||
rooms: z.array(baseRoomSchema.merge(selectedRoomSchema)),
|
||||
}),
|
||||
lang: z.nativeEnum(Lang),
|
||||
})
|
||||
|
||||
const logger = createLogger("trpc:availability:enterDetails")
|
||||
export const enterDetails = safeProtectedServiceProcedure
|
||||
.input(enterDetailsRoomsAvailabilityInputSchema)
|
||||
.use(async ({ ctx, input, next }) => {
|
||||
if (input.booking.searchType === SEARCH_TYPE_REDEMPTION) {
|
||||
if (ctx.session?.token.access_token) {
|
||||
const verifiedUser = await getVerifiedUser({ session: ctx.session })
|
||||
if (!verifiedUser?.error) {
|
||||
return next({
|
||||
ctx: {
|
||||
token: ctx.session.token.access_token,
|
||||
userPoints: verifiedUser?.data.membership?.currentPoints ?? 0,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
throw unauthorizedError()
|
||||
}
|
||||
return next({
|
||||
ctx: {
|
||||
token: ctx.serviceToken,
|
||||
},
|
||||
})
|
||||
})
|
||||
.query(async function ({ ctx, input }) {
|
||||
const availability = await getRoomsAvailability(
|
||||
input,
|
||||
ctx.token,
|
||||
ctx.serviceToken,
|
||||
ctx.userPoints
|
||||
)
|
||||
const hotelData = await getHotel(
|
||||
{
|
||||
hotelId: input.booking.hotelId,
|
||||
isCardOnlyPayment: false,
|
||||
language: input.lang || ctx.lang,
|
||||
},
|
||||
ctx.serviceToken
|
||||
)
|
||||
|
||||
const selectedRooms = []
|
||||
for (const [idx, room] of availability.entries()) {
|
||||
if (!room || "error" in room) {
|
||||
logger.error(`Availability failed: ${room.error}`, room.details)
|
||||
selectedRooms.push(null)
|
||||
continue
|
||||
}
|
||||
const bookingRoom = input.booking.rooms[idx]
|
||||
const selected = getSelectedRoomAvailability(
|
||||
bookingRoom.rateCode,
|
||||
room.rateDefinitions,
|
||||
room.roomConfigurations,
|
||||
bookingRoom.roomTypeCode,
|
||||
ctx.userPoints
|
||||
)
|
||||
if (!selected) {
|
||||
logger.error("Unable to find selected room")
|
||||
selectedRooms.push(null)
|
||||
continue
|
||||
}
|
||||
|
||||
const { rateDefinition, rateDefinitions, product, rooms, selectedRoom } =
|
||||
selected
|
||||
|
||||
const bedTypes = getBedTypes(
|
||||
rooms,
|
||||
selectedRoom.roomType,
|
||||
hotelData?.roomCategories
|
||||
)
|
||||
|
||||
const counterRateCode = input.booking.rooms[idx].counterRateCode
|
||||
const rateCode = input.booking.rooms[idx].rateCode
|
||||
let memberRateDefinition = undefined
|
||||
if ("member" in product && product.member && counterRateCode) {
|
||||
memberRateDefinition = rateDefinitions.find(
|
||||
(rate) =>
|
||||
(rate.rateCode.toLowerCase() === counterRateCode.toLowerCase() ||
|
||||
rate.rateCode.toLowerCase() === rateCode.toLowerCase()) &&
|
||||
rate.isMemberRate
|
||||
)
|
||||
}
|
||||
|
||||
const selectedPackages = input.booking.rooms[idx].packages
|
||||
selectedRooms.push({
|
||||
bedTypes,
|
||||
breakfastIncluded: rateDefinition.breakfastIncluded,
|
||||
cancellationText: rateDefinition.cancellationText,
|
||||
cancellationRule: rateDefinition.cancellationRule,
|
||||
isAvailable: selectedRoom.status === AvailabilityEnum.Available,
|
||||
isFlexRate: product.rate === RateEnum.flex,
|
||||
memberMustBeGuaranteed: memberRateDefinition?.mustBeGuaranteed,
|
||||
mustBeGuaranteed: rateDefinition.mustBeGuaranteed,
|
||||
packages: room.packages.filter((pkg) =>
|
||||
selectedPackages?.includes(pkg.code)
|
||||
),
|
||||
rate: product.rate,
|
||||
rateDefinitionTitle: rateDefinition.title,
|
||||
rateDetails: rateDefinition.generalTerms,
|
||||
memberRateDetails: memberRateDefinition?.generalTerms,
|
||||
// Send rate Title when it is a booking code rate
|
||||
rateTitle:
|
||||
rateDefinition.rateType !== RateTypeEnum.Regular
|
||||
? rateDefinition.title
|
||||
: undefined,
|
||||
rateType: rateDefinition.rateType,
|
||||
roomRate: product,
|
||||
roomType: selectedRoom.roomType,
|
||||
roomTypeCode: selectedRoom.roomTypeCode,
|
||||
})
|
||||
}
|
||||
|
||||
const totalBedsAvailableForRoomTypeCode: Record<string, number> = {}
|
||||
for (const selectedRoom of selectedRooms) {
|
||||
if (selectedRoom) {
|
||||
if (!totalBedsAvailableForRoomTypeCode[selectedRoom.roomTypeCode]) {
|
||||
totalBedsAvailableForRoomTypeCode[selectedRoom.roomTypeCode] =
|
||||
selectedRoom.bedTypes.reduce(
|
||||
(total, bedType) => total + bedType.roomsLeft,
|
||||
0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [idx, selectedRoom] of selectedRooms.entries()) {
|
||||
if (selectedRoom) {
|
||||
const totalBedsLeft =
|
||||
totalBedsAvailableForRoomTypeCode[selectedRoom.roomTypeCode]
|
||||
if (totalBedsLeft <= 0) {
|
||||
selectedRooms[idx] = null
|
||||
continue
|
||||
}
|
||||
totalBedsAvailableForRoomTypeCode[selectedRoom.roomTypeCode] =
|
||||
totalBedsAvailableForRoomTypeCode[selectedRoom.roomTypeCode] - 1
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedRooms.some((sr) => !sr)) {
|
||||
console.log("DEBUG: REDIRECTING TO SELECT RATE", selectedRooms)
|
||||
return selectRateRedirectURL(input, selectedRooms.map(Boolean))
|
||||
}
|
||||
|
||||
const rooms: Room[] = selectedRooms.filter((sr) => !!sr)
|
||||
return rooms
|
||||
})
|
||||
Reference in New Issue
Block a user