def filter_available(start_dt,
                      end_dt,
                      repetition,
                      include_pre_bookings=True,
                      include_pending_blockings=True):
     """Returns a SQLAlchemy filter criterion ensuring that the room is available during the given time."""
     # Check availability against reservation occurrences
     dummy_occurrences = ReservationOccurrence.create_series(
         start_dt, end_dt, repetition)
     overlap_criteria = ReservationOccurrence.filter_overlap(
         dummy_occurrences)
     reservation_criteria = [
         Reservation.room_id == Room.id, ReservationOccurrence.is_valid,
         overlap_criteria
     ]
     if not include_pre_bookings:
         reservation_criteria.append(Reservation.is_accepted)
     occurrences_filter = Reservation.occurrences.any(
         and_(*reservation_criteria))
     # Check availability against blockings
     if include_pending_blockings:
         valid_states = (BlockedRoom.State.accepted,
                         BlockedRoom.State.pending)
     else:
         valid_states = (BlockedRoom.State.accepted, )
     blocking_criteria = [
         BlockedRoom.blocking_id == Blocking.id,
         BlockedRoom.state.in_(valid_states),
         Blocking.start_date <= start_dt.date(),
         Blocking.end_date >= end_dt.date()
     ]
     blockings_filter = Room.blocked_rooms.any(and_(*blocking_criteria))
     return ~occurrences_filter & ~blockings_filter
def test_create_series(creation_params):
    for occ1, occ2 in izip(
            list(
                ReservationOccurrence.iter_create_occurrences(
                    **creation_params)),
            ReservationOccurrence.create_series(**creation_params)):
        assert occ1.start_dt == occ2.start_dt
        assert occ1.end_dt == occ2.end_dt
    def _get_all_conflicts(self, room, form, reservation_id=None):
        conflicts = defaultdict(list)
        pre_conflicts = defaultdict(list)

        candidates = ReservationOccurrence.create_series(
            form.start_dt.data, form.end_dt.data,
            (form.repeat_frequency.data, form.repeat_interval.data))
        occurrences = ReservationOccurrence.find_overlapping_with(
            room, candidates, reservation_id).all()

        for cand in candidates:
            for occ in occurrences:
                if cand.overlaps(occ):
                    if occ.reservation.is_accepted:
                        conflicts[cand].append(occ)
                    else:
                        pre_conflicts[cand].append(occ)

        return conflicts, pre_conflicts
    def _get_all_occurrences(self,
                             room_ids,
                             form,
                             flexible_days=0,
                             reservation_id=None):
        start_dt = form.start_dt.data
        end_dt = form.end_dt.data
        repeat_frequency = form.repeat_frequency.data
        repeat_interval = form.repeat_interval.data
        day_start_dt = datetime.combine(start_dt.date(), time())
        day_end_dt = datetime.combine(end_dt.date(), time(23, 59))
        flexible_start_dt = day_start_dt - timedelta(days=flexible_days)
        flexible_end_dt = day_end_dt + timedelta(days=flexible_days)

        occurrences = ReservationOccurrence.find(
            Reservation.room_id.in_(room_ids),
            Reservation.id != reservation_id,
            ReservationOccurrence.start_dt >= flexible_start_dt,
            ReservationOccurrence.end_dt <= flexible_end_dt,
            ReservationOccurrence.is_valid,
            _join=ReservationOccurrence.reservation,
            _eager=ReservationOccurrence.reservation).options(
                ReservationOccurrence.NO_RESERVATION_USER_STRATEGY).all()

        candidates = {}
        for days in xrange(-flexible_days, flexible_days + 1):
            offset = timedelta(days=days)
            series_start = start_dt + offset
            series_end = end_dt + offset
            if series_start < flexible_start_dt:
                continue
            candidates[series_start,
                       series_end] = ReservationOccurrence.create_series(
                           series_start, series_end,
                           (repeat_frequency, repeat_interval))
        return occurrences, candidates