hotel_beds 0.0.2 → 0.1.0
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 +4 -4
- data/Gemfile +1 -0
- data/README.md +17 -4
- data/hotel_beds.gemspec +1 -0
- data/lib/hotel_beds.rb +0 -2
- data/lib/hotel_beds/client.rb +7 -2
- data/lib/hotel_beds/connection.rb +8 -10
- data/lib/hotel_beds/{operation/search.rb → hotel_search/envelope.rb} +35 -21
- data/lib/hotel_beds/hotel_search/operation.rb +36 -0
- data/lib/hotel_beds/{model/search.rb → hotel_search/request.rb} +10 -9
- data/lib/hotel_beds/hotel_search/response.rb +90 -0
- data/lib/hotel_beds/model.rb +13 -0
- data/lib/hotel_beds/model/available_room.rb +6 -3
- data/lib/hotel_beds/model/hotel.rb +4 -3
- data/lib/hotel_beds/model/hotel_room.rb +5 -2
- data/lib/hotel_beds/version.rb +1 -1
- data/spec/features/hotel_search_spec.rb +55 -36
- data/spec/lib/hotel_beds/connection_spec.rb +2 -2
- data/spec/lib/hotel_beds/{model/search_spec.rb → hotel_search/request_spec.rb} +2 -2
- data/spec/lib/hotel_beds/version_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -0
- metadata +23 -13
- data/lib/hotel_beds/model/base.rb +0 -35
- data/lib/hotel_beds/model_invalid.rb +0 -12
- data/lib/hotel_beds/operation/base.rb +0 -29
- data/lib/hotel_beds/response/base.rb +0 -27
- data/lib/hotel_beds/response/search.rb +0 -43
- data/spec/lib/hotel_beds/model_invalid_spec.rb +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55dc805389b4efeb9ef72bd55a2399ec361b8092
|
|
4
|
+
data.tar.gz: 8d2a36c3f58e9b573dfe41d30d81436157c71c4e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1c5da4a532371c2b08dda8ef38d6393b1954c8d81672e355ae8b9082e4a347d8ab4f43a2af05446295dbd16de7560f15df43c2f0751602b8ea82a85a8cac53a
|
|
7
|
+
data.tar.gz: bfc1dc68a2794149cb659e82211ca595f564f2bdeccc5bb49a729dea40e79fda2cc0c06bcfc32dac977c9133ca96b29c7af7d840917c2232675a2ec65967ffee
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://codeclimate.com/github/platformq/hotel_beds)
|
|
1
|
+
[](https://www.codeship.io/projects/26188) [](https://codeclimate.com/github/platformq/hotel_beds) [](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
|
|
|
@@ -16,11 +16,24 @@ Manually, via command line:
|
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
|
+
# create the connection to HotelBeds
|
|
19
20
|
client = HotelBeds::Client.new(endpoint: :test, username: "user", password: "pass")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
# perform the search
|
|
23
|
+
search = client.perform_hotel_search({
|
|
24
|
+
check_in_date: Date.today,
|
|
25
|
+
check_out_date: Date.today + 1,
|
|
26
|
+
rooms: [{ adult_count: 2 }],
|
|
27
|
+
destination: "SYD"
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
# inspect the response
|
|
31
|
+
puts search.response.hotels
|
|
23
32
|
# => [<HotelBeds::Model::Hotel>, <HotelBeds::Model::Hotel>]
|
|
33
|
+
puts search.response.total_pages
|
|
34
|
+
# => 10
|
|
35
|
+
puts search.response.current_page
|
|
36
|
+
# => 1
|
|
24
37
|
|
|
25
38
|
## Contributing
|
|
26
39
|
|
data/hotel_beds.gemspec
CHANGED
|
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.add_development_dependency "rspec", "~> 3.0.0"
|
|
28
28
|
spec.add_development_dependency "guard-rspec", "~> 4.2.10"
|
|
29
29
|
spec.add_development_dependency "dotenv", "~> 0.11.1"
|
|
30
|
+
spec.add_development_dependency "codeclimate-test-reporter"
|
|
30
31
|
end
|
data/lib/hotel_beds.rb
CHANGED
data/lib/hotel_beds/client.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "hotel_beds/configuration"
|
|
2
2
|
require "hotel_beds/connection"
|
|
3
|
+
require "hotel_beds/hotel_search/operation"
|
|
3
4
|
|
|
4
5
|
module HotelBeds
|
|
5
6
|
class Client
|
|
@@ -12,8 +13,12 @@ module HotelBeds
|
|
|
12
13
|
freeze
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
# builds and performs a hotel search, returning an operation object which
|
|
17
|
+
# contains both the request and response objects.
|
|
18
|
+
def perform_hotel_search(*args)
|
|
19
|
+
HotelSearch::Operation.new(*args).perform(
|
|
20
|
+
connection: connection
|
|
21
|
+
)
|
|
17
22
|
end
|
|
18
23
|
end
|
|
19
24
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "savon"
|
|
2
|
+
require "securerandom"
|
|
2
3
|
|
|
3
4
|
module HotelBeds
|
|
4
5
|
class Connection
|
|
@@ -11,21 +12,20 @@ module HotelBeds
|
|
|
11
12
|
freeze
|
|
12
13
|
end
|
|
13
14
|
|
|
14
|
-
def
|
|
15
|
-
message =
|
|
16
|
-
message[operation.namespace] = message.fetch(operation.namespace).merge({
|
|
15
|
+
def call(method:, namespace:, data:)
|
|
16
|
+
message = { namespace => {
|
|
17
17
|
:@xmlns => "http://www.hotelbeds.com/schemas/2005/06/messages",
|
|
18
18
|
:"@xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
|
19
|
-
:"@xsi:schemaLocation" => "http://www.hotelbeds.com/schemas/2005/06/messages #{
|
|
20
|
-
:@echoToken =>
|
|
21
|
-
:@sessionId =>
|
|
19
|
+
:"@xsi:schemaLocation" => "http://www.hotelbeds.com/schemas/2005/06/messages #{namespace}.xsd",
|
|
20
|
+
:@echoToken => SecureRandom.hex[0..15],
|
|
21
|
+
:@sessionId => SecureRandom.hex[0..15],
|
|
22
22
|
:Credentials => {
|
|
23
23
|
User: configuration.username,
|
|
24
24
|
Password: configuration.password
|
|
25
25
|
}
|
|
26
|
-
})
|
|
26
|
+
}.merge(data) }
|
|
27
27
|
# send the call
|
|
28
|
-
response = client.call(
|
|
28
|
+
response = client.call(method, {
|
|
29
29
|
soap_action: "",
|
|
30
30
|
attributes: {
|
|
31
31
|
:"xmlns:hb" => "http://axis.frontend.hydra.hotelbeds.com",
|
|
@@ -33,8 +33,6 @@ module HotelBeds
|
|
|
33
33
|
},
|
|
34
34
|
message: message
|
|
35
35
|
})
|
|
36
|
-
# parse the response
|
|
37
|
-
operation.parse_response(response)
|
|
38
36
|
end
|
|
39
37
|
|
|
40
38
|
private
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
require "
|
|
2
|
-
require "hotel_beds/response/search"
|
|
1
|
+
require "delegate"
|
|
3
2
|
|
|
4
3
|
module HotelBeds
|
|
5
|
-
module
|
|
6
|
-
class
|
|
7
|
-
def
|
|
8
|
-
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def namespace
|
|
12
|
-
:HotelValuedAvailRQ
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def message
|
|
16
|
-
{ namespace => {
|
|
4
|
+
module HotelSearch
|
|
5
|
+
class Envelope < SimpleDelegator
|
|
6
|
+
def attributes
|
|
7
|
+
{
|
|
17
8
|
PaginationData: pagination_data,
|
|
18
9
|
Language: language,
|
|
19
10
|
CheckInDate: check_in_date,
|
|
20
11
|
CheckOutDate: check_out_date,
|
|
21
|
-
Destination: destination,
|
|
22
12
|
OccupancyList: occupancy_list
|
|
23
|
-
}
|
|
13
|
+
}.merge(Hash(destination)).merge(Hash(hotels)).merge(Hash(extra_params))
|
|
24
14
|
end
|
|
25
15
|
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
private
|
|
17
|
+
def extra_params
|
|
18
|
+
{ ExtraParamList: {
|
|
19
|
+
ExtendedData: [{
|
|
20
|
+
:@type => "EXT_ADDITIONAL_PARAM",
|
|
21
|
+
:Name => "PARAM_KEY_PRICE_BREAKDOWN",
|
|
22
|
+
:Value => "Y"
|
|
23
|
+
}, {
|
|
24
|
+
:@type => "EXT_ORDER",
|
|
25
|
+
:Name => "ORDER_CONTRACT_PRICE",
|
|
26
|
+
:Value => "ASC"
|
|
27
|
+
}]
|
|
28
|
+
} }
|
|
28
29
|
end
|
|
29
30
|
|
|
30
|
-
private
|
|
31
31
|
def pagination_data
|
|
32
32
|
{ :@pageNumber => Integer(page_number) }
|
|
33
33
|
end
|
|
@@ -45,7 +45,21 @@ module HotelBeds
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def destination
|
|
48
|
-
|
|
48
|
+
if __getobj__.destination
|
|
49
|
+
{ Destination: {
|
|
50
|
+
:@code => String(__getobj__.destination).upcase,
|
|
51
|
+
:@type => "SIMPLE"
|
|
52
|
+
} }
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def hotels
|
|
57
|
+
if Array(__getobj__.hotels).any?
|
|
58
|
+
{ HotelCodeList: {
|
|
59
|
+
:@withinResults => "Y",
|
|
60
|
+
:ProductCode => Array(__getobj__.hotels)
|
|
61
|
+
} }
|
|
62
|
+
end
|
|
49
63
|
end
|
|
50
64
|
|
|
51
65
|
def occupancy_list
|
|
@@ -56,7 +70,7 @@ module HotelBeds
|
|
|
56
70
|
AdultCount: Integer(room.adult_count),
|
|
57
71
|
ChildCount: Integer(room.child_count)
|
|
58
72
|
},
|
|
59
|
-
GuestList: room.child_ages.each { |age|
|
|
73
|
+
GuestList: Array(room.child_ages).each { |age|
|
|
60
74
|
{ Customer: { :@type => "CH", :Age => Integer(age) } }
|
|
61
75
|
}
|
|
62
76
|
} }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require_relative "request"
|
|
2
|
+
require_relative "response"
|
|
3
|
+
require_relative "envelope"
|
|
4
|
+
|
|
5
|
+
module HotelBeds
|
|
6
|
+
module HotelSearch
|
|
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(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: :getHotelValuedAvail,
|
|
30
|
+
namespace: :HotelValuedAvailRQ,
|
|
31
|
+
data: Envelope.new(request).attributes
|
|
32
|
+
})
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
require "hotel_beds/model
|
|
2
|
-
require "virtus"
|
|
3
|
-
require "active_model"
|
|
1
|
+
require "hotel_beds/model"
|
|
4
2
|
|
|
5
3
|
module HotelBeds
|
|
6
|
-
module
|
|
7
|
-
class
|
|
8
|
-
class Room
|
|
4
|
+
module HotelSearch
|
|
5
|
+
class Request
|
|
6
|
+
class Room
|
|
7
|
+
include HotelBeds::Model
|
|
8
|
+
|
|
9
9
|
# attributes
|
|
10
|
-
include Virtus.model
|
|
11
10
|
attribute :adult_count, Integer, default: 0
|
|
12
11
|
attribute :child_count, Integer, default: 0
|
|
13
12
|
attribute :child_ages, Array[Integer], default: Array.new
|
|
14
|
-
|
|
13
|
+
|
|
15
14
|
# validation
|
|
16
|
-
include ActiveModel::Validations
|
|
17
15
|
validates :adult_count, :child_count, numericality: {
|
|
18
16
|
greater_than_or_equal_to: 0,
|
|
19
17
|
less_than_or_equal_to: 4,
|
|
@@ -25,6 +23,8 @@ module HotelBeds
|
|
|
25
23
|
end
|
|
26
24
|
end
|
|
27
25
|
end
|
|
26
|
+
|
|
27
|
+
include HotelBeds::Model
|
|
28
28
|
|
|
29
29
|
# attributes
|
|
30
30
|
attribute :page_number, Integer, default: 1
|
|
@@ -32,6 +32,7 @@ module HotelBeds
|
|
|
32
32
|
attribute :check_in_date, Date
|
|
33
33
|
attribute :check_out_date, Date
|
|
34
34
|
attribute :destination, String
|
|
35
|
+
attribute :hotels, Array[Integer]
|
|
35
36
|
attribute :rooms, Array[Room]
|
|
36
37
|
|
|
37
38
|
# validation
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require "active_model/errors"
|
|
2
|
+
require "hotel_beds/model/hotel"
|
|
3
|
+
|
|
4
|
+
module HotelBeds
|
|
5
|
+
module HotelSearch
|
|
6
|
+
class Response
|
|
7
|
+
attr_accessor :headers, :body, :errors
|
|
8
|
+
private :headers=, :body=, :errors=
|
|
9
|
+
|
|
10
|
+
def initialize(response)
|
|
11
|
+
self.headers = response.header
|
|
12
|
+
self.body = Nokogiri::XML(response.body.fetch(:get_hotel_valued_avail))
|
|
13
|
+
self.errors = ActiveModel::Errors.new(self).tap do |errors|
|
|
14
|
+
if response.http_error?
|
|
15
|
+
errors.add(:base, "HTTP error")
|
|
16
|
+
elsif response.soap_fault?
|
|
17
|
+
errors.add(:base, "SOAP error")
|
|
18
|
+
elsif !response.success?
|
|
19
|
+
errors.add(:base, "Request failed")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
freeze
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def inspect
|
|
26
|
+
"<#{self.class.name} headers=#{headers.inspect} body=#{body.to_s}>"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def current_page
|
|
30
|
+
Integer(body.css("PaginationData").first.attr("currentPage"))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def total_pages
|
|
34
|
+
Integer(body.css("PaginationData").first.attr("totalPages"))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def hotels
|
|
38
|
+
body.css("ServiceHotel").lazy.map do |hotel|
|
|
39
|
+
HotelBeds::Model::Hotel.new({
|
|
40
|
+
id: hotel.css("HotelInfo Code").first.content,
|
|
41
|
+
name: hotel.css("HotelInfo Name").first.content,
|
|
42
|
+
images: hotel.css("HotelInfo ImageList Image Url").map(&:content),
|
|
43
|
+
latitude: hotel.css("HotelInfo Position").first.attr("latitude"),
|
|
44
|
+
longitude: hotel.css("HotelInfo Position").first.attr("longitude"),
|
|
45
|
+
results: parse_available_rooms(hotel.css("AvailableRoom"))
|
|
46
|
+
})
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def parse_available_rooms(rooms)
|
|
53
|
+
Array(rooms).map do |room|
|
|
54
|
+
{
|
|
55
|
+
adult_count: room.css("HotelOccupancy AdultCount").first.content,
|
|
56
|
+
child_count: room.css("HotelOccupancy ChildCount").first.content,
|
|
57
|
+
rooms: parse_hotel_rooms(room.css("HotelRoom"))
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def parse_hotel_rooms(rooms)
|
|
63
|
+
Array(rooms).map do |room|
|
|
64
|
+
{
|
|
65
|
+
number_available: room.attr("availCount"),
|
|
66
|
+
id: room.attr("SHRUI"),
|
|
67
|
+
description: room.css("RoomType").first.content,
|
|
68
|
+
board: room.css("Board").first.content,
|
|
69
|
+
price: room.css("Price Amount").first.content,
|
|
70
|
+
currency: body.css("Currency").first.attribute("code").value,
|
|
71
|
+
rates: parse_price_list(room.css("PriceList Price"))
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def parse_price_list(prices)
|
|
77
|
+
Array(prices).inject({}) do |result, price|
|
|
78
|
+
from = Date.parse(price.css("DateTimeFrom").first.attr("date"))
|
|
79
|
+
to = Date.parse(price.css("DateTimeTo").first.attr("date"))
|
|
80
|
+
dates = (from..to).to_a
|
|
81
|
+
amount = BigDecimal.new(price.css("Amount").first.content) / dates.size
|
|
82
|
+
dates.each do |date|
|
|
83
|
+
result.merge!(date => amount)
|
|
84
|
+
end
|
|
85
|
+
result
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
require "hotel_beds/model
|
|
2
|
-
|
|
1
|
+
require "hotel_beds/model"
|
|
2
|
+
require_relative "hotel_room"
|
|
3
3
|
|
|
4
4
|
module HotelBeds
|
|
5
5
|
module Model
|
|
6
6
|
class AvailableRoom
|
|
7
|
+
include HotelBeds::Model
|
|
8
|
+
|
|
7
9
|
# attributes
|
|
8
|
-
include Virtus.model
|
|
9
10
|
attribute :rooms, Array[HotelRoom]
|
|
11
|
+
attribute :adult_count, Integer
|
|
12
|
+
attribute :child_count, Integer
|
|
10
13
|
end
|
|
11
14
|
end
|
|
12
15
|
end
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
require "hotel_beds/model
|
|
2
|
-
|
|
1
|
+
require "hotel_beds/model"
|
|
2
|
+
require_relative "available_room"
|
|
3
3
|
|
|
4
4
|
module HotelBeds
|
|
5
5
|
module Model
|
|
6
6
|
class Hotel
|
|
7
|
+
include HotelBeds::Model
|
|
8
|
+
|
|
7
9
|
# attributes
|
|
8
|
-
include Virtus.model
|
|
9
10
|
attribute :id, Integer
|
|
10
11
|
attribute :name, String
|
|
11
12
|
attribute :images, Array[String]
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "hotel_beds/model"
|
|
2
2
|
|
|
3
3
|
module HotelBeds
|
|
4
4
|
module Model
|
|
5
5
|
class HotelRoom
|
|
6
|
+
include HotelBeds::Model
|
|
7
|
+
|
|
6
8
|
# attributes
|
|
7
|
-
include Virtus.model
|
|
8
9
|
attribute :id, Integer
|
|
9
10
|
attribute :description, String
|
|
10
11
|
attribute :board, String
|
|
11
12
|
attribute :price, BigDecimal
|
|
12
13
|
attribute :currency, String
|
|
14
|
+
attribute :number_available, Integer
|
|
15
|
+
attribute :rates, Hash[Date => BigDecimal]
|
|
13
16
|
end
|
|
14
17
|
end
|
|
15
18
|
end
|
data/lib/hotel_beds/version.rb
CHANGED
|
@@ -1,50 +1,69 @@
|
|
|
1
1
|
require "hotel_beds"
|
|
2
2
|
|
|
3
3
|
RSpec.describe "performing a hotel search" do
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
})
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
let(:response) { client.perform(search) }
|
|
4
|
+
describe "#response" do
|
|
5
|
+
before(:all) do
|
|
6
|
+
@client = HotelBeds::Client.new({
|
|
7
|
+
endpoint: :test,
|
|
8
|
+
username: ENV.fetch("HOTEL_BEDS_USERNAME"),
|
|
9
|
+
password: ENV.fetch("HOTEL_BEDS_PASSWORD"),
|
|
10
|
+
proxy: ENV.fetch("HOTEL_BEDS_PROXY", nil)
|
|
11
|
+
})
|
|
12
|
+
@check_in_date = Date.today + 28 + rand(10)
|
|
13
|
+
@check_out_date = @check_in_date + rand(3) + 1
|
|
14
|
+
@response = @client.perform_hotel_search({
|
|
15
|
+
check_in_date: @check_in_date,
|
|
16
|
+
check_out_date: @check_out_date,
|
|
17
|
+
rooms: [{ adult_count: 2 }],
|
|
18
|
+
destination: "SYD"
|
|
19
|
+
}).response
|
|
20
|
+
end
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
let(:check_in_date) { @check_in_date }
|
|
23
|
+
let(:check_out_date) { @check_out_date }
|
|
24
|
+
let(:response) { @response }
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
describe "#errors" do
|
|
27
|
+
subject { response.errors }
|
|
28
|
+
|
|
29
|
+
it "should be empty" do
|
|
30
|
+
expect(subject).to be_empty
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "#hotels" do
|
|
35
|
+
subject { response.hotels }
|
|
36
|
+
|
|
37
|
+
it "should return an array of the hotels available" do
|
|
38
|
+
expect(subject.to_a).to be_kind_of(Array)
|
|
39
|
+
expect(subject.first).to be_kind_of(HotelBeds::Model::Hotel)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should parse the rates correctly" do
|
|
43
|
+
room = subject.first.results.first.rooms.first
|
|
44
|
+
expect(room.price).to eq(room.rates.values.inject(:+))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should have the same number of rates as nights reuqested" do
|
|
48
|
+
room = subject.first.results.first.rooms.first
|
|
49
|
+
expect(room.rates.size).to eq(check_out_date - check_in_date)
|
|
50
|
+
end
|
|
32
51
|
end
|
|
33
|
-
end
|
|
34
52
|
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
describe "#current_page" do
|
|
54
|
+
subject { response.current_page }
|
|
37
55
|
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
it "should return '1'" do
|
|
57
|
+
expect(subject).to eq(1)
|
|
58
|
+
end
|
|
40
59
|
end
|
|
41
|
-
end
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
describe "#total_pages" do
|
|
62
|
+
subject { response.total_pages }
|
|
45
63
|
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
it "should be greater or equal to current page" do
|
|
65
|
+
expect(subject).to be >= response.current_page
|
|
66
|
+
end
|
|
48
67
|
end
|
|
49
68
|
end
|
|
50
69
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hotel_beds
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Townsend
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-07-
|
|
11
|
+
date: 2014-07-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: savon
|
|
@@ -136,6 +136,20 @@ dependencies:
|
|
|
136
136
|
- - "~>"
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
138
|
version: 0.11.1
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: codeclimate-test-reporter
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
139
153
|
description:
|
|
140
154
|
email:
|
|
141
155
|
- ryan@ryantownsend.co.uk
|
|
@@ -158,23 +172,20 @@ files:
|
|
|
158
172
|
- lib/hotel_beds/client.rb
|
|
159
173
|
- lib/hotel_beds/configuration.rb
|
|
160
174
|
- lib/hotel_beds/connection.rb
|
|
175
|
+
- lib/hotel_beds/hotel_search/envelope.rb
|
|
176
|
+
- lib/hotel_beds/hotel_search/operation.rb
|
|
177
|
+
- lib/hotel_beds/hotel_search/request.rb
|
|
178
|
+
- lib/hotel_beds/hotel_search/response.rb
|
|
179
|
+
- lib/hotel_beds/model.rb
|
|
161
180
|
- lib/hotel_beds/model/available_room.rb
|
|
162
|
-
- lib/hotel_beds/model/base.rb
|
|
163
181
|
- lib/hotel_beds/model/hotel.rb
|
|
164
182
|
- lib/hotel_beds/model/hotel_room.rb
|
|
165
|
-
- lib/hotel_beds/model/search.rb
|
|
166
|
-
- lib/hotel_beds/model_invalid.rb
|
|
167
|
-
- lib/hotel_beds/operation/base.rb
|
|
168
|
-
- lib/hotel_beds/operation/search.rb
|
|
169
|
-
- lib/hotel_beds/response/base.rb
|
|
170
|
-
- lib/hotel_beds/response/search.rb
|
|
171
183
|
- lib/hotel_beds/version.rb
|
|
172
184
|
- spec/features/hotel_search_spec.rb
|
|
173
185
|
- spec/lib/hotel_beds/client_spec.rb
|
|
174
186
|
- spec/lib/hotel_beds/configuration_spec.rb
|
|
175
187
|
- spec/lib/hotel_beds/connection_spec.rb
|
|
176
|
-
- spec/lib/hotel_beds/
|
|
177
|
-
- spec/lib/hotel_beds/model_invalid_spec.rb
|
|
188
|
+
- spec/lib/hotel_beds/hotel_search/request_spec.rb
|
|
178
189
|
- spec/lib/hotel_beds/version_spec.rb
|
|
179
190
|
- spec/spec_helper.rb
|
|
180
191
|
homepage: https://www.hotelsindex.com/open-source
|
|
@@ -206,7 +217,6 @@ test_files:
|
|
|
206
217
|
- spec/lib/hotel_beds/client_spec.rb
|
|
207
218
|
- spec/lib/hotel_beds/configuration_spec.rb
|
|
208
219
|
- spec/lib/hotel_beds/connection_spec.rb
|
|
209
|
-
- spec/lib/hotel_beds/
|
|
210
|
-
- spec/lib/hotel_beds/model_invalid_spec.rb
|
|
220
|
+
- spec/lib/hotel_beds/hotel_search/request_spec.rb
|
|
211
221
|
- spec/lib/hotel_beds/version_spec.rb
|
|
212
222
|
- spec/spec_helper.rb
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
require "hotel_beds/model_invalid"
|
|
2
|
-
require "securerandom"
|
|
3
|
-
require "virtus"
|
|
4
|
-
require "active_model"
|
|
5
|
-
|
|
6
|
-
module HotelBeds
|
|
7
|
-
module Model
|
|
8
|
-
class Base
|
|
9
|
-
# generator for random tokens
|
|
10
|
-
RANDOM_TOKEN = -> (model, attr) { SecureRandom.hex[0..15] }
|
|
11
|
-
|
|
12
|
-
# returns the operation for this model
|
|
13
|
-
def self.operation_class
|
|
14
|
-
HotelBeds::Operation.const_get(name.split("::").last)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# attributes
|
|
18
|
-
include Virtus.model
|
|
19
|
-
attribute :session_id, String, default: RANDOM_TOKEN, writer: :private
|
|
20
|
-
attribute :echo_token, String, default: RANDOM_TOKEN, writer: :private
|
|
21
|
-
|
|
22
|
-
# validation
|
|
23
|
-
include ActiveModel::Validations
|
|
24
|
-
validates :session_id, :echo_token, presence: true
|
|
25
|
-
|
|
26
|
-
def to_operation
|
|
27
|
-
if valid?
|
|
28
|
-
self.class.operation_class.new(self)
|
|
29
|
-
else
|
|
30
|
-
raise HotelsBeds::ModelInvalid.new(self)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
require "delegate"
|
|
2
|
-
require "securerandom"
|
|
3
|
-
|
|
4
|
-
module HotelBeds
|
|
5
|
-
module Operation
|
|
6
|
-
class Base < SimpleDelegator
|
|
7
|
-
def method
|
|
8
|
-
raise NotImplementedError, "#method should return a symbol for the \
|
|
9
|
-
remote method to be called"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def namespace
|
|
13
|
-
raise NotImplementedError, "#namespace should return a symbol for the \
|
|
14
|
-
root element within the <message> element"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def message
|
|
18
|
-
raise NotImplementedError, "#message should return a hash containing \
|
|
19
|
-
the contents of the <message> element, the #namespace should be \
|
|
20
|
-
included as a key"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def parse_response(response)
|
|
24
|
-
raise NotImplementedError, "#parse_response should accept a SOAP \
|
|
25
|
-
response and return a HotelBeds::Response::Base subclass object"
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
require "forwardable"
|
|
2
|
-
require "nokogiri"
|
|
3
|
-
|
|
4
|
-
module HotelBeds
|
|
5
|
-
module Response
|
|
6
|
-
class Base
|
|
7
|
-
# attributes
|
|
8
|
-
attr_accessor :response, :body, :headers
|
|
9
|
-
private :response, :response=, :body=, :headers=
|
|
10
|
-
|
|
11
|
-
# delegation
|
|
12
|
-
extend Forwardable
|
|
13
|
-
def_delegators :response, :success?, :soap_fault?, :http_error?
|
|
14
|
-
|
|
15
|
-
def initialize(response)
|
|
16
|
-
self.response = response
|
|
17
|
-
self.headers = response.header
|
|
18
|
-
self.body = Nokogiri::XML(response.body.fetch(:get_hotel_valued_avail))
|
|
19
|
-
freeze
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def inspect
|
|
23
|
-
"<#{self.class.name} headers=#{headers.inspect} body=#{body.inspect}>"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
require "hotel_beds/response/base"
|
|
2
|
-
require "hotel_beds/model/hotel"
|
|
3
|
-
require "hotel_beds/model/available_room"
|
|
4
|
-
require "hotel_beds/model/hotel_room"
|
|
5
|
-
|
|
6
|
-
module HotelBeds
|
|
7
|
-
module Response
|
|
8
|
-
class Search < Base
|
|
9
|
-
def current_page
|
|
10
|
-
Integer(body.css("PaginationData").attr("currentPage").value)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def total_pages
|
|
14
|
-
Integer(body.css("PaginationData").attr("totalPages").value)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def hotels
|
|
18
|
-
body.css("ServiceHotel").lazy.map do |hotel|
|
|
19
|
-
HotelBeds::Model::Hotel.new({
|
|
20
|
-
id: hotel.css("HotelInfo Code").first.content,
|
|
21
|
-
name: hotel.css("HotelInfo Name").first.content,
|
|
22
|
-
images: hotel.css("HotelInfo ImageList Image Url").map(&:content),
|
|
23
|
-
latitude: hotel.css("HotelInfo Position").attr("latitude").value,
|
|
24
|
-
longitude: hotel.css("HotelInfo Position").attr("longitude").value,
|
|
25
|
-
results: hotel.css("AvailableRoom").map { |result|
|
|
26
|
-
HotelBeds::Model::AvailableRoom.new({
|
|
27
|
-
rooms: result.css("HotelRoom").map { |room|
|
|
28
|
-
HotelBeds::Model::HotelRoom.new({
|
|
29
|
-
id: room.attribute("SHRUI").value,
|
|
30
|
-
description: room.css("RoomType").first.content,
|
|
31
|
-
board: room.css("Board").first.content,
|
|
32
|
-
price: room.css("Price Amount").first.content,
|
|
33
|
-
currency: body.css("Currency").first.attribute("code").value
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
require "hotel_beds/model_invalid"
|
|
2
|
-
|
|
3
|
-
RSpec.describe HotelBeds::ModelInvalid do
|
|
4
|
-
let(:model) { Object.new }
|
|
5
|
-
let(:instance) { described_class.new(model) }
|
|
6
|
-
|
|
7
|
-
describe "an instance" do
|
|
8
|
-
subject { instance }
|
|
9
|
-
|
|
10
|
-
it "should be immutable" do
|
|
11
|
-
expect(subject).to be_frozen
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
describe "#model" do
|
|
16
|
-
subject { instance.model }
|
|
17
|
-
|
|
18
|
-
it "should return the given model" do
|
|
19
|
-
expect(subject).to eq(model)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|