import {z} from 'zod' export type DateTimeOffset = {iso8601: string}; export type UserId = {id: string}; export type AdhocTravelerInfo = {registrarUserId?: UserId | undefined, externalId?: string | undefined}; export type AirRequestTravelerInfo = {userId?: UserId | undefined} | {adhocTravelerInfo?: AdhocTravelerInfo | undefined}; export type NameSuffix = 'NAME_SUFFIX_UNKNOWN' | 'SR' | 'JR' | 'MD' | 'PHD' | 'II' | 'III' | 'IV' | 'DO' | 'ATTY' | 'V' | 'VI' | 'ESQ' | 'DC' | 'DDS' | 'VM' | 'JD' | 'SECOND' | 'THIRD'; export type Name = {family1: string, family2?: string | undefined, given: string, middle?: string | undefined, suffix?: NameSuffix | undefined, preferred?: string | undefined}; export type AirlineInfo = {airlineCode: string, airlineName?: string | undefined}; export type PaymentMethod = 'PAYMENT_METHOD_UNKNOWN' | 'CREDIT_CARD' | 'BREX_POINTS' | 'CASH' | 'QANTAS_POINTS' | 'VENDOR_PROGRAM_PAYMENT' | 'DELAYED_INVOICING' | 'FLIGHT_CREDITS' | 'QANTAS_TRAVEL_FUND' | 'CUSTOM_VIRTUAL_PAYMENT' | 'FLIGHT_PASS' | 'MISCELLANEOUS_CREDIT_ORDER' | 'NO_PREPAYMENT' | 'DELAYED_PAYMENT'; export type FlightPassTax = {code?: string | undefined, amount?: Money | undefined}; export type FlightPassPaymentAmounts = {totalAmount?: Money | undefined, baseAmount?: Money | undefined, totalTaxes?: Money | undefined, taxBreakdown?: Array | undefined}; export type FlightPassPaymentMetadata = {flightPassNumber?: string | undefined, flightPassAmounts?: FlightPassPaymentAmounts | undefined}; export type FlightPassPaymentMetadataWrapper = {metadataType?: string | undefined, flightPassMetadata: FlightPassPaymentMetadata}; export type Money = {amount: number, currencyCode: string, convertedAmount?: number | undefined, convertedCurrency?: string | undefined, otherCoinage?: (Array<{coinageCode?: PaymentMethod | undefined, amount?: number | undefined, conversionRate?: number | undefined, preferredCurrencyConversionRate?: number | undefined, otherCoinageMetadata?: FlightPassPaymentMetadataWrapper | undefined}>) | undefined}; export type ThirdPartySource = 'UNKNOWN_SOURCE' | 'SABRE' | 'TRAVEL_FUSION' | 'AVIA' | 'NDC' | 'TRAINLINE' | 'ATPCO_NDC' | 'FARELOGIX_NDC' | 'OFFLINE' | 'CONNEXUS' | 'ROUTEHAPPY' | 'AMADEUS' | 'GIATA' | 'QBR' | 'BCD' | 'QANTAS_HOTELS' | 'SOUTHWEST' | 'EXPEDIA' | 'HOTEL_HUB' | 'MARRIOTT' | 'CLEARTRIP' | 'KYTE' | 'GROUNDSPAN' | 'SABRE_NDC' | 'BOOKING_COM' | 'CARTRAWLER' | 'PREMIER_INN' | 'TRAVELODGE' | 'ENTERPRISE' | 'HYATT' | 'HILTON' | 'EUROSTAR' | 'NATIONAL' | 'ALAMO' | 'AVIS' | 'BUDGET' | 'HERTZ' | 'DOLLAR' | 'THRIFTY' | 'FIREFLY' | 'AMADEUS_NDC' | 'SIXT'; export type Credit = {type: string, pnrOwningPcc: string, unusedCreditPcc: string, departureCountry?: string | undefined, arrivalCountry?: string | undefined, ticketType: 'TICKET_TYPE_UNKNOWN' | 'ETICKET' | 'MCO', departureDate?: DateTimeOffset | undefined, segmentsAvailable?: ('UNKNOWN' | 'ALL_OPEN' | 'PARTIAL' | 'OTHER') | undefined, traveler?: AirRequestTravelerInfo | undefined, passengerName?: Name | undefined, airlineInfo: AirlineInfo, totalFare: Money, issueDate?: DateTimeOffset | undefined, expiryDate: DateTimeOffset, source: ThirdPartySource, sourcePnr: string, flightIds?: Array | undefined, ticketNumber: string, travelerIndex?: number | undefined}; export type AirIntermediateRevalidateItineraryRequest = {searchId: string, itineraryId: string, rawCredits?: Array | undefined}; export type CreateApiV2AirIntermediateRevalidateItineraryArgs = {body: AirIntermediateRevalidateItineraryRequest}; export type CreateApiV2AirIntermediateRevalidateItineraryOptions = {baseUrl?: string | undefined, Bearer?: string | undefined, fetch?: typeof fetch | undefined}; export const paymentMethod = z.enum(["PAYMENT_METHOD_UNKNOWN", "CREDIT_CARD", "BREX_POINTS", "CASH", "QANTAS_POINTS", "VENDOR_PROGRAM_PAYMENT", "DELAYED_INVOICING", "FLIGHT_CREDITS", "QANTAS_TRAVEL_FUND", "CUSTOM_VIRTUAL_PAYMENT", "FLIGHT_PASS", "MISCELLANEOUS_CREDIT_ORDER", "NO_PREPAYMENT", "DELAYED_PAYMENT"]); export const flightPassTax = z.object({code: z.string().optional(), amount: z.lazy(() => money.optional())}); export const flightPassPaymentAmounts = z.object({totalAmount: z.lazy(() => money.optional()), baseAmount: z.lazy(() => money.optional()), totalTaxes: z.lazy(() => money.optional()), taxBreakdown: z.array(flightPassTax).optional()}); export const flightPassPaymentMetadata = z.object({flightPassNumber: z.string().optional(), flightPassAmounts: flightPassPaymentAmounts.optional()}); export const flightPassPaymentMetadataWrapper = z.object({metadataType: z.string().optional(), flightPassMetadata: flightPassPaymentMetadata}); export const money: z.ZodType = z.object({amount: z.number(), currencyCode: z.string(), convertedAmount: z.number().optional(), convertedCurrency: z.string().optional(), otherCoinage: z.array(z.object({coinageCode: paymentMethod.optional(), amount: z.number().optional(), conversionRate: z.number().optional(), preferredCurrencyConversionRate: z.number().optional(), otherCoinageMetadata: flightPassPaymentMetadataWrapper.optional()})).optional()}); export const tax = z.object({amount: money, taxCode: z.string().optional(), percentage: z.number().optional(), description: z.string().optional()}); export const taxBreakdown = z.array(tax); export const fareAmount = z.object({base: money, tax: money, taxBreakdown: taxBreakdown.optional()}); export const bookingFareBreakdown = z.object({totalFare: fareAmount, merchantFee: money.optional(), airlineFee: money.optional(), changeFee: money.optional(), appliedCreditValue: money.optional(), fareDifference: money.optional()}); export const passengerType = z.enum(["UNKNOWN_PASSENGER_TYPE", "ADULT", "CHILD", "INFANT", "INFANT_ON_LAP", "YOUTH", "SENIOR", "TEEN"]); export const passengerAge = z.object({numYears: z.number().int()}); export const perTravelerPrice = z.object({travelerType: passengerType, travelerAge: passengerAge, numTravelers: z.number().int(), amount: fareAmount, airlineFee: money.optional(), changeFee: fareAmount.optional(), taxBreakdown: taxBreakdown.optional(), supplierTravelerType: passengerType.optional()}); export const legPrice = z.object({legId: z.string().optional(), amount: fareAmount.optional(), travelerPrices: z.array(perTravelerPrice).optional(), airlineFee: money.optional(), changeFee: fareAmount.optional()}); export const pnrPolicyId = z.object({id: z.string(), version: z.string(), policyName: z.string().optional(), approvalType: z.enum(["HARD_APPROVAL", "SOFT_APPROVAL", "PASSIVE_APPROVAL"]).optional(), policyType: z.enum(["GLOBAL", "DEFAULT", "GROUP"]).optional()}); export const policyPredicate = z.enum(["UNKNOWN_PREDICATE_STRING", "MAX_FARE_PER_TRAVELLER_VIOLATION", "FARE_MORE_THAN_MINIMUM", "FARE_MORE_THAN_MEDIAN", "FARE_LESS_THAN_MEDIAN", "FARE_MORE_THAN_LLF", "MAX_FARE_PER_TRAVELLER_VIOLATION_INCLUDING_TAX", "MAX_FARE_PER_TRAVELLER_VIOLATION_EXCLUDING_TAX", "HOTEL_PAYMENT_OPTIONS_VIOLATION", "RAIL_BOOKING_WINDOW_GAP_VIOLATION", "RAIL_TRAVEL_CLASS_VIOLATION", "RAIL_TICKET_REFUNDABLE_VIOLATION", "RAIL_MAX_BOOKING_PRICE_VIOLATION_INCLUDING_TAX", "RAIL_MAX_BOOKING_PRICE_VIOLATION_EXCLUDING_TAX", "AIR_MAX_PRICE_MORE_THAN_LLF_VIOLATION_INCLUDING_TAX", "AIR_MAX_PRICE_MORE_THAN_LLF_VIOLATION_EXCLUDING_TAX", "HOTEL_RESTRICTED_KEYWORDS_VIOLATION", "RESTRICTED_LOCATION_VIOLATION", "FLIGHT_ADVANCE_BOOKING_WINDOW_DOMESTIC_VIOLATION", "FLIGHT_ADVANCE_BOOKING_WINDOW_INTERNATIONAL_VIOLATION", "FLIGHT_ADVANCE_BOOKING_WINDOW_VIOLATION", "ITINERARY_WITHIN_EVENT_TRAVEL_WINDOW", "HOTEL_IN_ALLOWED_HOTEL_LIST", "PAYMENT_ACCESS_VIOLATION", "AIRPORT_IN_ALLOWED_AIRPORT_LIST", "ITINERARY_TYPE_IS_NOT_IN_ALLOWED_BOOKING_TYPES", "PAYMENT_AIR_ADDON_VIOLATION", "MAX_HOTEL_BOOKING_PRICE_INCLUDING_TAX", "MAX_HOTEL_BOOKING_PRICE_EXCLUDING_TAX", "AIR_NUM_TRAVELERS_ALLOWED", "PREFERRED_VENDOR_VIOLATION", "SEAT_ADDON_VIOLATION", "BAGGAGE_ADDON_VIOLATION", "EARLY_BIRD_ADDON_VIOLATION", "WIFI_ADDON_VIOLATION", "RESTRICTED_BOOKING_VIOLATION", "HIGHEST_ALLOWED_CABIN_VIOLATION", "LOWEST_FARE_PER_HOTEL_PROPERTY_VIOLATION", "AIR_RESTRICTED_FARES_VIOLATION", "AIR_ANCILLARY_VIOLATION"]); export const length = z.object({length: z.number(), unit: z.enum(["UNKNOWN_UNIT", "KM", "MILE", "CENTIMETER", "METER"])}); export const latlng = z.object({latitude: z.number(), longitude: z.number()}); export const postalAddress = z.object({addressLines: z.array(z.string()), administrativeArea: z.string().optional(), administrativeAreaName: z.string().optional(), description: z.string().optional(), isDefault: z.boolean().optional(), languageCode: z.string().optional(), locality: z.string().optional(), locationCode: z.string().optional(), organization: z.string().optional(), postalCode: z.string().optional(), continentCode: z.string().optional(), recipients: z.array(z.string()).optional(), regionCode: z.string(), regionName: z.string().optional(), revision: z.number().int().optional(), sortingCode: z.string().optional(), sublocality: z.string().optional(), timezone: z.string().optional(), coordinates: latlng.optional()}); export const organizationAgencyId = z.object({id: z.string()}); export const organizationId = z.object({id: z.string()}); export const userId = z.object({id: z.string()}); export const companyId = z.object({id: z.string()}); export const primaryServiceProviderTmc = z.object({tmcId: companyId}); export const supplierType = z.enum(["SABRE", "AMADEUS", "TRAVEL_FUSION", "FARELOGIX_NDC", "ATPCO_NDC", "TRAINLINE", "AVIA", "QBR", "BCD", "QANTAS_HOTELS", "SOUTHWEST", "EXPEDIA", "HOTEL_HUB", "NDC", "MARRIOTT", "CLEARTRIP", "KYTE", "GROUNDSPAN", "SABRE_NDC", "BOOKING_COM", "CARTRAWLER", "PREMIER_INN", "TRAVELODGE", "ENTERPRISE", "HYATT", "HILTON", "NATIONAL", "ALAMO", "HERTZ", "DOLLAR", "THRIFTY", "FIREFLY", "EUROSTAR", "AVIS", "BUDGET", "AMADEUS_NDC", "SIXT"]); export const travelType = z.enum(["AIR", "HOTEL", "CAR", "RAIL", "LIMO", "MISC", "ALL"]); export const secondaryServiceProviderTmc = z.object({tmcId: companyId, supplier: supplierType, travelType: travelType}); export const tmcInfo = z.object({id: companyId, primaryServiceProviderTmc: primaryServiceProviderTmc, secondaryServiceProviderTmcs: z.array(secondaryServiceProviderTmc).optional(), partnerTmcId: companyId.optional()}); export const dimensions = z.object({height: z.number().int().optional(), width: z.number().int().optional()}); export const imageMetadata = z.object({variant: z.enum(["LIGHT", "DARK"]).optional()}); export const image = z.object({data: z.string().optional(), dimensions: dimensions.optional(), url: z.string().optional(), metadata: imageMetadata.optional()}); export const companyRef = z.object({id: companyId, name: z.string().optional(), logo: image.optional()}); export const tmcBasicInfo = z.object({contractingTmc: companyRef, bookingTmc: companyRef}); export const userOrgId = z.object({organizationAgencyId: organizationAgencyId.optional(), organizationId: organizationId, userId: userId, tmcInfo: tmcInfo.optional(), tmcBasicInfo: tmcBasicInfo.optional()}); export const legalEntityId = z.object({id: z.string()}); export const officeId = z.object({id: z.string()}); export const int32Range = z.object({min: z.number().int().optional(), max: z.number().int().optional()}); export const doubleRange = z.object({min: z.number().optional(), max: z.number().optional()}); export const persona = z.enum(["UNKNOWN_PERSONA", "EMPLOYEE", "GUEST", "PERSONAL", "RELATIVE", "ADHOC"]); export const travelClassHierarchy = z.enum(["UNKNOWN", "STANDARD", "COACH", "STANDARD_PREMIUM", "BUSINESS", "BUSINESS_PREMIUM", "FIRST", "SLEEPER"]); export const restrictedKeywordsWithReason = z.object({keyword: z.string().optional(), reason: z.string().optional()}); export const keywordsWithReasonList = z.object({keywords: z.array(restrictedKeywordsWithReason).optional()}); export const workerType = z.enum(["EMPLOYEE", "CONTINGENT", "SEASONAL", "INTERN", "GUEST"]); export const airRestrictedKeyword = z.object({keyword: z.string(), airlineCode: z.string().optional()}); export const airRestrictedFaresParams = z.object({airRestrictedKeywords: z.array(airRestrictedKeyword).optional()}); export const policyConstValue = z.union([z.object({displaySuffix: z.string().optional(), i: z.number().int().optional()}), z.object({displaySuffix: z.string().optional(), l: z.number().int().optional()}), z.object({displaySuffix: z.string().optional(), s: z.string().optional()}), z.object({displaySuffix: z.string().optional(), d: z.number().optional()}), z.object({displaySuffix: z.string().optional(), b: z.boolean().optional()}), z.object({displaySuffix: z.string().optional(), iList: z.array(z.number().int()).optional()}), z.object({displaySuffix: z.string().optional(), dList: z.array(z.number()).optional()}), z.object({displaySuffix: z.string().optional(), sList: z.array(z.string()).optional()}), z.object({displaySuffix: z.string().optional(), money: money.optional()}), z.object({displaySuffix: z.string().optional(), length: length.optional()}), z.object({displaySuffix: z.string().optional(), postalAddress: postalAddress.optional()}), z.object({displaySuffix: z.string().optional(), userOrgId: userOrgId.optional()}), z.object({displaySuffix: z.string().optional(), legalEntityId: legalEntityId.optional()}), z.object({displaySuffix: z.string().optional(), officeId: officeId.optional()}), z.object({displaySuffix: z.string().optional(), userOrgIdList: z.array(userOrgId).optional()}), z.object({displaySuffix: z.string().optional(), legalEntityIdList: z.array(legalEntityId).optional()}), z.object({displaySuffix: z.string().optional(), officeIdList: z.array(officeId).optional()}), z.object({displaySuffix: z.string().optional(), rating: z.number().optional()}), z.object({displaySuffix: z.string().optional(), percentage: z.number().optional()}), z.object({displaySuffix: z.string().optional(), iRange: int32Range.optional()}), z.object({displaySuffix: z.string().optional(), dRange: doubleRange.optional()}), z.object({displaySuffix: z.string().optional(), persona: persona.optional()}), z.object({displaySuffix: z.string().optional(), personaList: z.array(persona).optional()}), z.object({displaySuffix: z.string().optional(), railTravelClass: travelClassHierarchy.optional()}), z.object({displaySuffix: z.string().optional(), keywordWithReasonList: keywordsWithReasonList.optional()}), z.object({displaySuffix: z.string().optional(), workerType: workerType.optional()}), z.object({displaySuffix: z.string().optional(), workerTypeList: z.array(workerType).optional()}), z.object({displaySuffix: z.string().optional(), airRestrictedFaresParams: airRestrictedFaresParams.optional()}), z.object({displaySuffix: z.string().optional(), postalAddressList: z.array(postalAddress).optional()})]); export const policyViolationInfo = z.object({predicateString: z.string().optional(), predicate: policyPredicate.optional(), expectedValue: policyConstValue.optional(), actualValue: policyConstValue.optional()}); export const policyFlagAction = z.object({message: z.string().optional()}); export const policyAlertOnSelectionAction = z.object({message: z.string().optional()}); export const approvalType = z.enum(["HARD_APPROVAL", "SOFT_APPROVAL", "PASSIVE_APPROVAL", "PRE_APPROVAL"]); export const policyTakeApprovalAction = z.object({numHierarchyLevels: z.number().int().optional(), positionTitles: z.array(z.string()).optional(), userOrgIds: z.array(userOrgId).optional(), allRequired: z.boolean().optional(), hardApprovalRequired: z.boolean().optional(), approvalType: approvalType.optional()}); export const policyPreventBookingAction = z.object({prevent: z.boolean().optional(), reason: z.string().optional()}); export const splitPayment = z.object({inPolicyAmount: money.optional(), isAmountReimbursable: z.boolean().optional(), personalFopChargeableAmount: money.optional()}); export const policyAction = z.union([z.object({flag: policyFlagAction.optional()}), z.object({hide: z.boolean().optional()}), z.object({alertOnSelection: policyAlertOnSelectionAction.optional()}), z.object({takeApproval: policyTakeApprovalAction.optional()}), z.object({preventBooking: policyPreventBookingAction.optional()}), z.object({splitPayment: splitPayment.optional()})]); export const policyRuleResultInfo = z.object({violationInfos: z.array(policyViolationInfo).optional(), subViolationInfos: z.array(policyViolationInfo).optional(), actions: z.array(policyAction).optional()}); export const pnrPolicyInfo = z.object({policies: z.array(pnrPolicyId).optional(), ruleResultInfos: z.array(policyRuleResultInfo).optional()}); export const mcoIssuanceEligibility = z.enum(["ELIGIBLE", "NOT_ELIGIBLE", "MAYBE_ELIGIBLE"]); export const residueType = z.enum(["NO_RESIDUE", "MCO", "FORFEITED", "REFUNDED"]); export const airRevalidateItineraryResponse = z.object({bookingId: z.string().optional(), fareBreakDown: bookingFareBreakdown.optional(), legPrices: z.array(legPrice).optional(), perTravelerPrices: z.array(perTravelerPrice).optional(), policyDetails: pnrPolicyInfo.optional(), mcoIssuanceEligibility: mcoIssuanceEligibility.optional(), residueType: residueType.optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Validate air itinerary (interim) * * POST /v2/air/intermediate-revalidate-itinerary */ export const createApiV2AirIntermediateRevalidateItinerary = async (args: CreateApiV2AirIntermediateRevalidateItineraryArgs, options?: CreateApiV2AirIntermediateRevalidateItineraryOptions) => { const {baseUrl = "https://api-ext-sboxmeta.partners.spotnana.com", fetch: fetchFn = fetch, Bearer} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (Bearer !== undefined) headers.set('authorization', `Bearer ${Bearer}`) const url = `${baseUrl.replace(/\/+$/, '')}/v2/air/intermediate-revalidate-itinerary${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(airRevalidateItineraryResponse, await res.json()) };