def get_rooms_availability(rooms, start_dt, end_dt, repeat_frequency, repeat_interval): availability = OrderedDict() candidates = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) date_range = sorted(set(cand.start_dt.date() for cand in candidates)) occurrences = get_existing_rooms_occurrences(rooms, start_dt.replace(hour=0, minute=0), end_dt.replace(hour=23, minute=59), repeat_frequency, repeat_interval) blocked_rooms = get_rooms_blockings(rooms, start_dt.date(), end_dt.date()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) conflicts, pre_conflicts = get_rooms_conflicts(rooms, start_dt.replace(tzinfo=None), end_dt.replace(tzinfo=None), repeat_frequency, repeat_interval, blocked_rooms, nonbookable_periods, unbookable_hours) dates = list(candidate.start_dt.date() for candidate in candidates) for room in rooms: room_occurrences = occurrences.get(room.id, []) room_conflicts = conflicts.get(room.id, []) pre_room_conflicts = pre_conflicts.get(room.id, []) pre_bookings = [occ for occ in room_occurrences if not occ.reservation.is_accepted] existing_bookings = [occ for occ in room_occurrences if occ.reservation.is_accepted] room_blocked_rooms = blocked_rooms.get(room.id, []) room_nonbookable_periods = nonbookable_periods.get(room.id, []) room_unbookable_hours = unbookable_hours.get(room.id, []) availability[room.id] = {'room_id': room.id, 'candidates': group_by_occurrence_date(candidates), 'pre_bookings': group_by_occurrence_date(pre_bookings), 'bookings': group_by_occurrence_date(existing_bookings), 'conflicts': group_by_occurrence_date(room_conflicts), 'pre_conflicts': group_by_occurrence_date(pre_room_conflicts), 'blockings': group_blockings(room_blocked_rooms, dates), 'nonbookable_periods': group_nonbookable_periods(room_nonbookable_periods, dates), 'unbookable_hours': room_unbookable_hours} return date_range, availability
def get_room_calendar(start_date, end_date, room_ids, **filters): start_dt = datetime.combine(start_date, time(hour=0, minute=0)) end_dt = datetime.combine(end_date, time(hour=23, minute=59)) query = _bookings_query(dict(filters, **{'start_date': start_dt, 'end_date': end_dt, 'room_ids': room_ids})) query = query.order_by(db.func.indico.natsort(Room.full_name)) rooms = (Room.query .filter(Room.is_active, Room.id.in_(room_ids) if room_ids else True) .options(joinedload('location')) .order_by(db.func.indico.natsort(Room.full_name)) .all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [occ for occ in occurrences if not occ.reservation.is_accepted] existing_bookings = [occ for occ in occurrences if occ.reservation.is_accepted] calendar[room_id].update({ 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) }) return calendar
def get_rooms_availability(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, flexibility): period_days = (end_dt - start_dt).days availability = OrderedDict() candidates = ReservationOccurrence.create_series( start_dt, end_dt, (repeat_frequency, repeat_interval)) date_range = sorted(set(cand.start_dt.date() for cand in candidates)) occurrences = get_existing_rooms_occurrences( rooms, start_dt.replace(hour=0, minute=0), end_dt.replace(hour=23, minute=59), repeat_frequency, repeat_interval) blocked_rooms = get_rooms_blockings(rooms, start_dt.date(), end_dt.date()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods( rooms, start_dt, end_dt) conflicts, pre_conflicts = get_rooms_conflicts( rooms, start_dt.replace(tzinfo=None), end_dt.replace(tzinfo=None), repeat_frequency, repeat_interval, blocked_rooms, nonbookable_periods, unbookable_hours) dates = list(candidate.start_dt.date() for candidate in candidates) for room in rooms: booking_limit_days = room.booking_limit_days or rb_settings.get( 'booking_limit') if period_days > booking_limit_days: continue start_dt = start_dt + timedelta(days=flexibility) end_dt = end_dt + timedelta(days=flexibility) room_occurrences = occurrences.get(room.id, []) room_conflicts = conflicts.get(room.id, []) pre_room_conflicts = pre_conflicts.get(room.id, []) pre_bookings = [ occ for occ in room_occurrences if not occ.reservation.is_accepted ] existing_bookings = [ occ for occ in room_occurrences if occ.reservation.is_accepted ] room_blocked_rooms = blocked_rooms.get(room.id, []) room_nonbookable_periods = nonbookable_periods.get(room.id, []) room_unbookable_hours = unbookable_hours.get(room.id, []) availability[room.id] = { 'room': room, 'candidates': group_by_occurrence_date(candidates), 'pre_bookings': group_by_occurrence_date(pre_bookings), 'bookings': group_by_occurrence_date(existing_bookings), 'conflicts': group_by_occurrence_date(room_conflicts), 'pre_conflicts': group_by_occurrence_date(pre_room_conflicts), 'blockings': group_blockings(room_blocked_rooms, dates), 'nonbookable_periods': group_nonbookable_periods(room_nonbookable_periods, dates), 'unbookable_hours': room_unbookable_hours } return date_range, availability
def get_room_calendar(start_date, end_date, room_ids): start_dt = datetime.combine(start_date, time(hour=0, minute=0)) end_dt = datetime.combine(end_date, time(hour=23, minute=59)) reservation_strategy = contains_eager('reservation') reservation_strategy.noload('room') reservation_strategy.noload('booked_for_user') reservation_strategy.noload('created_by_user') query = (ReservationOccurrence.query.filter( ReservationOccurrence.is_valid).filter( ReservationOccurrence.start_dt >= start_dt, ReservationOccurrence.end_dt <= end_dt).join(Reservation).join(Room).filter( Room.is_active, Room.id.in_(room_ids) if room_ids else True).order_by( db.func.indico.natsort( Room.full_name)).options(reservation_strategy)) rooms = (Room.query.filter( Room.is_active, Room.id.in_(room_ids) if room_ids else True).options( joinedload('location')).order_by( db.func.indico.natsort(Room.full_name)).all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods( rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [ occ for occ in occurrences if not occ.reservation.is_accepted ] existing_bookings = [ occ for occ in occurrences if occ.reservation.is_accepted ] calendar[room_id].update({ 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) }) return calendar
def get_room_details_availability(room, start_dt, end_dt): dates = [d.date() for d in iterdays(start_dt, end_dt)] occurrences = get_existing_room_occurrences(room, start_dt, end_dt, RepeatFrequency.DAY, 1) pre_bookings = [ occ for occ in occurrences if not occ.reservation.is_accepted ] bookings = [occ for occ in occurrences if occ.reservation.is_accepted] blocked_rooms = get_rooms_blockings([room], start_dt.date(), end_dt.date()) nonoverridable_blocked_rooms = group_blocked_rooms( filter_blocked_rooms(blocked_rooms, nonoverridable_only=True, explicit=True)).get(room.id, []) overridable_blocked_rooms = group_blocked_rooms( filter_blocked_rooms(blocked_rooms, overridable_only=True, explicit=True)).get(room.id, []) unbookable_hours = get_rooms_unbookable_hours([room]).get(room.id, []) nonbookable_periods = get_rooms_nonbookable_periods([room], start_dt, end_dt).get( room.id, []) availability = [] for day in dates: iso_day = day.isoformat() nb_periods = serialize_nonbookable_periods( group_nonbookable_periods(nonbookable_periods, dates)).get(iso_day) availability.append({ 'bookings': serialize_occurrences( group_by_occurrence_date(bookings)).get(iso_day), 'pre_bookings': serialize_occurrences( group_by_occurrence_date(pre_bookings)).get(iso_day), 'blockings': serialize_blockings( group_blockings(nonoverridable_blocked_rooms, dates)).get(iso_day), 'overridable_blockings': (serialize_blockings( group_blockings(overridable_blocked_rooms, dates)).get(iso_day)), 'nonbookable_periods': nb_periods, 'unbookable_hours': serialize_unbookable_hours(unbookable_hours), 'day': iso_day, }) return sorted(availability, key=itemgetter('day'))
def _process(self, args): room = Room.get_one(args.pop('room_id')) user_id = args.pop('user_id', None) booked_for = User.get_one(user_id) if user_id else session.user is_prebooking = args.pop('is_prebooking') # Check that the booking is not longer than allowed booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(args['start_dt'], args['end_dt'], booking_limit_days): msg = (_('Bookings for the room "{}" may not be longer than {} days') .format(room.name, booking_limit_days)) raise ExpectedError(msg) try: resv = Reservation.create_from_data(room, dict(args, booked_for_user=booked_for), session.user, prebook=is_prebooking) db.session.flush() except NoReportError as e: db.session.rollback() raise ExpectedError(unicode(e)) serialized_occurrences = serialize_occurrences(group_by_occurrence_date(resv.occurrences.all())) if is_prebooking: data = {'pre_bookings': serialized_occurrences} else: data = {'bookings': serialized_occurrences} return jsonify(room_id=room.id, **data)
def _process(self, args): room = Room.get_one(args.pop('room_id')) user_id = args.pop('user_id', None) booked_for = User.get_one(user_id) if user_id else session.user is_prebooking = args.pop('is_prebooking') # Check that the booking is not longer than allowed booking_limit_days = room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(args['start_dt'], args['end_dt'], booking_limit_days): msg = (_('Bookings for the room "{}" may not be longer than {} days') .format(room.name, booking_limit_days)) raise ExpectedError(msg) try: resv = Reservation.create_from_data(room, dict(args, booked_for_user=booked_for), session.user, prebook=is_prebooking) db.session.flush() except NoReportError as e: db.session.rollback() raise ExpectedError(unicode(e)) serialized_occurrences = serialize_occurrences(group_by_occurrence_date(resv.occurrences.all())) if is_prebooking: data = {'pre_bookings': serialized_occurrences} else: data = {'bookings': serialized_occurrences} return jsonify(room_id=room.id, booking=reservation_details_schema.dump(resv).data, calendar_data=data)
def get_recurring_booking_suggestions(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, limit=None): data = [] booking_days = end_dt - start_dt booking_length = booking_days.days + 1 candidates = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) blocked_rooms = get_rooms_blockings(rooms, start_dt.date(), end_dt.date()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) conflicts = get_rooms_conflicts(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, blocked_rooms, nonbookable_periods, unbookable_hours)[0] for room in rooms: if limit and len(data) == limit: break suggestions = {} booking_limit = room.booking_limit_days or rb_settings.get('booking_limit') limit_exceeded = booking_limit is not None and booking_limit < booking_length if limit_exceeded: excess_days = booking_length - booking_limit suggestions['shorten'] = excess_days if not limit_exceeded: number_of_conflicting_days = len(group_by_occurrence_date(conflicts.get(room.id, []))) if number_of_conflicting_days and number_of_conflicting_days < len(candidates): suggestions['skip'] = number_of_conflicting_days if suggestions: data.append({'room': room, 'suggestions': suggestions}) return data
def _process(self): args = self.args args.setdefault('booked_for_user', session.user) if not is_booking_start_within_grace_period(args['start_dt'], session.user, args['admin_override_enabled']): raise ExpectedError(_('You cannot create a booking which starts in the past')) # Check that the booking is not longer than allowed booking_limit_days = self.room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(args['start_dt'], args['end_dt'], booking_limit_days): msg = (_('Bookings for the room "{}" may not be longer than {} days') .format(self.room.name, booking_limit_days)) raise ExpectedError(msg) try: resv = Reservation.create_from_data(self.room, args, session.user, prebook=self.prebook) if args.get('link_type') is not None and args.get('link_id') is not None: self._link_booking(resv, args['link_type'], args['link_id'], args['link_back']) db.session.flush() except NoReportError as e: db.session.rollback() raise ExpectedError(unicode(e)) serialized_occurrences = serialize_occurrences(group_by_occurrence_date(resv.occurrences.all())) if self.prebook: data = {'pre_bookings': serialized_occurrences} else: data = {'bookings': serialized_occurrences} return jsonify(room_id=self.room.id, booking=reservation_details_schema.dump(resv), calendar_data=data)
def _process(self): args = self.args user_id = args.pop('user_id', None) booked_for = User.get_one(user_id, is_deleted=False) if user_id else session.user # Check that the booking is not longer than allowed booking_limit_days = self.room.booking_limit_days or rb_settings.get('booking_limit') if not self._validate_room_booking_limit(args['start_dt'], args['end_dt'], booking_limit_days): msg = (_('Bookings for the room "{}" may not be longer than {} days') .format(self.room.name, booking_limit_days)) raise ExpectedError(msg) try: resv = Reservation.create_from_data(self.room, dict(args, booked_for_user=booked_for), session.user, prebook=self.prebook) if args.get('link_type') is not None and args.get('link_id') is not None: self._link_booking(resv, args['link_type'], args['link_id'], args['link_back']) db.session.flush() except NoReportError as e: db.session.rollback() raise ExpectedError(unicode(e)) serialized_occurrences = serialize_occurrences(group_by_occurrence_date(resv.occurrences.all())) if self.prebook: data = {'pre_bookings': serialized_occurrences} else: data = {'bookings': serialized_occurrences} return jsonify(room_id=self.room.id, booking=reservation_details_schema.dump(resv).data, calendar_data=data)
def _process(self): room_details = room_details_schema.dump(self.room).data start_dt = date.today() end_dt = start_dt + timedelta(days=4) last_bookings = group_by_occurrence_date( get_existing_room_occurrences(self.room, start_dt, end_dt, only_accepted=True)) range_bookings = { day.date(): last_bookings.get(day.date()) for day in iterdays(start_dt, end_dt) } bookings = [{ 'availability': { 'usage': bookings or [] }, 'label': dt, 'conflictIndicator': False, 'id': dt } for dt, bookings in serialize_occurrences( range_bookings).iteritems()] room_details['bookings'] = sorted(bookings, key=itemgetter('id')) return jsonify(room_details)
def get_number_of_skipped_days_for_rooms(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, limit=None): data = [] candidates = ReservationOccurrence.create_series( start_dt, end_dt, (repeat_frequency, repeat_interval)) blocked_rooms = get_rooms_blockings(rooms, start_dt.date(), end_dt.date()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods( rooms, start_dt, end_dt) conflicts, _ = get_rooms_conflicts(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, blocked_rooms, nonbookable_periods, unbookable_hours) for room in rooms: if limit and len(data) == limit: break number_of_conflicting_days = len( group_by_occurrence_date(conflicts.get(room.id, []))) if number_of_conflicting_days and number_of_conflicting_days < len( candidates): data.append({ 'room': room, 'suggestions': { 'skip': number_of_conflicting_days } }) return sorted(data, key=lambda item: item['suggestions']['skip'])
def get_room_calendar(day, room_ids): start_dt = datetime.combine(day, time(hour=0, minute=0)) end_dt = datetime.combine(day, time(hour=23, minute=59)) reservation_strategy = contains_eager('reservation') reservation_strategy.noload('room') reservation_strategy.noload('booked_for_user') reservation_strategy.noload('created_by_user') query = (ReservationOccurrence.query .filter(ReservationOccurrence.is_valid) .filter(ReservationOccurrence.start_dt >= start_dt, ReservationOccurrence.end_dt <= end_dt) .join(Reservation) .join(Room) .filter(Room.is_active, Room.id.in_(room_ids) if room_ids else True) .order_by(db.func.indico.natsort(Room.full_name)) .options(reservation_strategy)) rooms = (Room.query .filter(Room.is_active, Room.id.in_(room_ids) if room_ids else True) .options(joinedload('location')) .order_by(db.func.indico.natsort(Room.full_name)) .all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [occ for occ in occurrences if not occ.reservation.is_accepted] existing_bookings = [occ for occ in occurrences if occ.reservation.is_accepted] calendar[room_id].update({ 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) }) return calendar
def get_room_bookings(room, start_dt, end_dt, skip_booking_id=None): bookings = get_existing_room_occurrences(room, start_dt, end_dt, RepeatFrequency.DAY, 1, only_accepted=True, skip_booking_id=skip_booking_id) return serialize_occurrences(group_by_occurrence_date(bookings))
def get_active_bookings(limit, start_dt, last_reservation_id=None, **filters): criteria = [ReservationOccurrence.start_dt > start_dt] if last_reservation_id is not None: criteria.append(db.and_(db.cast(ReservationOccurrence.start_dt, db.Date) >= start_dt, ReservationOccurrence.reservation_id > last_reservation_id)) query = (_bookings_query(filters) .filter(db.or_(*criteria)) .order_by(ReservationOccurrence.start_dt, ReservationOccurrence.reservation_id, db.func.indico.natsort(Room.full_name)) .limit(limit)) bookings, total = with_total_rows(query) rows_left = total - limit if total > limit else total return group_by_occurrence_date(query, sort_by=lambda obj: (obj.start_dt, obj.reservation_id)), rows_left
def get_number_of_skipped_days_for_rooms(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, limit=None): data = [] candidates = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval)) blocked_rooms = get_rooms_blockings(rooms, start_dt.date(), end_dt.date()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) conflicts, _ = get_rooms_conflicts(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, blocked_rooms, nonbookable_periods, unbookable_hours) for room in rooms: if limit and len(data) == limit: break number_of_conflicting_days = len(group_by_occurrence_date(conflicts.get(room.id, []))) if number_of_conflicting_days and number_of_conflicting_days < len(candidates): data.append({'room': room, 'suggestions': {'skip': number_of_conflicting_days}}) return sorted(data, key=lambda item: item['suggestions']['skip'])
def get_active_bookings(limit, start_dt, last_reservation_id=None, **filters): criteria = [ReservationOccurrence.start_dt > start_dt] if last_reservation_id is not None: criteria.append( db.and_( db.cast(ReservationOccurrence.start_dt, db.Date) >= start_dt, ReservationOccurrence.reservation_id > last_reservation_id)) query = (_bookings_query(filters).filter(db.or_(*criteria)).order_by( ReservationOccurrence.start_dt, ReservationOccurrence.reservation_id, db.func.indico.natsort(Room.full_name)).limit(limit)) bookings, total = with_total_rows(query) rows_left = total - limit if total > limit else total return group_by_occurrence_date( query, sort_by=lambda obj: (obj.start_dt, obj.reservation_id)), rows_left
def get_room_details_availability(room, start_dt, end_dt): dates = [d.date() for d in iterdays(start_dt, end_dt)] bookings = get_existing_room_occurrences(room, start_dt, end_dt, RepeatFrequency.DAY, 1, only_accepted=True) blockings = get_rooms_blockings([room], start_dt.date(), end_dt.date()).get(room.id, []) unbookable_hours = get_rooms_unbookable_hours([room]).get(room.id, []) nonbookable_periods = get_rooms_nonbookable_periods([room], start_dt, end_dt).get(room.id, []) availability = [] for day in dates: iso_day = day.isoformat() availability.append({ 'bookings': serialize_occurrences(group_by_occurrence_date(bookings)).get(iso_day), 'blockings': serialize_blockings(group_blockings(blockings, dates)).get(iso_day), 'nonbookable_periods': serialize_nonbookable_periods( group_nonbookable_periods(nonbookable_periods, dates)).get(iso_day), 'unbookable_hours': serialize_unbookable_hours(unbookable_hours), 'day': iso_day, }) return sorted(availability, key=itemgetter('day'))
def get_room_details_availability(room, start_dt, end_dt): dates = [d.date() for d in iterdays(start_dt, end_dt)] bookings = get_existing_room_occurrences(room, start_dt, end_dt, RepeatFrequency.DAY, 1, only_accepted=True) blockings = get_rooms_blockings([room], start_dt.date(), end_dt.date()).get(room.id, []) unbookable_hours = get_rooms_unbookable_hours([room]).get(room.id, []) nonbookable_periods = get_rooms_nonbookable_periods([room], start_dt, end_dt).get(room.id, []) availability = [] for day in dates: iso_day = day.isoformat() nb_periods = serialize_nonbookable_periods(group_nonbookable_periods(nonbookable_periods, dates)).get(iso_day) availability.append({ 'bookings': serialize_occurrences(group_by_occurrence_date(bookings)).get(iso_day), 'blockings': serialize_blockings(group_blockings(blockings, dates)).get(iso_day), 'nonbookable_periods': nb_periods, 'unbookable_hours': serialize_unbookable_hours(unbookable_hours), 'day': iso_day, }) return sorted(availability, key=itemgetter('day'))
def get_booking_occurrences(booking): date_range = sorted( set(cand.start_dt.date() for cand in booking.occurrences)) occurrences = group_by_occurrence_date(booking.occurrences) return date_range, occurrences
def get_room_calendar(start_date, end_date, room_ids, include_inactive=False, **filters): start_dt = datetime.combine(start_date, time(hour=0, minute=0)) end_dt = datetime.combine(end_date, time(hour=23, minute=59)) query = _bookings_query( dict(filters, start_dt=start_dt, end_dt=end_dt, room_ids=room_ids, include_inactive=include_inactive)) query = query.order_by(db.func.indico.natsort(Room.full_name)) rooms = (Room.query.filter( Room.is_active, Room.id.in_(room_ids) if room_ids else True).options( joinedload('location')).order_by( db.func.indico.natsort(Room.full_name)).all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods( rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [ occ for occ in occurrences if occ.reservation.is_pending ] existing_bookings = [ occ for occ in occurrences if not occ.reservation.is_pending and occ.is_valid ] additional_data = { 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) } if include_inactive: additional_data.update({ 'cancellations': group_by_occurrence_date(occ for occ in occurrences if occ.is_cancelled), 'rejections': group_by_occurrence_date(occ for occ in occurrences if occ.is_rejected) }) calendar[room_id].update(additional_data) return calendar
def get_rooms_availability(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, skip_conflicts_with=None, admin_override_enabled=False): availability = OrderedDict() candidates = ReservationOccurrence.create_series( start_dt, end_dt, (repeat_frequency, repeat_interval)) date_range = sorted(set(cand.start_dt.date() for cand in candidates)) occurrences = get_existing_rooms_occurrences( rooms, start_dt.replace(hour=0, minute=0), end_dt.replace(hour=23, minute=59), repeat_frequency, repeat_interval) blocked_rooms = get_rooms_blockings(rooms, start_dt.date(), end_dt.date()) nonoverridable_blocked_rooms = group_blocked_rooms( filter_blocked_rooms(blocked_rooms, nonoverridable_only=True, explicit=True)) overridable_blocked_rooms = group_blocked_rooms( filter_blocked_rooms(blocked_rooms, overridable_only=True, explicit=True)) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods( rooms, start_dt, end_dt) conflicts, pre_conflicts, conflicting_candidates = get_rooms_conflicts( rooms, start_dt.replace(tzinfo=None), end_dt.replace(tzinfo=None), repeat_frequency, repeat_interval, nonoverridable_blocked_rooms, nonbookable_periods, unbookable_hours, skip_conflicts_with, allow_admin=admin_override_enabled) dates = list(candidate.start_dt.date() for candidate in candidates) for room in rooms: room_occurrences = occurrences.get(room.id, []) room_conflicting_candidates = conflicting_candidates.get(room.id, []) room_conflicts = conflicts.get(room.id, []) pre_room_conflicts = pre_conflicts.get(room.id, []) pre_bookings = [ occ for occ in room_occurrences if not occ.reservation.is_accepted ] existing_bookings = [ occ for occ in room_occurrences if occ.reservation.is_accepted ] room_nonoverridable_blocked_rooms = nonoverridable_blocked_rooms.get( room.id, []) room_overridable_blocked_rooms = overridable_blocked_rooms.get( room.id, []) room_nonbookable_periods = nonbookable_periods.get(room.id, []) room_unbookable_hours = unbookable_hours.get(room.id, []) room_candidates = get_room_candidates(candidates, room_conflicts, pre_room_conflicts) availability[room.id] = { 'room_id': room.id, 'candidates': group_by_occurrence_date(room_candidates), 'conflicting_candidates': group_by_occurrence_date(room_conflicting_candidates), 'pre_bookings': group_by_occurrence_date(pre_bookings), 'bookings': group_by_occurrence_date(existing_bookings), 'conflicts': group_by_occurrence_date(room_conflicts), 'pre_conflicts': group_by_occurrence_date(pre_room_conflicts), 'blockings': group_blockings(room_nonoverridable_blocked_rooms, dates), 'overridable_blockings': group_blockings(room_overridable_blocked_rooms, dates), 'nonbookable_periods': group_nonbookable_periods(room_nonbookable_periods, dates), 'unbookable_hours': room_unbookable_hours } return date_range, availability
def get_booking_occurrences(booking): date_range = sorted(set(cand.start_dt.date() for cand in booking.occurrences)) occurrences = group_by_occurrence_date(booking.occurrences) return date_range, occurrences