Module: ActiveBookings::Bookable::Core::InstanceMethods

Defined in:
lib/active_bookings/bookable/core.rb

Instance Method Summary collapse

Instance Method Details

#book!(booker, opts = {}) ⇒ Object

Accept a booking by a booker. This is an alias method, equivalent to @booker.book!(@bookable, opts)

Example:

@room.book!(@user, from: Date.today, to: Date.tomorrow, amount: 2)

Parameters:

  • booker

    The booker model

  • opts (defaults to: {})

    The booking options



279
280
281
# File 'lib/active_bookings/bookable/core.rb', line 279

def book!(booker, opts={})
  booker.book!(self, opts)
end

#booker?Boolean

Returns:

  • (Boolean)


293
294
295
# File 'lib/active_bookings/bookable/core.rb', line 293

def booker?
  self.class.booker?
end

#check_availability(opts) ⇒ Object

Check availability of current bookable

Example:

@room.check_availability!(from: Date.today, to: Date.tomorrow, amount: 2)

Parameters:

  • opts

    The booking options

Returns:

  • true if the bookable is available for given options, otherwise return false



262
263
264
265
266
267
268
# File 'lib/active_bookings/bookable/core.rb', line 262

def check_availability(opts)
  begin
    check_availability!(opts)
  rescue ActiveBookings::AvailabilityError
    false
  end
end

#check_availability!(opts) ⇒ Object

Check availability of current bookable, raising an error if the bookable is not available

Example:

@room.check_availability!(from: Date.today, to: Date.tomorrow, amount: 2)

Parameters:

  • opts

    The booking options

Returns:

  • true if the bookable is available for given options

Raises:

  • ActiveBookings::AvailabilityError if the bookable is not available for given options



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/active_bookings/bookable/core.rb', line 164

def check_availability!(opts)
  # validates options
  self.validate_booking_options!(opts)

  # Capacity check (done first because it doesn't require additional queries)
  if self.booking_opts[:capacity_type] != :none
    # Amount > capacity
    if opts[:amount] > self.capacity
      error = I18n.t('.active_bookings.availability.amount_gt_capacity', model: self.class.to_s)
      raise ActiveBookings::AvailabilityError.new error
    end
  end

  ##
  # Time check
  #
  if self.booking_opts[:time_type] == :range
    time_check_ok = true
    # If it's bookable across recurrences, just check start time and end time
    if self.booking_opts[:bookable_across_occurrences]
      # Check start time
      if !(ActiveBookings::TimeUtils.time_in_schedule?(self.schedule, opts[:time_start]))
        time_check_ok = false
      end
      # Check end time
      if !(ActiveBookings::TimeUtils.time_in_schedule?(self.schedule, opts[:time_end]))
        time_check_ok = false
      end
    # If it's not bookable across recurrences, check if the whole interval is included in an occurrence
    else
      # Check the whole interval
      if !(ActiveBookings::TimeUtils.interval_in_schedule?(self.schedule, opts[:time_start], opts[:time_end]))
        time_check_ok = false
      end
    end
    # If something went wrong
    unless time_check_ok
      error = I18n.t('.active_bookings.availability.unavailable_interval', model: self.class.to_s, time_start: opts[:time_start], time_end: opts[:time_end])
      raise ActiveBookings::AvailabilityError.new error
    end
  end
  if self.booking_opts[:time_type] == :fixed
    if !(ActiveBookings::TimeUtils.time_in_schedule?(self.schedule, opts[:time]))
      error = I18n.t('.active_bookings.availability.unavailable_time', model: self.class.to_s, time: opts[:time])
      raise ActiveBookings::AvailabilityError.new error
    end
  end

  ##
  # Real capacity check (calculated with overlapped bookings)
  #
  overlapped = ActiveBookings::Booking.overlapped(self, opts)
  # If capacity_type is :closed cannot book if already booked (no matter if amount < capacity)
  if (self.booking_opts[:capacity_type] == :closed && !overlapped.empty?)
    error = I18n.t('.active_bookings.availability.already_booked', model: self.class.to_s)
    raise ActiveBookings::AvailabilityError.new error
  end
  # if capacity_type is :open, check if amount <= maximum amount of overlapped booking
  if (self.booking_opts[:capacity_type] == :open && !overlapped.empty?)
    # if time_type is :range, split in sub-intervals and check the maximum sum of amounts against capacity for each sub-interval
    if (self.booking_opts[:time_type] == :range)
      # Map overlapped bookings to a set of intervals with amount
      intervals = overlapped.map { |e| {time_start: e.time_start, time_end: e.time_end, amount: e.amount} }
      # Make subintervals from overlapped bookings and check capacity for each of them
      ActiveBookings::TimeUtils.subintervals(intervals) do |a,b,op|
        case op
        when :open
          res = {amount: a[:amount] + b[:amount]}
        when :close
          res = {amount: a[:amount] - b[:amount]}
        end

        if (res[:amount] >= self.capacity)
          error = I18n.t('.active_bookings.availability.already_booked', model: self.class.to_s)
          raise ActiveBookings::AvailabilityError.new error
        end

        res
      end
    # else, just sum the amounts (fixed times are not intervals and they overlap if are the same)
    else
      if(overlapped.sum(:amount) + opts[:amount] > self.capacity)
        error = I18n.t('.active_bookings.availability.already_booked', model: self.class.to_s)
        raise ActiveBookings::AvailabilityError.new error
      end
    end
  end
  true
end

#validate_booking_options!(opts) ⇒ Object

Check if options passed for booking this Bookable are valid

Parameters:

  • opts

    The booking options

Raises:

  • ActiveBookings::OptionsInvalid if options are not valid



289
290
291
# File 'lib/active_bookings/bookable/core.rb', line 289

def validate_booking_options!(opts)
  self.class.validate_booking_options!(opts)
end