hotel_beds 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -44
- data/lib/hotel_beds/basket_remove/envelope.rb +16 -0
- data/lib/hotel_beds/basket_remove/operation.rb +36 -0
- data/lib/hotel_beds/basket_remove/request.rb +19 -0
- data/lib/hotel_beds/basket_remove/response.rb +31 -0
- data/lib/hotel_beds/client.rb +21 -0
- data/lib/hotel_beds/hotel_basket_add/request.rb +1 -1
- data/lib/hotel_beds/hotel_basket_add/response.rb +4 -35
- data/lib/hotel_beds/hotel_search/envelope.rb +10 -9
- data/lib/hotel_beds/hotel_search/request.rb +6 -4
- data/lib/hotel_beds/hotel_search/response.rb +4 -9
- data/lib/hotel_beds/model/available_room.rb +22 -1
- data/lib/hotel_beds/model/cancellation_policy.rb +0 -1
- data/lib/hotel_beds/model/comment.rb +13 -0
- data/lib/hotel_beds/model/contract.rb +15 -0
- data/lib/hotel_beds/model/customer.rb +21 -0
- data/lib/hotel_beds/model/destination.rb +13 -0
- data/lib/hotel_beds/model/hotel.rb +12 -7
- data/lib/hotel_beds/model/price.rb +18 -0
- data/lib/hotel_beds/model/purchase.rb +7 -2
- data/lib/hotel_beds/model/room.rb +0 -1
- data/lib/hotel_beds/model/service.rb +6 -4
- data/lib/hotel_beds/parser.rb +94 -0
- data/lib/hotel_beds/parser/available_room.rb +37 -0
- data/lib/hotel_beds/parser/cancellation_policy.rb +13 -0
- data/lib/hotel_beds/parser/comment.rb +13 -0
- data/lib/hotel_beds/parser/contract.rb +17 -0
- data/lib/hotel_beds/parser/customer.rb +18 -0
- data/lib/hotel_beds/parser/destination.rb +13 -0
- data/lib/hotel_beds/parser/errors.rb +39 -0
- data/lib/hotel_beds/parser/hotel.rb +27 -0
- data/lib/hotel_beds/parser/price.rb +14 -0
- data/lib/hotel_beds/parser/purchase.rb +24 -0
- data/lib/hotel_beds/parser/room_grouper.rb +104 -0
- data/lib/hotel_beds/parser/service.rb +21 -0
- data/lib/hotel_beds/purchase_confirm/envelope.rb +42 -0
- data/lib/hotel_beds/purchase_confirm/operation.rb +36 -0
- data/lib/hotel_beds/purchase_confirm/request.rb +72 -0
- data/lib/hotel_beds/purchase_confirm/response.rb +31 -0
- data/lib/hotel_beds/purchase_flush/envelope.rb +15 -0
- data/lib/hotel_beds/purchase_flush/operation.rb +36 -0
- data/lib/hotel_beds/purchase_flush/request.rb +17 -0
- data/lib/hotel_beds/purchase_flush/response.rb +26 -0
- data/lib/hotel_beds/version.rb +1 -1
- data/spec/features/flushing_the_basket_spec.rb +63 -0
- data/spec/features/ordering_a_hotel_room_spec.rb +96 -0
- data/spec/features/removing_a_basket_item_spec.rb +74 -0
- data/spec/lib/hotel_beds/hotel_search/request_spec.rb +4 -4
- data/spec/lib/hotel_beds/{hotel_search/parser → parser}/room_grouper_spec.rb +3 -3
- data/spec/lib/hotel_beds/parser/service_spec.rb +44 -0
- metadata +42 -15
- data/lib/hotel_beds/hotel_search/parser/errors.rb +0 -49
- data/lib/hotel_beds/hotel_search/parser/hotel.rb +0 -71
- data/lib/hotel_beds/hotel_search/parser/price.rb +0 -38
- data/lib/hotel_beds/hotel_search/parser/room.rb +0 -61
- data/lib/hotel_beds/hotel_search/parser/room_grouper.rb +0 -101
- data/spec/features/adding_a_hotel_to_basket_spec.rb +0 -58
- data/spec/features/grouped_hotel_search_spec.rb +0 -67
- data/spec/features/hotel_search_spec.rb +0 -113
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c3bea539610e13aca6d457ae561d8c62c5b52d0
|
4
|
+
data.tar.gz: 3b8365b3312998149cfa8bb1ede6a90aa5360525
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 756489f73cc0a066d6771508404a01c01710a75fd32f73664d44e8a9f0d73f87d48db06fa626a64a0c6e3eb5c74ac74bf0b6bda0944f1b1b5f03058cb72117b7
|
7
|
+
data.tar.gz: 0fda52e2b50755e68809154ae0094239c94ae2c63c488686acfa550fd2c39920fb45187ad05e2e9018c49a7418bf1e95b2b9ae81eccab2fb8836f725bb644d85
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[![Codeship Status](https://www.codeship.io/projects/808271e0-e973-0131-1052-5240ebfefa5a/status)](https://www.codeship.io/projects/26188) [![Gem Version](https://badge.fury.io/rb/hotel_beds.svg)](https://rubygems.org/gems/hotel_beds) [![Code Climate](https://codeclimate.com/github/platformq/hotel_beds.
|
1
|
+
[![Codeship Status](https://www.codeship.io/projects/808271e0-e973-0131-1052-5240ebfefa5a/status)](https://www.codeship.io/projects/26188) [![Gem Version](https://badge.fury.io/rb/hotel_beds.svg)](https://rubygems.org/gems/hotel_beds) [![Code Climate](https://codeclimate.com/github/platformq/hotel_beds/badges/gpa.svg)](https://codeclimate.com/github/platformq/hotel_beds) [![Code Climate](https://codeclimate.com/github/platformq/hotel_beds/badges/coverage.svg)](https://codeclimate.com/github/platformq/hotel_beds)
|
2
2
|
|
3
3
|
The `hotel_beds` gem interfaces with the [HotelBeds.com](http://www.hotelbeds.com/) SOAP API to search for and book hotel rooms.
|
4
4
|
|
@@ -18,6 +18,8 @@ Manually, via command line:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
It's best to check the [feature specs](https://github.com/platformq/hotel_beds/tree/master/spec/features) to see up-to-date examples, but a basic search example is below:
|
22
|
+
|
21
23
|
```ruby
|
22
24
|
# create the connection to HotelBeds
|
23
25
|
client = HotelBeds::Client.new(endpoint: :test, username: "user", password: "pass")
|
@@ -27,7 +29,7 @@ search = client.perform_hotel_search({
|
|
27
29
|
check_in_date: Date.today,
|
28
30
|
check_out_date: Date.today + 1,
|
29
31
|
rooms: [{ adult_count: 2 }],
|
30
|
-
|
32
|
+
destination_code: "SYD"
|
31
33
|
})
|
32
34
|
|
33
35
|
# inspect the response
|
@@ -37,48 +39,6 @@ puts search.response.total_pages
|
|
37
39
|
# => 10
|
38
40
|
puts search.response.current_page
|
39
41
|
# => 1
|
40
|
-
|
41
|
-
# place a booking
|
42
|
-
booking = client.perform_hotel_booking({
|
43
|
-
room_ids: [search.response.hotels.first.results.first.id],
|
44
|
-
people: [
|
45
|
-
{ title: "Mr", name: "David Smith", type: :adult },
|
46
|
-
{ title: "Mrs", name: "Jane Smith", type: :adult }
|
47
|
-
],
|
48
|
-
address: {
|
49
|
-
line_1: "123 Some Street",
|
50
|
-
city: "Townsville",
|
51
|
-
state: "New Statestown",
|
52
|
-
postcode: "NS1 1AB"
|
53
|
-
country: "UK"
|
54
|
-
},
|
55
|
-
phone_number: "+44 1234 567 890",
|
56
|
-
email: "david.smith@example.com"
|
57
|
-
})
|
58
|
-
|
59
|
-
# inspect the response
|
60
|
-
puts booking.response.reference
|
61
|
-
# => "ABC-123"
|
62
|
-
```
|
63
|
-
|
64
|
-
### Options
|
65
|
-
|
66
|
-
The HotelBeds API will return individual rooms, rather than being grouped by what you searched for (e.g. 2 rooms, 1 with 2 adults, 1 with 1 adult and 1 child). To fix this issue, you can enable result grouping by adding `group_results: true` to the `perform_hotel_search` call.
|
67
|
-
|
68
|
-
Example:
|
69
|
-
|
70
|
-
```ruby
|
71
|
-
# perform the search
|
72
|
-
search = client.perform_hotel_search({
|
73
|
-
check_in_date: Date.today,
|
74
|
-
check_out_date: Date.today + 1,
|
75
|
-
rooms: [
|
76
|
-
{ adult_count: 2 },
|
77
|
-
{ adult_count: 1, child_count: 1, child_ages: [7] }
|
78
|
-
],
|
79
|
-
destination: "SYD",
|
80
|
-
group_results: true
|
81
|
-
})
|
82
42
|
```
|
83
43
|
|
84
44
|
## Contributing
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "delegate"
|
2
|
+
|
3
|
+
module HotelBeds
|
4
|
+
module BasketRemove
|
5
|
+
class Envelope < SimpleDelegator
|
6
|
+
def attributes
|
7
|
+
{
|
8
|
+
:Language => language,
|
9
|
+
:@SPUI => service_id,
|
10
|
+
:@version => "2013/12",
|
11
|
+
:@purchaseToken => purchase_token
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative "request"
|
2
|
+
require_relative "response"
|
3
|
+
require_relative "envelope"
|
4
|
+
|
5
|
+
module HotelBeds
|
6
|
+
module BasketRemove
|
7
|
+
class Operation
|
8
|
+
attr_accessor :request, :response, :errors
|
9
|
+
private :request=, :response=, :errors=
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
self.request = Request.new(*args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def perform(connection:)
|
16
|
+
if request.valid?
|
17
|
+
self.response = Response.new(request, retrieve(connection))
|
18
|
+
self.errors = response.errors
|
19
|
+
else
|
20
|
+
self.errors = request.errors
|
21
|
+
end
|
22
|
+
freeze
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def retrieve(connection)
|
28
|
+
connection.call({
|
29
|
+
method: :serviceRemove,
|
30
|
+
namespace: :ServiceRemoveRQ,
|
31
|
+
data: Envelope.new(request).attributes
|
32
|
+
})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "hotel_beds/model"
|
2
|
+
|
3
|
+
module HotelBeds
|
4
|
+
module BasketRemove
|
5
|
+
class Request
|
6
|
+
include HotelBeds::Model
|
7
|
+
|
8
|
+
# attributes
|
9
|
+
attribute :language, String, default: "ENG"
|
10
|
+
attribute :purchase_token, String
|
11
|
+
attribute :service_id, String
|
12
|
+
|
13
|
+
|
14
|
+
# validation
|
15
|
+
validates :language, length: { is: 3 }
|
16
|
+
validates :service_id, :purchase_token, presence: true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "hotel_beds/parser/errors"
|
2
|
+
require "hotel_beds/parser/purchase"
|
3
|
+
|
4
|
+
module HotelBeds
|
5
|
+
module BasketRemove
|
6
|
+
class Response
|
7
|
+
attr_accessor :request, :headers, :body, :errors
|
8
|
+
private :request=, :headers=, :body=, :errors=
|
9
|
+
|
10
|
+
def initialize(request, response)
|
11
|
+
self.request = request
|
12
|
+
self.headers = response.header
|
13
|
+
self.body = Nokogiri::XML(response.body.fetch(:service_remove))
|
14
|
+
self.errors = HotelBeds::Parser::Errors.new(response).to_model(self)
|
15
|
+
freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
"<#{self.class.name} errors=#{errors.inspect} headers=#{headers.inspect} body=#{body.to_s}>"
|
20
|
+
end
|
21
|
+
|
22
|
+
def success?
|
23
|
+
errors.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def purchase
|
27
|
+
HotelBeds::Parser::Purchase.new(body.at_css("Purchase")).to_model
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/hotel_beds/client.rb
CHANGED
@@ -2,6 +2,9 @@ require "hotel_beds/configuration"
|
|
2
2
|
require "hotel_beds/connection"
|
3
3
|
require "hotel_beds/hotel_search/operation"
|
4
4
|
require "hotel_beds/hotel_basket_add/operation"
|
5
|
+
require "hotel_beds/purchase_confirm/operation"
|
6
|
+
require "hotel_beds/purchase_flush/operation"
|
7
|
+
require "hotel_beds/basket_remove/operation"
|
5
8
|
|
6
9
|
module HotelBeds
|
7
10
|
class Client
|
@@ -28,5 +31,23 @@ module HotelBeds
|
|
28
31
|
connection: connection
|
29
32
|
)
|
30
33
|
end
|
34
|
+
|
35
|
+
def confirm_purchase(*args)
|
36
|
+
PurchaseConfirm::Operation.new(*args).perform(
|
37
|
+
connection: connection
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def flush_purchase(*args)
|
42
|
+
PurchaseFlush::Operation.new(*args).perform(
|
43
|
+
connection: connection
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def remove_service_from_basket(*args)
|
48
|
+
BasketRemove::Operation.new(*args).perform(
|
49
|
+
connection: connection
|
50
|
+
)
|
51
|
+
end
|
31
52
|
end
|
32
53
|
end
|
@@ -19,7 +19,7 @@ module HotelBeds
|
|
19
19
|
attribute :rooms, Array[HotelBeds::Model::AvailableRoom]
|
20
20
|
|
21
21
|
# validation
|
22
|
-
validates :destination_code, length: { is: 3 }
|
22
|
+
validates :destination_code, length: { is: 3, allow_blank: false }
|
23
23
|
validates :rooms, length: { minimum: 1, maximum: 5 }
|
24
24
|
validates :session_id, :availability_token, :contract_name,
|
25
25
|
:contract_incoming_office_code, :check_in_date, :check_out_date,
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require "
|
2
|
-
require "hotel_beds/
|
1
|
+
require "hotel_beds/parser/errors"
|
2
|
+
require "hotel_beds/parser/purchase"
|
3
3
|
|
4
4
|
module HotelBeds
|
5
5
|
module HotelBasketAdd
|
@@ -11,22 +11,7 @@ module HotelBeds
|
|
11
11
|
self.request = request
|
12
12
|
self.headers = response.header
|
13
13
|
self.body = Nokogiri::XML(response.body.fetch(:service_add))
|
14
|
-
self.errors =
|
15
|
-
if response.http_error?
|
16
|
-
errors.add(:base, "HTTP error")
|
17
|
-
elsif response.soap_fault?
|
18
|
-
errors.add(:base, "SOAP error")
|
19
|
-
elsif !response.success?
|
20
|
-
errors.add(:base, "Request failed")
|
21
|
-
end
|
22
|
-
|
23
|
-
body.css("ErrorList Error").each do |error|
|
24
|
-
errors.add(:base, [
|
25
|
-
(sm = error.at_css("Message")) && sm.content,
|
26
|
-
(dm = error.at_css("DetailedMessage")) && dm.content
|
27
|
-
].compact.join("\n"))
|
28
|
-
end
|
29
|
-
end
|
14
|
+
self.errors = HotelBeds::Parser::Errors.new(response).to_model(self)
|
30
15
|
freeze
|
31
16
|
end
|
32
17
|
|
@@ -43,23 +28,7 @@ module HotelBeds
|
|
43
28
|
end
|
44
29
|
|
45
30
|
def purchase
|
46
|
-
|
47
|
-
HotelBeds::Model::Purchase.new({
|
48
|
-
id: purchase.attr("purchaseToken"),
|
49
|
-
currency: purchase.at_css("Currency").attr("code"),
|
50
|
-
amount: purchase.at_css("TotalPrice").content,
|
51
|
-
services: purchase.css("ServiceList Service").map { |service|
|
52
|
-
{
|
53
|
-
id: service.attr("SPUI"),
|
54
|
-
contract_name: service.at_css("Contract Name").content,
|
55
|
-
contract_incoming_office_code: service.at_css("Contract IncomingOffice").attr("code"),
|
56
|
-
check_in_date: Date.parse(service.at_css("DateFrom").attr("date")),
|
57
|
-
check_out_date: Date.parse(service.at_css("DateTo").attr("date")),
|
58
|
-
currency: service.at_css("Currency").attr("code"),
|
59
|
-
amount: service.at_css("TotalAmount").content
|
60
|
-
}
|
61
|
-
}
|
62
|
-
})
|
31
|
+
HotelBeds::Parser::Purchase.new(body.at_css("Purchase")).to_model
|
63
32
|
end
|
64
33
|
end
|
65
34
|
end
|
@@ -30,7 +30,10 @@ module HotelBeds
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def pagination_data
|
33
|
-
{
|
33
|
+
{
|
34
|
+
:@pageNumber => Integer(page_number),
|
35
|
+
:@itemsPerPage => Integer(items_per_page)
|
36
|
+
}
|
34
37
|
end
|
35
38
|
|
36
39
|
def language
|
@@ -46,19 +49,17 @@ module HotelBeds
|
|
46
49
|
end
|
47
50
|
|
48
51
|
def destination
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
} }
|
54
|
-
end
|
52
|
+
{ Destination: {
|
53
|
+
:@code => String(__getobj__.destination_code).upcase,
|
54
|
+
:@type => "SIMPLE"
|
55
|
+
} }
|
55
56
|
end
|
56
57
|
|
57
58
|
def hotels
|
58
|
-
if Array(__getobj__.
|
59
|
+
if Array(__getobj__.hotel_codes).any?
|
59
60
|
{ HotelCodeList: {
|
60
61
|
:@withinResults => "Y",
|
61
|
-
:ProductCode => Array(__getobj__.
|
62
|
+
:ProductCode => Array(__getobj__.hotel_codes)
|
62
63
|
} }
|
63
64
|
end
|
64
65
|
end
|
@@ -10,16 +10,18 @@ module HotelBeds
|
|
10
10
|
# attributes
|
11
11
|
attribute :session_id, String, default: SecureRandom.hex[0..15]
|
12
12
|
attribute :page_number, Integer, default: 1
|
13
|
+
attribute :items_per_page, Integer, default: 50
|
13
14
|
attribute :language, String, default: "ENG"
|
14
15
|
attribute :check_in_date, Date
|
15
16
|
attribute :check_out_date, Date
|
16
|
-
attribute :
|
17
|
-
attribute :
|
17
|
+
attribute :destination_code, String
|
18
|
+
attribute :hotel_codes, Array[Integer]
|
18
19
|
attribute :rooms, Array[HotelBeds::Model::RequestedRoom]
|
19
|
-
attribute :group_results, Virtus::Attribute::Boolean, default: false
|
20
20
|
|
21
21
|
# validation
|
22
|
-
validates :language, :
|
22
|
+
validates :language, :destination_code, length: {
|
23
|
+
is: 3, allow_blank: false
|
24
|
+
}
|
23
25
|
validates :session_id, :check_in_date, :check_out_date, presence: true
|
24
26
|
validates :rooms, length: { minimum: 1, maximum: 5 }
|
25
27
|
validates :page_number, numericality: {
|
@@ -1,6 +1,5 @@
|
|
1
|
-
require "hotel_beds/
|
2
|
-
require "hotel_beds/
|
3
|
-
require "hotel_beds/hotel_search/parser/hotel"
|
1
|
+
require "hotel_beds/parser/errors"
|
2
|
+
require "hotel_beds/parser/hotel"
|
4
3
|
|
5
4
|
module HotelBeds
|
6
5
|
module HotelSearch
|
@@ -12,7 +11,7 @@ module HotelBeds
|
|
12
11
|
self.request = request
|
13
12
|
self.headers = response.header
|
14
13
|
self.body = Nokogiri::XML(response.body.fetch(:get_hotel_valued_avail))
|
15
|
-
self.errors = HotelBeds::
|
14
|
+
self.errors = HotelBeds::Parser::Errors.new(response).to_model(self)
|
16
15
|
freeze
|
17
16
|
end
|
18
17
|
|
@@ -46,11 +45,7 @@ module HotelBeds
|
|
46
45
|
|
47
46
|
def hotels
|
48
47
|
body.css("ServiceHotel").lazy.map do |hotel|
|
49
|
-
HotelBeds::
|
50
|
-
hotel: hotel,
|
51
|
-
currency: currency,
|
52
|
-
request: request
|
53
|
-
)
|
48
|
+
HotelBeds::Parser::Hotel.new(hotel).to_model
|
54
49
|
end
|
55
50
|
end
|
56
51
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require "hotel_beds/model/room"
|
2
|
+
require "hotel_beds/model/price"
|
2
3
|
require "hotel_beds/model/cancellation_policy"
|
4
|
+
require "hotel_beds/model/customer"
|
3
5
|
|
4
6
|
module HotelBeds
|
5
7
|
module Model
|
@@ -15,8 +17,27 @@ module HotelBeds
|
|
15
17
|
attribute :price, BigDecimal
|
16
18
|
attribute :number_available, Integer
|
17
19
|
attribute :rates, Hash[Date => BigDecimal]
|
18
|
-
attribute :cancellation_policies, Array[CancellationPolicy],
|
20
|
+
attribute :cancellation_policies, Array[HotelBeds::Model::CancellationPolicy],
|
19
21
|
default: Array.new
|
22
|
+
attribute :customers, Array[HotelBeds::Model::Customer],
|
23
|
+
default: Array.new
|
24
|
+
|
25
|
+
def rates=(values)
|
26
|
+
if values.kind_of?(Array)
|
27
|
+
prices = values.map do |attrs|
|
28
|
+
HotelBeds::Model::Price.new(attrs)
|
29
|
+
end
|
30
|
+
hash = prices.inject(Hash.new) do |result, price|
|
31
|
+
price.dates.each do |date|
|
32
|
+
result.merge!(date => price.amount)
|
33
|
+
end
|
34
|
+
result
|
35
|
+
end
|
36
|
+
super(hash)
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
20
41
|
end
|
21
42
|
end
|
22
43
|
end
|