tapi 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TAPI
3
+ module V3
4
+ module Configurable
5
+
6
+ def self.included(klass)
7
+ klass.extend(ClassMethods)
8
+ end
9
+
10
+ def config
11
+ Thread.current[:tapi_config] ||= {}
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ def config
17
+ Thread.current[:tapi_config] ||= {}
18
+ end
19
+
20
+ def config=(config)
21
+ Thread.current[:tapi_config] = config
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module TAPI
2
+
3
+ class Error < RuntimeError
4
+ attr_accessor :response_code, :request_url, :response_body
5
+
6
+ def to_s
7
+ "Status code: #{response_code}\nRequest url: #{request_url}\n\n\n#{response_body}"
8
+ end
9
+ end
10
+
11
+ class BadRequestError < Error
12
+ end
13
+
14
+ class NotFoundError < Error
15
+ end
16
+
17
+ class ExpiredError < Error
18
+ end
19
+
20
+ class MovedError < Error
21
+ end
22
+
23
+ class InternalServerError < Error
24
+ end
25
+
26
+ end
@@ -0,0 +1,124 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TAPI
3
+ module V3
4
+ module Flights
5
+ class Search < TAPI::V3::GenericSearch
6
+
7
+ AIRPORTCODEEXPR = /^[\w]{3}$/
8
+
9
+ attr_accessor :origin, :destination, :comfort
10
+ attr_reader :leaves_on, :returns_on, :one_way, :adults, :children, :infants
11
+
12
+ def leaves_on=(date)
13
+ @leaves_on = coerce_date(date) rescue nil
14
+ end
15
+
16
+ def returns_on=(date)
17
+ @returns_on = coerce_date(date) rescue nil
18
+ end
19
+
20
+ def one_way=(value)
21
+ @one_way = value.to_s == 'true'
22
+ end
23
+
24
+ def adults=(value)
25
+ @adults = value.to_i
26
+ end
27
+
28
+ def children=(value)
29
+ @children = value.to_i
30
+ end
31
+
32
+ def infants=(value)
33
+ @infants = value.to_i
34
+ end
35
+
36
+ validates_numericality_of :adults, "Bitte wählen Sie die Anzahl der Erwachsenen."
37
+ validates_numericality_of :children, "Bitte wählen Sie die Anzahl der Kinder."
38
+ validates_numericality_of :infants, "Bitte wählen Sie die Anzahl der Babies."
39
+
40
+ validate do
41
+ if leaves_on and leaves_on < Date.today
42
+ add_error :leaves_on, "Abflug muss in der Zukunft liegen."
43
+ end
44
+
45
+ if returns_on and leaves_on and returns_on < leaves_on
46
+ add_error :returns_on, "Rückflug muss später als der Hinflug sein."
47
+ end
48
+
49
+ if leaves_on.nil?
50
+ add_error :leaves_on, "Bitte wählen Sie ein gültiges Abflugdatum aus."
51
+ end
52
+
53
+ if one_way.to_s == 'true' and not returns_on.to_s.empty?
54
+ add_error :returns_on, "Bitte wählen Sie entweder One-Way oder ein Rückflugdatum aus."
55
+ end
56
+
57
+ if one_way.to_s != 'true' and returns_on.to_s.empty?
58
+ add_error :returns_on, "Bitte wählen Sie ein gültiges Datum aus."
59
+ end
60
+
61
+ if adults.to_i < infants.to_i
62
+ add_error :passengers, "Die Anzahl der Erwachsenen muss mindestens gleich der Babies sein."
63
+ end
64
+
65
+ if adults.to_i < 1
66
+ add_error :passengers, "Es muss mindestens ein Erwachsener fliegen."
67
+ end
68
+
69
+ unless AIRPORTCODEEXPR =~ origin.to_s
70
+ add_error :origin, "Bitte wählen Sie einen Startflughafen."
71
+ end
72
+
73
+ unless AIRPORTCODEEXPR =~ destination.to_s
74
+ add_error :destination, "Bitte wählen Sie einen Zielflughafen."
75
+ end
76
+
77
+ unless /^(E|B|EB|BE)$/ =~ comfort
78
+ add_error :passengers, "Bitte geben Die einen gültigen Code für den Comfort an."
79
+ end
80
+
81
+ unless origin.to_s.empty? or destination.to_s.empty?
82
+ if origin == destination
83
+ add_error :destination, "Bitte wählen Sie unterschiedliche Start- und Zielflughäfen."
84
+ end
85
+ end
86
+ end
87
+
88
+ def item_path
89
+ 'flights'
90
+ end
91
+
92
+ def initialize(options = {})
93
+ @errors = {}
94
+ self.origin = options[:origin]
95
+ self.destination = options[:destination]
96
+ self.leaves_on = options[:leaves_on]
97
+ self.returns_on = options[:returns_on]
98
+ self.one_way = options[:one_way]
99
+ self.adults = options[:adults] || 1
100
+ self.children = options[:children] || 0
101
+ self.infants = options[:infants] || 0
102
+ self.comfort = (options[:comfort] || "E").upcase
103
+ end
104
+
105
+ def parameters
106
+ {
107
+ :key => config[:key],
108
+ :format => 'json',
109
+ :origin => origin,
110
+ :destination => destination,
111
+ :leaves_on => leaves_on.to_s,
112
+ :returns_on => returns_on.to_s,
113
+ :one_way => one_way,
114
+ :adults => adults,
115
+ :children => children,
116
+ :infants => infants,
117
+ :comfort => comfort
118
+ }
119
+ end
120
+
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,97 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TAPI
3
+ module V3
4
+ class GenericSearch
5
+
6
+ extend Validations
7
+
8
+ attr_reader :client, :client_urls, :started_at, :start_time
9
+ attr_accessor :errors
10
+
11
+ def id
12
+ if @id
13
+ @id
14
+ elsif @client and @client.respond_to?(:id)
15
+ @client.id
16
+ end
17
+ end
18
+
19
+ def id=(id)
20
+ @id = id
21
+ end
22
+
23
+ include Configurable
24
+ include Utils
25
+
26
+ def add_error(name, message)
27
+ (errors[name] ||= []) << message
28
+ end
29
+
30
+ def valid?
31
+ errors.clear
32
+
33
+ self.class.inherited_validations.each do |validation|
34
+ instance_eval(&validation)
35
+ end
36
+
37
+ errors.empty?
38
+ end
39
+
40
+ def has_errors?
41
+ errors.any?
42
+ end
43
+
44
+ def reload
45
+ load_client
46
+ self
47
+ end
48
+
49
+ def api_url
50
+ port = config[:port] == 80 ? '' : ":#{config[:port]}"
51
+ "http://#{ config[:host] }#{ port }#{ config[:path] }"
52
+ end
53
+
54
+ def api_key
55
+ config[:key]
56
+ end
57
+
58
+ def post_url
59
+ api_url + '/' + item_path + '/searches.json'
60
+ end
61
+
62
+ def get(path, options={})
63
+ TAPI::V3::Client.new_from_get(api_url + path + '.json', options.merge(:key => api_key)).first
64
+ end
65
+
66
+ def start!
67
+ @started_at = Time.now
68
+ @client = TAPI::V3::Client.new_from_post(post_url, parameters).search
69
+ @start_time = Time.now - @started_at
70
+ @client_urls = @client.urls
71
+ end
72
+
73
+ def load_client
74
+ if @client_urls
75
+ client, etag = TAPI::V3::Client.new_from_get(@client_urls[:search_url], {}, @etag)
76
+ @client, @etag = client.search, etag unless @etag == etag
77
+ end
78
+ end
79
+
80
+ def restart!
81
+ if @client_urls
82
+ TAPI::V3::Client.new_from_post(@client_urls[:restart_url], {})
83
+ load_client
84
+ end
85
+ end
86
+
87
+ def method_missing(key, *args)
88
+ begin
89
+ @client.send(key, *args)
90
+ rescue NoMethodError
91
+ raise NoMethodError, "undefined method `#{key}' for #{self.class}", caller
92
+ end
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,213 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TAPI
3
+ module V3
4
+ module Hotels
5
+ class Search < TAPI::V3::GenericSearch
6
+ attr_accessor :expired
7
+
8
+ attr_reader :arrival_date, :departure_date, :city_id, :region_id, :hotel_id
9
+ attr_reader :room_configuration, :single_rooms_count, :double_rooms_count
10
+
11
+ validates_numericality_of :single_rooms_count, "Bitte wählen Sie die Anzahl der Einzelzimmer."
12
+ validates_numericality_of :double_rooms_count, "Bitte wählen Sie die Anzahl der Doppelzimmer."
13
+
14
+ validates_presence_of :arrival_date, "Bitte wählen Sie ein gültiges Datum."
15
+ validates_presence_of :departure_date, "Bitte wählen Sie ein gültiges Datum."
16
+
17
+ validate do
18
+ if arrival_date and arrival_date < Date.today
19
+ add_error :arrival_date, "Das Anreisedatum darf nicht in der Vergangenheit liegen."
20
+ end
21
+
22
+ if single_rooms_count == 0 and double_rooms_count == 0
23
+ add_error :room_configuration, "Bitte mindestens ein Zimmer angeben."
24
+ end
25
+
26
+ if (single_rooms_count + double_rooms_count) > 3
27
+ add_error :room_configuration, "Bitte nicht mehr als 3 Zimmer angeben."
28
+ end
29
+
30
+ if arrival_date and departure_date and departure_date <= arrival_date
31
+ add_error :departure_date, "Das Abreisedatum muss mindestens einen Tag nach der Ankunft liegen."
32
+ end
33
+
34
+ if city_id.blank? and region_id.blank? and hotel_id.blank?
35
+ add_error :city_id, "Bitte geben Sie den gewünschten Aufenthaltsort an."
36
+ end
37
+
38
+ end
39
+
40
+ class << self
41
+
42
+ def parse_room_configuration(str)
43
+ rooms_strings = str.split('][').map {|r| r.gsub(/\]|\[/, '').split('|')}
44
+ raise ArgumentError, "#{str} is not a valid room configuration hash !" if rooms_strings.length > 3 || rooms_strings.empty?
45
+ room_collection = {}
46
+ rooms = rooms_strings.each_with_index do |guests, i|
47
+ room_collection[i + 1] ||= {}
48
+ guests.each do |g|
49
+ case g
50
+ when 'A'
51
+ room_collection[i + 1]['adults'] ||= 0
52
+ room_collection[i + 1]['adults'] += 1
53
+ when /\d/
54
+ room_collection[i + 1]['child'] ||= {}
55
+ last_key = room_collection[i + 1]['child'].keys.min || 0
56
+ room_collection[i + 1]['child'][last_key + 1] = g.to_i
57
+ else
58
+ raise ArgumentError, "#{str} is not a valid room configuration hash !"
59
+ end
60
+ end
61
+ end
62
+ room_collection
63
+ end
64
+
65
+ end # class
66
+
67
+ def initialize(options = {})
68
+ @errors = {}
69
+ @single_rooms_count = 0
70
+ @double_rooms_count = 0
71
+
72
+ self.arrival_date = options[:arrival_date]
73
+ self.departure_date = options[:departure_date]
74
+
75
+ self.city_id = options[:city_id]
76
+ self.region_id = options[:region_id]
77
+ self.hotel_id = options[:hotel_id]
78
+
79
+ if options[:room_configuration].blank?
80
+ self.single_rooms_count = options[:single_rooms_count] || 1
81
+ self.double_rooms_count = options[:double_rooms_count] || 0
82
+ else
83
+ self.room_configuration = options[:room_configuration]
84
+ end
85
+ end
86
+
87
+ def item_path
88
+ 'hotels'
89
+ end
90
+
91
+ def state
92
+ @client.status_detailed.state if @client
93
+ end
94
+
95
+ def location
96
+ case
97
+ when city_id then city
98
+ when region_id then region
99
+ when hotel_id then hotel
100
+ end
101
+ end
102
+
103
+ def location_type
104
+ case
105
+ when city_id then :city
106
+ when region_id then :region
107
+ when hotel_id then :hotel
108
+ end
109
+ end
110
+
111
+ def location_id
112
+ city_id || region_id || hotel_id
113
+ end
114
+
115
+ def arrival_date=(date)
116
+ @arrival_date = coerce_date(date)
117
+ rescue TypeError => e
118
+ Client.logger.debug e.message
119
+ Client.logger.debug e.backtrace.join("\n")
120
+ end
121
+
122
+ def departure_date=(date)
123
+ @departure_date = coerce_date(date)
124
+ rescue TypeError => e
125
+ Client.logger.debug e.message
126
+ Client.logger.debug e.backtrace.join("\n")
127
+ end
128
+
129
+ def city_id=(id)
130
+ @city_id = id.to_i unless id.to_s.empty?
131
+ end
132
+
133
+ def region_id=(id)
134
+ @region_id = id.to_i unless id.to_s.empty?
135
+ end
136
+
137
+ def hotel_id=(id)
138
+ @hotel_id = id.to_i unless id.to_s.empty?
139
+ end
140
+
141
+ def city
142
+ @city ||= get("/locations/cities/#{city_id}").city unless city_id.to_s.empty?
143
+ end
144
+
145
+ def region
146
+ @region ||= get("/locations/regions/#{region_id}").region unless region_id.to_s.empty?
147
+ end
148
+
149
+ def hotel
150
+ @hotel ||= get("/locations/hotels/#{hotel_id}").hotel unless hotel_id.to_s.empty?
151
+ end
152
+
153
+ def room_configuration=(config)
154
+ @room_configuration = config
155
+ rooms = Search.parse_room_configuration(config).values
156
+
157
+ @single_rooms_count = rooms.count { |room| room['adults'] == 1 }
158
+ @double_rooms_count = rooms.count { |room| room['adults'] == 2 }
159
+ end
160
+
161
+ def single_rooms_count=(count)
162
+ @single_rooms_count = Integer(count)
163
+ update_room_configuration!
164
+ end
165
+
166
+ def double_rooms_count=(count)
167
+ @double_rooms_count = Integer(count)
168
+ update_room_configuration!
169
+ end
170
+
171
+ def update_room_configuration!
172
+ @room_configuration = ('[A]' * single_rooms_count) + ('[A|A]' * double_rooms_count)
173
+ end
174
+
175
+ def to_param
176
+ {
177
+ :location_type => location_type,
178
+ :location_id => location_id,
179
+ :arrival_date => arrival_date.to_s,
180
+ :departure_date => departure_date.to_s,
181
+ :single_rooms_count => single_rooms_count,
182
+ :double_rooms_count => double_rooms_count
183
+ }
184
+ end
185
+
186
+ def parameters
187
+ {
188
+ :key => config[:key],
189
+ :format => 'json',
190
+ :city_id => city_id,
191
+ :region_id => region_id,
192
+ :hotel_id => hotel_id,
193
+ :arrival_date => arrival_date.to_s,
194
+ :departure_date => departure_date.to_s,
195
+ :room_configuration => room_configuration
196
+ }
197
+ end
198
+
199
+ # create a hotel search with the same parameters
200
+ # for a given hotel
201
+ def hotel_search(result_or_hotel_id)
202
+ hotel_id = result_or_hotel_id.is_a?(Fixnum) ? result_or_hotel_id : result_or_hotel_id.hotel_id
203
+ params = parameters
204
+ params.delete(:city_id)
205
+ params.delete(:region_id)
206
+ params[:hotel_id] = hotel_id
207
+ TAPI::V3::Hotels::Search.new(params)
208
+ end
209
+
210
+ end
211
+ end
212
+ end
213
+ end