Module: ActsAsBookable::Bookable::Core::InstanceMethods

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

Instance Method Summary collapse

Instance Method Details

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

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

Example:

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

Parameters:

  • booker

    The booker model

  • opts (defaults to: {})

    The booking options



269
270
271
# File 'lib/acts_as_bookable/bookable/core.rb', line 269

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

#booker?Boolean

Returns:

  • (Boolean)


283
284
285
# File 'lib/acts_as_bookable/bookable/core.rb', line 283

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



252
253
254
255
256
257
258
# File 'lib/acts_as_bookable/bookable/core.rb', line 252

def check_availability(opts)
  begin
    check_availability!(opts)
  rescue ActsAsBookable::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:

  • ActsAsBookable::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
# File 'lib/acts_as_bookable/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
      raise ActsAsBookable::AvailabilityError.new ActsAsBookable::T.er('.availability.amount_gt_capacity', model: self.class.to_s)
    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 !(ActsAsBookable::TimeUtils.time_in_schedule?(self.schedule, opts[:time_start]))
        time_check_ok = false
      end
      # Check end time
      if !(ActsAsBookable::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 !(ActsAsBookable::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
      raise ActsAsBookable::AvailabilityError.new ActsAsBookable::T.er('.availability.unavailable_interval', model: self.class.to_s, time_start: opts[:time_start], time_end: opts[:time_end])
    end
  end
  if self.booking_opts[:time_type] == :fixed
    if !(ActsAsBookable::TimeUtils.time_in_schedule?(self.schedule, opts[:time]))
      raise ActsAsBookable::AvailabilityError.new ActsAsBookable::T.er('.availability.unavailable_time', model: self.class.to_s, time: opts[:time])
    end
  end

  ##
  # Real capacity check (calculated with overlapped bookings)
  #
  overlapped = ActsAsBookable::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?)
    raise ActsAsBookable::AvailabilityError.new ActsAsBookable::T.er('.availability.already_booked', model: self.class.to_s)
  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
      ActsAsBookable::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
        raise ActsAsBookable::AvailabilityError.new ActsAsBookable::T.er('.availability.already_booked', model: self.class.to_s) if (res[:amount] > self.capacity)
        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)
        raise ActsAsBookable::AvailabilityError.new ActsAsBookable::T.er('.availability.already_booked', model: self.class.to_s)
      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:

  • ActsAsBookable::OptionsInvalid if options are not valid



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

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