hostconnect 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/CHANGELOG +8 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.markdown +16 -0
  4. data/Rakefile +48 -0
  5. data/hostconnect.gemspec +44 -0
  6. data/lib/hostconnect/builder.rb +50 -0
  7. data/lib/hostconnect/builders/add_service_builder.rb +60 -0
  8. data/lib/hostconnect/builders/agent_info_builder.rb +19 -0
  9. data/lib/hostconnect/builders/get_booking_builder.rb +24 -0
  10. data/lib/hostconnect/builders/get_booking_payment_summary_builder.rb +20 -0
  11. data/lib/hostconnect/builders/get_locations_builder.rb +18 -0
  12. data/lib/hostconnect/builders/get_services_builder.rb +18 -0
  13. data/lib/hostconnect/builders/get_system_settings_builder.rb +18 -0
  14. data/lib/hostconnect/builders/list_bookings_builder.rb +27 -0
  15. data/lib/hostconnect/builders/new_booking_info_builder.rb +23 -0
  16. data/lib/hostconnect/builders/option_info_builder.rb +49 -0
  17. data/lib/hostconnect/builders/pax_details_builder.rb +21 -0
  18. data/lib/hostconnect/builders/ping_builder.rb +11 -0
  19. data/lib/hostconnect/builders/record_booking_payment_builder.rb +25 -0
  20. data/lib/hostconnect/builders/room_config_builder.rb +25 -0
  21. data/lib/hostconnect/builders/service_line_note_builder.rb +17 -0
  22. data/lib/hostconnect/builders/suppler_info_builder.rb +27 -0
  23. data/lib/hostconnect/client.rb +32 -0
  24. data/lib/hostconnect/coercion.rb +50 -0
  25. data/lib/hostconnect/core_extensions/string.rb +18 -0
  26. data/lib/hostconnect/core_extensions/symbol.rb +9 -0
  27. data/lib/hostconnect/response.rb +119 -0
  28. data/lib/hostconnect/responses/add_service.rb +4 -0
  29. data/lib/hostconnect/responses/agent_info.rb +7 -0
  30. data/lib/hostconnect/responses/get_booking.rb +20 -0
  31. data/lib/hostconnect/responses/get_booking_payment_summary.rb +21 -0
  32. data/lib/hostconnect/responses/get_locations.rb +21 -0
  33. data/lib/hostconnect/responses/get_services.rb +21 -0
  34. data/lib/hostconnect/responses/get_system_settings.rb +24 -0
  35. data/lib/hostconnect/responses/list_bookings.rb +14 -0
  36. data/lib/hostconnect/responses/option_info.rb +60 -0
  37. data/lib/hostconnect/responses/ping.rb +7 -0
  38. data/lib/hostconnect/responses/record_booking_payment.rb +4 -0
  39. data/lib/hostconnect/responses/supplier_info.rb +31 -0
  40. data/lib/hostconnect/rtf_document.rb +19 -0
  41. data/lib/hostconnect/translation.rb +22 -0
  42. data/lib/hostconnect.rb +58 -0
  43. data/spec/builders/add_service_builder_spec.rb +36 -0
  44. data/spec/builders/agent_info_builder_spec.rb +13 -0
  45. data/spec/builders/get_locations_builder_spec.rb +13 -0
  46. data/spec/builders/new_booking_info_builder_spec.rb +34 -0
  47. data/spec/builders/option_info_builder_spec.rb +48 -0
  48. data/spec/builders/pax_details_builder_spec.rb +41 -0
  49. data/spec/builders/ping_builder_spec.rb +23 -0
  50. data/spec/builders/room_config_builder_spec.rb +60 -0
  51. data/spec/client_spec.rb +20 -0
  52. data/spec/coercion_spec.rb +85 -0
  53. data/spec/core_extensions_spec.rb +17 -0
  54. data/spec/fixtures/requests/add_service_request/hotel_booking.xml +42 -0
  55. data/spec/fixtures/requests/agent_info.xml +8 -0
  56. data/spec/fixtures/requests/get_locations.xml +8 -0
  57. data/spec/fixtures/requests/option_info/hotel_search.xml +11 -0
  58. data/spec/fixtures/requests/option_info/hotel_search_total_stay_price.xml +18 -0
  59. data/spec/fixtures/requests/option_info/option_number.xml +10 -0
  60. data/spec/fixtures/requests/ping.xml +5 -0
  61. data/spec/fixtures/responses/add_service.xml +11 -0
  62. data/spec/fixtures/responses/agent_info.xml +12 -0
  63. data/spec/fixtures/responses/agent_info_error.xml +7 -0
  64. data/spec/fixtures/responses/get_booking.xml +40 -0
  65. data/spec/fixtures/responses/get_locations.xml +48 -0
  66. data/spec/fixtures/responses/get_system_settings.xml +28 -0
  67. data/spec/fixtures/responses/option_info/hotel_price.xml +17 -0
  68. data/spec/fixtures/responses/option_info/hotel_search.xml +721 -0
  69. data/spec/fixtures/responses/option_info/hotel_search_with_stay_price.xml +470 -0
  70. data/spec/fixtures/responses/option_info/option_number.xml +14 -0
  71. data/spec/fixtures/responses/option_info/tours.xml +74 -0
  72. data/spec/fixtures/responses/ping.xml +8 -0
  73. data/spec/responses/add_service_spec.rb +13 -0
  74. data/spec/responses/agent_info_spec.rb +24 -0
  75. data/spec/responses/get_booking_spec.rb +33 -0
  76. data/spec/responses/get_locations_spec.rb +29 -0
  77. data/spec/responses/get_system_settings_spec.rb +21 -0
  78. data/spec/responses/option_info_spec.rb +48 -0
  79. data/spec/responses/ping_spec.rb +22 -0
  80. data/spec/spec_helper.rb +13 -0
  81. data/spec/translation_spec.rb +18 -0
  82. metadata +259 -0
@@ -0,0 +1,50 @@
1
+ module HostConnect
2
+ # Coercion
3
+ #
4
+ # Possible Types:
5
+ # * String
6
+ # * Strings with multiple lines (don't know yet if these must be handled specifically)
7
+ # * Boolean (Y/N)
8
+ # * Date (yyyy-mm-dd)
9
+ # * Time (hhmm)
10
+ # * Integer
11
+ # * Integer list (In an integer list, a single space is used to separate integer values.)
12
+ # * Price (Prices returned are Tourplan prices multiplied by 100, + currency stuff..)
13
+ #
14
+ # It must be possible to convert this data from/to native Ruby objects
15
+ class Coercion
16
+ # Convert HostConnect formatted data to Ruby objects
17
+ def self.from_hc(data)
18
+ case data
19
+ when /^[0-9]+\d*$/ then data.to_i
20
+ when /^(\d+\s){2,}[0-9 ]*$/ then data.split.collect { |i| i.to_i }
21
+ when /^\s*$/ then nil
22
+ when /\d{4}-\d\d-\d\d/ then Date.parse(data)
23
+ when "Y" then true
24
+ when "N" then false
25
+ else data.strip
26
+ end
27
+ end
28
+
29
+ # Convert Ruby objects to HostConnect formatted data
30
+ def self.to_hc(data)
31
+ case data
32
+ when Integer then data.to_s
33
+ when Date then data.to_s
34
+ when nil then ""
35
+ when true then "Y"
36
+ when false then "N"
37
+ else data.strip
38
+ end
39
+ end
40
+
41
+ # Time strings are i.e "2310"
42
+ def self.time(string)
43
+ Time.parse(string[0,2] << ":" << string[2,4])
44
+ end
45
+
46
+ def self.price(string)
47
+ (string.to_f / 100).round
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,18 @@
1
+ class String
2
+ def requestify
3
+ self.gsub(/Id$/, 'ID')
4
+ end
5
+
6
+ # Useful for heredocs - removes whitespace margin.
7
+ def margin
8
+ lines = self.dup.split($/)
9
+
10
+ min_margin = 0
11
+ lines.each do |line|
12
+ if line =~ /^(\s+)/ && (min_margin == 0 || $1.size < min_margin)
13
+ min_margin = $1.size
14
+ end
15
+ end
16
+ lines.map { |line| line.sub(/^\s{#{min_margin}}/, '') }.join($/)
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ class Symbol
2
+ def classify
3
+ ActiveSupport::Inflector.classify(self.to_s)
4
+ end
5
+
6
+ def camelize
7
+ ActiveSupport::Inflector.camelize(self.to_s)
8
+ end
9
+ end
@@ -0,0 +1,119 @@
1
+ module HostConnect
2
+ # Abstract response class. Each subclass takes the XML responses and turns them into
3
+ # a basic datastructure, with each element available as an attribute.
4
+ class AbstractResponse
5
+ # Yields each element
6
+ def each
7
+ elements.each { |e| yield e }
8
+ end
9
+
10
+ # Returns the first element
11
+ def first
12
+ elements.first
13
+ end
14
+
15
+ # Returns the last element
16
+ def last
17
+ elements.last
18
+ end
19
+
20
+ # Act like an array
21
+ def [](num)
22
+ elements[num]
23
+ end
24
+
25
+ # Exposes the element-array of responses which consists of multiple elements.
26
+ # Raises an error if used on non-collection responses (Ping etc).
27
+ def elements
28
+ (@elements.blank?) ? raise(ArgumentError, "Not a collection") : @elements
29
+ end
30
+
31
+ protected
32
+ def parse(xml)
33
+ @data = Hpricot.XML xml
34
+ error_reply = @data.search("/Reply/ErrorReply/Error")
35
+ unless error_reply.blank?
36
+ error_msg = error_reply.innerHTML
37
+ error_code = error_msg[0..3].to_i
38
+
39
+ # See http://www.tourplan.com/support/Connector/ErrorMessages.html
40
+ error_description = case error_code
41
+ when 1000 then "General error."
42
+ when 1001 then "Missing input."
43
+ when 1002 then "Illegal input."
44
+ when 1003 then "Data communications link within iCom failed."
45
+ when 1004 then "A timeout occurred while an iCom component was waiting for something to happen."
46
+ when 1005 then "A database access error occurred within an iCom component."
47
+ when 1006 then "An error occurred when an iCom component attempted a file access of some sort."
48
+ when 1007 then "Data servlet cache not loaded."
49
+ when 1008 then "An error was reported by the iCom booking engine."
50
+ when 1009 then "The booking engine is currently off-line."
51
+ when 1040 then "No merchant account."
52
+ when 1050 then "Booking not found."
53
+ when 1051 then "Agent not found (or wrong password given)."
54
+ when 1052 then "Option not found."
55
+ when 1053 then "Service line not found."
56
+ when 1054 then "Operation is illegal on a read-only booking."
57
+ when 1055 then "Operation is illegal for an agent over their credit limit."
58
+ when 1056 then "Operation is illegal for this service line."
59
+ when 1057 then "Permission denied for this operation."
60
+ when 1058 then "The object the request is trying to create already exists."
61
+ when 1059 then "Supplier not found."
62
+ when 1060 then "Database record not found."
63
+ when 1061 then "Supplier exists."
64
+ when 1062 then "Option exists."
65
+ when 1063 then "Agent exists, but has no default currency (iS iCom only)."
66
+ when 1064 then "Operation is illegal on a non-iCom booking."
67
+ when 1065 then "Login failed; two or more agents have this login."
68
+ when 2000 then "Credit card expired."
69
+ when 2001 then "Credit card number invalid (is non-numeric, or fails validation check)."
70
+ when 2002 then "Card wrong type (card type does not match the specified card type)."
71
+ when 2006 then "Operation requested is not valid for a confirmed booking."
72
+ when 2007 then "Operation requested is not valid for a quote."
73
+ when 2008 then "Error accessing external card payment system."
74
+ when 2009 then "Transaction refused by external card payment system."
75
+ when 2010 then "All services already cancelled."
76
+ when 2011 then "Attempt to add service violates a MinSCU requirement at the option rate level."
77
+ when 2050 then "Connector refused request. No valid hostConnect or webConnect entry was found that permitted the specfied request by the specified agent from the source IP address of the request."
78
+ when 5000 then "The specified BookingUpdateCount is no longer valid; request rejected."
79
+ when 5001 then "The specified ServiceLineUpdateCount is no longer valid; request rejected."
80
+ else "Unknown error."
81
+ end
82
+
83
+ HostConnect.logger.fatal "Exception thrown: " + error_description
84
+ raise ArgumentError, error_msg << " (" << error_description << ")"
85
+ end
86
+ end
87
+
88
+ private
89
+ def initialize(xml)
90
+ parse xml
91
+ private_methods.include?("populate") ? populate : set_attrs
92
+ end
93
+
94
+ # Sets all instance variables. This only works for the simple requests.
95
+ # For convenience, query methods gets defined for booleans.
96
+ def set_attrs
97
+ reply_name = ActiveSupport::Inflector.demodulize(self.class) << "Reply"
98
+ @data.search("/Reply/" << reply_name) do |n|
99
+ n.containers.each do |e|
100
+ var = e.name.underscore
101
+
102
+ # Special treatment for variables that end with "_price"
103
+ if var =~ /_price$/
104
+ value = Coercion.price(Hpricot.uxs(e.innerHTML))
105
+ else
106
+ value = Coercion.from_hc(Hpricot.uxs(e.innerHTML))
107
+ end
108
+
109
+ if value.kind_of?(FalseClass) || value.kind_of?(TrueClass)
110
+ eval "def #{var}?; #{var}; end"
111
+ end
112
+
113
+ instance_variable_set("@#{var}", value)
114
+ self.class.class_eval "attr_reader :#{var}"
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,4 @@
1
+ module HostConnect
2
+ class AddService < AbstractResponse
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module HostConnect
2
+ class AgentInfo < AbstractResponse
3
+ def to_s
4
+ name
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ module HostConnect
2
+ class GetBooking < AbstractResponse
3
+ private
4
+ def populate
5
+ set_attrs
6
+
7
+ @services = []
8
+ @data.search("/Reply/GetBookingReply/Services/Service").each do |service|
9
+ s = Struct.new(:service_line_id, :service_line_update_count, :opt,
10
+ :status).new
11
+ s.service_line_id = (service/"ServiceLineId").innerHTML.to_i
12
+ s.service_line_update_count = (service/"ServiceLineUpdateCount").innerHTML.to_i
13
+ s.opt = (service/"Opt").innerHTML
14
+ s.status = (service/"Status").innerHTML
15
+
16
+ @services << s
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module HostConnect
2
+ class GetBookingPaymentSummary < AbstractResponse
3
+ private
4
+ def populate
5
+ @data.search("/Reply/GetBookingPaymentSummaryReply") do |n|
6
+ n.containers.each do |e|
7
+ var = e.name.underscore
8
+
9
+ if var == "currency"
10
+ value = Hpricot.uxs(e.innerHTML)
11
+ else
12
+ value = Coercion.price(Hpricot.uxs(e.innerHTML))
13
+ end
14
+
15
+ instance_variable_set("@#{var}", value)
16
+ self.class.class_eval "attr_reader :#{var}"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module HostConnect
2
+ class GetLocations < AbstractResponse
3
+ include Enumerable
4
+
5
+ def size
6
+ @size ||= @data.search("/Reply/GetLocationsReply/Locations/Location").size
7
+ end
8
+
9
+ private
10
+ def populate
11
+ @elements = []
12
+
13
+ @data.search("/Reply/GetLocationsReply/Locations/Location").each do |location|
14
+ s = Struct.new(:code, :name).new
15
+ s.code = (location/"Code").innerHTML
16
+ s.name = (location/"Name").innerHTML
17
+ @elements << s
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module HostConnect
2
+ class GetServices < AbstractResponse
3
+ include Enumerable
4
+
5
+ def size
6
+ @size ||= @data.search("/Reply/GetServicesReply/TPLServices/TPLService").size
7
+ end
8
+
9
+ private
10
+ def populate
11
+ @elements = []
12
+
13
+ @data.search("/Reply/GetServicesReply/TPLServices/TPLService").each do |location|
14
+ s = Struct.new(:code, :name).new
15
+ s.code = (location/"Code").innerHTML
16
+ s.name = (location/"Name").innerHTML
17
+ @elements << s
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module HostConnect
2
+ class GetSystemSettings < AbstractResponse
3
+ private
4
+ def populate
5
+ set_attrs
6
+
7
+ @countries = []
8
+ @data.search("/Reply/GetSystemSettingsReply/Countries/Country").each do |country|
9
+ c = Struct.new(:country_name, :destination_names).new
10
+ c.country_name = (country/"CountryName").innerHTML
11
+
12
+ c.destination_names = []
13
+
14
+ (country/"DestinationNames/DestinationName").each do |destination_name|
15
+ d = Struct.new(:destination_name).new
16
+ d.destination_name = destination_name.innerHTML
17
+ c.destination_names << d
18
+ end
19
+
20
+ @countries << c
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ module HostConnect
2
+ class ListBookings < AbstractResponse
3
+ include Enumerable
4
+
5
+ def size
6
+ @size ||= @data.search("/Reply/ListBookingsReply/*").size
7
+ end
8
+
9
+ private
10
+ def populate
11
+ @elements = []
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,60 @@
1
+ module HostConnect
2
+ class OptionInfo < AbstractResponse
3
+ include Enumerable
4
+
5
+ def size
6
+ @size ||= @data.search("/Reply/OptionInfoReply/Option").size
7
+ end
8
+
9
+ private
10
+ def populate
11
+ @elements = []
12
+ @data.search("/Reply/OptionInfoReply/Option").each do |option|
13
+ s = OpenStruct.new
14
+ s.opt = Coercion.from_hc((option/"Opt").innerHTML)
15
+ s.option_number = Coercion.from_hc((option/"OptionNumber").innerHTML)
16
+
17
+ general = (option/"OptGeneral")
18
+ unless general.blank?
19
+ r = Struct.new(:description, :comment, :periods).new
20
+ r.description = (general/"Description").first.innerHTML
21
+ r.comment = (general/"Comment").innerHTML
22
+ r.periods = (general/"Periods").innerHTML.to_i
23
+
24
+ s.general = r
25
+ end
26
+
27
+ stay_results = (option/"OptStayResults")
28
+ unless stay_results.blank?
29
+ r = Struct.new(:availability, :currency, :total_price, :rate_name,
30
+ :rate_text).new
31
+ r.availability = (stay_results/"Availability").innerHTML
32
+ r.currency = (stay_results/"Currency").innerHTML
33
+ r.total_price = Coercion.price((stay_results/"TotalPrice").innerHTML)
34
+ r.rate_name = (stay_results/"RateName").innerHTML
35
+ r.rate_text = (stay_results/"RateText").innerHTML
36
+
37
+ s.stay_results = r
38
+ end
39
+
40
+ rates = (option/"OptRates")
41
+ unless rates.blank?
42
+ r = OpenStruct.new
43
+ r.currency = (rates/"Currency").innerHTML
44
+
45
+ room_rates = Struct.new(:single_rate, :double_rate, :twin_rate, :triple_rate).new
46
+ room_rates.single_rate = Coercion.price((rates/"RoomRates/SingleRate").innerHTML)
47
+ room_rates.double_rate = Coercion.price((rates/"RoomRates/DoubleRate").innerHTML)
48
+ room_rates.twin_rate = Coercion.price((rates/"RoomRates/TwinRate").innerHTML)
49
+ room_rates.triple_rate = Coercion.price((rates/"RoomRates/TripleRate").innerHTML)
50
+
51
+ r.rate = OpenStruct.new
52
+ r.rate.room_rates = room_rates
53
+ s.rates = r
54
+ end
55
+
56
+ @elements << s
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,7 @@
1
+ module HostConnect
2
+ class Ping < AbstractResponse
3
+ def to_s
4
+ backend << " " << version
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module HostConnect
2
+ class RecordBookingPayment < AbstractResponse
3
+ end
4
+ end
@@ -0,0 +1,31 @@
1
+ module HostConnect
2
+ class SupplierInfo < AbstractResponse
3
+ include Enumerable
4
+
5
+ def size
6
+ @size ||= @data.search("/Reply/SupplierInfoReply/Suppliers/Supplier").size
7
+ end
8
+
9
+ private
10
+ def populate
11
+ @elements = []
12
+
13
+ @data.search("/Reply/SupplierInfoReply/Suppliers/Supplier").each do |supplier|
14
+ s = Struct.new(:supplier_id, :supplier_code, :name, :address1, :address2,
15
+ :address3, :address4, :address5, :post_code, :supplier_note).new
16
+ s.supplier_id = (supplier/"SupplierId").innerHTML
17
+ s.supplier_code = (supplier/"SupplierCode").innerHTML
18
+ s.name = (supplier/"Name").innerHTML
19
+ s.address1 = (supplier/"Address1").innerHTML
20
+ s.address2 = (supplier/"Address2").innerHTML
21
+ s.address3 = (supplier/"Address3").innerHTML
22
+ s.address4 = (supplier/"Address4").innerHTML
23
+ s.address5 = (supplier/"Address5").innerHTML
24
+ s.post_code = (supplier/"PostCode").innerHTML
25
+ s.supplier_note = (supplier/"SupplierNotes"/"SupplierNote"/"NoteText").innerHTML
26
+
27
+ @elements << s
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module HostConnect
2
+ # For setting up simple RTF Documents
3
+ class RtfDocument
4
+ def initialize(paragraphs)
5
+ @document = RTF::Document.new(RTF::Font.new(RTF::Font::ROMAN, 'Times New Roman'))
6
+ paragraphs.each do |p|
7
+ @document.paragraph << p
8
+ end
9
+ end
10
+
11
+ def to_rtf
12
+ @document.to_rtf
13
+ end
14
+
15
+ def to_s
16
+ @document.to_s
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ module HostConnect
2
+ # Translate to/from HostConnect codes
3
+ class Translation
4
+ GRAMMAR = {
5
+ "SG" => "Single",
6
+ "TW" => "Twin",
7
+ "DB" => "Double",
8
+ "TR" => "Triple",
9
+ "QD" => "Quad",
10
+ "CF" => "Confirmed",
11
+ "CX" => "Cancelled",
12
+ "FQ" => "FIT Quote",
13
+ "IN" => "Internet Booking",
14
+ "RQ" => "Request",
15
+ "CRCD" => "Credit Card Payment"
16
+ }
17
+
18
+ def self.translate(string)
19
+ (string =~ /^[A-Z]{2}$/) ? GRAMMAR[string] : GRAMMAR.invert[string]
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,58 @@
1
+ # This file begins the loading sequence.
2
+ pwd = File.dirname(__FILE__)
3
+
4
+ # This line just let's us require anything in the +lib+ sub-folder
5
+ # without specifying a full path.
6
+ $LOAD_PATH.unshift(pwd)
7
+
8
+ # Require dependencies
9
+ %w[rubygems net/https builder date time ostruct hpricot rtf
10
+ active_support yaml logger].each { |lib| require lib }
11
+
12
+ # Require HostConnect files
13
+ %w[client response builder rtf_document translation
14
+ coercion].each { |lib| require "#{pwd}/hostconnect/#{lib}" }
15
+
16
+ Dir.glob("#{pwd}/hostconnect/builders/*.rb").each { |file| require file }
17
+ Dir.glob("#{pwd}/hostconnect/responses/*.rb").each { |file| require file }
18
+ Dir.glob("#{pwd}/hostconnect/core_extensions/*.rb").each { |file| require file }
19
+
20
+ module HostConnect
21
+ extend self
22
+
23
+ module Version
24
+ MAJOR = '0'
25
+ MINOR = '1'
26
+ REVISION = '6'
27
+ def self.combined
28
+ [MAJOR, MINOR, REVISION].join('.')
29
+ end
30
+ end
31
+
32
+ def setup(env, config)
33
+ config[:dtd] =
34
+ 'http://www.tourplan.com/support/Connector/hostConnect_' + config[:version] + '.dtd'
35
+ @@config = OpenStruct.new config
36
+
37
+ log_level = case env
38
+ when :test then Logger::WARN
39
+ when :development then Logger::DEBUG
40
+ when :production then Logger::ERROR
41
+ else raise ArgumentError, 'Incorrect environment: ' + env.to_s
42
+ end
43
+
44
+ log_path = config[:log_path] || "log/"
45
+ @@logger = Logger.new(log_path + env.to_s + ".log")
46
+ @@logger.level = log_level
47
+ @@logger.formatter = Logger::Formatter.new
48
+ @@logger.datetime_format = "%Y-%d-%m %H:%M:%S"
49
+ end
50
+
51
+ def config
52
+ @@config
53
+ end
54
+
55
+ def logger
56
+ @@logger
57
+ end
58
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe HostConnect::AddServiceBuilder do
4
+ before(:each) do
5
+ @xml = File.read("./spec/fixtures/requests/add_service_request/hotel_booking.xml")
6
+ end
7
+
8
+ it "should produce xml" do
9
+ req = AddServiceBuilder.new(:agent_id => "EURTAT", :password => "EURTAT")
10
+
11
+ req.new_booking_info = NewBookingInfoBuilder.new(:name => "Jessop Mr/Mrs", :qb => "B")
12
+
13
+ pax1 = PaxDetailsBuilder.new(:title => "Mr", :forename => "Rob",
14
+ :surname => "Jardim", :pax_type => "A",
15
+ :date_of_birth => "1980-12-24")
16
+ pax2 = PaxDetailsBuilder.new(:title => "Mrs", :forename => "Sally",
17
+ :surname => "Jardim", :pax_type => "A",
18
+ :date_of_birth => "1980-12-24")
19
+
20
+ room = RoomConfigBuilder.new(:adults => 2, :room_type => "TW",
21
+ :pax_list => [ pax1, pax2 ])
22
+ req.room_configs = [ room ]
23
+
24
+ req.opt = "LONACCUMLONSTDBCB"
25
+ req.date_from = "2007-10-07"
26
+ req.scu_qty = "2"
27
+
28
+ req.ud_text1 = "+4799999999"
29
+ req.ud_text2 = "contact@email.net"
30
+ req.ud_text3 = "Norway"
31
+ req.ud_text4 = false
32
+ req.ud_text5 = "Smoking"
33
+
34
+ req.to_s.should == @xml
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe HostConnect::AgentInfoBuilder do
4
+ before(:each) do
5
+ @xml = File.read("./spec/fixtures/requests/agent_info.xml")
6
+ end
7
+
8
+ it "should produce xml" do
9
+ req = AgentInfoBuilder.new(:agent_id => "EURTAT", :password => "EURTAT")
10
+
11
+ req.to_s.should == @xml
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe HostConnect::GetLocationsBuilder do
4
+ before(:each) do
5
+ @xml = File.read("./spec/fixtures/requests/get_locations.xml")
6
+ end
7
+
8
+ it "should produce xml" do
9
+ req = GetLocationsBuilder.new(:agent_id => "EURTAT", :password => "EURTAT")
10
+
11
+ req.to_s.should == @xml
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe HostConnect::NewBookingInfoBuilder do
4
+ before(:each) do
5
+ @xml = <<-END
6
+ <NewBookingInfo>
7
+ <Name>Jessop Mr/Mrs</Name>
8
+ <QB>B</QB>
9
+ </NewBookingInfo>
10
+ END
11
+ end
12
+
13
+ it "should produce correct xml" do
14
+ req = NewBookingInfoBuilder.new(:name => "Jessop Mr/Mrs", :qb => "B")
15
+
16
+ req.to_s.should == @xml
17
+ end
18
+
19
+ it "should be possible to set and change the attributes directly" do
20
+ req = NewBookingInfoBuilder.new
21
+ req.name = "Jessop Mr/Mrs"
22
+ req.qb = "B"
23
+
24
+ req.to_s.should == @xml
25
+
26
+ req.qb = "X"
27
+ req.to_s.should_not == @xml
28
+ end
29
+
30
+ it "should return a XML Builder object" do
31
+ req = NewBookingInfoBuilder.new({})
32
+ req.to_xml.should respond_to(:target!)
33
+ end
34
+ end