chrono/tests/api/test_statistics.py

315 lines
13 KiB
Python

import datetime
import pytest
from chrono.agendas.models import Agenda, Booking, Category, Desk, Event, MeetingType, VirtualMember
from chrono.utils.timezone import now
pytestmark = pytest.mark.django_db
def test_statistics_list(app, user):
agenda = Agenda.objects.create(label='Foo bar')
agenda2 = Agenda.objects.create(label='Bar foo')
Agenda.objects.create(label='Virtual', kind='virtual')
category = Category.objects.create(label='Category A')
category2 = Category.objects.create(label='Category B')
# unauthorized
app.get('/api/statistics/', status=401)
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/statistics/')
agenda_filter = [x for x in resp.json['data'][0]['filters'] if x['id'] == 'agenda'][0]
assert agenda_filter['options'] == [
{'id': '_all', 'label': 'All'},
{'id': 'bar-foo', 'label': 'Bar foo'},
{'id': 'foo-bar', 'label': 'Foo bar'},
{'id': 'virtual', 'label': 'Virtual'},
]
agenda.category = category
agenda.save()
resp = app.get('/api/statistics/')
agenda_filter = [x for x in resp.json['data'][0]['filters'] if x['id'] == 'agenda'][0]
assert agenda_filter['options'] == [
[None, [{'id': '_all', 'label': 'All'}]],
[
'Category A',
[
{'id': 'category:category-a', 'label': 'All agendas of category Category A'},
{'id': 'foo-bar', 'label': 'Foo bar'},
],
],
['Misc', [{'id': 'bar-foo', 'label': 'Bar foo'}, {'id': 'virtual', 'label': 'Virtual'}]],
]
agenda2.category = category2
agenda2.save()
resp = app.get('/api/statistics/')
agenda_filter = [x for x in resp.json['data'][0]['filters'] if x['id'] == 'agenda'][0]
assert agenda_filter['options'] == [
[None, [{'id': '_all', 'label': 'All'}]],
[
'Category A',
[
{'id': 'category:category-a', 'label': 'All agendas of category Category A'},
{'id': 'foo-bar', 'label': 'Foo bar'},
],
],
[
'Category B',
[
{'id': 'category:category-b', 'label': 'All agendas of category Category B'},
{'id': 'bar-foo', 'label': 'Bar foo'},
],
],
['Misc', [{'id': 'virtual', 'label': 'Virtual'}]],
]
def test_statistics_bookings(app, user, freezer):
freezer.move_to('2020-10-01')
agenda = Agenda.objects.create(
label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=0
)
event1 = Event.objects.create(start_datetime=now().replace(day=10), places=5, agenda=agenda)
event2 = Event.objects.create(start_datetime=now().replace(day=15), places=5, agenda=agenda)
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/statistics/')
url = [x for x in resp.json['data'] if x['id'] == 'bookings_count'][0]['url']
resp = app.get(url)
assert len(resp.json['data']['series']) == 0
for _ in range(10):
Booking.objects.create(event=event1)
Booking.objects.create(event=event1, cancellation_datetime=now())
Booking.objects.create(event=event2)
resp = app.get(url + '?time_interval=day')
assert resp.json['data']['x_labels'] == ['2020-10-10', '2020-10-15']
assert resp.json['data']['series'] == [{'label': 'Bookings Count', 'data': [10, 1]}]
# period filter
resp = app.get(url + '?start=2020-10-14&end=2020-10-16')
assert resp.json['data']['x_labels'] == ['2020-10-15']
assert resp.json['data']['series'] == [{'label': 'Bookings Count', 'data': [1]}]
category = Category.objects.create(label='Category A', slug='category-a')
agenda = Agenda.objects.create(label='Bar foo', kind='events', category=category)
event3 = Event.objects.create(start_datetime=now().replace(day=25), places=5, agenda=agenda)
Booking.objects.create(event=event3)
# category filter
resp = app.get(url + '?agenda=category:category-a')
assert resp.json['data']['x_labels'] == ['2020-10-25']
assert resp.json['data']['series'] == [{'label': 'Bookings Count', 'data': [1]}]
# agenda filter
resp = app.get(url + '?agenda=bar-foo')
assert resp.json['data']['x_labels'] == ['2020-10-25']
assert resp.json['data']['series'] == [{'label': 'Bookings Count', 'data': [1]}]
# invalid time_interval
resp = app.get(url + '?time_interval=month', status=400)
assert resp.json['err'] == 1
assert 'time_interval' in resp.json['errors']
# absence/presence
for i in range(10):
booking = Booking.objects.create(event=event3)
if i % 2:
booking.mark_user_presence()
else:
booking.mark_user_absence()
event4 = Event.objects.create(start_datetime=now().replace(month=11, day=1), places=5, agenda=agenda)
booking = Booking.objects.create(event=event4)
booking.mark_user_presence()
Booking.objects.create(event=event4, primary_booking=booking)
resp = app.get(url + '?group_by=user_was_present')
assert resp.json['data']['x_labels'] == ['2020-10-10', '2020-10-15', '2020-10-25', '2020-11-01']
assert resp.json['data']['series'] == [
{'label': 'Absent', 'data': [None, None, 5, None]},
{'label': 'Booked', 'data': [10, 1, 1, None]},
{'label': 'Present', 'data': [None, None, 5, 2]},
]
for i in range(9):
booking = Booking.objects.create(event=event3 if i % 2 else event4, extra_data={'menu': 'vegetables'})
if i % 3:
booking.mark_user_presence()
else:
booking.mark_user_absence()
for i in range(5):
booking = Booking.objects.create(event=event3 if i % 2 else event4, extra_data={'menu': 'meet'})
if i % 3:
booking.mark_user_presence()
else:
booking.mark_user_absence()
resp = app.get(url + '?group_by=menu')
assert resp.json['data']['x_labels'] == ['2020-10-10', '2020-10-15', '2020-10-25', '2020-11-01']
assert resp.json['data']['series'] == [
{'label': 'None', 'data': [10, 1, 11, 2]},
{'label': 'meet', 'data': [None, None, 2, 3]},
{'label': 'vegetables', 'data': [None, None, 4, 5]},
]
resp = app.get(url + '?group_by=user_was_present&group_by=menu')
assert resp.json['data']['x_labels'] == ['2020-10-10', '2020-10-15', '2020-10-25', '2020-11-01']
assert resp.json['data']['series'] == [
{'label': 'Absent / None', 'data': [None, None, 5, None]},
{'label': 'Absent / meet', 'data': [None, None, 1, 1]},
{'label': 'Absent / vegetables', 'data': [None, None, 1, 2]},
{'label': 'Booked / None', 'data': [10, 1, 1, None]},
{'label': 'Present / None', 'data': [None, None, 5, 2]},
{'label': 'Present / meet', 'data': [None, None, 1, 2]},
{'label': 'Present / vegetables', 'data': [None, None, 3, 3]},
]
def test_statistics_bookings_subfilters_list(app, user):
category = Category.objects.create(label='Category A')
agenda = Agenda.objects.create(label='Foo bar', kind='events', category=category)
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/statistics/')
url = [x for x in resp.json['data'] if x['id'] == 'bookings_count'][0]['url']
resp = app.get(url)
assert resp.json['data']['subfilters'] == []
resp = app.get(url + '?agenda=foo-bar')
assert len(resp.json['data']['subfilters']) == 1
assert resp.json['data']['subfilters'][0]['id'] == 'group_by'
assert len(resp.json['data']['subfilters'][0]['options']) == 1
assert resp.json['data']['subfilters'][0]['options'][0] == {
'id': 'user_was_present',
'label': 'Presence/Absence',
}
# extra data is shown in subfilters
event = Event.objects.create(start_datetime=now(), places=5, agenda=agenda)
Booking.objects.create(event=event, extra_data={'test': 'xxx'})
resp = app.get(url + '?agenda=foo-bar')
assert len(resp.json['data']['subfilters'][0]['options']) == 2
assert resp.json['data']['subfilters'][0]['options'][0] == {
'id': 'user_was_present',
'label': 'Presence/Absence',
}
assert resp.json['data']['subfilters'][0]['options'][1] == {'id': 'test', 'label': 'Test'}
resp = app.get(url + '?agenda=category:category-a')
assert len(resp.json['data']['subfilters'][0]['options']) == 2
category_b = Category.objects.create(label='Category B')
Agenda.objects.create(label='Other', kind='events', category=category_b)
resp = app.get(url + '?agenda=other')
assert len(resp.json['data']['subfilters'][0]['options']) == 1
resp = app.get(url + '?agenda=category:category-b')
assert len(resp.json['data']['subfilters'][0]['options']) == 1
Agenda.objects.create(label='Meetings', kind='meetings', category=category_b)
resp = app.get(url + '?agenda=meetings')
assert resp.json['data']['subfilters'] == []
resp = app.get(url + '?agenda=category:category-b')
assert len(resp.json['data']['subfilters'][0]['options']) == 1
resp = app.get(url + '?agenda=xxx', status=400)
assert resp.json['err_desc'] == 'No agendas found.'
resp = app.get(url + '?agenda=category:xxx', status=400)
assert resp.json['err_desc'] == 'No agendas found.'
@pytest.mark.freeze_time('2020-10-01 14:00')
def test_statistics_bookings_virtual(app, user):
agenda_foo = Agenda.objects.create(label='Agenda Foo', kind='meetings')
mt = MeetingType.objects.create(agenda=agenda_foo, label='Meeting Type', duration=30)
desk = Desk.objects.create(agenda=agenda_foo, label='Desk 1')
# 3 bookings on 01/10
for i in range(3):
start_datetime = now() + datetime.timedelta(hours=i)
event = Event.objects.create(
agenda=agenda_foo, meeting_type=mt, places=1, start_datetime=start_datetime, desk=desk
)
Booking.objects.create(event=event)
# 1 booking on 02/10
start_datetime = now() + datetime.timedelta(days=1)
event = Event.objects.create(
agenda=agenda_foo, meeting_type=mt, places=1, start_datetime=start_datetime, desk=desk
)
real_booking = Booking.objects.create(event=event)
agenda_bar = Agenda.objects.create(label='Agenda Bar', kind='meetings')
mt = MeetingType.objects.create(agenda=agenda_bar, label='Meeting Type', duration=30)
desk = Desk.objects.create(agenda=agenda_bar, label='Desk 1')
# 1 booking on 02/10
start_datetime = now() + datetime.timedelta(days=1, hours=1)
event = Event.objects.create(
agenda=agenda_bar, meeting_type=mt, places=1, start_datetime=start_datetime, desk=desk
)
Booking.objects.create(event=event)
# 2 bookings on 03/10
for i in range(2):
start_datetime = now() + datetime.timedelta(days=2, hours=i)
event = Event.objects.create(
agenda=agenda_bar, meeting_type=mt, places=1, start_datetime=start_datetime, desk=desk
)
Booking.objects.create(event=event)
virtual_agenda = Agenda.objects.create(slug='virtual_agenda', kind='virtual')
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=agenda_foo)
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=agenda_bar)
# normal booking on 01/10
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(start_datetime=now(), places=5, agenda=agenda)
Booking.objects.create(event=event)
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/statistics/')
url = [x for x in resp.json['data'] if x['id'] == 'bookings_count'][0]['url']
resp = app.get(url + '?time_interval=day')
assert resp.json['data']['x_labels'] == ['2020-10-01', '2020-10-02', '2020-10-03']
assert resp.json['data']['series'][0]['data'] == [4, 2, 2]
resp = app.get(url + '?time_interval=day&agenda=virtual_agenda')
assert resp.json['data']['x_labels'] == ['2020-10-01', '2020-10-02', '2020-10-03']
assert resp.json['data']['series'][0]['data'] == [3, 2, 2]
# filter on category containing both real and virtual
category = Category.objects.create(label='Category A')
virtual_agenda.category = category
virtual_agenda.save()
agenda_foo.category = category
agenda_foo.save()
resp = app.get(url + '?time_interval=day&agenda=category:category-a')
assert resp.json['data']['x_labels'] == ['2020-10-01', '2020-10-02', '2020-10-03']
assert resp.json['data']['series'][0]['data'] == [3, 2, 2]
# check subfilters from real agendas are found
real_booking.extra_data = {'menu': 'vegetables'}
real_booking.save()
resp = app.get(url + '?agenda=virtual_agenda')
assert len(resp.json['data']['subfilters'][0]['options']) == 1
assert resp.json['data']['subfilters'][0]['options'][0] == {'id': 'menu', 'label': 'Menu'}