Ejemplo n.º 1
0
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 = group_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
Ejemplo n.º 2
0
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'))
Ejemplo n.º 3
0
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'))
Ejemplo n.º 4
0
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 = group_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
Ejemplo n.º 5
0
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))
    bookings = query.order_by(db.func.indico.natsort(Room.full_name)).all()
    rooms = set()
    if room_ids:
        rooms = set(Room.query
                    .filter(~Room.is_deleted, Room.id.in_(room_ids))
                    .options(joinedload('location')))

    rooms.update(b.reservation.room for b in bookings)
    rooms = sorted(rooms, key=lambda r: natural_sort_key(r.full_name))
    occurrences_by_room = groupby(bookings, attrgetter('reservation.room_id'))
    unbookable_hours = get_rooms_unbookable_hours(rooms)
    nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt)
    blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt)
    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))
    dates = [d.date() for d in iterdays(start_dt, end_dt)]

    calendar = {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(nonoverridable_blocked_rooms.get(room.id, []), dates),
        'overridable_blockings': group_blockings(overridable_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]
        concurrent_pre_bookings = get_concurrent_pre_bookings(pre_bookings)

        additional_data = {
            'bookings': group_by_occurrence_date(existing_bookings),
            'pre_bookings': group_by_occurrence_date(pre_bookings),
            'concurrent_pre_bookings': group_by_occurrence_date(concurrent_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
Ejemplo n.º 6
0
def get_rooms_availability(rooms, start_dt, end_dt, repeat_frequency, repeat_interval, skip_conflicts_with=None,
                           admin_override_enabled=False, skip_past_conflicts=False):
    availability = {}
    candidates = ReservationOccurrence.create_series(start_dt, end_dt, (repeat_frequency, repeat_interval))
    date_range = sorted({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, skip_past_conflicts=skip_past_conflicts
    )
    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]
        concurrent_pre_bookings = get_concurrent_pre_bookings(pre_bookings) if pre_bookings else []
        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)
        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),
                                 'concurrent_pre_bookings': group_by_occurrence_date(concurrent_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
Ejemplo n.º 7
0
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_deleted, 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)
    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))
    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(nonoverridable_blocked_rooms.get(room.id, []), dates),
        'overridable_blockings': group_blockings(overridable_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
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
def get_single_booking_suggestions(rooms, start_dt, end_dt, limit=None):
    data = []
    new_start_dt = start_dt - timedelta(minutes=BOOKING_TIME_DIFF)
    new_end_dt = end_dt + timedelta(minutes=BOOKING_TIME_DIFF)
    nonbookable_periods = get_rooms_nonbookable_periods(
        rooms, start_dt, end_dt)
    rooms = [room for room in rooms if room.id not in nonbookable_periods]

    if not rooms:
        return data

    unbookable_hours = get_rooms_unbookable_hours(rooms)
    rooms_occurrences = get_existing_rooms_occurrences(rooms,
                                                       new_start_dt,
                                                       new_end_dt,
                                                       RepeatFrequency.NEVER,
                                                       None,
                                                       allow_overlapping=True)
    for room in rooms:
        if limit and len(data) == limit:
            break

        suggestions = {}
        taken_periods = [(occ.start_dt, occ.end_dt)
                         for occ in rooms_occurrences.get(room.id, [])]
        if room.id in unbookable_hours:
            taken_periods.extend((datetime.combine(start_dt, uh.start_time),
                                  datetime.combine(end_dt, uh.end_time))
                                 for uh in unbookable_hours[room.id])

        taken_periods = sorted(taken_periods)
        suggested_time = get_start_time_suggestion(taken_periods, start_dt,
                                                   end_dt)
        if suggested_time:
            suggested_time_change = (suggested_time -
                                     start_dt).total_seconds() / 60
            if suggested_time_change and abs(
                    suggested_time_change) <= BOOKING_TIME_DIFF:
                suggestions['time'] = suggested_time_change

        duration_suggestion = get_duration_suggestion(taken_periods, start_dt,
                                                      end_dt)
        original_duration = (end_dt - start_dt).total_seconds() / 60
        if duration_suggestion and duration_suggestion <= DURATION_FACTOR * original_duration:
            suggestions['duration'] = duration_suggestion
        if suggestions:
            data.append({'room': room, 'suggestions': suggestions})
    return data
Ejemplo n.º 10
0
def serialize_booking_details(booking):
    from indico.modules.rb.operations.blockings import filter_blocked_rooms, get_rooms_blockings, group_blocked_rooms
    from indico.modules.rb.operations.bookings import (get_booking_occurrences, get_existing_room_occurrences,
                                                       group_blockings, group_nonbookable_periods)
    from indico.modules.rb.operations.misc import get_rooms_nonbookable_periods, get_rooms_unbookable_hours
    from indico.modules.rb.schemas import reservation_details_schema, reservation_occurrences_schema_with_permissions

    attributes = reservation_details_schema.dump(booking)
    date_range, occurrences = get_booking_occurrences(booking)
    booking_details = dict(attributes)
    occurrences_by_type = dict(bookings={}, cancellations={}, rejections={}, other={}, blockings={},
                               unbookable_hours={}, nonbookable_periods={}, overridable_blockings={})
    booking_details['occurrences'] = occurrences_by_type
    booking_details['date_range'] = [dt.isoformat() for dt in date_range]
    for dt, [occ] in occurrences.iteritems():
        serialized_occ = reservation_occurrences_schema_with_permissions.dump([occ])
        if occ.is_cancelled:
            occurrences_by_type['cancellations'][dt.isoformat()] = serialized_occ
        elif occ.is_rejected:
            occurrences_by_type['rejections'][dt.isoformat()] = serialized_occ
        occurrences_by_type['bookings'][dt.isoformat()] = serialized_occ if occ.is_valid else []

    start_dt = datetime.combine(booking.start_dt, time.min)
    end_dt = datetime.combine(booking.end_dt, time.max)
    unbookable_hours = get_rooms_unbookable_hours([booking.room]).get(booking.room.id, [])
    other_bookings = get_existing_room_occurrences(booking.room, start_dt, end_dt, booking.repeat_frequency,
                                                   booking.repeat_interval, only_accepted=True,
                                                   skip_booking_id=booking.id)
    blocked_rooms = get_rooms_blockings([booking.room], start_dt.date(), end_dt.date())
    overridable_blockings = group_blocked_rooms(filter_blocked_rooms(blocked_rooms,
                                                                     overridable_only=True,
                                                                     explicit=True)).get(booking.room.id, [])
    nonoverridable_blockings = group_blocked_rooms(filter_blocked_rooms(blocked_rooms,
                                                                        nonoverridable_only=True,
                                                                        explicit=True)).get(booking.room.id, [])
    nonbookable_periods = get_rooms_nonbookable_periods([booking.room], start_dt, end_dt).get(booking.room.id, [])
    nonbookable_periods_grouped = group_nonbookable_periods(nonbookable_periods, date_range)
    occurrences_by_type['other'] = serialize_occurrences(group_by_occurrence_date(other_bookings))
    occurrences_by_type['blockings'] = serialize_blockings(group_blockings(nonoverridable_blockings, date_range))
    occurrences_by_type['overridable_blockings'] = serialize_blockings(group_blockings(overridable_blockings,
                                                                                       date_range))
    occurrences_by_type['unbookable_hours'] = serialize_unbookable_hours(unbookable_hours)
    occurrences_by_type['nonbookable_periods'] = serialize_nonbookable_periods(nonbookable_periods_grouped)
    return booking_details
Ejemplo n.º 11
0
def serialize_booking_details(booking):
    from indico.modules.rb.operations.blockings import filter_blocked_rooms, get_rooms_blockings, group_blocked_rooms
    from indico.modules.rb.operations.bookings import (get_booking_occurrences, get_existing_room_occurrences,
                                                       group_blockings, group_nonbookable_periods)
    from indico.modules.rb.operations.misc import get_rooms_nonbookable_periods, get_rooms_unbookable_hours
    from indico.modules.rb.schemas import reservation_details_schema, reservation_occurrences_schema_with_permissions

    attributes = reservation_details_schema.dump(booking)
    date_range, occurrences = get_booking_occurrences(booking)
    booking_details = dict(attributes)
    occurrences_by_type = dict(bookings={}, cancellations={}, rejections={}, other={}, blockings={},
                               unbookable_hours={}, nonbookable_periods={}, overridable_blockings={})
    booking_details['occurrences'] = occurrences_by_type
    booking_details['date_range'] = [dt.isoformat() for dt in date_range]
    for dt, [occ] in occurrences.items():
        serialized_occ = reservation_occurrences_schema_with_permissions.dump([occ])
        if occ.is_cancelled:
            occurrences_by_type['cancellations'][dt.isoformat()] = serialized_occ
        elif occ.is_rejected:
            occurrences_by_type['rejections'][dt.isoformat()] = serialized_occ
        occurrences_by_type['bookings'][dt.isoformat()] = serialized_occ if occ.is_valid else []

    start_dt = datetime.combine(booking.start_dt, time.min)
    end_dt = datetime.combine(booking.end_dt, time.max)
    unbookable_hours = get_rooms_unbookable_hours([booking.room]).get(booking.room.id, [])
    other_bookings = get_existing_room_occurrences(booking.room, start_dt, end_dt, booking.repeat_frequency,
                                                   booking.repeat_interval, skip_booking_id=booking.id)
    blocked_rooms = get_rooms_blockings([booking.room], start_dt.date(), end_dt.date())
    overridable_blockings = group_blocked_rooms(filter_blocked_rooms(blocked_rooms,
                                                                     overridable_only=True,
                                                                     explicit=True)).get(booking.room.id, [])
    nonoverridable_blockings = group_blocked_rooms(filter_blocked_rooms(blocked_rooms,
                                                                        nonoverridable_only=True,
                                                                        explicit=True)).get(booking.room.id, [])
    nonbookable_periods = get_rooms_nonbookable_periods([booking.room], start_dt, end_dt).get(booking.room.id, [])
    nonbookable_periods_grouped = group_nonbookable_periods(nonbookable_periods, date_range)
    occurrences_by_type['other'] = serialize_occurrences(group_by_occurrence_date(other_bookings))
    occurrences_by_type['blockings'] = serialize_blockings(group_blockings(nonoverridable_blockings, date_range))
    occurrences_by_type['overridable_blockings'] = serialize_blockings(group_blockings(overridable_blockings,
                                                                                       date_range))
    occurrences_by_type['unbookable_hours'] = serialize_unbookable_hours(unbookable_hours)
    occurrences_by_type['nonbookable_periods'] = serialize_nonbookable_periods(nonbookable_periods_grouped)
    return booking_details
Ejemplo n.º 12
0
def get_single_booking_suggestions(rooms, start_dt, end_dt, limit=None):
    data = []
    new_start_dt = start_dt - timedelta(minutes=BOOKING_TIME_DIFF)
    new_end_dt = end_dt + timedelta(minutes=BOOKING_TIME_DIFF)
    nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt)
    rooms = [room for room in rooms if room.id not in nonbookable_periods]

    if not rooms:
        return data

    unbookable_hours = get_rooms_unbookable_hours(rooms)
    rooms_occurrences = get_existing_rooms_occurrences(rooms, new_start_dt, new_end_dt, RepeatFrequency.NEVER, None,
                                                       allow_overlapping=True)
    for room in rooms:
        if limit and len(data) == limit:
            break

        suggestions = {}
        taken_periods = [(occ.start_dt, occ.end_dt) for occ in rooms_occurrences.get(room.id, [])]
        if room.id in unbookable_hours:
            taken_periods.extend((datetime.combine(start_dt, uh.start_time), datetime.combine(end_dt, uh.end_time))
                                 for uh in unbookable_hours[room.id])

        taken_periods = sorted(taken_periods)
        suggested_time = get_start_time_suggestion(taken_periods, start_dt, end_dt)
        if suggested_time:
            suggested_time_change = (suggested_time - start_dt).total_seconds() / 60
            if suggested_time_change and abs(suggested_time_change) <= BOOKING_TIME_DIFF:
                suggestions['time'] = suggested_time_change

        duration_suggestion = get_duration_suggestion(taken_periods, start_dt, end_dt)
        original_duration = (end_dt - start_dt).total_seconds() / 60
        if duration_suggestion and duration_suggestion <= DURATION_FACTOR * original_duration:
            suggestions['duration'] = duration_suggestion
        if suggestions:
            data.append({'room': room, 'suggestions': suggestions})
    return data
Ejemplo n.º 13
0
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,
    }
Ejemplo n.º 14
0
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,
    }