import { z } from "zod" import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { env } from "../../../../env/server" import { protectedProcedure } from "../../../procedures" import type { LoginType } from "@scandic-hotels/common/constants/loginType" const outputSchema = z.object({ eurobonusNumber: z.string(), firstName: z.string().optional(), lastName: z.string().optional(), linkStatus: z.enum(["LINKED", "PENDING", "UNLINKED"]), isBlocked: z.boolean(), enrollmentDate: z.string(), birthdate: z.string(), mobileNumber: z.string(), email: z.string().email(), points: z.object({ balances: z.array( z.object({ expirationDate: z.string(), points: z.number(), }) ), total: z.number(), }), tier: z.string(), tierStartDate: z.string(), /* `null` if customer is (i.) Lifetime Gold and tier is Gold or (ii.) tier is Basic. If customer is Lifetime Gold and tier is above Gold (e.g., Diamond), there will be a tier end date */ tierEndDate: z.string().nullable(), lifeTimeGold: z.boolean(), tierBoostRequestedByScandic: z.boolean(), whoBoosted: z .enum(["NO-BOOST", "SAS", "SCANDIC", "UNKNOWN"]) .default("UNKNOWN") .catch((ctx) => { sasLogger.warn(`Unknown whoBoosted value received: ${ctx.input}`) return "UNKNOWN" }), tierBoostDescription: z.string().optional(), tierMatchStatus: z .enum(["MATCHED", "FAILED", "PENDING", "UNMATCHED"]) .optional(), }) const sasLogger = createLogger("SAS") const url = new URL("/api/scandic-partnership/v1/profile", env.SAS_API_ENDPOINT) const requiredLoginType: LoginType[] = ["sas"] export const getEuroBonusProfile = protectedProcedure .output(outputSchema) .query(async function ({ ctx }) { return await getEuroBonusProfileData({ accessToken: ctx.session.token.access_token, loginType: ctx.session.token.loginType, }) }) export async function getEuroBonusProfileData({ accessToken, loginType, }: { loginType: LoginType accessToken: string }) { if (!accessToken) { throw new Error("Access token is required to fetch EuroBonus profile") } if (!requiredLoginType.includes(loginType)) { throw new Error( `Failed to fetch EuroBonus profile, expected loginType to be "${requiredLoginType}" but was "${loginType}"` ) } const response = await fetch(url, { headers: { "Content-Type": "application/json", "Ocp-Apim-Subscription-Key": env.SAS_OCP_APIM, Authorization: `Bearer ${accessToken}`, }, }) if (!response.ok) { sasLogger.error( `Failed to get EuroBonus profile, status: ${response.status}, statusText: ${response.statusText}` ) throw new Error("Failed to fetch EuroBonus profile", { cause: { status: response.status, statusText: response.statusText }, }) } const responseJson = await response.json() const data = outputSchema.safeParse(responseJson) if (!data.success) { sasLogger.error( `Failed to parse EuroBonus profile, cause: ${data.error.cause}, message: ${data.error.message}` ) throw new Error(`Failed to parse EuroBonus profile: ${data.error.message}`) } return data.data }