def is_parallel(self, in_session=False): siblings = self.siblings if not in_session else self.session_siblings for sibling in siblings: if overlaps((self.start_dt, self.end_dt), (sibling.start_dt, sibling.end_dt)): return True return False
def overlaps(self, occurrence, skip_self=False): if self.reservation and occurrence.reservation and self.reservation.room_id != occurrence.reservation.room_id: raise ValueError( 'ReservationOccurrence objects of different rooms') if skip_self and self.reservation and occurrence.reservation and self.reservation == occurrence.reservation: return False return date_time.overlaps((self.start_dt, self.end_dt), (occurrence.start_dt, occurrence.end_dt))
def find_requests(talks=False, from_dt=None, to_dt=None, services=None, states=None): """Finds requests matching certain criteria. :param talks: if True, yield ``(request, contrib, start_dt)`` tuples instead of just requests, i.e. the same request may be yielded multiple times :param from_dt: earliest event/contribution to include :param to_dt: latest event/contribution to include :param states: acceptable request states (by default anything but withdrawn) :param services: set of services that must have been requested """ from indico_audiovisual.definition import AVRequest query = Request.query.filter_by(type=AVRequest.name) if states is not None: query = query.filter(Request.state.in_(states)) else: query = query.filter(Request.state != RequestState.withdrawn) if from_dt is not None or to_dt is not None: query = query.join(Event).filter(Event.happens_between(from_dt, to_dt)) # We only want the latest one for each event query = limit_groups(query, Request, Request.event_id, Request.created_dt.desc(), 1) query = query.options(joinedload('event')) for req in query: event = req.event # Skip requests which do not have the requested services or are outside the date range if services and not (set(req.data['services']) & services): continue elif to_dt is not None and event.start_dt > to_dt: continue if not talks: yield req continue # Lectures don't have contributions so we use the event info directly if event.type == 'lecture': yield req, event, event.start_dt continue contribs = [x[0] for x in get_selected_contributions(req)] for contrib in contribs: contrib_start = _get_start_date(contrib) contrib_end = _get_end_date(contrib) if from_dt is not None and to_dt is not None and not overlaps( (contrib_start, contrib_end), (from_dt, to_dt)): continue elif from_dt and _get_start_date(contrib) < from_dt: continue elif to_dt and _get_end_date(contrib) > to_dt: continue yield req, contrib, _get_start_date(contrib)
def happens_between(self, from_dt=None, to_dt=None): """Check whether the event takes place within two dates""" if from_dt is not None and to_dt is not None: # any event that takes place during the specified range return overlaps((self.start_dt, self.end_dt), (from_dt, to_dt), inclusive=True) elif from_dt is not None: # any event that starts on/after the specified date return self.start_dt >= from_dt elif to_dt is not None: # any event that ends on/before the specifed date return self.end_dt <= to_dt else: return True
def happens_between(self, from_dt=None, to_dt=None): """Check whether the event takes place within two dates.""" if from_dt is not None and to_dt is not None: # any event that takes place during the specified range return overlaps((self.start_dt, self.end_dt), (from_dt, to_dt), inclusive=True) elif from_dt is not None: # any event that starts on/after the specified date return self.start_dt >= from_dt elif to_dt is not None: # any event that ends on/before the specifed date return self.end_dt <= to_dt else: return True
def _produce_candidate_bars(self): blocked_rooms_by_room = MultiDict((br.room_id, br) for br in self.blocked_rooms) for room in self.rooms: blocked_rooms = blocked_rooms_by_room.getlist(room.id) for (start_dt, end_dt), candidates in self.candidates.iteritems(): # Check if there's a blocking for blocked_room in blocked_rooms: blocking = blocked_room.blocking if overlaps((start_dt.date(), end_dt.date()), (blocking.start_date, blocking.end_date), inclusive=True): break else: # In case we didn't break the loop due to a match blocking = None for cand in candidates: bar = Bar.from_candidate(cand, room.id, start_dt, end_dt, blocking) self.bars.append(bar)
def get_duration_suggestion(occurrences, from_, to): old_duration = (to - from_).total_seconds() / 60 duration = old_duration all_occurrences_overlap = all(overlaps((from_, to), occ) for occ in occurrences) # Don't calculate duration suggestion, if there are at least # two existing bookings conflicting with the specified dates if all_occurrences_overlap and len(occurrences) > 1: return for (start, end) in occurrences: if start <= from_: continue if from_ < end < to: if start > from_: continue duration -= (end - from_).total_seconds() / 60 if from_ < start < to: if end < to: continue duration -= (to - start).total_seconds() / 60 return abs(duration - old_duration) if old_duration != duration else None
def check_room_available(room, start_dt, end_dt): occurrences = get_existing_room_occurrences(room, start_dt, end_dt, allow_overlapping=True) prebookings = [ occ for occ in occurrences if not occ.reservation.is_accepted ] bookings = [occ for occ in occurrences if occ.reservation.is_accepted] unbookable_hours = get_rooms_unbookable_hours([room]) hours_overlap = any( hours for hours in unbookable_hours if overlaps((start_dt.time(), end_dt.time()), (hours.start_time, hours.end_time))) nonbookable_periods = any( get_rooms_nonbookable_periods([room], start_dt, end_dt)) blockings = get_rooms_blockings([room], start_dt, end_dt).get(room.id, []) blocked_for_user = any(blocking for blocking in blockings if not blocking.blocking.can_be_overridden( session.user, room, explicit_only=True)) user_booking = any(booking for booking in bookings if booking.reservation.booked_for_id == session.user.id) user_prebooking = any( prebooking for prebooking in prebookings if prebooking.reservation.booked_for_id == session.user.id) return { 'can_book': room.can_book(session.user, allow_admin=False), 'can_prebook': room.can_prebook(session.user, allow_admin=False), 'conflict_booking': any(bookings), 'conflict_prebooking': any(prebookings), 'unbookable': (hours_overlap or nonbookable_periods or blocked_for_user), 'user_booking': user_booking, 'user_prebooking': user_prebooking, }
def check_room_available(room, start_dt, end_dt): occurrences = get_existing_room_occurrences(room, start_dt, end_dt, allow_overlapping=True) prebookings = [occ for occ in occurrences if not occ.reservation.is_accepted] bookings = [occ for occ in occurrences if occ.reservation.is_accepted] unbookable_hours = get_rooms_unbookable_hours([room]) hours_overlap = any(hours for hours in unbookable_hours if overlaps((start_dt.time(), end_dt.time()), (hours.start_time, hours.end_time))) nonbookable_periods = any(get_rooms_nonbookable_periods([room], start_dt, end_dt)) blocked_rooms = get_rooms_blockings([room], start_dt, end_dt) nonoverridable_blocked_rooms = filter_blocked_rooms(blocked_rooms, nonoverridable_only=True, explicit=True) blocked_for_user = any(nonoverridable_blocked_rooms) user_booking = any(booking for booking in bookings if booking.reservation.booked_for_id == session.user.id) user_prebooking = any(prebooking for prebooking in prebookings if prebooking.reservation.booked_for_id == session.user.id) return { 'can_book': room.can_book(session.user, allow_admin=False), 'can_prebook': room.can_prebook(session.user, allow_admin=False), 'conflict_booking': any(bookings), 'conflict_prebooking': any(prebookings), 'unbookable': (hours_overlap or nonbookable_periods or blocked_for_user), 'user_booking': user_booking, 'user_prebooking': user_prebooking, }
def overlaps(self, occurrence, skip_self=False): if self.reservation and occurrence.reservation and self.reservation.room_id != occurrence.reservation.room_id: raise ValueError('ReservationOccurrence objects of different rooms') if skip_self and self.reservation and occurrence.reservation and self.reservation == occurrence.reservation: return False return date_time.overlaps((self.start_dt, self.end_dt), (occurrence.start_dt, occurrence.end_dt))