import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { createCounter } from "@scandic-hotels/common/telemetry" import { router } from "../../.." import * as api from "../../../api" import { createRefIdPlugin } from "../../../plugins/refIdToConfirmationNumber" import { safeProtectedServiceProcedure } from "../../../procedures" import { addPackageInput, cancelBookingsInput, guaranteeBookingInput, removePackageInput, resendConfirmationInput, updateBookingInput, } from "../input" import { bookingConfirmationSchema } from "../output" import { cancelBooking } from "../utils" import { createBookingSchema } from "./create/schema" import { create } from "./create" const refIdPlugin = createRefIdPlugin() const bookingLogger = createLogger("trpc.booking") export const bookingMutationRouter = router({ create, priceChange: safeProtectedServiceProcedure .concat(refIdPlugin.toConfirmationNumber) .use(async ({ ctx, next }) => { const token = await ctx.getScandicUserToken() return next({ ctx: { token, }, }) }) .mutation(async function ({ ctx }) { const { confirmationNumber } = ctx const priceChangeCounter = createCounter("trpc.booking.price-change") const metricsPriceChange = priceChangeCounter.init({ confirmationNumber }) metricsPriceChange.start() const token = ctx.token ?? ctx.serviceToken const headers = { Authorization: `Bearer ${token}`, } const apiResponse = await api.put( api.endpoints.v1.Booking.priceChange(confirmationNumber), { headers, } ) if (!apiResponse.ok) { await metricsPriceChange.httpError(apiResponse) return null } const apiJson = await apiResponse.json() const verifiedData = createBookingSchema.safeParse(apiJson) if (!verifiedData.success) { metricsPriceChange.validationError(verifiedData.error) return null } metricsPriceChange.success() return verifiedData.data }), cancel: safeProtectedServiceProcedure .input(cancelBookingsInput) .concat(refIdPlugin.toConfirmationNumbers) .use(async ({ ctx, next }) => { const token = await ctx.getScandicUserToken() return next({ ctx: { token, }, }) }) .mutation(async function ({ ctx, input }) { const { confirmationNumbers } = ctx const { language } = input const token = ctx.token ?? ctx.serviceToken const responses = await Promise.allSettled( confirmationNumbers.map((confirmationNumber) => cancelBooking(confirmationNumber, language, token) ) ) const cancelledRoomsSuccessfully: (string | null)[] = [] for (const [idx, response] of responses.entries()) { if (response.status === "fulfilled") { if (response.value) { cancelledRoomsSuccessfully.push(confirmationNumbers[idx]) continue } } else { bookingLogger.error( `Cancelling booking failed for confirmationNumber: ${confirmationNumbers[idx]}`, response.reason ) } cancelledRoomsSuccessfully.push(null) } return cancelledRoomsSuccessfully }), packages: safeProtectedServiceProcedure .input(addPackageInput) .concat(refIdPlugin.toConfirmationNumber) .use(async ({ ctx, next }) => { const token = await ctx.getScandicUserToken() return next({ ctx: { token, }, }) }) .mutation(async function ({ ctx, input }) { const { confirmationNumber } = ctx const { language, refId, ...body } = input const addPackageCounter = createCounter("trpc.booking.package.add") const metricsAddPackage = addPackageCounter.init({ confirmationNumber, language, }) metricsAddPackage.start() const token = ctx.token ?? ctx.serviceToken const headers = { Authorization: `Bearer ${token}`, } const apiResponse = await api.post( api.endpoints.v1.Booking.packages(confirmationNumber), { headers, body: body, }, { language } ) if (!apiResponse.ok) { await metricsAddPackage.httpError(apiResponse) return null } const apiJson = await apiResponse.json() const verifiedData = createBookingSchema.safeParse(apiJson) if (!verifiedData.success) { metricsAddPackage.validationError(verifiedData.error) return null } metricsAddPackage.success() return verifiedData.data }), guarantee: safeProtectedServiceProcedure .input(guaranteeBookingInput) .concat(refIdPlugin.toConfirmationNumber) .use(async ({ ctx, next }) => { const token = await ctx.getScandicUserToken() return next({ ctx: { token, }, }) }) .mutation(async function ({ ctx, input }) { const { confirmationNumber } = ctx const { language, refId, ...body } = input const guaranteeBookingCounter = createCounter("trpc.booking.guarantee") const metricsGuaranteeBooking = guaranteeBookingCounter.init({ confirmationNumber, language, }) metricsGuaranteeBooking.start() const token = ctx.token ?? ctx.serviceToken const headers = { Authorization: `Bearer ${token}`, } const apiResponse = await api.put( api.endpoints.v1.Booking.guarantee(confirmationNumber), { headers, body: body, }, { language } ) if (!apiResponse.ok) { await metricsGuaranteeBooking.httpError(apiResponse) return null } const apiJson = await apiResponse.json() const verifiedData = createBookingSchema.safeParse(apiJson) if (!verifiedData.success) { metricsGuaranteeBooking.validationError(verifiedData.error) return null } metricsGuaranteeBooking.success() return verifiedData.data }), update: safeProtectedServiceProcedure .input(updateBookingInput) .concat(refIdPlugin.toConfirmationNumber) .use(async ({ ctx, next }) => { const token = await ctx.getScandicUserToken() return next({ ctx: { token, }, }) }) .mutation(async function ({ ctx, input }) { const { confirmationNumber } = ctx const { language, refId, ...body } = input const updateBookingCounter = createCounter("trpc.booking.update") const metricsUpdateBooking = updateBookingCounter.init({ confirmationNumber, language, }) metricsUpdateBooking.start() const token = ctx.token ?? ctx.serviceToken const apiResponse = await api.put( api.endpoints.v1.Booking.booking(confirmationNumber), { body, headers: { Authorization: `Bearer ${token}`, }, }, { language } ) if (!apiResponse.ok) { await metricsUpdateBooking.httpError(apiResponse) return null } const apiJson = await apiResponse.json() const verifiedData = bookingConfirmationSchema.safeParse(apiJson) if (!verifiedData.success) { metricsUpdateBooking.validationError(verifiedData.error) return null } metricsUpdateBooking.success() return verifiedData.data }), removePackage: safeProtectedServiceProcedure .input(removePackageInput) .concat(refIdPlugin.toConfirmationNumber) .use(async ({ ctx, next }) => { const token = await ctx.getScandicUserToken() return next({ ctx: { token, }, }) }) .mutation(async function ({ ctx, input }) { const { confirmationNumber } = ctx const { codes, language } = input const removePackageCounter = createCounter("trpc.booking.package.remove") const metricsRemovePackage = removePackageCounter.init({ confirmationNumber, codes, language, }) metricsRemovePackage.start() const token = ctx.token ?? ctx.serviceToken const headers = { Authorization: `Bearer ${token}`, } const apiResponse = await api.remove( api.endpoints.v1.Booking.packages(confirmationNumber), { headers, }, [["language", language], ...codes.map((code) => ["codes", code])] ) if (!apiResponse.ok) { await metricsRemovePackage.httpError(apiResponse) return false } metricsRemovePackage.success() return true }), resendConfirmation: safeProtectedServiceProcedure .input(resendConfirmationInput) .concat(refIdPlugin.toConfirmationNumber) .use(async ({ ctx, next }) => { const token = await ctx.getScandicUserToken() return next({ ctx: { token, }, }) }) .mutation(async function ({ ctx, input }) { const { confirmationNumber } = ctx const resendConfirmationCounter = createCounter( "trpc.booking.confirmation.resend" ) const metricsResendConfirmation = resendConfirmationCounter.init({ confirmationNumber, }) metricsResendConfirmation.start() const token = ctx.token ?? ctx.serviceToken const headers = { Authorization: `Bearer ${token}`, } const apiResponse = await api.post( api.endpoints.v1.Booking.confirmNotification(confirmationNumber), { headers, }, { language: input.language } ) if (!apiResponse.ok) { await metricsResendConfirmation.httpError(apiResponse) return false } metricsResendConfirmation.success() return true }), })