quicktravel_client 1.0.2
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 +25 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.ruby-version +1 -0
- data/.travis.yml +18 -0
- data/Gemfile +5 -0
- data/LICENSE +22 -0
- data/README.md +17 -0
- data/Rakefile +18 -0
- data/bootstrap/boot.rb +4 -0
- data/examples/example_config.rb +4 -0
- data/examples/login_example.rb +25 -0
- data/lib/extensions.rb +12 -0
- data/lib/quick_travel/accommodation.rb +72 -0
- data/lib/quick_travel/adapter.rb +283 -0
- data/lib/quick_travel/adapter_exception.rb +20 -0
- data/lib/quick_travel/address.rb +27 -0
- data/lib/quick_travel/adjustment.rb +8 -0
- data/lib/quick_travel/background_check.rb +9 -0
- data/lib/quick_travel/bed_configuration.rb +7 -0
- data/lib/quick_travel/bed_requirement.rb +7 -0
- data/lib/quick_travel/booking.rb +370 -0
- data/lib/quick_travel/cache.rb +38 -0
- data/lib/quick_travel/client.rb +8 -0
- data/lib/quick_travel/client_type.rb +6 -0
- data/lib/quick_travel/config.rb +26 -0
- data/lib/quick_travel/connection_error.rb +9 -0
- data/lib/quick_travel/constants.rb +16 -0
- data/lib/quick_travel/contact.rb +5 -0
- data/lib/quick_travel/country.rb +11 -0
- data/lib/quick_travel/credit_card.rb +12 -0
- data/lib/quick_travel/discounts/booking_discount.rb +18 -0
- data/lib/quick_travel/discounts/discount.rb +21 -0
- data/lib/quick_travel/discounts/discount_tree.rb +35 -0
- data/lib/quick_travel/discounts.rb +3 -0
- data/lib/quick_travel/document.rb +20 -0
- data/lib/quick_travel/document_group.rb +14 -0
- data/lib/quick_travel/encrypt.rb +13 -0
- data/lib/quick_travel/graphic.rb +18 -0
- data/lib/quick_travel/init_from_hash.rb +16 -0
- data/lib/quick_travel/location.rb +14 -0
- data/lib/quick_travel/mock.rb +41 -0
- data/lib/quick_travel/party.rb +49 -0
- data/lib/quick_travel/passenger.rb +7 -0
- data/lib/quick_travel/passenger_price_break.rb +8 -0
- data/lib/quick_travel/passenger_type.rb +21 -0
- data/lib/quick_travel/payment.rb +41 -0
- data/lib/quick_travel/payment_type.rb +37 -0
- data/lib/quick_travel/price.rb +14 -0
- data/lib/quick_travel/product.rb +165 -0
- data/lib/quick_travel/product_configuration.rb +134 -0
- data/lib/quick_travel/product_passenger_search_criteria.rb +28 -0
- data/lib/quick_travel/product_type.rb +28 -0
- data/lib/quick_travel/property.rb +99 -0
- data/lib/quick_travel/property_facility.rb +7 -0
- data/lib/quick_travel/property_type.rb +20 -0
- data/lib/quick_travel/region.rb +21 -0
- data/lib/quick_travel/reservation.rb +110 -0
- data/lib/quick_travel/resource.rb +50 -0
- data/lib/quick_travel/room_facility.rb +7 -0
- data/lib/quick_travel/route.rb +81 -0
- data/lib/quick_travel/route_stop.rb +7 -0
- data/lib/quick_travel/search.rb +14 -0
- data/lib/quick_travel/service.rb +5 -0
- data/lib/quick_travel/trip.rb +8 -0
- data/lib/quick_travel/vehicle.rb +17 -0
- data/lib/quick_travel/vehicle_type.rb +11 -0
- data/lib/quick_travel/version.rb +3 -0
- data/lib/quick_travel.rb +59 -0
- data/lib/quicktravel_client.rb +1 -0
- data/quicktravel_client.gemspec +37 -0
- data/spec/booking_spec.rb +107 -0
- data/spec/country_spec.rb +18 -0
- data/spec/credit_card_spec.rb +11 -0
- data/spec/discounts_spec.rb +121 -0
- data/spec/passenger_type_spec.rb +32 -0
- data/spec/payment_type_spec.rb +18 -0
- data/spec/product_spec.rb +82 -0
- data/spec/region_spec.rb +29 -0
- data/spec/reservation_spec.rb +50 -0
- data/spec/resource_spec.rb +22 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/support/cassettes/booking_create.yml +50 -0
- data/spec/support/cassettes/booking_create_legacy.yml +50 -0
- data/spec/support/cassettes/booking_discounts.yml +53 -0
- data/spec/support/cassettes/booking_documents.yml +48 -0
- data/spec/support/cassettes/booking_show.yml +49 -0
- data/spec/support/cassettes/booking_update.yml +94 -0
- data/spec/support/cassettes/booking_with_discounts.yml +72 -0
- data/spec/support/cassettes/booking_with_documents.yml +117 -0
- data/spec/support/cassettes/booking_with_nested_attributes.yml +187 -0
- data/spec/support/cassettes/country_all.yml +127 -0
- data/spec/support/cassettes/create_reservation_fail.yml +47 -0
- data/spec/support/cassettes/create_reservation_with_booking.yml +53 -0
- data/spec/support/cassettes/passenger_all.yml +48 -0
- data/spec/support/cassettes/product_date_range_bookability.yml +118 -0
- data/spec/support/cassettes/product_show.yml +52 -0
- data/spec/support/cassettes/region_index.yml +48 -0
- data/spec/support/cassettes/region_show.yml +48 -0
- data/spec/support/cassettes/reservation_with_extra_picks.yml +165 -0
- data/spec/support/cassettes/resource_fare_bases.yml +97 -0
- data/spec/support/cassettes/resource_show.yml +50 -0
- metadata +421 -0
@@ -0,0 +1,370 @@
|
|
1
|
+
require 'quick_travel/adapter'
|
2
|
+
require 'quick_travel/passenger'
|
3
|
+
require 'quick_travel/vehicle'
|
4
|
+
require 'quick_travel/payment'
|
5
|
+
require 'quick_travel/payment_type'
|
6
|
+
require 'quick_travel/discounts'
|
7
|
+
|
8
|
+
module QuickTravel
|
9
|
+
class Booking < Adapter
|
10
|
+
attr_accessor :reference, :state, :client_id, :first_travel_date, :created_at, :access_token
|
11
|
+
attr_accessor :gross_in_cents, :commission_in_cents, :cost_in_cents, :balance_in_cents, :paid_in_cents, :surcharge_in_cents
|
12
|
+
attr_accessor :deposit_in_cents, :deposit_due_on, :deposit_relevant
|
13
|
+
|
14
|
+
attr_accessor :id # booking_id. I am initializing this data member when we create booking.
|
15
|
+
attr_accessor :client_address, :client_party, :client_contact,
|
16
|
+
:customer_contact_name, :customer_contact_phone, :customer_contact_mobile, :customer_contact_email,
|
17
|
+
:post_code, :country_id, :referral_code_id,
|
18
|
+
:discardable_in, :inactivatable_in,
|
19
|
+
:promo_code, :web_site_name,
|
20
|
+
:insurance_offered, :public_comments
|
21
|
+
|
22
|
+
money :gross, :balance, :commission, :paid, :surcharge, :deposit
|
23
|
+
|
24
|
+
def self.api_base
|
25
|
+
'/api/bookings'
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.front_office_base
|
29
|
+
'/front_office/bookings'
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.find_by_reference(reference)
|
33
|
+
find_all!("#{api_base}/reference/#{reference}.json").first
|
34
|
+
end
|
35
|
+
|
36
|
+
def documents(regenerate = false)
|
37
|
+
Document.find_all!("#{Booking.api_base}/#{@id}/documents.json",
|
38
|
+
last_group: true, regenerate: regenerate)
|
39
|
+
end
|
40
|
+
|
41
|
+
def payments
|
42
|
+
Payment.find_all!("#{Booking.front_office_base}/#{@id}/payments.json")
|
43
|
+
end
|
44
|
+
|
45
|
+
def payment_types
|
46
|
+
PaymentType.find_all!("#{Booking.front_office_base}/#{@id}/payment_types.json")
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_account_payment_type
|
50
|
+
payment_types_by_code = payment_types.group_by(&:code)
|
51
|
+
|
52
|
+
# Try on-account, or if not, on-account-with-reference
|
53
|
+
payment_types_by_code['on_account_without_reference'].try(:first) ||
|
54
|
+
payment_types_by_code['on_account_with_reference'].try(:first)
|
55
|
+
end
|
56
|
+
|
57
|
+
def country
|
58
|
+
Country.find(@country_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
def deposit_due_on
|
62
|
+
@deposit_due_on_parsed ||= parse_date(@deposit_due_on)
|
63
|
+
end
|
64
|
+
|
65
|
+
def balance_due_on
|
66
|
+
@balance_due_on_parsed ||= parse_date(@balance_due_on)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Create an empty booking
|
70
|
+
#
|
71
|
+
# Note, options pertain to initializing booking with some values:
|
72
|
+
#
|
73
|
+
# options = {
|
74
|
+
# :when => "28-04-2010" ,
|
75
|
+
# :passengers => { "1" => nil, "2" => nil, "3" => nil, "4" => nil , "5" => nil } ,
|
76
|
+
# :include_vehicle => nil , :vehicle => { :vehicle_type_id => nil , :length , :weight } ,
|
77
|
+
# :vehicle_return_weight => nil ,
|
78
|
+
# :include_trailer => nil ,
|
79
|
+
# :trailer => { :vehicle_type_id => nil , :length => nil }
|
80
|
+
# }
|
81
|
+
def self.create(options = {})
|
82
|
+
default_options = { referral_code_id: DEFAULT_REFERRAL_CODE_ID }
|
83
|
+
options = { booking: default_options.merge(options) }
|
84
|
+
|
85
|
+
response = post_and_validate("#{front_office_base}.json", options)
|
86
|
+
fail AdapterException.new(response) unless response['id']
|
87
|
+
|
88
|
+
return nil unless response['id']
|
89
|
+
Booking.new(response)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Update an existing booking
|
93
|
+
def update(options = {})
|
94
|
+
response = put_and_validate("#{api_base}/#{@id}.json", booking: options)
|
95
|
+
# id is returned if other attributes change otherwise success: true
|
96
|
+
fail AdapterException.new(response) unless response['id'] || response['success']
|
97
|
+
|
98
|
+
Booking.find(@id)
|
99
|
+
end
|
100
|
+
|
101
|
+
# ###
|
102
|
+
# Updates:
|
103
|
+
# - Client information
|
104
|
+
# - Client contact
|
105
|
+
# - Client address
|
106
|
+
# - Pax details
|
107
|
+
# - Vehicle details
|
108
|
+
def update_with_nested_attributes!(booking_args = {})
|
109
|
+
response = put_and_validate("#{api_base}/#{@id}/update_with_nested_attributes.json",
|
110
|
+
booking: booking_args)
|
111
|
+
fail AdapterException.new(response) unless response['id']
|
112
|
+
Booking.find(response['id'])
|
113
|
+
end
|
114
|
+
|
115
|
+
def remove_unassigned_passengers
|
116
|
+
put_and_validate("/api/bookings/#{@id}/remove_unassigned_passengers")
|
117
|
+
end
|
118
|
+
|
119
|
+
# Create an accommodation reservation from the given options
|
120
|
+
#
|
121
|
+
# Returns current booking object after having added the reservation
|
122
|
+
#
|
123
|
+
# reservations_options = {
|
124
|
+
# :id => nil ,
|
125
|
+
# :first_travel_date => nil,
|
126
|
+
# :last_travel_date => nil,
|
127
|
+
# :resource_id => nil ,
|
128
|
+
# :passenger_ids => {} ,
|
129
|
+
# :vehicle_ids => {} ,
|
130
|
+
# :bed_configuration_id => nil ,
|
131
|
+
# :tariff_level_id => nil
|
132
|
+
# }
|
133
|
+
#
|
134
|
+
# Example 2:
|
135
|
+
# reservations_options = {
|
136
|
+
# :first_trave_date => "28-04-2010",
|
137
|
+
# :last_travel_date => "28-04-2010",
|
138
|
+
# :resource_id => 89,
|
139
|
+
# :bed_configuration_id => 581,
|
140
|
+
# :passenger_ids => {""=>nil},
|
141
|
+
# :vehicle_ids => {""=>nil}
|
142
|
+
# }
|
143
|
+
def accommodation_reserve(reservations_options = {})
|
144
|
+
if reservations_options[:last_travel_date].nil?
|
145
|
+
fail AdapterException.new('No checkout date specified')
|
146
|
+
end
|
147
|
+
|
148
|
+
last_travel_date = Date.strptime(reservations_options[:last_travel_date], '%d/%m/%Y')
|
149
|
+
|
150
|
+
# Because QT requires last-date to be the date of use, we have to subtract one
|
151
|
+
last_travel_date -= 1
|
152
|
+
|
153
|
+
options = { reservations: reservations_options }
|
154
|
+
options[:reservations][:last_travel_date] = last_travel_date.strftime(QT_DATE_FORMAT)
|
155
|
+
|
156
|
+
reserve('accommodations/create_or_update', options)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Reserve a scheduled trips resource
|
160
|
+
# Returns current booking object after having added the reservation
|
161
|
+
#
|
162
|
+
# Note:
|
163
|
+
# Forward_options and return_options look similar, but each is a different trip
|
164
|
+
#
|
165
|
+
# Example:
|
166
|
+
# forward_options = {
|
167
|
+
# :passenger_ids => {} ,
|
168
|
+
# :vehicle_ids => {} ,
|
169
|
+
# :first_travel_date => nil,
|
170
|
+
# :tariff_level_id => nil ,
|
171
|
+
# :resource_id => nil ,
|
172
|
+
# :trip_id => nil
|
173
|
+
# }
|
174
|
+
def scheduled_trips_reserve(segments = {})
|
175
|
+
reserve(:scheduled_trips, segments.merge(segments: segments.keys))
|
176
|
+
end
|
177
|
+
|
178
|
+
def scheduled_trips_update(segments = {})
|
179
|
+
params = segments.merge(segments: segments.keys)
|
180
|
+
params[:booking_id] = @id
|
181
|
+
put_and_validate('/reservation_for/scheduled_trips/bulk_update.json', params)
|
182
|
+
Booking.find(@id)
|
183
|
+
end
|
184
|
+
|
185
|
+
def generics_reserve(options)
|
186
|
+
reserve(:generics, options)
|
187
|
+
end
|
188
|
+
|
189
|
+
def item_reserve(options)
|
190
|
+
reserve(:items, options)
|
191
|
+
end
|
192
|
+
|
193
|
+
def tour_reserve(options)
|
194
|
+
reserve(:packages, options)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Delete a reservation
|
198
|
+
#
|
199
|
+
# Returns current booking object after deleting the reservation
|
200
|
+
def delete_reservation(reservation)
|
201
|
+
delete_reservation_by_id(reservation.id)
|
202
|
+
end
|
203
|
+
|
204
|
+
def delete_reservation_by_id(reservation_id)
|
205
|
+
if state != 'new'
|
206
|
+
fail AdapterException.new('Reservation cannot be deleted unless the booking is new')
|
207
|
+
end
|
208
|
+
|
209
|
+
delete_and_validate("#{api_base}/#{@id}/reservations/#{reservation_id}.json")
|
210
|
+
refresh!
|
211
|
+
end
|
212
|
+
|
213
|
+
def refresh!
|
214
|
+
Booking.find(@id) # refresh
|
215
|
+
end
|
216
|
+
|
217
|
+
# Generate passenger objects from passenger data (hash)
|
218
|
+
def passengers
|
219
|
+
@passengers ||=
|
220
|
+
@passengers_attributes.map { |passenger| Passenger.new(passenger) }
|
221
|
+
end
|
222
|
+
|
223
|
+
# Generate passenger objects from passenger data (hash)
|
224
|
+
def vehicles
|
225
|
+
@vehicles ||=
|
226
|
+
@vehicles_attributes.map { |vehicle| Vehicle.new(vehicle) }
|
227
|
+
end
|
228
|
+
|
229
|
+
def find_passenger_by_id(pid)
|
230
|
+
passengers.detect { |p| p.id.to_i == pid.to_i }
|
231
|
+
end
|
232
|
+
|
233
|
+
def find_vehicle_by_id(vid)
|
234
|
+
vehicles.detect { |v| v.id.to_i == vid.to_i }
|
235
|
+
end
|
236
|
+
|
237
|
+
def passenger_types_counts
|
238
|
+
passengers.each_with_object(Hash.new(0)) do |passenger, hash|
|
239
|
+
hash[passenger.passenger_type_id] += 1
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def vehicles_hash
|
244
|
+
@vehicles
|
245
|
+
end
|
246
|
+
|
247
|
+
# It returns booking items for a booking.
|
248
|
+
# Array of BookingItem
|
249
|
+
def reservations
|
250
|
+
fail AdapterException, 'Reservations have not been set from API' if @reservations_attributes.nil?
|
251
|
+
@_reservations_object_array ||= @reservations_attributes.map { |item| Reservation.new(item) }
|
252
|
+
end
|
253
|
+
|
254
|
+
def legacy_reservations
|
255
|
+
@_reservations_object_array = @reservations.map { |item| Reservation.new(item) }
|
256
|
+
end
|
257
|
+
|
258
|
+
def client_address
|
259
|
+
@client_address_object ||= Address.new(@client_address)
|
260
|
+
end
|
261
|
+
|
262
|
+
def client_party
|
263
|
+
@client_party_object ||= Party.new(@client_party)
|
264
|
+
end
|
265
|
+
|
266
|
+
def client_contact
|
267
|
+
@client_contact_object ||= Contact.new(@client_contact)
|
268
|
+
end
|
269
|
+
|
270
|
+
def client
|
271
|
+
@client_object ||= Client.new(@client)
|
272
|
+
end
|
273
|
+
|
274
|
+
def calculate_existing_and_new_vehicles_for(required_vehicle_types)
|
275
|
+
return [[], []] if required_vehicle_types.blank?
|
276
|
+
|
277
|
+
vehicle_types_to_add = []
|
278
|
+
existing_vehicle_ids_to_assign = []
|
279
|
+
|
280
|
+
vehicles_yet_to_include = try(:vehicles)
|
281
|
+
|
282
|
+
required_vehicle_types.each do |searched_vehicle_type_hash|
|
283
|
+
matching_existing_vehicle = vehicles_yet_to_include.detect { |veh| veh.vehicle_type_id.to_i == searched_vehicle_type_hash[:vehicle_type_id].to_i }
|
284
|
+
if matching_existing_vehicle
|
285
|
+
existing_vehicle_ids_to_assign << matching_existing_vehicle.id.to_i
|
286
|
+
vehicles_yet_to_include -= [matching_existing_vehicle]
|
287
|
+
|
288
|
+
else
|
289
|
+
vehicle_types_to_add << searched_vehicle_type_hash
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
[existing_vehicle_ids_to_assign, vehicle_types_to_add]
|
294
|
+
end
|
295
|
+
|
296
|
+
def include_reservation_of?(product_type_id)
|
297
|
+
reservations.any? { |r| r.product_type_id.to_i == product_type_id }
|
298
|
+
end
|
299
|
+
|
300
|
+
def includes_resource_class?(resource_class_name)
|
301
|
+
reservations.any? { |r| r.resource_class_name == resource_class_name }
|
302
|
+
end
|
303
|
+
|
304
|
+
def clear_unfinished_reservations!
|
305
|
+
booking = self
|
306
|
+
reservations.reject(&:complete).each do |reservation|
|
307
|
+
# This will return updated booking..
|
308
|
+
booking = delete_reservation(reservation)
|
309
|
+
end
|
310
|
+
booking
|
311
|
+
end
|
312
|
+
|
313
|
+
def finalised?
|
314
|
+
(balance_in_cents == 0 && state != 'new' && !reservations.empty?) || state == 'quote'
|
315
|
+
end
|
316
|
+
|
317
|
+
def discount
|
318
|
+
@discount ||= fetch_discount
|
319
|
+
end
|
320
|
+
|
321
|
+
def discount_on(reservation)
|
322
|
+
discount.discount_on(reservation.id)
|
323
|
+
end
|
324
|
+
|
325
|
+
def total_discount_on(reservation)
|
326
|
+
discount.total_discount_on(reservation.id)
|
327
|
+
end
|
328
|
+
|
329
|
+
def calculate_price_quote(segments = {})
|
330
|
+
params = segments.merge(segments: segments.keys)
|
331
|
+
response = post_and_validate("#{api_base}/#{@id}/price_quotes/calculate", params)
|
332
|
+
Money.new(response['quoted_booking_gross_in_cents'])
|
333
|
+
end
|
334
|
+
|
335
|
+
def activate!
|
336
|
+
put_and_validate("#{api_base}/#{@id}/activate")
|
337
|
+
end
|
338
|
+
|
339
|
+
def subscribe_to_email_list(email = nil)
|
340
|
+
params = email.nil? ? {} : { email: email }
|
341
|
+
put_and_validate("#{api_base}/#{@id}/subscribe_to_email_list", params)
|
342
|
+
end
|
343
|
+
|
344
|
+
# secureAccessCodeString is simply a MAC algorithm (using SHA1) on the booking id string.
|
345
|
+
# it is using @id that is booking.id and configuration constant QUICK_TRAVEL_ACCESS_KEY
|
346
|
+
def secure_access_code
|
347
|
+
Encrypt.access_key(@id.to_s)
|
348
|
+
end
|
349
|
+
|
350
|
+
protected
|
351
|
+
|
352
|
+
def reserve(url, options)
|
353
|
+
options[:booking_id] = @id
|
354
|
+
post_and_validate("/reservation_for/#{url}.json", options)
|
355
|
+
Booking.find(@id)
|
356
|
+
end
|
357
|
+
|
358
|
+
private
|
359
|
+
|
360
|
+
def parse_date(hash)
|
361
|
+
return if hash.blank? || hash['_value'].blank?
|
362
|
+
hash['_value'].to_date
|
363
|
+
end
|
364
|
+
|
365
|
+
def fetch_discount
|
366
|
+
attributes = get_and_validate("#{api_base}/#{@id}/discount.json")
|
367
|
+
QuickTravel::Discounts::BookingDiscount.new(attributes)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module QuickTravel
|
2
|
+
module Cache
|
3
|
+
def cache(key, &block)
|
4
|
+
QuickTravel::Cache.cache(key) do
|
5
|
+
block.call
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.cache(key)
|
10
|
+
cached_value = cache_store.read(key)
|
11
|
+
return cached_value unless cached_value.nil?
|
12
|
+
return nil unless block_given?
|
13
|
+
yield.tap { |value| cache_store.write(key, value) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.cache_store
|
17
|
+
@@cache_store
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.cache_store=(store)
|
21
|
+
@@cache_store = store
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class DefaultCacheStore
|
26
|
+
def initialize
|
27
|
+
@store = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def write(key, value)
|
31
|
+
@store[key] = value
|
32
|
+
end
|
33
|
+
|
34
|
+
def read(key)
|
35
|
+
@store[key]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'quick_travel/adapter'
|
2
|
+
|
3
|
+
module QuickTravel
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :url, :access_key, :version
|
6
|
+
|
7
|
+
def url=(url)
|
8
|
+
@url = url
|
9
|
+
QuickTravel::Adapter.base_uri url
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_writer :access_key
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configure
|
16
|
+
yield QuickTravel.config
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.config
|
20
|
+
@config ||= QuickTravel::Configuration.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.url
|
24
|
+
config.url
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
### DELETE ME! Left here only so you can pull out the constants for the few that we should be keeping.
|
2
|
+
|
3
|
+
module QuickTravel
|
4
|
+
LOGIN_URL = '/parties/login' # CMS_SSL_URL + '/parties/login'
|
5
|
+
|
6
|
+
DEFAULT_LOCATION_ID_FOR_ACCOMM_SEARCH = 3 # Kingscote
|
7
|
+
DEFAULT_REGION_ID_FOR_ACCOMM_SEARCH = 1 # Kangaroo Island
|
8
|
+
DEFAULT_PROPERTY_TYPE_ID_FOR_ACCOMM_SEARCH = 1
|
9
|
+
|
10
|
+
# System wide
|
11
|
+
PROPERTY_CACHE_TIMEOUT = 1440 # minutes
|
12
|
+
AUSTRALIA_COUNTRY_ID = 14
|
13
|
+
QT_DATE_FORMAT = '%d-%m-%Y'
|
14
|
+
|
15
|
+
DEFAULT_REFERRAL_CODE_ID = 33
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module QuickTravel
|
2
|
+
class CreditCard
|
3
|
+
def self.type_from_number(number)
|
4
|
+
case number.to_s
|
5
|
+
when /^4.*$/ then 'visa'
|
6
|
+
when /^5[1-5].*$/ then 'master'
|
7
|
+
when /^3[4,7].*$/ then 'american_express'
|
8
|
+
when /^3[0,6,8].*$/ then 'diners_club'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module QuickTravel
|
2
|
+
module Discounts
|
3
|
+
class BookingDiscount < DiscountTree
|
4
|
+
def initialize(attrs = {})
|
5
|
+
super(
|
6
|
+
attrs.merge(
|
7
|
+
'root' => attrs,
|
8
|
+
'children' => attrs['reservation_discounts']
|
9
|
+
)
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def reservation_discounts
|
14
|
+
@children
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module QuickTravel
|
2
|
+
module Discounts
|
3
|
+
class Discount
|
4
|
+
attr_reader :target
|
5
|
+
attr_reader :original_price, :discounted_price, :discount, :reason
|
6
|
+
|
7
|
+
def initialize(attrs = {})
|
8
|
+
@target = OpenStruct.new(attrs.fetch('target').slice('id', 'type'))
|
9
|
+
|
10
|
+
@original_price = Money.new(attrs.fetch('original_price_in_cents'))
|
11
|
+
@discounted_price = Money.new(attrs.fetch('discounted_price_in_cents'))
|
12
|
+
@discount = Money.new(attrs.fetch('discount_in_cents'))
|
13
|
+
@reason = attrs.fetch('reason')
|
14
|
+
end
|
15
|
+
|
16
|
+
def applied_on?(id, type = 'Reservation')
|
17
|
+
@target.type == type && @target.id == id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module QuickTravel
|
2
|
+
module Discounts
|
3
|
+
class DiscountTree < Discount
|
4
|
+
attr_reader :root, :children
|
5
|
+
|
6
|
+
def initialize(attrs = {})
|
7
|
+
super(attrs)
|
8
|
+
@root = Discount.new(attrs['root'])
|
9
|
+
@children = attrs.fetch('children', []).map do |child_attrs|
|
10
|
+
DiscountTree.new(child_attrs)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def discount_on(id, type = 'Reservation')
|
15
|
+
return @root if applied_on?(id, type)
|
16
|
+
find_and_return_on_children { |child| child.discount_on(id, type) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def total_discount_on(id, type = 'Reservation')
|
20
|
+
return self if applied_on?(id, type)
|
21
|
+
find_and_return_on_children { |child| child.total_discount_on(id, type) }
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def find_and_return_on_children(&block)
|
27
|
+
@children.each do |child|
|
28
|
+
result = block.call(child)
|
29
|
+
return result unless result.nil?
|
30
|
+
end
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'quick_travel/adapter'
|
2
|
+
|
3
|
+
module QuickTravel
|
4
|
+
class Document < Adapter
|
5
|
+
attr_accessor :id, :booking_id, :name
|
6
|
+
|
7
|
+
self.api_base = "/front_office/bookings/#{@booking_id}/documents"
|
8
|
+
|
9
|
+
# We used to direct the browser to QT directly
|
10
|
+
# Now, we proxy over to it, and return the data
|
11
|
+
# def pdf_url
|
12
|
+
# #"#{QuickTravel.config.url}/api/bookings/#{@booking_id}/documents/#{@id}.pdf?key=#{access_key("document:#{@id}")}"
|
13
|
+
# end
|
14
|
+
|
15
|
+
# Do a second request fetching the PDF
|
16
|
+
def fetch_pdf
|
17
|
+
get_and_validate "/api/bookings/#{@booking_id}/documents/#{@id}.pdf"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'quick_travel/adapter'
|
2
|
+
require 'quick_travel/encrypt'
|
3
|
+
|
4
|
+
module QuickTravel
|
5
|
+
class DocumentGroup < Adapter
|
6
|
+
attr_accessor :id, :booking_id
|
7
|
+
|
8
|
+
self.api_base = "/front_office/bookings/#{@booking_id}/document_groups"
|
9
|
+
|
10
|
+
def pdf_url
|
11
|
+
"#{QuickTravel.config.url}/api/bookings/#{@booking_id}/document_groups/#{@id}.pdf?key=#{Encrypt.access_key("document_group:#{@id}")}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
DIGEST = OpenSSL::Digest.new('sha256')
|
5
|
+
|
6
|
+
module QuickTravel
|
7
|
+
module Encrypt
|
8
|
+
def self.access_key(text)
|
9
|
+
digest = OpenSSL::HMAC.hexdigest(DIGEST, QuickTravel.config.access_key, text)
|
10
|
+
Base64.encode64s(digest).chomp
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module QuickTravel
|
2
|
+
class Graphic
|
3
|
+
attr_accessor :thumbnails, :image_uid
|
4
|
+
|
5
|
+
def initialize(g)
|
6
|
+
@image_uid = g['image_uid']
|
7
|
+
end
|
8
|
+
|
9
|
+
def path(thumbnail_name)
|
10
|
+
result = @thumbnails.find_all { |t| t['thumbnail'] == thumbnail_name.to_s }
|
11
|
+
'/media/cache/' + result.first['filename'] unless result.blank?
|
12
|
+
end
|
13
|
+
|
14
|
+
def url(thumbnail_name)
|
15
|
+
QuickTravel.url + path(thumbnail_name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module QuickTravel
|
2
|
+
module InitFromHash
|
3
|
+
def initialize(hash = {})
|
4
|
+
return nil if hash.blank?
|
5
|
+
|
6
|
+
hash.each do |attr, val|
|
7
|
+
# set datamember of the object using hash key and value
|
8
|
+
if respond_to?("#{attr}=")
|
9
|
+
send("#{attr}=", val)
|
10
|
+
else
|
11
|
+
instance_variable_set("@#{attr}".to_sym, val)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|