sabre_dev_studio-flight 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +54 -0
- data/Rakefile +20 -0
- data/lib/sabre_dev_studio-flight/airports_at_cities_lookup.rb +13 -0
- data/lib/sabre_dev_studio-flight/api.rb +209 -0
- data/lib/sabre_dev_studio-flight/city_pairs_lookup.rb +13 -0
- data/lib/sabre_dev_studio-flight/destination_finder.rb +13 -0
- data/lib/sabre_dev_studio-flight/fare_range.rb +13 -0
- data/lib/sabre_dev_studio-flight/instaflights_search.rb +13 -0
- data/lib/sabre_dev_studio-flight/lead_price_calendar.rb +13 -0
- data/lib/sabre_dev_studio-flight/low_fare_forecast.rb +13 -0
- data/lib/sabre_dev_studio-flight/multiairport_city_lookup.rb +13 -0
- data/lib/sabre_dev_studio-flight/shop/streamlined_destinations.rb +38 -0
- data/lib/sabre_dev_studio-flight/shop/streamlined_itineraries.rb +225 -0
- data/lib/sabre_dev_studio-flight/theme_airport_lookup.rb +13 -0
- data/lib/sabre_dev_studio-flight/travel_seasonality.rb +13 -0
- data/lib/sabre_dev_studio-flight/travel_theme_lookup.rb +13 -0
- data/lib/sabre_dev_studio-flight/version.rb +5 -0
- data/lib/sabre_dev_studio-flight.rb +6 -0
- data/sabre_dev_studio-flight.gemspec +24 -0
- data/test/api_test.rb +194 -0
- data/test/fixtures/air_shopping_themes.json +113 -0
- data/test/fixtures/airports_at_cities_lookup.json +26 -0
- data/test/fixtures/city_pairs.json +16708 -0
- data/test/fixtures/destination_air_shop.json +481 -0
- data/test/fixtures/fare_range.json +35 -0
- data/test/fixtures/future_dates_lead_fare_shop.json +2525 -0
- data/test/fixtures/low_fare_forecast.json +28 -0
- data/test/fixtures/multiairport_city_lookup.json +164 -0
- data/test/fixtures/single_date_air_shop.json +352 -0
- data/test/fixtures/theme_airport_lookup.json +77 -0
- data/test/fixtures/theme_airports.json +32 -0
- data/test/fixtures/travel_seasonality.json +379 -0
- data/test/test_helper.rb +32 -0
- metadata +149 -0
@@ -0,0 +1,225 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
options = {
|
4
|
+
:origin => 'ATL',
|
5
|
+
:destination => 'LAS',
|
6
|
+
:departuredate => '2014-06-01',
|
7
|
+
:returndate => '2014-06-05',
|
8
|
+
:limit => 300
|
9
|
+
}
|
10
|
+
itineraries = SabreDevStudio::Flight::Api.single_date_air_shop(options); nil
|
11
|
+
streamlined_itineraries = SabreDevStudio::Flight::Shop::StreamlinedItineraries.new(itineraries.response['PricedItineraries']); nil
|
12
|
+
|
13
|
+
-- or --
|
14
|
+
|
15
|
+
require 'json'
|
16
|
+
itineraries = JSON.parse(File.read('./test/fixtures/single_date_air_shop.json')); nil
|
17
|
+
streamlined_itineraries = SabreDevStudio::Flight::Shop::StreamlinedItineraries.new(itineraries['PricedItineraries']); nil
|
18
|
+
pp streamlined_itineraries; nil
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
# require 'digest'
|
23
|
+
module SabreDevStudio
|
24
|
+
module Flight
|
25
|
+
module Shop
|
26
|
+
class StreamlinedItineraries
|
27
|
+
attr_reader :flights, :outbounds, :min_price, :max_price,
|
28
|
+
:min_outbound_duration, :max_outbound_duration, :airline_codes
|
29
|
+
|
30
|
+
def initialize(itineraries)
|
31
|
+
@flights = []
|
32
|
+
@outbounds = []
|
33
|
+
@min_price = @max_price = nil
|
34
|
+
@min_outbound_duration = @max_outbound_duration = nil
|
35
|
+
outbound_flights = Hash.new
|
36
|
+
outbound_flight = nil
|
37
|
+
|
38
|
+
itineraries.each do |itin|
|
39
|
+
segments = itin['AirItinerary']['OriginDestinationOptions']['OriginDestinationOption']
|
40
|
+
amount = itin['AirItineraryPricingInfo']['ItinTotalFare']['TotalFare']['Amount'].to_f
|
41
|
+
segments.each_with_index.each do |segment, idx|
|
42
|
+
direction = idx % 2 == 0 ? 'outbound' : 'inbound'
|
43
|
+
flight = Flight.new(segment['FlightSegment'], direction, segment['ElapsedTime'])
|
44
|
+
@flights << flight.to_hash
|
45
|
+
|
46
|
+
set_price(amount)
|
47
|
+
if flight.direction == 'outbound'
|
48
|
+
set_duration(flight.duration)
|
49
|
+
outbound_flight = flight
|
50
|
+
outbound_flights[outbound_flight.sha] ||= OutboundFlight.new(flight, amount)
|
51
|
+
else
|
52
|
+
outbound_flights[outbound_flight.sha].add_inbound_flight(flight, amount)
|
53
|
+
end
|
54
|
+
|
55
|
+
if segment['FlightSegment'].is_a?(Array)
|
56
|
+
segment['FlightSegment'].each_with_index do |flight_segment, idx|
|
57
|
+
# next if idx > 0
|
58
|
+
connection = Flight.new(flight_segment, 'connecting', segment['ElapsedTime'])
|
59
|
+
next if connection.sha == flight.sha
|
60
|
+
@flights << connection.to_hash
|
61
|
+
flight.add_connecting_flight(connection)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@airline_codes = @flights.map { |f| f[:airlines] }.flatten.uniq.sort
|
68
|
+
@flights.uniq!
|
69
|
+
@outbounds = outbound_flights.values.map(&:to_hash)
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_price(fare)
|
73
|
+
@min_price = fare if @min_price.nil? || fare < @min_price
|
74
|
+
@max_price = fare if @max_price.nil? || fare > @max_price
|
75
|
+
end
|
76
|
+
def set_duration(duration)
|
77
|
+
@min_outbound_duration = duration if @min_outbound_duration.nil? || duration < @min_outbound_duration
|
78
|
+
@max_outbound_duration = duration if @max_outbound_duration.nil? || duration > @max_outbound_duration
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class Flight
|
83
|
+
attr_reader :direction, :airlines, :duration, :flight_number,
|
84
|
+
:departure_airport, :arrival_airport,
|
85
|
+
:stops, :departure_time, :arrival_time, :connections
|
86
|
+
|
87
|
+
def initialize(flight_segment, direction, duration)
|
88
|
+
@airlines = []
|
89
|
+
@stops = []
|
90
|
+
@connections = []
|
91
|
+
@direction = direction
|
92
|
+
if direction == 'connecting'
|
93
|
+
@duration = flight_segment['ElapsedTime']
|
94
|
+
else
|
95
|
+
@duration = duration
|
96
|
+
end
|
97
|
+
parse_data(flight_segment)
|
98
|
+
end
|
99
|
+
|
100
|
+
def sha
|
101
|
+
str = "#{@airlines.first}_#{@flight_number}_#{@departure_airport}_#{@departure_time}"
|
102
|
+
# Digest::SHA1.hexdigest(str)
|
103
|
+
str
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_hash
|
107
|
+
{
|
108
|
+
uid: sha,
|
109
|
+
direction: @direction,
|
110
|
+
airlines: airlines.uniq,
|
111
|
+
duration: minutes_to_time(duration),
|
112
|
+
departureAirport: departure_airport,
|
113
|
+
arrivalAirport: arrival_airport,
|
114
|
+
stops: stops,
|
115
|
+
connections: connections,
|
116
|
+
departureTime: reformat_date_time(departure_time),
|
117
|
+
arrivalTime: reformat_date_time(arrival_time)
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_connecting_flight(flight)
|
122
|
+
@connections << flight.sha
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def parse_data(flight_segment)
|
128
|
+
if flight_segment.is_a?(Array)
|
129
|
+
flight_segment.each_with_index do |segment, idx|
|
130
|
+
if idx == 0
|
131
|
+
@departure_airport = segment['DepartureAirport']['LocationCode']
|
132
|
+
@departure_time = segment['DepartureDateTime']
|
133
|
+
@stops << segment['ArrivalAirport']['LocationCode']
|
134
|
+
@airlines << segment['MarketingAirline']['Code']
|
135
|
+
@flight_number = segment['FlightNumber']
|
136
|
+
elsif idx == flight_segment.length - 1
|
137
|
+
@arrival_airport = segment['ArrivalAirport']['LocationCode']
|
138
|
+
@arrival_time = segment['ArrivalDateTime']
|
139
|
+
@airlines << segment['MarketingAirline']['Code']
|
140
|
+
else
|
141
|
+
@stops << segment['ArrivalAirport']['LocationCode']
|
142
|
+
@airlines << segment['MarketingAirline']['Code']
|
143
|
+
end
|
144
|
+
end
|
145
|
+
else
|
146
|
+
@departure_airport = flight_segment['DepartureAirport']['LocationCode']
|
147
|
+
@arrival_airport = flight_segment['ArrivalAirport']['LocationCode']
|
148
|
+
@departure_time = flight_segment['DepartureDateTime']
|
149
|
+
@arrival_time = flight_segment['ArrivalDateTime']
|
150
|
+
@airlines << flight_segment['MarketingAirline']['Code']
|
151
|
+
@flight_number = flight_segment['FlightNumber']
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def minutes_to_time(minutes)
|
156
|
+
minutes = minutes.to_i
|
157
|
+
{
|
158
|
+
hour: minutes / 60,
|
159
|
+
minutes: minutes % 60,
|
160
|
+
raw: minutes
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
164
|
+
# "2013-06-01T09:56:00" --> "9:56 am"
|
165
|
+
# "2013-06-01T19:06:00" --> "7:06 pm"
|
166
|
+
def reformat_date_time(datetime)
|
167
|
+
datetime =~ /\d+-\d+-\d+T(\d+):(\d+):\d+/
|
168
|
+
hour, minute = $1.to_i, $2.to_i
|
169
|
+
am_pm = hour < 12 ? 'am' : 'pm'
|
170
|
+
|
171
|
+
hour = hour % 12
|
172
|
+
hour = hour == 0 ? 12 : hour
|
173
|
+
minute = sprintf("%02d", minute)
|
174
|
+
"#{hour}:#{minute} #{am_pm}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class OutboundFlight
|
179
|
+
attr_reader :flight_uuid, :inbounds, :min_price, :max_price,
|
180
|
+
:duration, :min_inbound_duration, :max_inbound_duration
|
181
|
+
|
182
|
+
def initialize(flight, price)
|
183
|
+
@flight_uuid = flight.sha
|
184
|
+
@min_price = @max_price = price
|
185
|
+
@inbounds = []
|
186
|
+
@duration = flight.duration
|
187
|
+
@min_inbound_duration = @max_inbound_duration = nil
|
188
|
+
end
|
189
|
+
|
190
|
+
def add_inbound_flight(flight, price)
|
191
|
+
set_min_price(price)
|
192
|
+
set_inbound_duration(flight.duration)
|
193
|
+
@inbounds << {
|
194
|
+
flight_uuid: flight.sha,
|
195
|
+
price: price
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
def to_hash
|
200
|
+
{
|
201
|
+
flight_uuid: flight_uuid,
|
202
|
+
min_price: min_price,
|
203
|
+
max_price: max_price,
|
204
|
+
duration: duration,
|
205
|
+
min_inbound_duration: min_inbound_duration,
|
206
|
+
max_inbound_duration: max_inbound_duration,
|
207
|
+
inbounds: inbounds.uniq
|
208
|
+
}
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
def set_min_price(price)
|
214
|
+
@min_price = price if price < @min_price
|
215
|
+
@max_price = price if price > @max_price
|
216
|
+
end
|
217
|
+
|
218
|
+
def set_inbound_duration(duration)
|
219
|
+
@min_inbound_duration = duration if @min_inbound_duration.nil? || duration < @min_inbound_duration
|
220
|
+
@max_inbound_duration = duration if @max_inbound_duration.nil? || duration > @max_inbound_duration
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SabreDevStudio
|
2
|
+
module Flight
|
3
|
+
|
4
|
+
##
|
5
|
+
# Air Shopping Themes Convenience Object
|
6
|
+
#
|
7
|
+
# ==== Documentation:
|
8
|
+
# https://developer.sabre.com/docs/read/rest_apis/theme_airport_lookup
|
9
|
+
class ThemeAirportLookup < SabreDevStudio::RequestObject
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SabreDevStudio
|
2
|
+
module Flight
|
3
|
+
|
4
|
+
##
|
5
|
+
# Air Shopping Themes Convenience Object
|
6
|
+
#
|
7
|
+
# ==== Documentation:
|
8
|
+
# https://developer.sabre.com/docs/read/rest_apis/travel_theme_lookup
|
9
|
+
class TravelThemeLookup < SabreDevStudio::RequestObject
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
require 'sabre_dev_studio'
|
2
|
+
require File.expand_path("../sabre_dev_studio-flight/api", __FILE__)
|
3
|
+
require File.expand_path("../sabre_dev_studio-flight/version", __FILE__)
|
4
|
+
|
5
|
+
require File.expand_path("../sabre_dev_studio-flight/shop/streamlined_destinations", __FILE__)
|
6
|
+
require File.expand_path("../sabre_dev_studio-flight/shop/streamlined_itineraries", __FILE__)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sabre_dev_studio-flight/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "sabre_dev_studio-flight"
|
8
|
+
gem.version = SabreDevStudio::Flight::VERSION
|
9
|
+
gem.authors = ["Barrett Clark"]
|
10
|
+
gem.email = ["barrett.clark@sabre.com"]
|
11
|
+
gem.description = %q{Access the Sabre Travel Platform Services (TPS) Dev Studio Flight API}
|
12
|
+
gem.summary = %q{Access the Sabre Dev Studio API}
|
13
|
+
gem.homepage = "http://developer.sabre.com"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency 'geminabox'
|
21
|
+
gem.add_development_dependency 'webmock'
|
22
|
+
gem.add_development_dependency 'rdoc'
|
23
|
+
gem.add_runtime_dependency 'sabre_dev_studio'
|
24
|
+
end
|
data/test/api_test.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
require File.expand_path("../test_helper", __FILE__)
|
2
|
+
|
3
|
+
class ApiTests < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
SabreDevStudio.configure do |c|
|
6
|
+
c.user = 'USER'
|
7
|
+
c.group = 'GROUP'
|
8
|
+
c.domain = 'DOMAIN'
|
9
|
+
c.password = 'PASSWORD'
|
10
|
+
c.uri = 'https://api.test.sabre.com'
|
11
|
+
end
|
12
|
+
stub_request(:post, "https://VjE6VVNFUjpHUk9VUDpET01BSU4%3D:UEFTU1dPUkQ%3D@api.test.sabre.com/v1/auth/token").
|
13
|
+
to_return(:status => 200, :body =>"{\"access_token\":\"Shared/IDL:IceSess\\\\/SessMgr:1\\\\.0.IDL/Common/!ICESMS\\\\/ACPCRTD!ICESMSLB\\\\/CRT.LB!-3801964284027024638!507667!0!F557CBE649675!E2E-1\",\"token_type\":\"bearer\",\"expires_in\":1800}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_air_shopping_theme_api
|
17
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/themes").
|
18
|
+
to_return(json_response('air_shopping_themes.json'))
|
19
|
+
air_shopping_themes = SabreDevStudio::Flight::Api.air_shopping_themes
|
20
|
+
assert_equal 11, air_shopping_themes.response['Themes'].count
|
21
|
+
assert_equal 'BEACH', air_shopping_themes.response['Themes'].first['Theme']
|
22
|
+
assert_equal 'BEACH', air_shopping_themes.themes.first.theme
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_theme_airport_lookup_api
|
26
|
+
theme = 'DISNEY'
|
27
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/themes/#{theme}").
|
28
|
+
to_return(json_response('theme_airport_lookup.json'))
|
29
|
+
airports = SabreDevStudio::Flight::Api.theme_airport_lookup(theme)
|
30
|
+
assert_equal 7, airports.destinations.count
|
31
|
+
assert_equal 'BUR', airports.destinations.first.destination
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_destination_air_shop_api
|
35
|
+
options = {
|
36
|
+
:origin => 'LAS',
|
37
|
+
:lengthofstay => 1,
|
38
|
+
:theme => 'MOUNTAINS'
|
39
|
+
}
|
40
|
+
uri = Addressable::URI.new
|
41
|
+
uri.query_values = options
|
42
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/flights/fares?#{uri.query}").
|
43
|
+
to_return(json_response('destination_air_shop.json'))
|
44
|
+
fares = SabreDevStudio::Flight::Api.destination_air_shop(options)
|
45
|
+
assert_equal options[:origin], fares.origin_location
|
46
|
+
assert_equal 31, fares.fare_info.count
|
47
|
+
assert_equal 158, fares.fare_info.first.lowest_fare
|
48
|
+
date = SabreDevStudio::Helpers::DateExtensions.make_date(fares.fare_info.first.departure_date_time)
|
49
|
+
assert_equal 4, date.month
|
50
|
+
assert_equal options[:origin], fares.response['OriginLocation']
|
51
|
+
assert_equal 158, fares.response['FareInfo'].first['LowestFare']
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_future_dates_lead_fare_shop_api
|
55
|
+
options = {
|
56
|
+
:origin => 'JFK',
|
57
|
+
:destination => 'LAX',
|
58
|
+
:lengthofstay => 5
|
59
|
+
}
|
60
|
+
uri = Addressable::URI.new
|
61
|
+
uri.query_values = options
|
62
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/flights/fares?#{uri.query}").
|
63
|
+
to_return(json_response('future_dates_lead_fare_shop.json'))
|
64
|
+
fares = SabreDevStudio::Flight::Api.future_dates_lead_fare_shop(options)
|
65
|
+
assert_equal options[:origin], fares.origin_location
|
66
|
+
assert_equal 193, fares.fare_info.count
|
67
|
+
assert_equal 792, fares.fare_info.first.lowest_fare
|
68
|
+
assert_equal options[:origin], fares.response['OriginLocation']
|
69
|
+
assert_equal 792, fares.response['FareInfo'].first['LowestFare']
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_single_date_air_shop_api
|
73
|
+
options = {
|
74
|
+
:origin => 'JFK',
|
75
|
+
:destination => 'LAX',
|
76
|
+
:departuredate => '2014-10-01',
|
77
|
+
:returndate => '2014-10-05',
|
78
|
+
:onlineitinerariesonly => 'N',
|
79
|
+
:limit => 1,
|
80
|
+
:offset => 1,
|
81
|
+
:sortby => 'totalfare',
|
82
|
+
:order => 'asc',
|
83
|
+
:sortby2 => 'departuretime',
|
84
|
+
:order2 => 'dsc'
|
85
|
+
}
|
86
|
+
uri = Addressable::URI.new
|
87
|
+
uri.query_values = options
|
88
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/flights?#{uri.query}").
|
89
|
+
to_return(json_response('single_date_air_shop.json'))
|
90
|
+
fares = SabreDevStudio::Flight::Api.single_date_air_shop(options)
|
91
|
+
assert_equal options[:origin], fares.origin_location
|
92
|
+
assert_equal 387.0, fares.priced_itineraries.first.air_itinerary_pricing_info.itin_total_fare.total_fare.amount
|
93
|
+
assert_equal options[:origin], fares.response['OriginLocation']
|
94
|
+
assert_equal 387, fares.response['PricedItineraries'].first['AirItineraryPricingInfo']['ItinTotalFare']['TotalFare']['Amount']
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_low_fare_forecast_api
|
98
|
+
options = {
|
99
|
+
:origin => 'JFK',
|
100
|
+
:destination => 'LAX',
|
101
|
+
:departuredate => '2014-10-01',
|
102
|
+
:returndate => '2014-10-05'
|
103
|
+
}
|
104
|
+
uri = Addressable::URI.new
|
105
|
+
uri.query_values = options
|
106
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/forecast/flights/fares?#{uri.query}").
|
107
|
+
to_return(json_response('low_fare_forecast.json'))
|
108
|
+
forecast = SabreDevStudio::Flight::Api.low_fare_forecast(options)
|
109
|
+
assert_equal options[:origin], forecast.origin_location
|
110
|
+
assert_equal options[:origin], forecast.response['OriginLocation']
|
111
|
+
assert_equal options[:destination], forecast.response['DestinationLocation']
|
112
|
+
assert_equal 387.0, forecast.response['LowestFare']
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_fare_range_api
|
116
|
+
options = {
|
117
|
+
:origin => 'JFK',
|
118
|
+
:destination => 'LAX',
|
119
|
+
:earliestdeparturedate => '2014-06-01',
|
120
|
+
:latestdeparturedate => '2014-06-01',
|
121
|
+
:lengthofstay => 4
|
122
|
+
}
|
123
|
+
uri = Addressable::URI.new
|
124
|
+
uri.query_values = options
|
125
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/historical/flights/fares?#{uri.query}").
|
126
|
+
to_return(json_response('fare_range.json'))
|
127
|
+
fare_range = SabreDevStudio::Flight::Api.fare_range(options)
|
128
|
+
assert_equal options[:origin], fare_range.origin_location
|
129
|
+
assert_equal options[:destination], fare_range.destination_location
|
130
|
+
assert_equal 1, fare_range.fare_data.count
|
131
|
+
assert_equal options[:origin], fare_range.response['OriginLocation']
|
132
|
+
assert_equal options[:destination], fare_range.response['DestinationLocation']
|
133
|
+
assert_equal 1, fare_range.response['FareData'].count
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_travel_seasonality_api
|
137
|
+
destination = 'DFW'
|
138
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/historical/flights/#{destination}/seasonality").
|
139
|
+
to_return(json_response('travel_seasonality.json'))
|
140
|
+
travel_seasonality = SabreDevStudio::Flight::Api.travel_seasonality(destination)
|
141
|
+
assert_equal destination, travel_seasonality.destination_location
|
142
|
+
assert_equal 52, travel_seasonality.seasonality.count
|
143
|
+
assert_equal 1, travel_seasonality.seasonality.first.year_week_number
|
144
|
+
assert_equal destination, travel_seasonality.response['DestinationLocation']
|
145
|
+
assert_equal 52, travel_seasonality.response['Seasonality'].count
|
146
|
+
assert_equal 1, travel_seasonality.response['Seasonality'].first['YearWeekNumber']
|
147
|
+
assert_equal 'Low', travel_seasonality.response['Seasonality'].first['SeasonalityIndicator']
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_city_pairs_lookup_api
|
151
|
+
options = {
|
152
|
+
:origincountry => 'US',
|
153
|
+
:destinationcountry => 'US'
|
154
|
+
}
|
155
|
+
uri = Addressable::URI.new
|
156
|
+
uri.query_values = options
|
157
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/lists/airports/supported/origins-destinations?#{uri.query}").
|
158
|
+
to_return(json_response('city_pairs.json'))
|
159
|
+
city_pairs = SabreDevStudio::Flight::Api.city_pairs_lookup(options)
|
160
|
+
assert_equal 982, city_pairs.origin_destination_locations.count
|
161
|
+
assert_equal 'DEN', city_pairs.origin_destination_locations.first.origin_location.airport_code
|
162
|
+
assert_equal 'ABQ', city_pairs.origin_destination_locations.first.destination_location.airport_code
|
163
|
+
assert_equal 982, city_pairs.response['OriginDestinationLocations'].count
|
164
|
+
assert_equal 'DEN', city_pairs.response['OriginDestinationLocations'].first['OriginLocation']['AirportCode']
|
165
|
+
assert_equal 'ABQ', city_pairs.response['OriginDestinationLocations'].first['DestinationLocation']['AirportCode']
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_multiairport_city_lookup_api
|
169
|
+
options = { :country => 'US' }
|
170
|
+
uri = Addressable::URI.new
|
171
|
+
uri.query_values = options
|
172
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/lists/cities?#{uri.query}").
|
173
|
+
to_return(json_response('multiairport_city_lookup.json'))
|
174
|
+
city_lookup = SabreDevStudio::Flight::Api.multiairport_city_lookup(options)
|
175
|
+
assert_equal 15, city_lookup.cities.count
|
176
|
+
assert_equal 'WAS', city_lookup.cities.last.code
|
177
|
+
assert_equal 15, city_lookup.response['Cities'].count
|
178
|
+
assert_equal 'WAS', city_lookup.response['Cities'].last['code']
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_airports_at_cities_lookup_api
|
182
|
+
options = { :city => 'QDF' }
|
183
|
+
uri = Addressable::URI.new
|
184
|
+
uri.query_values = options
|
185
|
+
stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/lists/airports?#{uri.query}").
|
186
|
+
to_return(json_response('airports_at_cities_lookup.json'))
|
187
|
+
airports = SabreDevStudio::Flight::Api.airports_at_cities_lookup(options)
|
188
|
+
assert_equal 3, airports.airports.count
|
189
|
+
assert_equal 'EWR', airports.airports.first.code
|
190
|
+
assert_equal 'NEWARK', airports.airports.first.name
|
191
|
+
assert_equal 3, airports.response['Airports'].count
|
192
|
+
assert_equal 'EWR', airports.response['Airports'].first['code']
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
{
|
2
|
+
"Themes": [
|
3
|
+
{
|
4
|
+
"Theme": "BEACH",
|
5
|
+
"Links": [
|
6
|
+
{
|
7
|
+
"rel": "destinations",
|
8
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/BEACH"
|
9
|
+
}
|
10
|
+
]
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"Theme": "DISNEY",
|
14
|
+
"Links": [
|
15
|
+
{
|
16
|
+
"rel": "destinations",
|
17
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/DISNEY"
|
18
|
+
}
|
19
|
+
]
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"Theme": "GAMBLING",
|
23
|
+
"Links": [
|
24
|
+
{
|
25
|
+
"rel": "destinations",
|
26
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/GAMBLING"
|
27
|
+
}
|
28
|
+
]
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"Theme": "HISTORIC",
|
32
|
+
"Links": [
|
33
|
+
{
|
34
|
+
"rel": "destinations",
|
35
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/HISTORIC"
|
36
|
+
}
|
37
|
+
]
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"Theme": "MOUNTAINS",
|
41
|
+
"Links": [
|
42
|
+
{
|
43
|
+
"rel": "destinations",
|
44
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/MOUNTAINS"
|
45
|
+
}
|
46
|
+
]
|
47
|
+
},
|
48
|
+
{
|
49
|
+
"Theme": "NATIONAL-PARKS",
|
50
|
+
"Links": [
|
51
|
+
{
|
52
|
+
"rel": "destinations",
|
53
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/NATIONAL-PARKS"
|
54
|
+
}
|
55
|
+
]
|
56
|
+
},
|
57
|
+
{
|
58
|
+
"Theme": "OUTDOORS",
|
59
|
+
"Links": [
|
60
|
+
{
|
61
|
+
"rel": "destinations",
|
62
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/OUTDOORS"
|
63
|
+
}
|
64
|
+
]
|
65
|
+
},
|
66
|
+
{
|
67
|
+
"Theme": "ROMANTIC",
|
68
|
+
"Links": [
|
69
|
+
{
|
70
|
+
"rel": "destinations",
|
71
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/ROMANTIC"
|
72
|
+
}
|
73
|
+
]
|
74
|
+
},
|
75
|
+
{
|
76
|
+
"Theme": "SHOPPING",
|
77
|
+
"Links": [
|
78
|
+
{
|
79
|
+
"rel": "destinations",
|
80
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/SHOPPING"
|
81
|
+
}
|
82
|
+
]
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"Theme": "SKIING",
|
86
|
+
"Links": [
|
87
|
+
{
|
88
|
+
"rel": "destinations",
|
89
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/SKIING"
|
90
|
+
}
|
91
|
+
]
|
92
|
+
},
|
93
|
+
{
|
94
|
+
"Theme": "THEME-PARK",
|
95
|
+
"Links": [
|
96
|
+
{
|
97
|
+
"rel": "destinations",
|
98
|
+
"href": "https://api.test.sabre.com/v1/shop/themes/THEME-PARK"
|
99
|
+
}
|
100
|
+
]
|
101
|
+
}
|
102
|
+
],
|
103
|
+
"Links": [
|
104
|
+
{
|
105
|
+
"rel": "self",
|
106
|
+
"href": "https://api.test.sabre.com/v1/shop/themes"
|
107
|
+
},
|
108
|
+
{
|
109
|
+
"rel": "linkTemplate",
|
110
|
+
"href": "https://api.test.sabre.com/v1/shop/themes"
|
111
|
+
}
|
112
|
+
]
|
113
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"Airports": [
|
3
|
+
{
|
4
|
+
"code": "EWR",
|
5
|
+
"name": "NEWARK"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"code": "JFK",
|
9
|
+
"name": "NEW YORK JFK"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"code": "LGA",
|
13
|
+
"name": "NEW YORK LGA"
|
14
|
+
}
|
15
|
+
],
|
16
|
+
"Links": [
|
17
|
+
{
|
18
|
+
"rel": "self",
|
19
|
+
"href": "https://api.test.sabre.com/v1/lists/airports?country=US&city=NYC"
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"rel": "linkTemplate",
|
23
|
+
"href": "https://api.test.sabre.com/v1/lists/airports?city=<city>"
|
24
|
+
}
|
25
|
+
]
|
26
|
+
}
|