liteapi 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 +7 -0
- data/CHANGELOG.md +51 -0
- data/LICENSE.txt +21 -0
- data/README.md +938 -0
- data/lib/liteapi/analytics.rb +49 -0
- data/lib/liteapi/booking.rb +73 -0
- data/lib/liteapi/client.rb +100 -0
- data/lib/liteapi/configuration.rb +25 -0
- data/lib/liteapi/connection.rb +136 -0
- data/lib/liteapi/errors.rb +24 -0
- data/lib/liteapi/guests.rb +64 -0
- data/lib/liteapi/rates.rb +77 -0
- data/lib/liteapi/static_data.rb +92 -0
- data/lib/liteapi/version.rb +5 -0
- data/lib/liteapi/vouchers.rb +100 -0
- data/lib/liteapi.rb +31 -0
- metadata +89 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liteapi
|
|
4
|
+
module Analytics
|
|
5
|
+
# Retrieve weekly analytics
|
|
6
|
+
#
|
|
7
|
+
# Fetches weekly analytics data for a date range.
|
|
8
|
+
#
|
|
9
|
+
# @param from [String] Start date (YYYY-MM-DD)
|
|
10
|
+
# @param to [String] End date (YYYY-MM-DD)
|
|
11
|
+
# @return [Hash] Weekly analytics data
|
|
12
|
+
def weekly_analytics(from:, to:)
|
|
13
|
+
dashboard_post('analytics/weekly', { from: from, to: to })
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Retrieve detailed analytics report
|
|
17
|
+
#
|
|
18
|
+
# Fetches a detailed analytics report including revenue and sales data.
|
|
19
|
+
#
|
|
20
|
+
# @param from [String] Start date (YYYY-MM-DD)
|
|
21
|
+
# @param to [String] End date (YYYY-MM-DD)
|
|
22
|
+
# @return [Hash] Detailed analytics report
|
|
23
|
+
def analytics_report(from:, to:)
|
|
24
|
+
dashboard_post('analytics/report', { from: from, to: to })
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Retrieve market analytics
|
|
28
|
+
#
|
|
29
|
+
# Fetches market-level analytics data.
|
|
30
|
+
#
|
|
31
|
+
# @param from [String] Start date (YYYY-MM-DD)
|
|
32
|
+
# @param to [String] End date (YYYY-MM-DD)
|
|
33
|
+
# @return [Hash] Market analytics data
|
|
34
|
+
def market_analytics(from:, to:)
|
|
35
|
+
dashboard_post('analytics/market', { from: from, to: to })
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Retrieve most booked hotels
|
|
39
|
+
#
|
|
40
|
+
# Fetches data on most booked hotels during a date range.
|
|
41
|
+
#
|
|
42
|
+
# @param from [String] Start date (YYYY-MM-DD)
|
|
43
|
+
# @param to [String] End date (YYYY-MM-DD)
|
|
44
|
+
# @return [Array] List of most booked hotels
|
|
45
|
+
def most_booked_hotels(from:, to:)
|
|
46
|
+
dashboard_post('analytics/top-hotels', { from: from, to: to })
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liteapi
|
|
4
|
+
module Booking
|
|
5
|
+
# Pre-book a rate to confirm availability and pricing
|
|
6
|
+
#
|
|
7
|
+
# Confirms if the room and rates are still available. Returns a prebook_id
|
|
8
|
+
# needed for the final booking.
|
|
9
|
+
#
|
|
10
|
+
# @param offer_id [String] The offer/rate ID from full_rates
|
|
11
|
+
# @return [Hash] Prebook confirmation with prebook_id
|
|
12
|
+
def prebook(offer_id:)
|
|
13
|
+
book_post('rates/prebook', { offerId: offer_id })
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Complete a booking
|
|
17
|
+
#
|
|
18
|
+
# Confirms the booking with guest and payment information.
|
|
19
|
+
#
|
|
20
|
+
# @param prebook_id [String] The prebook ID from prebook response
|
|
21
|
+
# @param guest [Hash] Guest information (first_name, last_name, email)
|
|
22
|
+
# @param payment [Hash] Payment information (card holder name, number, expiry, cvc)
|
|
23
|
+
# @param client_reference [String, nil] Your reference for this booking
|
|
24
|
+
# @return [Hash] Booking confirmation with booking_id
|
|
25
|
+
def book(prebook_id:, guest:, payment:, client_reference: nil)
|
|
26
|
+
body = {
|
|
27
|
+
prebookId: prebook_id,
|
|
28
|
+
guestInfo: {
|
|
29
|
+
guestFirstName: guest[:first_name],
|
|
30
|
+
guestLastName: guest[:last_name],
|
|
31
|
+
guestEmail: guest[:email]
|
|
32
|
+
},
|
|
33
|
+
paymentMethod: {
|
|
34
|
+
holderName: payment[:holder_name],
|
|
35
|
+
paymentMethodId: payment[:payment_method_id] || 'creditCard',
|
|
36
|
+
cardNumber: payment[:card_number],
|
|
37
|
+
expireDate: payment[:expire_date],
|
|
38
|
+
cvc: payment[:cvc]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
body[:clientReference] = client_reference if client_reference
|
|
42
|
+
|
|
43
|
+
book_post('rates/book', body)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# List bookings by client reference
|
|
47
|
+
#
|
|
48
|
+
# @param client_reference [String] Your reference to search for
|
|
49
|
+
# @return [Array] List of bookings
|
|
50
|
+
def bookings(client_reference:)
|
|
51
|
+
book_get('bookings', clientReference: client_reference)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Retrieve a specific booking
|
|
55
|
+
#
|
|
56
|
+
# @param booking_id [String] The booking ID
|
|
57
|
+
# @return [Hash] Booking details
|
|
58
|
+
def booking(booking_id)
|
|
59
|
+
book_get("bookings/#{booking_id}")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Cancel a booking
|
|
63
|
+
#
|
|
64
|
+
# Cancellation success depends on the cancellation policy.
|
|
65
|
+
# Non-refundable bookings or those past the cancellation date cannot be cancelled.
|
|
66
|
+
#
|
|
67
|
+
# @param booking_id [String] The booking ID to cancel
|
|
68
|
+
# @return [Hash] Cancellation confirmation
|
|
69
|
+
def cancel_booking(booking_id)
|
|
70
|
+
book_put("bookings/#{booking_id}")
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liteapi
|
|
4
|
+
class Client
|
|
5
|
+
include StaticData
|
|
6
|
+
include Rates
|
|
7
|
+
include Booking
|
|
8
|
+
include Guests
|
|
9
|
+
include Vouchers
|
|
10
|
+
include Analytics
|
|
11
|
+
|
|
12
|
+
attr_reader :api_key, :base_url, :book_base_url, :dashboard_base_url,
|
|
13
|
+
:timeout, :open_timeout, :max_retries
|
|
14
|
+
|
|
15
|
+
def initialize(api_key: nil, base_url: nil, book_base_url: nil, dashboard_base_url: nil,
|
|
16
|
+
timeout: nil, open_timeout: nil, max_retries: nil)
|
|
17
|
+
config = Liteapi.configuration
|
|
18
|
+
|
|
19
|
+
@api_key = api_key || config.api_key
|
|
20
|
+
@base_url = base_url || config.base_url
|
|
21
|
+
@book_base_url = book_base_url || config.book_base_url
|
|
22
|
+
@dashboard_base_url = dashboard_base_url || config.dashboard_base_url
|
|
23
|
+
@timeout = timeout || config.timeout
|
|
24
|
+
@open_timeout = open_timeout || config.open_timeout
|
|
25
|
+
@max_retries = max_retries || config.max_retries
|
|
26
|
+
|
|
27
|
+
validate_api_key!
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def validate_api_key!
|
|
33
|
+
return if @api_key && !@api_key.empty?
|
|
34
|
+
|
|
35
|
+
raise Liteapi::Error, 'API key is required. Set via Liteapi.configure or pass api_key: to Client.new'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def connection
|
|
39
|
+
@connection ||= Connection.new(
|
|
40
|
+
api_key: @api_key,
|
|
41
|
+
base_url: @base_url,
|
|
42
|
+
timeout: @timeout,
|
|
43
|
+
open_timeout: @open_timeout,
|
|
44
|
+
max_retries: @max_retries
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def book_connection
|
|
49
|
+
@book_connection ||= Connection.new(
|
|
50
|
+
api_key: @api_key,
|
|
51
|
+
base_url: @book_base_url,
|
|
52
|
+
timeout: @timeout,
|
|
53
|
+
open_timeout: @open_timeout,
|
|
54
|
+
max_retries: @max_retries
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def dashboard_connection
|
|
59
|
+
@dashboard_connection ||= Connection.new(
|
|
60
|
+
api_key: @api_key,
|
|
61
|
+
base_url: @dashboard_base_url,
|
|
62
|
+
timeout: @timeout,
|
|
63
|
+
open_timeout: @open_timeout,
|
|
64
|
+
max_retries: @max_retries
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def get(path, params = {})
|
|
69
|
+
connection.get(path, params)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def post(path, body = {})
|
|
73
|
+
connection.post(path, body)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def put(path, body = {})
|
|
77
|
+
connection.put(path, body)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def book_get(path, params = {})
|
|
81
|
+
book_connection.get(path, params)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def book_post(path, body = {})
|
|
85
|
+
book_connection.post(path, body)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def book_put(path, body = {})
|
|
89
|
+
book_connection.put(path, body)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def dashboard_get(path, params = {})
|
|
93
|
+
dashboard_connection.get(path, params)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def dashboard_post(path, body = {})
|
|
97
|
+
dashboard_connection.post(path, body)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liteapi
|
|
4
|
+
class Configuration
|
|
5
|
+
attr_accessor :api_key, :base_url, :book_base_url, :dashboard_base_url,
|
|
6
|
+
:timeout, :open_timeout, :max_retries
|
|
7
|
+
|
|
8
|
+
DEFAULT_BASE_URL = 'https://api.liteapi.travel/v3.0'
|
|
9
|
+
DEFAULT_BOOK_BASE_URL = 'https://book.liteapi.travel/v3.0'
|
|
10
|
+
DEFAULT_DASHBOARD_BASE_URL = 'https://da.liteapi.travel'
|
|
11
|
+
DEFAULT_TIMEOUT = 30
|
|
12
|
+
DEFAULT_OPEN_TIMEOUT = 10
|
|
13
|
+
DEFAULT_MAX_RETRIES = 3
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@api_key = ENV.fetch('LITEAPI_API_KEY', nil)
|
|
17
|
+
@base_url = DEFAULT_BASE_URL
|
|
18
|
+
@book_base_url = DEFAULT_BOOK_BASE_URL
|
|
19
|
+
@dashboard_base_url = DEFAULT_DASHBOARD_BASE_URL
|
|
20
|
+
@timeout = DEFAULT_TIMEOUT
|
|
21
|
+
@open_timeout = DEFAULT_OPEN_TIMEOUT
|
|
22
|
+
@max_retries = DEFAULT_MAX_RETRIES
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'faraday'
|
|
4
|
+
require 'faraday/retry'
|
|
5
|
+
|
|
6
|
+
module Liteapi
|
|
7
|
+
class Connection
|
|
8
|
+
RETRY_STATUSES = [429, 500, 502, 503, 504].freeze
|
|
9
|
+
|
|
10
|
+
def initialize(api_key:, base_url:, timeout:, open_timeout:, max_retries:)
|
|
11
|
+
@api_key = api_key
|
|
12
|
+
@base_url = base_url
|
|
13
|
+
@timeout = timeout
|
|
14
|
+
@open_timeout = open_timeout
|
|
15
|
+
@max_retries = max_retries
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def get(path, params = {})
|
|
19
|
+
request(:get, path, params)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def post(path, body = {})
|
|
23
|
+
request(:post, path, body)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def put(path, body = {})
|
|
27
|
+
request(:put, path, body)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def request(method, path, payload)
|
|
33
|
+
response = connection.public_send(method, path) do |req|
|
|
34
|
+
case method
|
|
35
|
+
when :get
|
|
36
|
+
req.params = payload if payload.any?
|
|
37
|
+
when :post, :put
|
|
38
|
+
req.body = payload
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
handle_response(response)
|
|
43
|
+
rescue Faraday::TimeoutError
|
|
44
|
+
raise Liteapi::Error, 'Request timed out'
|
|
45
|
+
rescue Faraday::ConnectionFailed
|
|
46
|
+
raise Liteapi::Error, 'Connection failed'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def handle_response(response)
|
|
50
|
+
body = response.body || {}
|
|
51
|
+
|
|
52
|
+
case response.status
|
|
53
|
+
when 200..299
|
|
54
|
+
body['data']
|
|
55
|
+
when 401
|
|
56
|
+
raise AuthenticationError.new(
|
|
57
|
+
error_message(body),
|
|
58
|
+
status: response.status,
|
|
59
|
+
code: body.dig('error', 'code'),
|
|
60
|
+
response: body
|
|
61
|
+
)
|
|
62
|
+
when 404
|
|
63
|
+
raise NotFoundError.new(
|
|
64
|
+
error_message(body),
|
|
65
|
+
status: response.status,
|
|
66
|
+
code: body.dig('error', 'code'),
|
|
67
|
+
response: body
|
|
68
|
+
)
|
|
69
|
+
when 422
|
|
70
|
+
raise ValidationError.new(
|
|
71
|
+
error_message(body),
|
|
72
|
+
status: response.status,
|
|
73
|
+
code: body.dig('error', 'code'),
|
|
74
|
+
response: body
|
|
75
|
+
)
|
|
76
|
+
when 429
|
|
77
|
+
raise RateLimitError.new(
|
|
78
|
+
error_message(body),
|
|
79
|
+
status: response.status,
|
|
80
|
+
code: body.dig('error', 'code'),
|
|
81
|
+
response: body
|
|
82
|
+
)
|
|
83
|
+
when 400..499
|
|
84
|
+
raise ClientError.new(
|
|
85
|
+
error_message(body),
|
|
86
|
+
status: response.status,
|
|
87
|
+
code: body.dig('error', 'code'),
|
|
88
|
+
response: body
|
|
89
|
+
)
|
|
90
|
+
when 500..599
|
|
91
|
+
raise ServerError.new(
|
|
92
|
+
error_message(body),
|
|
93
|
+
status: response.status,
|
|
94
|
+
code: body.dig('error', 'code'),
|
|
95
|
+
response: body
|
|
96
|
+
)
|
|
97
|
+
else
|
|
98
|
+
raise APIError.new(
|
|
99
|
+
"Unexpected response status: #{response.status}",
|
|
100
|
+
status: response.status,
|
|
101
|
+
response: body
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def error_message(body)
|
|
107
|
+
body.dig('error', 'message') || body['message'] || 'Unknown error'
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def connection
|
|
111
|
+
@connection ||= Faraday.new(url: @base_url) do |f|
|
|
112
|
+
f.request :json
|
|
113
|
+
f.response :json
|
|
114
|
+
f.request :retry, retry_options
|
|
115
|
+
f.options.timeout = @timeout
|
|
116
|
+
f.options.open_timeout = @open_timeout
|
|
117
|
+
f.headers['X-API-Key'] = @api_key
|
|
118
|
+
f.headers['Accept'] = 'application/json'
|
|
119
|
+
f.adapter Faraday.default_adapter
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def retry_options
|
|
124
|
+
{
|
|
125
|
+
max: @max_retries,
|
|
126
|
+
interval: 0.5,
|
|
127
|
+
interval_randomness: 0.5,
|
|
128
|
+
backoff_factor: 2,
|
|
129
|
+
retry_statuses: RETRY_STATUSES,
|
|
130
|
+
retry_block: ->(_env, _options, retries, exception) {
|
|
131
|
+
# Could add logging here if needed
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liteapi
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
|
|
6
|
+
class APIError < Error
|
|
7
|
+
attr_reader :status, :code, :response
|
|
8
|
+
|
|
9
|
+
def initialize(message = nil, status: nil, code: nil, response: nil)
|
|
10
|
+
@status = status
|
|
11
|
+
@code = code
|
|
12
|
+
@response = response
|
|
13
|
+
super(message)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class ClientError < APIError; end
|
|
18
|
+
class ServerError < APIError; end
|
|
19
|
+
|
|
20
|
+
class AuthenticationError < ClientError; end
|
|
21
|
+
class NotFoundError < ClientError; end
|
|
22
|
+
class RateLimitError < ClientError; end
|
|
23
|
+
class ValidationError < ClientError; end
|
|
24
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liteapi
|
|
4
|
+
module Guests
|
|
5
|
+
# Get loyalty program status
|
|
6
|
+
#
|
|
7
|
+
# Returns current loyalty program settings including status and cashback rates.
|
|
8
|
+
#
|
|
9
|
+
# @return [Hash] Loyalty program details
|
|
10
|
+
def loyalty
|
|
11
|
+
get('guests/loyalty')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Enable loyalty program
|
|
15
|
+
#
|
|
16
|
+
# Creates a new loyalty program with specified settings.
|
|
17
|
+
#
|
|
18
|
+
# @param status [String] Program status ('enabled' or 'disabled')
|
|
19
|
+
# @param cashback_rate [Float] Cashback rate (e.g., 0.03 = 3%)
|
|
20
|
+
# @return [Hash] Loyalty program details
|
|
21
|
+
def enable_loyalty(status:, cashback_rate:)
|
|
22
|
+
post('guests/loyalty', {
|
|
23
|
+
status: status,
|
|
24
|
+
cashbackRate: cashback_rate
|
|
25
|
+
})
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Update loyalty program
|
|
29
|
+
#
|
|
30
|
+
# Updates existing loyalty program settings.
|
|
31
|
+
#
|
|
32
|
+
# @param status [String] Program status ('enabled' or 'disabled')
|
|
33
|
+
# @param cashback_rate [Float] Cashback rate (e.g., 0.03 = 3%)
|
|
34
|
+
# @return [Hash] Updated loyalty program details
|
|
35
|
+
def update_loyalty(status:, cashback_rate:)
|
|
36
|
+
put('guests/loyalty', {
|
|
37
|
+
status: status,
|
|
38
|
+
cashbackRate: cashback_rate
|
|
39
|
+
})
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Get guest details
|
|
43
|
+
#
|
|
44
|
+
# Retrieves detailed information about a guest including personal data,
|
|
45
|
+
# loyalty points, and booking history.
|
|
46
|
+
#
|
|
47
|
+
# @param guest_id [String, Integer] Guest identifier
|
|
48
|
+
# @return [Hash] Guest details
|
|
49
|
+
def guest(guest_id)
|
|
50
|
+
get("guests/#{guest_id}")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Get guest bookings
|
|
54
|
+
#
|
|
55
|
+
# Retrieves all bookings for a specific guest with loyalty points
|
|
56
|
+
# and cashback information.
|
|
57
|
+
#
|
|
58
|
+
# @param guest_id [String, Integer] Guest identifier
|
|
59
|
+
# @return [Array] List of guest bookings
|
|
60
|
+
def guest_bookings(guest_id)
|
|
61
|
+
get("guests/#{guest_id}/bookings")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liteapi
|
|
4
|
+
module Rates
|
|
5
|
+
# Search for full rates and availability for hotels
|
|
6
|
+
#
|
|
7
|
+
# Returns all available rooms with rates, cancellation policies for a list of hotel IDs.
|
|
8
|
+
# Includes loyalty rewards if guest_id is provided.
|
|
9
|
+
#
|
|
10
|
+
# @param hotel_ids [Array<String>] List of hotel IDs to search
|
|
11
|
+
# @param checkin [String] Check-in date (YYYY-MM-DD)
|
|
12
|
+
# @param checkout [String] Check-out date (YYYY-MM-DD)
|
|
13
|
+
# @param occupancies [Array<Hash>] Room occupancies, each with :rooms, :adults, :children (ages array)
|
|
14
|
+
# @param guest_nationality [String] Guest nationality (ISO-2)
|
|
15
|
+
# @param currency [String] Currency code
|
|
16
|
+
# @param guest_id [String, nil] Guest ID for loyalty pricing
|
|
17
|
+
# @return [Hash] Rates and availability data
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# client.full_rates(
|
|
21
|
+
# hotel_ids: ['lp1234', 'lp5678'],
|
|
22
|
+
# checkin: '2025-03-01',
|
|
23
|
+
# checkout: '2025-03-03',
|
|
24
|
+
# occupancies: [{ rooms: 1, adults: 2, children: [5, 10] }],
|
|
25
|
+
# guest_nationality: 'US',
|
|
26
|
+
# currency: 'USD'
|
|
27
|
+
# )
|
|
28
|
+
def full_rates(hotel_ids:, checkin:, checkout:, occupancies:, guest_nationality:, currency:,
|
|
29
|
+
guest_id: nil)
|
|
30
|
+
body = {
|
|
31
|
+
hotelIds: hotel_ids,
|
|
32
|
+
checkin: checkin,
|
|
33
|
+
checkout: checkout,
|
|
34
|
+
occupancies: occupancies,
|
|
35
|
+
guestNationality: guest_nationality,
|
|
36
|
+
currency: currency
|
|
37
|
+
}
|
|
38
|
+
body[:guestId] = guest_id if guest_id
|
|
39
|
+
|
|
40
|
+
post('hotels/rates', body)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Search for minimum rates for hotels
|
|
44
|
+
#
|
|
45
|
+
# Returns only the minimum rate per hotel for quick comparisons.
|
|
46
|
+
#
|
|
47
|
+
# @param hotel_ids [Array<String>] List of hotel IDs to search
|
|
48
|
+
# @param checkin [String] Check-in date (YYYY-MM-DD)
|
|
49
|
+
# @param checkout [String] Check-out date (YYYY-MM-DD)
|
|
50
|
+
# @param occupancies [Array<Hash>] Room occupancies, each with :rooms, :adults, :children (ages array)
|
|
51
|
+
# @param guest_nationality [String] Guest nationality (ISO-2)
|
|
52
|
+
# @param currency [String] Currency code
|
|
53
|
+
# @return [Hash] Minimum rates data
|
|
54
|
+
#
|
|
55
|
+
# @example
|
|
56
|
+
# client.min_rates(
|
|
57
|
+
# hotel_ids: ['lp1234'],
|
|
58
|
+
# checkin: '2025-03-01',
|
|
59
|
+
# checkout: '2025-03-03',
|
|
60
|
+
# occupancies: [{ rooms: 1, adults: 2 }],
|
|
61
|
+
# guest_nationality: 'US',
|
|
62
|
+
# currency: 'USD'
|
|
63
|
+
# )
|
|
64
|
+
def min_rates(hotel_ids:, checkin:, checkout:, occupancies:, guest_nationality:, currency:)
|
|
65
|
+
body = {
|
|
66
|
+
hotelIds: hotel_ids,
|
|
67
|
+
checkin: checkin,
|
|
68
|
+
checkout: checkout,
|
|
69
|
+
occupancies: occupancies,
|
|
70
|
+
guestNationality: guest_nationality,
|
|
71
|
+
currency: currency
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
post('hotels/min-rates', body)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liteapi
|
|
4
|
+
module StaticData
|
|
5
|
+
# Returns list of all countries with ISO-2 codes
|
|
6
|
+
def countries
|
|
7
|
+
get('data/countries')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Returns list of cities for a country
|
|
11
|
+
#
|
|
12
|
+
# @param country_code [String] ISO-2 country code (e.g., 'SG', 'US')
|
|
13
|
+
def cities(country_code:)
|
|
14
|
+
get('data/cities', countryCode: country_code)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Search for places and areas
|
|
18
|
+
#
|
|
19
|
+
# @param query [String] Search text (e.g., 'Rome', 'Manhattan')
|
|
20
|
+
# @param type [String, nil] Filter by place type (e.g., 'hotel')
|
|
21
|
+
# @param language [String] Language for results (default: 'en')
|
|
22
|
+
def places(query:, type: nil, language: 'en')
|
|
23
|
+
params = { textQuery: query, language: language }
|
|
24
|
+
params[:type] = type if type
|
|
25
|
+
get('data/places', params)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns all available currency codes
|
|
29
|
+
def currencies
|
|
30
|
+
get('data/currencies')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns IATA codes for all airports
|
|
34
|
+
def iata_codes
|
|
35
|
+
get('data/iataCodes')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns list of hotel facility types
|
|
39
|
+
def hotel_facilities
|
|
40
|
+
get('data/facilities')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns list of hotel types (Hotel, Hostel, Resort, etc.)
|
|
44
|
+
def hotel_types
|
|
45
|
+
get('data/hotelTypes')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns list of hotel chains
|
|
49
|
+
def hotel_chains
|
|
50
|
+
get('data/chains')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Search for hotels
|
|
54
|
+
#
|
|
55
|
+
# @param country_code [String] ISO-2 country code (required)
|
|
56
|
+
# @param city_name [String, nil] Filter by city name
|
|
57
|
+
# @param latitude [Float, nil] Latitude for geo search
|
|
58
|
+
# @param longitude [Float, nil] Longitude for geo search
|
|
59
|
+
# @param radius [Integer, nil] Search radius in km (for geo search)
|
|
60
|
+
# @param language [String] Language for results (default: 'en')
|
|
61
|
+
def hotels(country_code:, city_name: nil, latitude: nil, longitude: nil, radius: nil, language: 'en')
|
|
62
|
+
params = { countryCode: country_code, language: language }
|
|
63
|
+
params[:cityName] = city_name if city_name
|
|
64
|
+
params[:latitude] = latitude if latitude
|
|
65
|
+
params[:longitude] = longitude if longitude
|
|
66
|
+
params[:radius] = radius if radius
|
|
67
|
+
get('data/hotels', params)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Get detailed hotel information
|
|
71
|
+
#
|
|
72
|
+
# @param hotel_id [String] Hotel identifier
|
|
73
|
+
# @param language [String, nil] Language for results
|
|
74
|
+
def hotel(hotel_id, language: nil)
|
|
75
|
+
params = { hotelId: hotel_id }
|
|
76
|
+
params[:language] = language if language
|
|
77
|
+
get('data/hotel', params)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Get hotel reviews with optional sentiment analysis
|
|
81
|
+
#
|
|
82
|
+
# @param hotel_id [String] Hotel identifier
|
|
83
|
+
# @param limit [Integer, nil] Maximum reviews to return (max 1000)
|
|
84
|
+
# @param sentiment [Boolean] Include sentiment analysis
|
|
85
|
+
def hotel_reviews(hotel_id:, limit: nil, sentiment: false)
|
|
86
|
+
params = { hotelId: hotel_id }
|
|
87
|
+
params[:limit] = limit if limit
|
|
88
|
+
params[:getSentiment] = sentiment if sentiment
|
|
89
|
+
get('data/reviews', params)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|