hotel_beds 0.3.2 → 0.4.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -44
  3. data/lib/hotel_beds/basket_remove/envelope.rb +16 -0
  4. data/lib/hotel_beds/basket_remove/operation.rb +36 -0
  5. data/lib/hotel_beds/basket_remove/request.rb +19 -0
  6. data/lib/hotel_beds/basket_remove/response.rb +31 -0
  7. data/lib/hotel_beds/client.rb +21 -0
  8. data/lib/hotel_beds/hotel_basket_add/request.rb +1 -1
  9. data/lib/hotel_beds/hotel_basket_add/response.rb +4 -35
  10. data/lib/hotel_beds/hotel_search/envelope.rb +10 -9
  11. data/lib/hotel_beds/hotel_search/request.rb +6 -4
  12. data/lib/hotel_beds/hotel_search/response.rb +4 -9
  13. data/lib/hotel_beds/model/available_room.rb +22 -1
  14. data/lib/hotel_beds/model/cancellation_policy.rb +0 -1
  15. data/lib/hotel_beds/model/comment.rb +13 -0
  16. data/lib/hotel_beds/model/contract.rb +15 -0
  17. data/lib/hotel_beds/model/customer.rb +21 -0
  18. data/lib/hotel_beds/model/destination.rb +13 -0
  19. data/lib/hotel_beds/model/hotel.rb +12 -7
  20. data/lib/hotel_beds/model/price.rb +18 -0
  21. data/lib/hotel_beds/model/purchase.rb +7 -2
  22. data/lib/hotel_beds/model/room.rb +0 -1
  23. data/lib/hotel_beds/model/service.rb +6 -4
  24. data/lib/hotel_beds/parser.rb +94 -0
  25. data/lib/hotel_beds/parser/available_room.rb +37 -0
  26. data/lib/hotel_beds/parser/cancellation_policy.rb +13 -0
  27. data/lib/hotel_beds/parser/comment.rb +13 -0
  28. data/lib/hotel_beds/parser/contract.rb +17 -0
  29. data/lib/hotel_beds/parser/customer.rb +18 -0
  30. data/lib/hotel_beds/parser/destination.rb +13 -0
  31. data/lib/hotel_beds/parser/errors.rb +39 -0
  32. data/lib/hotel_beds/parser/hotel.rb +27 -0
  33. data/lib/hotel_beds/parser/price.rb +14 -0
  34. data/lib/hotel_beds/parser/purchase.rb +24 -0
  35. data/lib/hotel_beds/parser/room_grouper.rb +104 -0
  36. data/lib/hotel_beds/parser/service.rb +21 -0
  37. data/lib/hotel_beds/purchase_confirm/envelope.rb +42 -0
  38. data/lib/hotel_beds/purchase_confirm/operation.rb +36 -0
  39. data/lib/hotel_beds/purchase_confirm/request.rb +72 -0
  40. data/lib/hotel_beds/purchase_confirm/response.rb +31 -0
  41. data/lib/hotel_beds/purchase_flush/envelope.rb +15 -0
  42. data/lib/hotel_beds/purchase_flush/operation.rb +36 -0
  43. data/lib/hotel_beds/purchase_flush/request.rb +17 -0
  44. data/lib/hotel_beds/purchase_flush/response.rb +26 -0
  45. data/lib/hotel_beds/version.rb +1 -1
  46. data/spec/features/flushing_the_basket_spec.rb +63 -0
  47. data/spec/features/ordering_a_hotel_room_spec.rb +96 -0
  48. data/spec/features/removing_a_basket_item_spec.rb +74 -0
  49. data/spec/lib/hotel_beds/hotel_search/request_spec.rb +4 -4
  50. data/spec/lib/hotel_beds/{hotel_search/parser → parser}/room_grouper_spec.rb +3 -3
  51. data/spec/lib/hotel_beds/parser/service_spec.rb +44 -0
  52. metadata +42 -15
  53. data/lib/hotel_beds/hotel_search/parser/errors.rb +0 -49
  54. data/lib/hotel_beds/hotel_search/parser/hotel.rb +0 -71
  55. data/lib/hotel_beds/hotel_search/parser/price.rb +0 -38
  56. data/lib/hotel_beds/hotel_search/parser/room.rb +0 -61
  57. data/lib/hotel_beds/hotel_search/parser/room_grouper.rb +0 -101
  58. data/spec/features/adding_a_hotel_to_basket_spec.rb +0 -58
  59. data/spec/features/grouped_hotel_search_spec.rb +0 -67
  60. data/spec/features/hotel_search_spec.rb +0 -113
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee35be3ac5b6c786cf81e423804de3fb925c32a7
4
- data.tar.gz: b9f28db962220a6b808fc2c5d3c7fed476d3fedb
3
+ metadata.gz: 7c3bea539610e13aca6d457ae561d8c62c5b52d0
4
+ data.tar.gz: 3b8365b3312998149cfa8bb1ede6a90aa5360525
5
5
  SHA512:
6
- metadata.gz: a5a5fd5bd3cc26f982de37ba7f34fedb03a9b0c43f841146e43d81d31b11a2cac08d5baa04ba691cc110b500662420810963ceda565a2e5a6a222146dafa9066
7
- data.tar.gz: 6ad26f49b7bb40ac1ac51ad4f6aec8dfaf39fa205ef92bc4e2e6cfad74eba043c2ff02427b959da7b44009a3dc4748c8d254e11b9547ec002cab532c3dbccde6
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.png)](https://codeclimate.com/github/platformq/hotel_beds) [![Code Climate](https://codeclimate.com/github/platformq/hotel_beds/coverage.png)](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
- destination: "SYD"
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
@@ -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 "active_model/errors"
2
- require "hotel_beds/model/purchase"
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 = ActiveModel::Errors.new(self).tap do |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
- purchase = body.at_css("Purchase")
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
- { :@pageNumber => Integer(page_number) }
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
- if __getobj__.destination
50
- { Destination: {
51
- :@code => String(__getobj__.destination).upcase,
52
- :@type => "SIMPLE"
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__.hotels).any?
59
+ if Array(__getobj__.hotel_codes).any?
59
60
  { HotelCodeList: {
60
61
  :@withinResults => "Y",
61
- :ProductCode => Array(__getobj__.hotels)
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 :destination, String
17
- attribute :hotels, Array[Integer]
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, :destination, length: { is: 3 }
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/model/hotel"
2
- require "hotel_beds/hotel_search/parser/errors"
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::HotelSearch::Parser::Errors.call(response, body)
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::HotelSearch::Parser::Hotel.call(
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
@@ -8,7 +8,6 @@ module HotelBeds
8
8
  # attributes
9
9
  attribute :amount, BigDecimal
10
10
  attribute :from, Time
11
- attribute :to, Date
12
11
  end
13
12
  end
14
13
  end
@@ -0,0 +1,13 @@
1
+ require "hotel_beds/model"
2
+
3
+ module HotelBeds
4
+ module Model
5
+ class Comment
6
+ include HotelBeds::Model
7
+
8
+ # attributes
9
+ attribute :type, String
10
+ attribute :content, String
11
+ end
12
+ end
13
+ end