Ending up doing some extra things: Consolidated booking queries: We had both cancel and cancelMany, but functionally they’re the same, only one accepts an array and the other doesn’t. Didn’t see much point in keeping the single cancel as it wasn’t used anywhere. Thus, I could rename cancelMany to be the one stop method. remove method for API now properly supports body so we don’t have to hijack the typing in certain places * fix(SW-2508): now sending additional params to cancel api for new contract Approved-by: Niclas Edenvin
306 lines
8.6 KiB
TypeScript
306 lines
8.6 KiB
TypeScript
import * as api from "@/lib/api"
|
|
import { getMembershipNumber } from "@/server/routers/user/utils"
|
|
import { createCounter } from "@/server/telemetry"
|
|
import { router, safeProtectedServiceProcedure } from "@/server/trpc"
|
|
|
|
import {
|
|
addPackageInput,
|
|
cancelBookingsInput,
|
|
createBookingInput,
|
|
guaranteeBookingInput,
|
|
priceChangeInput,
|
|
removePackageInput,
|
|
updateBookingInput,
|
|
} from "./input"
|
|
import { bookingConfirmationSchema, createBookingSchema } from "./output"
|
|
import { cancelBooking } from "./utils"
|
|
|
|
export const bookingMutationRouter = router({
|
|
create: safeProtectedServiceProcedure
|
|
.input(createBookingInput)
|
|
.mutation(async function ({ ctx, input }) {
|
|
const accessToken = ctx.session?.token.access_token ?? ctx.serviceToken
|
|
const { language, ...inputWithoutLang } = input
|
|
const { hotelId, checkInDate, checkOutDate } = inputWithoutLang
|
|
|
|
const createBookingCounter = createCounter("trpc.booking", "create")
|
|
const metricsCreateBooking = createBookingCounter.init({
|
|
membershipNumber: await getMembershipNumber(ctx.session),
|
|
checkInDate,
|
|
checkOutDate,
|
|
hotelId,
|
|
language,
|
|
})
|
|
|
|
metricsCreateBooking.start()
|
|
|
|
const headers = {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
}
|
|
|
|
const apiResponse = await api.post(
|
|
api.endpoints.v1.Booking.bookings,
|
|
{
|
|
headers,
|
|
body: inputWithoutLang,
|
|
},
|
|
{ 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
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
const apiJson = await apiResponse.json()
|
|
|
|
const verifiedData = createBookingSchema.safeParse(apiJson)
|
|
if (!verifiedData.success) {
|
|
metricsCreateBooking.validationError(verifiedData.error)
|
|
return null
|
|
}
|
|
|
|
metricsCreateBooking.success()
|
|
|
|
return verifiedData.data
|
|
}),
|
|
priceChange: safeProtectedServiceProcedure
|
|
.input(priceChangeInput)
|
|
.mutation(async function ({ ctx, input }) {
|
|
const { confirmationNumber } = input
|
|
|
|
const priceChangeCounter = createCounter("trpc.booking", "price-change")
|
|
const metricsPriceChange = priceChangeCounter.init({ confirmationNumber })
|
|
|
|
metricsPriceChange.start()
|
|
|
|
const accessToken = ctx.session?.token.access_token ?? ctx.serviceToken
|
|
|
|
const headers = {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
}
|
|
|
|
const apiResponse = await api.put(
|
|
api.endpoints.v1.Booking.priceChange(confirmationNumber),
|
|
{
|
|
headers,
|
|
body: input,
|
|
}
|
|
)
|
|
|
|
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)
|
|
.mutation(async function ({ ctx, input }) {
|
|
const token = ctx.session?.token.access_token ?? ctx.serviceToken
|
|
const { confirmationNumbers, language } = input
|
|
|
|
const responses = await Promise.allSettled(
|
|
confirmationNumbers.map((confirmationNumber) =>
|
|
cancelBooking(confirmationNumber, language, token)
|
|
)
|
|
)
|
|
|
|
const cancelledRoomsSuccessfully = []
|
|
for (const [idx, response] of responses.entries()) {
|
|
if (response.status === "fulfilled") {
|
|
if (response.value) {
|
|
cancelledRoomsSuccessfully.push(true)
|
|
continue
|
|
}
|
|
} else {
|
|
console.info(
|
|
`Cancelling booking failed for confirmationNumber: ${confirmationNumbers[idx]}`
|
|
)
|
|
console.error(response.reason)
|
|
}
|
|
|
|
cancelledRoomsSuccessfully.push(false)
|
|
}
|
|
|
|
return cancelledRoomsSuccessfully
|
|
}),
|
|
packages: safeProtectedServiceProcedure
|
|
.input(addPackageInput)
|
|
.mutation(async function ({ ctx, input }) {
|
|
const accessToken = ctx.session?.token.access_token ?? ctx.serviceToken
|
|
const { confirmationNumber, ...body } = input
|
|
|
|
const addPackageCounter = createCounter("trpc.booking", "package.add")
|
|
const metricsAddPackage = addPackageCounter.init({ confirmationNumber })
|
|
|
|
metricsAddPackage.start()
|
|
|
|
const headers = {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
}
|
|
|
|
const apiResponse = await api.post(
|
|
api.endpoints.v1.Booking.packages(confirmationNumber),
|
|
{
|
|
headers,
|
|
body: body,
|
|
}
|
|
)
|
|
|
|
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)
|
|
.mutation(async function ({ ctx, input }) {
|
|
const accessToken = ctx.session?.token.access_token ?? ctx.serviceToken
|
|
const { confirmationNumber, language, ...body } = input
|
|
|
|
const guaranteeBookingCounter = createCounter("trpc.booking", "guarantee")
|
|
const metricsGuaranteeBooking = guaranteeBookingCounter.init({
|
|
confirmationNumber,
|
|
})
|
|
|
|
metricsGuaranteeBooking.start()
|
|
|
|
const headers = {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
}
|
|
|
|
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)
|
|
.mutation(async function ({ ctx, input }) {
|
|
const accessToken = ctx.session?.token.access_token || ctx.serviceToken
|
|
const { confirmationNumber, ...body } = input
|
|
|
|
const updateBookingCounter = createCounter("trpc.booking", "update")
|
|
const metricsUpdateBooking = updateBookingCounter.init({
|
|
confirmationNumber,
|
|
})
|
|
|
|
metricsUpdateBooking.start()
|
|
|
|
const apiResponse = await api.put(
|
|
api.endpoints.v1.Booking.booking(confirmationNumber),
|
|
{
|
|
body,
|
|
headers: {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
},
|
|
}
|
|
)
|
|
|
|
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)
|
|
.mutation(async function ({ ctx, input }) {
|
|
const accessToken = ctx.session?.token.access_token ?? ctx.serviceToken
|
|
const { confirmationNumber, codes, language } = input
|
|
|
|
const removePackageCounter = createCounter(
|
|
"trpc.booking",
|
|
"package.remove"
|
|
)
|
|
const metricsRemovePackage = removePackageCounter.init({
|
|
confirmationNumber,
|
|
codes,
|
|
language,
|
|
})
|
|
|
|
metricsRemovePackage.start()
|
|
|
|
const headers = {
|
|
Authorization: `Bearer ${accessToken}`,
|
|
}
|
|
|
|
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
|
|
}),
|
|
})
|