Class: VendorsService::Klook::AvailabilityService

Inherits:
BaseOperationService
  • Object
show all
Includes:
Api::Vendor::V1::Klook::Concerns::SerializerUtils
Defined in:
app/services/vendors_service/klook/availability_service.rb

Overview

VendorsService::Klook::AvailabilityService

This service provides methods to query and format availability data for Klook vendor integration. It supports calendar-level and timeslot-level availability queries, merging static timeslot definitions with dynamic inventory checks. All timeslot hashes are formatted consistently.

Input:

- restaurant: Restaurant object
- restaurant_package: RestaurantPackage object
- payload: Hash with keys:
    :start_date [String] (optional) - Start date for range queries (YYYY-MM-DD)
    :end_date [String] (optional) - End date for range queries (YYYY-MM-DD)
    :date [String] (optional) - Specific date for single-day queries (YYYY-MM-DD)
    :date_times [Array<String>] (optional) - Array of ISO8601 datetime strings for specific timeslot queries

Output:

- calendar_dates_availability_data: Array of hashes, each with keys:
    :local_date [String], :available [Boolean], :vacancies [Integer], :capacity [Integer]
- check_start_times_availability_data: Array of timeslot hashes, each with keys:
    :local_date_time_start [String], :local_date_time_end [String], :available [Boolean], :vacancies [Integer], :capacity [Integer]

Edge Cases:

- Handles per_pack pricing models by dividing seat/capacity counts.
- If no available timeslots, returns all defined timeslots as unavailable.
- If available timeslots exist outside defined timeslots, includes them.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(restaurant, restaurant_package, payload) ⇒ AvailabilityService

Initializes the service with the required parameters.

Parameters:

  • restaurant (Restaurant)

    The restaurant object

  • restaurant_package (RestaurantPackage)

    The restaurant package object

  • payload (Hash)

    The payload containing availability parameters

    • :start_date [String] (optional) Start date for availability checks (YYYY-MM-DD)

    • :end_date [String] (optional) End date for availability checks (YYYY-MM-DD)

    • :date [String] (optional) Specific date for availability checks (YYYY-MM-DD)

    • :date_times [Array<String>] (optional) Array of ISO8601 datetime strings for timeslot checks



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'app/services/vendors_service/klook/availability_service.rb', line 45

def initialize(restaurant, restaurant_package, payload)
  @restaurant = restaurant
  @timezone = restaurant.time_zone || 'Asia/Bangkok'
  @restaurant_package = restaurant_package
  @inv_checker = create_inv_checker_instance
  @start_date = payload[:start_date].to_s
  @end_date = payload[:end_date].to_s
  @date = payload[:date].to_s
  @date_times = payload[:date_times]
  @adult = restaurant_package.package.decide_min_seat
  @kids = 0
  @is_per_pack = restaurant_package&.package&.dynamic_price_pricing_model&.to_sym == :per_pack
  @per_pack_qty = is_per_pack ? restaurant_package&.package&.dynamic_pricings&.first&.per_pack.to_i : 1
end

Instance Attribute Details

#adultObject (readonly)

Returns the value of attribute adult.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def adult
  @adult
end

#dateObject (readonly)

Returns the value of attribute date.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def date
  @date
end

#date_timesObject (readonly)

Returns the value of attribute date_times.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def date_times
  @date_times
end

#end_dateObject (readonly)

Returns the value of attribute end_date.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def end_date
  @end_date
end

#inv_checkerObject (readonly)

Returns the value of attribute inv_checker.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def inv_checker
  @inv_checker
end

#is_per_packObject (readonly)

Returns the value of attribute is_per_pack.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def is_per_pack
  @is_per_pack
end

#kidsObject (readonly)

Returns the value of attribute kids.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def kids
  @kids
end

#per_pack_qtyObject (readonly)

Returns the value of attribute per_pack_qty.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def per_pack_qty
  @per_pack_qty
end

#restaurantObject (readonly)

Returns the value of attribute restaurant.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def restaurant
  @restaurant
end

#restaurant_packageObject (readonly)

Returns the value of attribute restaurant_package.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def restaurant_package
  @restaurant_package
end

#start_dateObject (readonly)

Returns the value of attribute start_date.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def start_date
  @start_date
end

#timezoneObject (readonly)

Returns the value of attribute timezone.



32
33
34
# File 'app/services/vendors_service/klook/availability_service.rb', line 32

def timezone
  @timezone
end

Instance Method Details

#calendar_dates_availability_dataArray<Hash>

Returns a list of dates with overall availability details.

Example output: [

{ local_date: "2024-06-01", available: true, vacancies: 5, capacity: 10 },
{ local_date: "2024-06-02", available: false, vacancies: 0, capacity: 10 }

]

Returns:

  • (Array<Hash>)

    Each hash contains:

    • :local_date [String] Date as string (YYYY-MM-DD)

    • :available [Boolean] Availability status

    • :vacancies [Integer] Number of seats left

    • :capacity [Integer] Total seats (quantity available)



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'app/services/vendors_service/klook/availability_service.rb', line 73

def calendar_dates_availability_data
  inv_checker.find_available_dates(adult: adult, kids: kids, start_date: start_date, end_date: end_date).
    map do |d|
    # we need to send inventory in terms of number of packs if package is a per_pack
    divisor = is_per_pack ? per_pack_qty : 1
    seat_left = d['seat_left'].to_i / divisor
    quantity_available = d['quantity_available'].to_i / divisor
    availability = d['availability'] && seat_left.positive?
    {
      local_date: d['date'].to_s,
      available: availability,
      vacancies: seat_left,
      capacity: quantity_available,
    }
  end.compact
rescue StandardError => e
  APMErrorHandler.report(
    'Error in calendar_dates_availability_data',
    exception: e,
    context: { backtrace: e.backtrace },
  )
  []
end

#check_start_times_availability_dataObject

Returns an array of timeslot availability hashes for the requested date(s) or timeslot(s).

Input:

- Uses @start_date, @end_date, @date, or @date_times from initialization payload.
- If :start_date and :end_date are present, returns all timeslots for the date range.
- If :date is present, returns all timeslots for that date.
- If :date_times is present, returns only the requested timeslots.

Output:

- [Array<Hash>] Each hash contains:
    :local_date_time_start [String] ISO8601 formatted start time
    :local_date_time_end [String] ISO8601 formatted end time
    :available [Boolean] Availability status
    :vacancies [Integer] Number of seats left
    :capacity [Integer] Total seats (quantity available)

Edge Cases:

- Handles per_pack pricing models by dividing seat/capacity counts.
- If no available timeslots, returns all defined timeslots as unavailable.
- If available timeslots exist outside defined timeslots, includes them.


117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'app/services/vendors_service/klook/availability_service.rb', line 117

def check_start_times_availability_data
  if (start_date.present? && end_date.present?) || date.present?
    available_dates = date.present? ? [Date.parse(date)] : (Date.parse(start_date)..Date.parse(end_date)).to_a
    available_dates.flat_map { |d| merged_timeslots_for_date(d) }
  elsif date_times.present?
    date_times.flat_map do |ts|
      ts_date, dt_key = ts.to_time.in_time_zone(timezone).yield_self { |dt| [dt.to_date, dt.rfc3339] }
      merged_timeslots_for_date(ts_date).detect { |a| a[:local_date_time_start] == dt_key }
    end.compact
  end
rescue StandardError => e
  APMErrorHandler.report(
    'Error in check_start_times_availability_data',
    exception: e,
    context: { backtrace: e.backtrace },
  )
  []
end