import "server-only" import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod" import { createCounter } from "@scandic-hotels/common/telemetry" import * as api from "../../../api" import { badGatewayError, extractResponseDetails, serverErrorByStatus, } from "../../../errors" import { toApiLang } from "../../../utils" import { createBookingSchema } from "./schema" import type { CreateBookingInput } from "../../../routers/booking/mutation/createBookingRoute/schema" export async function createBooking(input: CreateBookingInput, token: string) { validateInputData(input) const createBookingCounter = createCounter("trpc.booking.create") const metricsCreateBooking = createBookingCounter.init({ ...input, rooms: input.rooms.map(({ guest, ...room }) => { const { becomeMember, membershipNumber } = guest return { ...room, guest: { becomeMember, membershipNumber } } }), }) metricsCreateBooking.start() const apiResponse = await api.post( api.endpoints.v1.Booking.bookings, { headers: { Authorization: `Bearer ${token}`, }, body: input, }, { language: toApiLang(input.language) } ) if (!apiResponse.ok) { await metricsCreateBooking.httpError(apiResponse) const apiJson = await apiResponse.json() if ("errors" in apiJson && apiJson.errors.length) { const error = apiJson.errors[0] return { error: true, cause: error.code } as const } throw serverErrorByStatus( apiResponse.status, await extractResponseDetails(apiResponse), "createBooking failed" ) } const apiJson = await apiResponse.json() const verifiedData = createBookingSchema.safeParse(apiJson) if (!verifiedData.success) { metricsCreateBooking.validationError(verifiedData.error) throw badGatewayError({ message: "Invalid response from createBooking", errorDetails: { validationError: verifiedData.error }, }) } metricsCreateBooking.success() return verifiedData.data } function validateInputData(input: CreateBookingInput) { if (!input.payment) { return } if (input.payment.paymentMethod !== PaymentMethodEnum.PartnerPoints) { return } if (!input.partnerSpecific?.eurobonusAccessToken) { throw new Error( "Missing partnerSpecific data for PartnerPoints payment method" ) } }