import { z } from "zod" import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { env } from "../../../../env/server" import { protectedProcedure } from "../../../procedures" import type { Session } from "next-auth" 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) export async function getEuroBonusProfileData(session: Session) { if (session.token.loginType !== "sas") { return { error: { message: `Failed to fetch EuroBonus profile, expected loginType to be "sas" but was ${session.token.loginType}`, }, } as const } if (!session.token.expires_at || session.token.expires_at < Date.now()) { return { error: { message: "Token expired sas", }, } as const } const response = await fetch(url, { headers: { "Content-Type": "application/json", "Ocp-Apim-Subscription-Key": env.SAS_OCP_APIM, Authorization: `Bearer ${session?.token?.access_token}`, }, }) if (!response.ok) { sasLogger.error( `Failed to get EuroBonus profile, status: ${response.status}, statusText: ${response.statusText}` ) return { error: { message: "Failed to fetch EuroBonus profile", cause: { status: response.status, statusText: response.statusText }, }, } as const } 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}` ) return { error: { message: `Failed to parse EuroBonus profile: ${data.error.message}`, cause: { status: response.status, statusText: response.statusText }, }, } as const } return data } export const getEuroBonusProfile = protectedProcedure.query(async function ({ ctx, }) { const verifiedSasUser = await getEuroBonusProfileData(ctx.session) if ("error" in verifiedSasUser) { throw new Error(verifiedSasUser.error?.message, { cause: verifiedSasUser.error?.cause, }) } return verifiedSasUser.data })