Merged in feat/sw-3642-inject-sas-eb-payment (pull request #3243)

feat(SW-3642): Enable SAS EB payments

* Wip add SAS eb payment

* Add validate payment call

* Check booking status payment method to determine validation

* Clean up getPaymentData

* Fix PartnerPoints casing

* Add comment for validatePartnerPayment error handling

* Remove comment


Approved-by: Joakim Jäderberg
This commit is contained in:
Anton Gunnarsson
2025-12-11 13:23:12 +00:00
parent eb90c382b8
commit 7faa9933a2
19 changed files with 489 additions and 110 deletions

View File

@@ -48,7 +48,7 @@ export async function EnterDetailsPage({
// This should never happen unless a user tampers with the URL
if (
!config.redemptionEnabled &&
config.redemptionType === "disabled" &&
booking.searchType === SEARCH_TYPE_REDEMPTION
) {
throw new Error("Redemptions are disabled")

View File

@@ -19,6 +19,8 @@ import { serverClient } from "../trpc"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { NextSearchParams } from "../types"
import { CreateBookingSchema } from "@scandic-hotels/trpc/routers/booking/mutation/create/schema"
import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod"
type PaymentCallbackPageProps = {
lang: Lang
@@ -48,11 +50,28 @@ export async function PaymentCallbackPage({
}
const returnUrl = details(lang)
const searchObject = new URLSearchParams()
let errorMessage = undefined
if (status === PaymentCallbackStatusEnum.Cancel) {
const searchObject = new URLSearchParams()
searchObject.set("errorCode", BookingErrorCodeEnum.TransactionCancelled)
return (
<BookingFlowConfig config={config}>
<HandleErrorCallback
returnUrl={returnUrl.toString()}
searchObject={searchObject}
status={status}
/>
</BookingFlowConfig>
)
}
if (status === PaymentCallbackStatusEnum.Error) {
logger.error(
`[payment-callback] error status received for ${confirmationNumber}, status: ${status}`
)
const searchObject = new URLSearchParams()
searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed)
const errorMessage = `Failed to get booking status for ${confirmationNumber}, status: ${status}`
return (
<BookingFlowConfig config={config}>
<HandleErrorCallback
@@ -81,14 +100,24 @@ export async function PaymentCallbackPage({
}
const booking = await getBooking(confirmationNumber, lang, token)
const refId = booking?.refId
if (
status === PaymentCallbackStatusEnum.Success &&
confirmationNumber &&
refId
) {
const caller = await serverClient()
const bookingStatus = refId
? await caller.booking.status({
refId,
})
: null
if (status === PaymentCallbackStatusEnum.Success && refId) {
const shouldValidatePayment =
bookingStatus?.booking.paymentMethod === PaymentMethodEnum.PartnerPoints
if (shouldValidatePayment) {
// TODO We probably need better error handling for this mutation,
// but for now we've just implemented the happy path
await caller.booking.validatePartnerPayment({ confirmationNumber })
}
const expire = Math.floor(Date.now() / 1000) + 60
const sig = encrypt(expire.toString())
const confirmationUrl = `${bookingConfirmation(lang)}?RefId=${encodeURIComponent(refId)}`
@@ -108,49 +137,67 @@ export async function PaymentCallbackPage({
)
}
if (refId) {
try {
const caller = await serverClient()
const bookingStatus = await caller.booking.status({
refId,
})
return (
<HandleBookingStatusError
status={status}
booking={bookingStatus?.booking ?? null}
returnUrl={returnUrl.toString()}
confirmationNumber={confirmationNumber}
config={config}
/>
)
}
const { booking } = bookingStatus
// TODO: how to handle errors for multiple rooms?
const error = booking.errors.find((e) => e.errorCode)
errorMessage =
error?.description ??
`No error message found for booking ${confirmationNumber}, status: ${status}`
searchObject.set(
"errorCode",
error
? error.errorCode.toString()
: BookingErrorCodeEnum.TransactionFailed
)
} catch {
logger.error(
`[payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}`
)
searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed)
errorMessage = `Failed to get booking status for ${confirmationNumber}, status: ${status}`
}
}
if (status === PaymentCallbackStatusEnum.Error) {
function HandleBookingStatusError({
booking,
confirmationNumber,
returnUrl,
config,
status,
}: {
booking: CreateBookingSchema | null
confirmationNumber?: string
returnUrl: string
config: BookingFlowConfig
status: PaymentCallbackStatusEnum
}) {
if (!booking) {
logger.error(
`[payment-callback] error status received for ${confirmationNumber}, status: ${status}`
`[payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}`
)
const searchObject = new URLSearchParams()
searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed)
errorMessage = `Failed to get booking status for ${confirmationNumber}, status: ${status}`
const errorMessage = `Failed to get booking status for ${confirmationNumber}, status: ${status}`
return (
<BookingFlowConfig config={config}>
<HandleErrorCallback
returnUrl={returnUrl}
searchObject={searchObject}
status={status}
errorMessage={errorMessage}
/>
</BookingFlowConfig>
)
}
// TODO: how to handle errors for multiple rooms?
const error = booking.errors.find((e) => e.errorCode)
const errorMessage =
error?.description ??
`No error message found for booking ${confirmationNumber}, status: ${status}`
const searchObject = new URLSearchParams()
searchObject.set(
"errorCode",
error ? error.errorCode.toString() : BookingErrorCodeEnum.TransactionFailed
)
return (
<BookingFlowConfig config={config}>
<HandleErrorCallback
returnUrl={returnUrl.toString()}
returnUrl={returnUrl}
searchObject={searchObject}
status={status}
errorMessage={errorMessage}