agendas: add date filter params on datetimes api (#48078)
This commit is contained in:
parent
7f826697dc
commit
6d0e8a57ad
|
@ -64,25 +64,34 @@ def format_response_datetime(dt):
|
|||
return localtime(dt).strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
|
||||
def get_min_datetime(agenda):
|
||||
def get_min_datetime(agenda, start_datetime=None):
|
||||
if agenda.minimal_booking_delay is None:
|
||||
return None
|
||||
return start_datetime
|
||||
|
||||
min_datetime = now() + datetime.timedelta(days=agenda.minimal_booking_delay)
|
||||
return min_datetime.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
min_datetime = min_datetime.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
if start_datetime is None:
|
||||
return min_datetime
|
||||
return max(min_datetime, start_datetime)
|
||||
|
||||
|
||||
def get_max_datetime(agenda):
|
||||
def get_max_datetime(agenda, end_datetime=None):
|
||||
if agenda.maximal_booking_delay is None:
|
||||
return None
|
||||
return end_datetime
|
||||
|
||||
max_datetime = now() + datetime.timedelta(days=agenda.maximal_booking_delay)
|
||||
max_datetime = max_datetime.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
return max_datetime
|
||||
if end_datetime is None:
|
||||
return max_datetime
|
||||
return min(max_datetime, end_datetime)
|
||||
|
||||
|
||||
TimeSlot = collections.namedtuple('TimeSlot', ['start_datetime', 'end_datetime', 'full', 'desk'])
|
||||
|
||||
|
||||
def get_all_slots(base_agenda, meeting_type, resources=None, unique=False):
|
||||
def get_all_slots(
|
||||
base_agenda, meeting_type, resources=None, unique=False, start_datetime=None, end_datetime=None
|
||||
):
|
||||
'''Get all occupation state of all possible slots for the given agenda (of
|
||||
its real agendas for a virtual agenda) and the given meeting_type.
|
||||
|
||||
|
@ -107,8 +116,8 @@ def get_all_slots(base_agenda, meeting_type, resources=None, unique=False):
|
|||
# that the base_meeting_duration for the virtual agenda is always the same
|
||||
# as the base meeting duration of each real agenda.
|
||||
base_meeting_duration = base_agenda.get_base_meeting_duration()
|
||||
base_min_datetime = get_min_datetime(base_agenda)
|
||||
base_max_datetime = get_max_datetime(base_agenda)
|
||||
base_min_datetime = get_min_datetime(base_agenda, start_datetime)
|
||||
base_max_datetime = get_max_datetime(base_agenda, end_datetime)
|
||||
|
||||
meeting_duration = meeting_type.duration
|
||||
meeting_duration_td = datetime.timedelta(minutes=meeting_duration)
|
||||
|
@ -121,8 +130,8 @@ def get_all_slots(base_agenda, meeting_type, resources=None, unique=False):
|
|||
agenda_ids_by_min_max_datetimes = collections.defaultdict(set)
|
||||
agenda_id_min_max_datetime = {}
|
||||
for agenda in agendas:
|
||||
used_min_datetime = base_min_datetime or get_min_datetime(agenda)
|
||||
used_max_datetime = base_max_datetime or get_max_datetime(agenda)
|
||||
used_min_datetime = base_min_datetime or get_min_datetime(agenda, start_datetime)
|
||||
used_max_datetime = base_max_datetime or get_max_datetime(agenda, end_datetime)
|
||||
agenda_ids_by_min_max_datetimes[(used_min_datetime, used_max_datetime)].add(agenda.id)
|
||||
agenda_id_min_max_datetime[agenda.id] = (used_min_datetime, used_max_datetime)
|
||||
|
||||
|
@ -519,6 +528,32 @@ class MeetingDatetimes(APIView):
|
|||
except APIError as e:
|
||||
return e.to_response()
|
||||
|
||||
start_datetime = None
|
||||
if 'date_start' in request.GET:
|
||||
try:
|
||||
start_datetime = make_aware(
|
||||
datetime.datetime.combine(parse_date(request.GET['date_start']), datetime.time(0, 0))
|
||||
)
|
||||
except TypeError as e:
|
||||
raise APIError(
|
||||
_('date_start format must be YYYY-MM-DD'),
|
||||
err_class='date_start format must be YYYY-MM-DD',
|
||||
http_status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
end_datetime = None
|
||||
if 'date_end' in request.GET:
|
||||
try:
|
||||
end_datetime = make_aware(
|
||||
datetime.datetime.combine(parse_date(request.GET['date_end']), datetime.time(0, 0))
|
||||
)
|
||||
except TypeError as e:
|
||||
raise APIError(
|
||||
_('date_end format must be YYYY-MM-DD'),
|
||||
err_class='date_end format must be YYYY-MM-DD',
|
||||
http_status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
# Generate an unique slot for each possible meeting [start_datetime,
|
||||
# end_datetime] range.
|
||||
# First use get_all_slots() to get each possible meeting by desk and
|
||||
|
@ -532,7 +567,16 @@ class MeetingDatetimes(APIView):
|
|||
# The generator also remove slots starting before the current time.
|
||||
def unique_slots():
|
||||
last_slot = None
|
||||
all_slots = list(get_all_slots(agenda, meeting_type, resources=resources, unique=True))
|
||||
all_slots = list(
|
||||
get_all_slots(
|
||||
agenda,
|
||||
meeting_type,
|
||||
resources=resources,
|
||||
unique=True,
|
||||
start_datetime=start_datetime,
|
||||
end_datetime=end_datetime,
|
||||
)
|
||||
)
|
||||
for slot in sorted(all_slots, key=lambda slot: slot[:3]):
|
||||
if slot.start_datetime < now_datetime:
|
||||
continue
|
||||
|
|
|
@ -4504,3 +4504,78 @@ def test_datetimes_maximal_booking_delay(app, user):
|
|||
resp = app.get(api_url)
|
||||
data = resp.json['data']
|
||||
assert len(data) == 4
|
||||
|
||||
|
||||
def test_meetings_and_virtual_datetimes_date_filter(app):
|
||||
agenda_foo = Agenda.objects.create(
|
||||
label=u'Agenda Foo', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=7
|
||||
)
|
||||
meeting_type = MeetingType.objects.create(agenda=agenda_foo, label='Meeting Type', duration=30)
|
||||
desk_foo = Desk.objects.create(agenda=agenda_foo, label='Desk 1')
|
||||
weekday1 = (localtime(now())).weekday() + 1 % 7
|
||||
weekday2 = (localtime(now())).weekday() + 2 % 7
|
||||
weekday3 = (localtime(now())).weekday() + 3 % 7
|
||||
weekday4 = (localtime(now())).weekday() + 4 % 7
|
||||
weekday5 = (localtime(now())).weekday() + 5 % 7
|
||||
weekday6 = (localtime(now())).weekday() + 6 % 7
|
||||
for weekday in (weekday1, weekday2, weekday3, weekday4, weekday5, weekday6):
|
||||
TimePeriod.objects.create(
|
||||
weekday=weekday, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=desk_foo,
|
||||
)
|
||||
|
||||
virtual_agenda = Agenda.objects.create(
|
||||
label=u'Agenda Virtual', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=7
|
||||
)
|
||||
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=agenda_foo)
|
||||
|
||||
# 4 slots each day * 6 days
|
||||
foo_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda_foo.slug, meeting_type.slug)
|
||||
resp = app.get(foo_api_url)
|
||||
assert len(resp.json['data']) == 24
|
||||
virtual_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, meeting_type.slug)
|
||||
resp = app.get(virtual_api_url)
|
||||
assert len(resp.json['data']) == 24
|
||||
|
||||
# exclude weekday1 through date_start, 4 slots each day * 5 days
|
||||
params = {'date_start': (localtime(now()) + datetime.timedelta(days=2)).date().isoformat()}
|
||||
resp = app.get(foo_api_url, params=params)
|
||||
assert len(resp.json['data']) == 20
|
||||
resp = app.get(virtual_api_url, params=params)
|
||||
assert len(resp.json['data']) == 20
|
||||
|
||||
# minimal_booking_delay (which exclude weekday1 and wekkday2 ) takes precedence
|
||||
# 4 slots each day * 4 days
|
||||
agenda_foo.minimal_booking_delay = 3
|
||||
agenda_foo.save()
|
||||
resp = app.get(foo_api_url, params=params)
|
||||
assert len(resp.json['data']) == 16
|
||||
# also on virtual agenda
|
||||
virtual_agenda.minimal_booking_delay = 3
|
||||
virtual_agenda.save()
|
||||
resp = app.get(virtual_api_url, params=params)
|
||||
assert len(resp.json['data']) == 16
|
||||
|
||||
# reset
|
||||
agenda_foo.minimal_booking_delay = 1
|
||||
virtual_agenda.minimal_booking_delay = 1
|
||||
agenda_foo.save()
|
||||
virtual_agenda.save()
|
||||
|
||||
# exclude weekday6 through date_end, 4 slots each day * 5 days
|
||||
params = {'date_end': (localtime(now()) + datetime.timedelta(days=6)).date().isoformat()}
|
||||
resp = app.get(foo_api_url, params=params)
|
||||
assert len(resp.json['data']) == 20
|
||||
resp = app.get(virtual_api_url, params=params)
|
||||
assert len(resp.json['data']) == 20
|
||||
|
||||
# maximal_booking_delay (which exclude weekday5 and weekday6 ) takes precedence
|
||||
# 4 slots each day * 4 days
|
||||
agenda_foo.maximal_booking_delay = 5
|
||||
agenda_foo.save()
|
||||
resp = app.get(foo_api_url, params=params)
|
||||
assert len(resp.json['data']) == 16
|
||||
# also on virtual agenda
|
||||
virtual_agenda.maximal_booking_delay = 5
|
||||
virtual_agenda.save()
|
||||
resp = app.get(virtual_api_url, params=params)
|
||||
assert len(resp.json['data']) == 16
|
||||
|
|
Loading…
Reference in New Issue