LBF 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/Rakefile +2 -0
- data/lbf.gemspec +26 -0
- data/lib/lbf/deep_fetch.rb +10 -0
- data/lib/lbf/lbf_client.rb +35 -0
- data/lib/lbf/lbf_exceptions.rb +2 -0
- data/lib/lbf/lbf_fare.rb +18 -0
- data/lib/lbf/lbf_layover.rb +11 -0
- data/lib/lbf/lbf_plane.rb +8 -0
- data/lib/lbf/lbf_quote.rb +99 -0
- data/lib/lbf/lbf_request.rb +130 -0
- data/lib/lbf/lbf_response.rb +33 -0
- data/lib/lbf/lbf_segment.rb +51 -0
- data/lib/lbf/lbf_traveler.rb +10 -0
- data/lib/lbf/lbf_trip.rb +32 -0
- data/lib/lbf/version.rb +3 -0
- data/lib/lbf.rb +22 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5284874c3a5f3f19e9467153016a4fa96cf2a7d9
|
4
|
+
data.tar.gz: 651b62e651a3486a79d320753eeb2e1febb2b8eb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d1f779461701be841101cd36951db59f8d4be2768a7298c1445d6948ed7d5fa9ab596632561798fa77b8b7e5a3007b22fb7a5ed439754fe0d68260c8f3a7ec39
|
7
|
+
data.tar.gz: de78338b81f2e7ce4c1044f9d9b1b752aa2095c5a8151790b3dc807b54026233f53a211724e89f0a87597e441ec4144afb5ae03b7a91f0608a334f588000e694
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) <year> <copyright holders>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# LBF
|
2
|
+
|
3
|
+
This is a big ol' pile of nested service objects for interacting with the Look
|
4
|
+
Buy Fly SOAP API.
|
5
|
+
|
6
|
+
**This is a work in progress**
|
7
|
+
|
8
|
+
#### Todo:
|
9
|
+
* Make dependencies leaner (don't require activesupport/all)
|
10
|
+
* Tests!
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'lbf'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install lbf
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'lbf'
|
31
|
+
|
32
|
+
client = LBF::Client.new(username: 'lbf_username', # required
|
33
|
+
url_id: '42', # required
|
34
|
+
password: 'lbf_password', # required
|
35
|
+
)
|
36
|
+
|
37
|
+
request = LBF::Request.new(origin: 'sdf', # required
|
38
|
+
destination: 'sna', # required
|
39
|
+
ip: '208.73.215.97', # required
|
40
|
+
departure_date: Date.tomorrow, # required
|
41
|
+
return_date: Date.tomorrow + 7.days # optional
|
42
|
+
)
|
43
|
+
client.search request
|
44
|
+
```
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
1. Fork it ( https://github.com/oversee-ffleming/lbf/fork )
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
50
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
52
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lbf.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'lbf/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "LBF"
|
8
|
+
spec.version = LBF::VERSION
|
9
|
+
spec.authors = ["Forrest Fleming"]
|
10
|
+
spec.email = ["ffleming@oversee.net"]
|
11
|
+
spec.summary = %q{Gem for making requests from LBF API}
|
12
|
+
spec.description = %q{Pile of service objects for making requests to the LBF API and its responses}
|
13
|
+
spec.homepage = "https://github.com/Oversee/Travel-LBFSoap"
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
spec.license = 'MIT'
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
21
|
+
|
22
|
+
spec.add_runtime_dependency 'savon', '~> 2.10'
|
23
|
+
spec.add_runtime_dependency 'rubyntlm', '0.3.2'
|
24
|
+
spec.add_runtime_dependency 'activesupport', '~> 4.1'
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class LBF::Client
|
2
|
+
attr_reader :username, :password, :url_id, :wsdl, :cart_path
|
3
|
+
def initialize(opts=defaults)
|
4
|
+
options = defaults.merge(opts)
|
5
|
+
%i(username password url_id).each do |key|
|
6
|
+
raise ArgumentError, "Must supply #{key}" unless options.has_key?(key)
|
7
|
+
end
|
8
|
+
@username = options[:username]
|
9
|
+
@password = options[:password]
|
10
|
+
@url_id = options[:url_id]
|
11
|
+
@wsdl = options[:wsdl]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Searches the LBF API and returns a response object
|
15
|
+
# @param [LBF::Request] The Request object that will be sent to the API
|
16
|
+
# @return [LBF::Response] The appropriate LBF::Response object
|
17
|
+
def search(request=LBF::Request.new)
|
18
|
+
client = Savon.client(pretty_print_xml: true, log_level: :debug,
|
19
|
+
log: true, wsdl: @wsdl)
|
20
|
+
request.client = self
|
21
|
+
savon_resp = client.call :afs1, xml: request.to_xml
|
22
|
+
response = LBF::Response.new(savon_resp.body)
|
23
|
+
response.errors.map {|e| raise e }
|
24
|
+
response
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def defaults
|
30
|
+
{
|
31
|
+
wsdl: 'http://webservices.lbftravel.com/services/4.2/ezAirFareService.asmx?WSDL'
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/lbf/lbf_fare.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# This is fare information for LBF. Not all keys from the fare_hash are exposed in the object; see below
|
2
|
+
# if we need to expand.
|
3
|
+
class LBF::Fare
|
4
|
+
def initialize(fare_hash)
|
5
|
+
# {:base=>"1653.9400", :tax_and_fees=>"272.4600", :total=>"1926.4000", :sale_total=>"1926.4000",
|
6
|
+
# :promo_code=>nil, :promo_discount=>"0.0000", :insurance_total=>"0", :markup=>"0",
|
7
|
+
# :tax_and_fees_adult=>"136.2300", :tax_and_fees_child=>"136.2300", :tax_and_fees_infant=>"0",
|
8
|
+
# :fare_type=>"P", :insurance_per_traveler=>"0"}
|
9
|
+
@base = BigDecimal.new fare_hash[:base]
|
10
|
+
@taxes_and_fees = BigDecimal.new fare_hash[:tax_and_fees]
|
11
|
+
@total = BigDecimal.new fare_hash[:total]
|
12
|
+
@markup = BigDecimal.new fare_hash[:markup]
|
13
|
+
@fare_type = fare_hash[:fare_type]
|
14
|
+
@discount = BigDecimal.new fare_hash[:promo_discount]
|
15
|
+
@promo_code = fare_hash[:promo_code] || 'None'
|
16
|
+
@insurance_per_traveler = BigDecimal.new fare_hash[:insurance_per_traveler]
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class LBF::Layover
|
2
|
+
attr_reader :duration, :airport
|
3
|
+
|
4
|
+
# NB: The :duration method (and corresponding ivar) are in seconds
|
5
|
+
def initialize(segment_hash)
|
6
|
+
@duration = segment_hash[:connection_duration].to_i.minutes
|
7
|
+
@airport = segment_hash[:dest]
|
8
|
+
@comment = segment_hash[:connection_comment]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# Each Quote is a proposal from LBF for the requested trip. Its trips are the legs of the flight: there will
|
2
|
+
# be one trip in :trips if it is a one-way flight, and two if it is a round-trip flight. Each quote has a
|
3
|
+
# pile of IDs that are used to create the appropriate URL string for checkout (which currently doesn't seem
|
4
|
+
# to work, but was created according to the API docs).
|
5
|
+
#
|
6
|
+
# Of particular note are the all_cabins? and nearby_airports? methods. If all_cabins? is true, then the
|
7
|
+
# quote will include at least one segment in a cabin type other than that specified in the LBF::Request.
|
8
|
+
# Similarly, if :nearby_airports? is true, then either the origin or destination is not that which was
|
9
|
+
# requested, but rather an airport that is nearby.
|
10
|
+
#
|
11
|
+
# If :offline_only? is true, then we can't display actual inforamtion about the trip. We can just display
|
12
|
+
# the price and a number to call for booking information.
|
13
|
+
class LBF::Quote
|
14
|
+
# Has Trip(s) and IDs and Travelers
|
15
|
+
attr_reader :arrival, :departure, :fare, :trips, :travelers, :warnings, :cabin_comments,
|
16
|
+
:id, :group_id, :session_id, :tickets, :seats_remaining
|
17
|
+
|
18
|
+
def initialize(quote_hash)
|
19
|
+
@hash = quote_hash
|
20
|
+
@arrival = DateTime.strptime("#{quote_hash[:arr_dt]} #{quote_hash[:arr_tm]}", '%m/%d/%Y %H%M')
|
21
|
+
@departure = DateTime.strptime("#{quote_hash[:dep_dt]} #{quote_hash[:dep_tm]}", '%m/%d/%Y %H%M')
|
22
|
+
@fare = LBF::Fare.new quote_hash[:quote_air_fare]
|
23
|
+
@trips = trips_from(quote_hash.deep_fetch :quote_air_trips, :quote_air_trip)
|
24
|
+
@travelers = travelers_from(quote_hash.deep_fetch :quote_air_travelers, :quote_air_traveler)
|
25
|
+
@warnings = warnings_from(quote_hash[:warning])
|
26
|
+
@cabin_comments = cabin_comments_from(quote_hash[:cabin_comments])
|
27
|
+
@id = quote_hash[:air_quote_id]
|
28
|
+
@group_id = quote_hash[:session_air_id]
|
29
|
+
@session_id = quote_hash[:visit_session_id]
|
30
|
+
@tickets = quote_hash[:tickets].to_i
|
31
|
+
@seats_remaining = quote_hash[:seats_remaining].to_i
|
32
|
+
@all_cabins = quote_hash[:cabin_indicator].to_i == 1
|
33
|
+
@international = !!quote_hash[:international]
|
34
|
+
@nearby_airports = !!quote_hash[:nearby_airport_indicator]
|
35
|
+
@offline_only = !!quote_hash[:offline_airline_indicator]
|
36
|
+
@tournet = !!quote_hash[:tournet_indicator]
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_h
|
40
|
+
@hash
|
41
|
+
end
|
42
|
+
|
43
|
+
def query_string
|
44
|
+
"?AirSID=#{group_id}&FARE=#{id}&SesnID=#{session_id}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def tournet?
|
48
|
+
@tournet
|
49
|
+
end
|
50
|
+
|
51
|
+
def all_cabins?
|
52
|
+
@all_cabins
|
53
|
+
end
|
54
|
+
|
55
|
+
def online?
|
56
|
+
!offline_only?
|
57
|
+
end
|
58
|
+
|
59
|
+
def offline_only?
|
60
|
+
@offline_only
|
61
|
+
end
|
62
|
+
|
63
|
+
def international?
|
64
|
+
@international
|
65
|
+
end
|
66
|
+
|
67
|
+
def domestic?
|
68
|
+
!international?
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def cabin_comments_from(comments_str)
|
74
|
+
return '' if comments_str.nil?
|
75
|
+
comments_str.to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
# The API doc don't specify how this works, so I'm assuming it's the same as the comments field.
|
79
|
+
def warnings_from(warning_str)
|
80
|
+
return '' if warning_str.nil?
|
81
|
+
warning_str.to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
# The appropriate deep_fetch can return either a hash or an array of hashes,
|
85
|
+
# so we have to handle that in this method
|
86
|
+
def trips_from(trip_arr)
|
87
|
+
return [] if trip_arr.nil?
|
88
|
+
trip_arr = [trip_arr].flatten
|
89
|
+
trip_arr.map {|t| LBF::Trip.new(t)}
|
90
|
+
end
|
91
|
+
|
92
|
+
# The appropriate deep_fetch can return either a hash or an array of hashes,
|
93
|
+
# so we have to handle that in this method
|
94
|
+
def travelers_from(trav_arr)
|
95
|
+
return [] if trav_arr.nil?
|
96
|
+
trav_arr = [trav_arr].flatten
|
97
|
+
trav_arr.map {|t| LBF::Traveler.new(t)}
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# This class just creates a (very specific) XML document with the appropriate request information to send
|
2
|
+
# to the LBF API.
|
3
|
+
class LBF::Request
|
4
|
+
AIRPORT_METHODS = %i(origin destination)
|
5
|
+
INT_METHODS = %i(adults children infants)
|
6
|
+
DATE_METHODS = %i(departure_date return_date)
|
7
|
+
OTHER_METHODS = %i(cabin ip)
|
8
|
+
ALL_METHODS = (AIRPORT_METHODS + INT_METHODS + DATE_METHODS + OTHER_METHODS)
|
9
|
+
CABINS = {coach: 'Y', business: 'C', first_class: 'F'}
|
10
|
+
|
11
|
+
attr_reader *ALL_METHODS
|
12
|
+
attr_accessor :client
|
13
|
+
|
14
|
+
AIRPORT_METHODS.each do |meth|
|
15
|
+
define_method("#{meth}=".to_sym) do |arg|
|
16
|
+
raise ArgumentError, "Argument must be a 3-letter airport code" unless arg =~ /[a-zA-Z]{3}/
|
17
|
+
instance_variable_set("@#{meth}", arg.upcase)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
INT_METHODS.each do |meth|
|
22
|
+
define_method("#{meth}=".to_sym) do |arg|
|
23
|
+
raise ArgumentError, "Argument must be an Integer" unless arg.is_a?(Integer)
|
24
|
+
instance_variable_set("@#{meth}", arg)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
DATE_METHODS.each do |meth|
|
29
|
+
define_method("#{meth}=".to_sym) do |arg|
|
30
|
+
raise ArgumentError, "Date must respond to :strftime" unless arg.respond_to?(:strftime)
|
31
|
+
instance_variable_set("@#{meth}", arg)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(opts=defaults)
|
36
|
+
%i(origin destination
|
37
|
+
departure_date ip).each { |key| raise ArgumentError, "Must specify :#{key}" unless opts.keys.include? key }
|
38
|
+
options = defaults.merge(opts).select { |k,v| ALL_METHODS.include? k }
|
39
|
+
options.each { |k, v| self.send("#{k}=", v) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def cabin=(symbol)
|
43
|
+
raise ArgumentError, "Cabin must be one of #{CABINS.keys}" unless CABINS.keys.include? symbol
|
44
|
+
@cabin = symbol
|
45
|
+
end
|
46
|
+
|
47
|
+
def ip=(arg)
|
48
|
+
@ip = IPAddr.new("#{arg}")
|
49
|
+
end
|
50
|
+
|
51
|
+
def roundtrip?
|
52
|
+
departure_date.present? && return_date.present?
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_xml
|
56
|
+
<<-XML.strip_heredoc
|
57
|
+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
58
|
+
#{header}
|
59
|
+
#{body}
|
60
|
+
</soap:Envelope>
|
61
|
+
XML
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def defaults
|
67
|
+
{
|
68
|
+
adults: 1,
|
69
|
+
children: 1,
|
70
|
+
infants: 0,
|
71
|
+
cabin: :coach
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def header
|
76
|
+
<<-HEADER.strip_heredoc
|
77
|
+
<soap:Header>
|
78
|
+
<AuthHeader xmlns="ezgds">
|
79
|
+
<Uname>#{client.username}</Uname>
|
80
|
+
<Pwd>#{client.password}</Pwd>
|
81
|
+
<URL>#{client.url_id}</URL>
|
82
|
+
<VisitSessionID>0</VisitSessionID>
|
83
|
+
<IP>#{ip}</IP>
|
84
|
+
</AuthHeader>
|
85
|
+
</soap:Header>
|
86
|
+
HEADER
|
87
|
+
end
|
88
|
+
|
89
|
+
def body
|
90
|
+
<<-BODY.strip_heredoc
|
91
|
+
<soap:Body>
|
92
|
+
<AFS1 xmlns="ezgds">
|
93
|
+
<ezQuoteAirRequest>
|
94
|
+
<QuoteAirRequestTrips>
|
95
|
+
#{depart_trip_xml}
|
96
|
+
#{return_trip_xml if roundtrip?}
|
97
|
+
</QuoteAirRequestTrips>
|
98
|
+
<PreferredAirline />
|
99
|
+
<Cabin>#{CABINS[cabin]}</Cabin>
|
100
|
+
<Adt>#{adults}</Adt>
|
101
|
+
<Chd>#{children}</Chd>
|
102
|
+
<Inf>#{infants}</Inf>
|
103
|
+
<PromoID>0</PromoID>
|
104
|
+
<CMPCode>0</CMPCode>
|
105
|
+
</ezQuoteAirRequest>
|
106
|
+
</AFS1>
|
107
|
+
</soap:Body>
|
108
|
+
BODY
|
109
|
+
end
|
110
|
+
|
111
|
+
def depart_trip_xml
|
112
|
+
<<-DEPART.strip_heredoc
|
113
|
+
<QuoteAirRequestTrip>
|
114
|
+
<DepDt>#{departure_date.strftime '%m/%d/%Y'}</DepDt>
|
115
|
+
<Orig>#{origin}</Orig>
|
116
|
+
<Dest>#{destination}</Dest>
|
117
|
+
</QuoteAirRequestTrip>
|
118
|
+
DEPART
|
119
|
+
end
|
120
|
+
|
121
|
+
def return_trip_xml
|
122
|
+
<<-RETURN.strip_heredoc
|
123
|
+
<QuoteAirRequestTrip>
|
124
|
+
<DepDt>#{return_date.strftime '%m/%d/%Y'}</DepDt>
|
125
|
+
<Orig>#{destination}</Orig>
|
126
|
+
<Dest>#{origin}</Dest>
|
127
|
+
</QuoteAirRequestTrip>
|
128
|
+
RETURN
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Returned by LBF::Client.search. This object contains an array of LBF::Quotes and an array of
|
2
|
+
# LBF::SearchErrors. :quotes will have a single element if a one-way flight was requeted, and two
|
3
|
+
# if a roundtrip flight was requested.
|
4
|
+
class LBF::Response
|
5
|
+
attr_reader :quotes, :errors
|
6
|
+
def initialize(hsh)
|
7
|
+
@hash = hsh
|
8
|
+
@errors = errors_from(@hash.deep_fetch :afs1_response, :afs1_result, :quote_air, :error_list)
|
9
|
+
@quotes = quotes_from(@hash.deep_fetch :afs1_response, :afs1_result, :quote_air)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h
|
13
|
+
@hash
|
14
|
+
end
|
15
|
+
|
16
|
+
def error?
|
17
|
+
!errors.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def errors_from(err_hash)
|
23
|
+
return [] if err_hash.nil?
|
24
|
+
err_hash.values.map { |msg| LBF::SearchError.new(msg) }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Can be a hash or an array of hashes, so we have to handle that
|
28
|
+
def quotes_from(quotes_arr)
|
29
|
+
return [] if quotes_arr.nil?
|
30
|
+
quotes_arr = [quotes_arr].flatten
|
31
|
+
quotes_arr.map { |q| LBF::Quote.new(q) }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# A segment of an LBF trip. Since not everything from the incoming segment_hash is exposed, see comment
|
2
|
+
# below for segment information
|
3
|
+
class LBF::Segment
|
4
|
+
attr_reader :plane, :origin, :destination, :airline, :comments, :arrival, :departure, :flight
|
5
|
+
def initialize(segment_hash)
|
6
|
+
# {
|
7
|
+
# :equipment=>"Canadair Regional Jet 900", :e_ticket=>true, :equipment_code=>"CR9", :flight_stops=>"0",
|
8
|
+
# :airline=>"US", :orig=>"DFW", :duration=>nil, :dest=>"SDF", :airline_name=>"Us Airways",
|
9
|
+
# :flight_operator=>nil, :codeshare_comments=>"MESA AIRLINES AS AMERICAN EAGLE",
|
10
|
+
# :flight_operator_name=>"MESA AIRLINES AS AMERICAN EAGLE", :flight_number=>"5746",
|
11
|
+
# :orig_name=>"Dallas, Fort Worth Intl", :dest_name=>"Louisville, Louisville Intl",
|
12
|
+
# :arr_dt=>"04/04/2015", :dep_dt=>"04/04/2015", :arr_tm=>"1819", :dep_tm=>"1510", :arr_terminal=>nil,
|
13
|
+
# :dep_terminal=>"B", :connection_duration=>"0",
|
14
|
+
# :seats=>"7", :class_of_service=>"V", :cabin=>"Y",
|
15
|
+
# :cabin_name=>"Economy",
|
16
|
+
# :comments=> {
|
17
|
+
# :string=>"Operated By MESA AIRLINES AS AMERICAN EAGLE"
|
18
|
+
# },
|
19
|
+
# :segment_stops=> {
|
20
|
+
# :quote_air_segment_stop=> {
|
21
|
+
# :airport=>"DEN",
|
22
|
+
# :arrive_date=>"4/8/2015",
|
23
|
+
# :arrive_time=>"1531",
|
24
|
+
# :depart_date=>"4/8/2015",
|
25
|
+
# :depart_time=>"1621"
|
26
|
+
# }
|
27
|
+
# }
|
28
|
+
# }
|
29
|
+
@plane = LBF::Plane.new(segment_hash[:equipment], segment_hash[:equipment_code])
|
30
|
+
@e_ticket = segment_hash[:e_ticket]
|
31
|
+
@stops = segment_hash[:flight_stops].to_i
|
32
|
+
@origin = segment_hash[:orig]
|
33
|
+
@destination = segment_hash[:dest]
|
34
|
+
@airline = segment_hash[:airline_name]
|
35
|
+
@comments = comments_from segment_hash[:comments]
|
36
|
+
@arrival = DateTime.strptime("#{segment_hash[:arr_dt]} #{segment_hash[:arr_tm]}", '%m/%d/%Y %H%M')
|
37
|
+
@departure = DateTime.strptime("#{segment_hash[:dep_dt]} #{segment_hash[:dep_tm]}", '%m/%d/%Y %H%M')
|
38
|
+
@flight = segment_hash[:flight_number].to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
def e_ticket?
|
42
|
+
@e_ticket
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def comments_from(comments_hash)
|
48
|
+
return [] if comments_hash.nil?
|
49
|
+
comments_hash.values
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# A traveler, according to LBF
|
2
|
+
class LBF::Traveler
|
3
|
+
TRAVELER_CATEGORY = LBF::Request::CABINS.invert
|
4
|
+
def initialize(trav_hash)
|
5
|
+
@category = TRAVELER_CATEGORY[trav_hash[:category].upcase]
|
6
|
+
@fare = BigDecimal.new trav_hash[:fare]
|
7
|
+
@taxes_and_fees = BigDecimal.new trav_hash[:fare_tax_and_fees]
|
8
|
+
@total_price = BigDecimal.new trav_hash[:fare_total]
|
9
|
+
end
|
10
|
+
end
|
data/lib/lbf/lbf_trip.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# A trip, e.g. from LAS to LAX. Will contain multiple segments if it isn't a non-stop flight. Also
|
2
|
+
# includes layover information. Segments can have segment stops, for stops that aren't segments. This might
|
3
|
+
# mean that the plane stops, but the traveler doesn't get off. It's not clear from the documentation.
|
4
|
+
# Segment stops are not exposed.
|
5
|
+
class LBF::Trip
|
6
|
+
attr_reader :duration, :arrival, :departure, :origin, :destination, :notes
|
7
|
+
|
8
|
+
# NB: The :duration method (and corresponding ivar) are in seconds
|
9
|
+
def initialize(trip_hash)
|
10
|
+
@duration = trip_hash[:duration].to_i.minutes
|
11
|
+
@arrival = DateTime.strptime("#{trip_hash[:arr_dt]} #{trip_hash[:arr_tm]}", '%m/%d/%Y %H%M')
|
12
|
+
@departure = DateTime.strptime("#{trip_hash[:dep_dt]} #{trip_hash[:dep_tm]}", '%m/%d/%Y %H%M')
|
13
|
+
@origin = trip_hash[:orig]
|
14
|
+
@destination = trip_hash[:dest]
|
15
|
+
@notes = trip_hash[:duration_notes]
|
16
|
+
@segments = segments_from(trip_hash.deep_fetch :quote_air_segments, :quote_air_segment)
|
17
|
+
@layovers = layovers_from(trip_hash.deep_fetch :quote_air_segments, :quote_air_segment)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def layovers_from(segment_arr)
|
23
|
+
return [] if segment_arr.nil?
|
24
|
+
segment_arr.map { |s| LBF::Layover.new(s) unless s[:connection_duration].to_i == 0 }.compact
|
25
|
+
end
|
26
|
+
|
27
|
+
def segments_from(segment_arr)
|
28
|
+
return [] if segment_arr.nil?
|
29
|
+
segment_arr.map { |s| LBF::Segment.new s }
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/lbf/version.rb
ADDED
data/lib/lbf.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module LBF
|
2
|
+
end
|
3
|
+
require 'lbf/version'
|
4
|
+
require 'lbf/lbf_client'
|
5
|
+
require 'lbf/lbf_request'
|
6
|
+
require 'lbf/lbf_response'
|
7
|
+
require 'lbf/lbf_exceptions'
|
8
|
+
require 'lbf/lbf_quote'
|
9
|
+
require 'lbf/lbf_trip'
|
10
|
+
require 'lbf/lbf_traveler'
|
11
|
+
require 'lbf/lbf_fare'
|
12
|
+
require 'lbf/lbf_segment'
|
13
|
+
require 'lbf/lbf_plane'
|
14
|
+
require 'lbf/lbf_layover'
|
15
|
+
require 'lbf/deep_fetch'
|
16
|
+
require 'savon'
|
17
|
+
require 'pp'
|
18
|
+
require 'date'
|
19
|
+
require 'active_support/all'
|
20
|
+
require 'ipaddr'
|
21
|
+
require 'bigdecimal'
|
22
|
+
I18n.config.enforce_available_locales = false
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: LBF
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Forrest Fleming
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: savon
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.10'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubyntlm
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.3.2
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.3.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.1'
|
69
|
+
description: Pile of service objects for making requests to the LBF API and its responses
|
70
|
+
email:
|
71
|
+
- ffleming@oversee.net
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lbf.gemspec
|
82
|
+
- lib/lbf.rb
|
83
|
+
- lib/lbf/deep_fetch.rb
|
84
|
+
- lib/lbf/lbf_client.rb
|
85
|
+
- lib/lbf/lbf_exceptions.rb
|
86
|
+
- lib/lbf/lbf_fare.rb
|
87
|
+
- lib/lbf/lbf_layover.rb
|
88
|
+
- lib/lbf/lbf_plane.rb
|
89
|
+
- lib/lbf/lbf_quote.rb
|
90
|
+
- lib/lbf/lbf_request.rb
|
91
|
+
- lib/lbf/lbf_response.rb
|
92
|
+
- lib/lbf/lbf_segment.rb
|
93
|
+
- lib/lbf/lbf_traveler.rb
|
94
|
+
- lib/lbf/lbf_trip.rb
|
95
|
+
- lib/lbf/version.rb
|
96
|
+
homepage: https://github.com/Oversee/Travel-LBFSoap
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project:
|
116
|
+
rubygems_version: 2.2.2
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: Gem for making requests from LBF API
|
120
|
+
test_files: []
|