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:
@@ -0,0 +1,204 @@
|
||||
import stringify from "json-stable-stringify-without-jsonify"
|
||||
|
||||
import { getCacheClient } from "@scandic-hotels/common/dataCache"
|
||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||
|
||||
import * as api from "../../../api"
|
||||
import { SEARCH_TYPE_REDEMPTION } from "../../../constants/booking"
|
||||
import { RoomPackageCodeEnum } from "../../../enums/roomFilter"
|
||||
import { AvailabilityEnum } from "../../../enums/selectHotel"
|
||||
import { toApiLang } from "../../../utils"
|
||||
import { generateChildrenString } from "../helpers"
|
||||
import { roomsAvailabilitySchema } from "../output"
|
||||
import { getPackages } from "./getPackages"
|
||||
import { getRoomFeaturesInventory } from "./getRoomFeaturesInventory"
|
||||
|
||||
import type { RoomsAvailabilityOutputSchema } from "../availability/selectRate/rooms/schema"
|
||||
|
||||
export async function getRoomsAvailability(
|
||||
input: RoomsAvailabilityOutputSchema,
|
||||
token: string,
|
||||
serviceToken: string,
|
||||
userPoints: number | undefined
|
||||
) {
|
||||
const {
|
||||
booking: { bookingCode, fromDate, hotelId, rooms, searchType, toDate },
|
||||
lang,
|
||||
} = input
|
||||
|
||||
const redemption = searchType === SEARCH_TYPE_REDEMPTION
|
||||
|
||||
const getRoomsAvailabilityCounter = createCounter(
|
||||
"hotel",
|
||||
"getRoomsAvailability"
|
||||
)
|
||||
const metricsGetRoomsAvailability = getRoomsAvailabilityCounter.init({
|
||||
input,
|
||||
redemption,
|
||||
})
|
||||
|
||||
metricsGetRoomsAvailability.start()
|
||||
|
||||
const apiLang = toApiLang(lang)
|
||||
|
||||
const baseCacheKey = {
|
||||
bookingCode,
|
||||
fromDate,
|
||||
hotelId,
|
||||
lang,
|
||||
searchType,
|
||||
toDate,
|
||||
}
|
||||
|
||||
const cacheClient = await getCacheClient()
|
||||
const availabilityResponses = await Promise.allSettled(
|
||||
rooms.map((room) => {
|
||||
const cacheKey = {
|
||||
...baseCacheKey,
|
||||
room,
|
||||
}
|
||||
const result = cacheClient.cacheOrGet(
|
||||
stringify(cacheKey),
|
||||
async function () {
|
||||
{
|
||||
const params = {
|
||||
adults: room.adults,
|
||||
language: apiLang,
|
||||
roomStayStartDate: fromDate,
|
||||
roomStayEndDate: toDate,
|
||||
...(room.childrenInRoom?.length && {
|
||||
children: generateChildrenString(room.childrenInRoom),
|
||||
}),
|
||||
...(room.bookingCode && { bookingCode: room.bookingCode }),
|
||||
...(redemption && { isRedemption: "true" }),
|
||||
}
|
||||
|
||||
const apiResponse = await api.get(
|
||||
api.endpoints.v1.Availability.hotel(hotelId),
|
||||
{
|
||||
cache: undefined, // overwrite default
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
},
|
||||
params
|
||||
)
|
||||
|
||||
if (!apiResponse.ok) {
|
||||
await metricsGetRoomsAvailability.httpError(apiResponse)
|
||||
const text = await apiResponse.text()
|
||||
return { error: "http_error", details: text }
|
||||
}
|
||||
|
||||
const apiJson = await apiResponse.json()
|
||||
const validateAvailabilityData =
|
||||
roomsAvailabilitySchema.safeParse(apiJson)
|
||||
if (!validateAvailabilityData.success) {
|
||||
metricsGetRoomsAvailability.validationError(
|
||||
validateAvailabilityData.error
|
||||
)
|
||||
|
||||
return {
|
||||
error: "validation_error",
|
||||
details: validateAvailabilityData.error,
|
||||
}
|
||||
}
|
||||
|
||||
if (redemption) {
|
||||
for (const roomConfig of validateAvailabilityData.data
|
||||
.roomConfigurations) {
|
||||
for (const product of roomConfig.redemptions) {
|
||||
if (userPoints) {
|
||||
product.redemption.hasEnoughPoints =
|
||||
userPoints >= product.redemption.localPrice.pointsPerStay
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const roomFeatures = await getPackages(
|
||||
{
|
||||
adults: room.adults,
|
||||
children: room.childrenInRoom?.length || 0,
|
||||
endDate: input.booking.toDate,
|
||||
hotelId: input.booking.hotelId,
|
||||
lang,
|
||||
packageCodes: [
|
||||
RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
|
||||
RoomPackageCodeEnum.ALLERGY_ROOM,
|
||||
RoomPackageCodeEnum.PET_ROOM,
|
||||
],
|
||||
startDate: input.booking.fromDate,
|
||||
},
|
||||
serviceToken
|
||||
)
|
||||
|
||||
if (roomFeatures) {
|
||||
validateAvailabilityData.data.packages = roomFeatures
|
||||
}
|
||||
|
||||
// Fetch packages
|
||||
if (room.packages?.length) {
|
||||
const roomFeaturesInventory = await getRoomFeaturesInventory(
|
||||
{
|
||||
adults: room.adults,
|
||||
childrenInRoom: room.childrenInRoom,
|
||||
endDate: input.booking.toDate,
|
||||
hotelId: input.booking.hotelId,
|
||||
lang,
|
||||
roomFeatureCodes: room.packages,
|
||||
startDate: input.booking.fromDate,
|
||||
},
|
||||
serviceToken
|
||||
)
|
||||
|
||||
if (roomFeaturesInventory) {
|
||||
const features = roomFeaturesInventory.reduce<
|
||||
Record<string, number>
|
||||
>((fts, feat) => {
|
||||
fts[feat.roomTypeCode] = feat.features?.[0]?.inventory ?? 0
|
||||
return fts
|
||||
}, {})
|
||||
|
||||
const updatedRoomConfigurations =
|
||||
validateAvailabilityData.data.roomConfigurations
|
||||
// This filter is needed since we can get availability
|
||||
// back from roomFeatures yet the availability call
|
||||
// says there are no rooms left...
|
||||
.filter((rc) => rc.roomsLeft)
|
||||
.filter((rc) => features?.[rc.roomTypeCode])
|
||||
.map((rc) => ({
|
||||
...rc,
|
||||
roomsLeft: features[rc.roomTypeCode],
|
||||
status: AvailabilityEnum.Available,
|
||||
}))
|
||||
|
||||
validateAvailabilityData.data.roomConfigurations =
|
||||
updatedRoomConfigurations
|
||||
}
|
||||
}
|
||||
|
||||
return validateAvailabilityData.data
|
||||
}
|
||||
},
|
||||
"1m"
|
||||
)
|
||||
|
||||
return result
|
||||
})
|
||||
)
|
||||
|
||||
const data = availabilityResponses.map((availability) => {
|
||||
if (availability.status === "fulfilled") {
|
||||
return availability.value
|
||||
}
|
||||
return {
|
||||
details: availability.reason,
|
||||
error: "request_failure",
|
||||
}
|
||||
})
|
||||
|
||||
metricsGetRoomsAvailability.success()
|
||||
|
||||
return data
|
||||
}
|
||||
Reference in New Issue
Block a user