2433 lines
83 KiB
Python
2433 lines
83 KiB
Python
import datetime
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
from django.db import connection
|
|
from django.test.utils import CaptureQueriesContext
|
|
|
|
from chrono.agendas.models import Agenda, Booking, BookingCheck, Desk, Event, EventsType, Subscription
|
|
from chrono.apps.snapshot.models import AgendaSnapshot
|
|
from chrono.utils.timezone import localtime, make_aware, now
|
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
|
|
def test_status(app, user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=(now() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
|
|
places=10,
|
|
agenda=agenda,
|
|
custom_fields={
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
},
|
|
)
|
|
agenda2 = Agenda.objects.create(label='Foo bar2', kind='events', minimal_booking_delay=0)
|
|
# other event with the same slug but in another agenda
|
|
Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=(now() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
|
|
places=5,
|
|
agenda=agenda2,
|
|
)
|
|
Booking.objects.create(event=event)
|
|
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.slug, event.slug), status=401)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.get('/api/agenda/%s/status/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['err'] == 0
|
|
assert resp.json == {
|
|
'err': 0,
|
|
'id': 'event-slug',
|
|
'slug': 'event-slug',
|
|
'primary_event': None,
|
|
'text': str(event),
|
|
'label': '',
|
|
'agenda_label': 'Foo bar',
|
|
'date': localtime(event.start_datetime).strftime('%Y-%m-%d'),
|
|
'datetime': localtime(event.start_datetime).strftime('%Y-%m-%d %H:%M:%S'),
|
|
'end_datetime': '',
|
|
'description': None,
|
|
'pricing': None,
|
|
'url': None,
|
|
'disabled': False,
|
|
'duration': None,
|
|
'checked': False,
|
|
'check_locked': False,
|
|
'invoiced': False,
|
|
'api': {
|
|
'bookings_url': 'http://testserver/api/agenda/foo-bar/bookings/event-slug/',
|
|
'fillslot_url': 'http://testserver/api/agenda/foo-bar/fillslot/event-slug/',
|
|
'status_url': 'http://testserver/api/agenda/foo-bar/status/event-slug/',
|
|
'check_url': 'http://testserver/api/agenda/foo-bar/check/event-slug/',
|
|
'backoffice_url': 'http://testserver/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk),
|
|
},
|
|
'places': {'available': 9, 'reserved': 1, 'total': 10, 'full': False, 'has_waiting_list': False},
|
|
}
|
|
assert 'waiting_list_total' not in resp.json['places']
|
|
|
|
events_type = EventsType.objects.create(
|
|
label='Foo',
|
|
custom_fields=[
|
|
{'varname': 'text', 'label': 'Text', 'field_type': 'text'},
|
|
{'varname': 'textarea', 'label': 'TextArea', 'field_type': 'textarea'},
|
|
{'varname': 'bool', 'label': 'Bool', 'field_type': 'bool'},
|
|
],
|
|
)
|
|
agenda.events_type = events_type
|
|
agenda.save()
|
|
resp = app.get('/api/agenda/%s/status/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json == {
|
|
'err': 0,
|
|
'id': 'event-slug',
|
|
'slug': 'event-slug',
|
|
'primary_event': None,
|
|
'text': str(event),
|
|
'label': '',
|
|
'agenda_label': 'Foo bar',
|
|
'date': localtime(event.start_datetime).strftime('%Y-%m-%d'),
|
|
'datetime': localtime(event.start_datetime).strftime('%Y-%m-%d %H:%M:%S'),
|
|
'end_datetime': '',
|
|
'description': None,
|
|
'pricing': None,
|
|
'url': None,
|
|
'disabled': False,
|
|
'duration': None,
|
|
'checked': False,
|
|
'check_locked': False,
|
|
'invoiced': False,
|
|
'custom_field_text': 'foo',
|
|
'custom_field_textarea': 'foo bar',
|
|
'custom_field_bool': True,
|
|
'api': {
|
|
'bookings_url': 'http://testserver/api/agenda/foo-bar/bookings/event-slug/',
|
|
'fillslot_url': 'http://testserver/api/agenda/foo-bar/fillslot/event-slug/',
|
|
'status_url': 'http://testserver/api/agenda/foo-bar/status/event-slug/',
|
|
'check_url': 'http://testserver/api/agenda/foo-bar/check/event-slug/',
|
|
'backoffice_url': 'http://testserver/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk),
|
|
},
|
|
'places': {'available': 9, 'reserved': 1, 'total': 10, 'full': False, 'has_waiting_list': False},
|
|
}
|
|
|
|
Booking(event=event, in_waiting_list=True).save()
|
|
event.waiting_list_places = 5
|
|
event.save()
|
|
resp = app.get('/api/agenda/%s/status/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['places']['waiting_list_total'] == 5
|
|
assert resp.json['places']['waiting_list_available'] == 4
|
|
assert resp.json['places']['waiting_list_reserved'] == 1
|
|
|
|
# wrong kind
|
|
for kind in ['meetings', 'virtual']:
|
|
agenda.kind = kind
|
|
agenda.save()
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.pk, event.slug), status=404)
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.slug, event.slug), status=404)
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-02-23')
|
|
def test_status_url(app, user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events', minimal_booking_delay=0)
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
start_datetime=(now() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.pk, event.pk))
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.slug, event.slug))
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.pk, event.slug))
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.slug, event.pk))
|
|
|
|
# unknown event
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.pk, 0), status=404)
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.slug, 0), status=404)
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.pk, 'foobar'), status=404)
|
|
app.get('/api/agenda/%s/status/%s/' % (agenda.slug, 'foobar'), status=404)
|
|
|
|
# unknown agenda
|
|
app.get('/api/agenda/%s/status/%s/' % (0, event.pk), status=404)
|
|
app.get('/api/agenda/%s/status/%s/' % (0, event.slug), status=404)
|
|
app.get('/api/agenda/%s/status/%s/' % ('foobar', event.pk), status=404)
|
|
app.get('/api/agenda/%s/status/%s/' % ('foobar', event.slug), status=404)
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-02-23')
|
|
def test_event_checked(app, user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
event = Event.objects.create(
|
|
label='xyz',
|
|
start_datetime=now() - datetime.timedelta(days=1),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
assert event.checked is False
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug))
|
|
event.refresh_from_db()
|
|
assert event.checked is True
|
|
|
|
resp = app.get('/api/agenda/%s/status/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['checked'] is True
|
|
|
|
# already checked
|
|
app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug))
|
|
event.refresh_from_db()
|
|
assert event.checked is True
|
|
|
|
# wrong kind
|
|
agenda.kind = 'meetings'
|
|
agenda.save()
|
|
app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug), status=404)
|
|
agenda.kind = 'virtual'
|
|
agenda.save()
|
|
app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug), status=404)
|
|
|
|
|
|
def test_event_notify_checked(app, user):
|
|
agenda = Agenda.objects.create(label='Events', kind='events')
|
|
event = Event.objects.create(
|
|
label='xyz',
|
|
start_datetime=now() - datetime.timedelta(days=1),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
assert event.checked is False
|
|
|
|
for i in range(8):
|
|
booking = Booking.objects.create(
|
|
event=event,
|
|
presence_callback_url='https://example.invalid/presence/%s' % i,
|
|
absence_callback_url='https://example.invalid/absence/%s' % i,
|
|
)
|
|
if i < 3:
|
|
booking.mark_user_presence()
|
|
elif i < 7:
|
|
booking.mark_user_absence()
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
with mock.patch('chrono.utils.requests_wrapper.RequestsSession.send') as mock_send:
|
|
mock_response = mock.Mock(status_code=200)
|
|
mock_send.return_value = mock_response
|
|
app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug))
|
|
event.refresh_from_db()
|
|
assert event.checked is True
|
|
|
|
assert {x[0][0].url for x in mock_send.call_args_list} == {
|
|
'https://example.invalid/presence/0',
|
|
'https://example.invalid/presence/1',
|
|
'https://example.invalid/presence/2',
|
|
'https://example.invalid/absence/3',
|
|
'https://example.invalid/absence/4',
|
|
'https://example.invalid/absence/5',
|
|
'https://example.invalid/absence/6',
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'days_in, days_out, err_msg',
|
|
[
|
|
(1, None, 'Expected a list of items but got type "int".'),
|
|
('2', [3], None),
|
|
([3], [4], None),
|
|
(['4'], [5], None),
|
|
([1, 2], [2, 3], None),
|
|
(['2', '3'], [3, 4], None),
|
|
('4, 5', [5, 6], None),
|
|
],
|
|
)
|
|
def test_string_or_list_serialiser(app, user, days_in, days_out, err_msg):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
agenda = Agenda(label='Foo bar')
|
|
agenda.maximal_booking_delay = 0
|
|
agenda.save()
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
api_url = '/api/agenda/%s/event/' % (agenda.slug)
|
|
|
|
params = {
|
|
'start_datetime': '2022-02-03 16:00',
|
|
'places': '1',
|
|
'recurrence_days': days_in,
|
|
'recurrence_end_date': '2022-02-13',
|
|
}
|
|
if not err_msg:
|
|
resp = app.post_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
assert Event.objects.get(primary_event__isnull=True).recurrence_days == days_out
|
|
else:
|
|
resp = app.post_json(api_url, params=params, status=400)
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['recurrence_days'][0] == err_msg
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-11-01')
|
|
def test_add_event(app, user):
|
|
api_url = '/api/agenda/%s/event/' % ('999')
|
|
|
|
# no authentication
|
|
resp = app.post(api_url, status=401)
|
|
assert resp.json['detail'] == 'Authentication credentials were not provided.'
|
|
|
|
# wrong password
|
|
app.authorization = ('Basic', ('john.doe', 'wrong'))
|
|
resp = app.post(api_url, status=401)
|
|
assert resp.json['detail'] == 'Invalid username/password.'
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
# missing agenda
|
|
resp = app.post(api_url, status=404)
|
|
assert resp.json['detail'] == 'Not found.'
|
|
|
|
# using meeting agenda
|
|
meeting_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='meetings')
|
|
api_url = '/api/agenda/%s/event/' % (meeting_agenda.slug)
|
|
resp = app.post(api_url, status=404)
|
|
assert resp.json['detail'] == 'Not found.'
|
|
|
|
agenda = Agenda.objects.create(label='Foo bar', maximal_booking_delay=0)
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
api_url = '/api/agenda/%s/event/' % (agenda.slug)
|
|
|
|
# missing fields
|
|
resp = app.post(api_url, status=400)
|
|
assert resp.json['err']
|
|
assert resp.json['errors'] == {
|
|
'start_datetime': ['This field is required.'],
|
|
'places': ['This field is required.'],
|
|
}
|
|
|
|
# add with errors in datetime parts
|
|
params = {
|
|
'start_datetime': '2021-11-15 minuit',
|
|
'places': 10,
|
|
}
|
|
resp = app.post_json(api_url, params=params, status=400)
|
|
assert resp.json['err']
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert 'Datetime has wrong format' in resp.json['errors']['start_datetime'][0]
|
|
|
|
# add an event
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'places': 10,
|
|
}
|
|
resp = app.post_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
assert resp.json['data']['id'] == 'foo-bar-event'
|
|
assert {'api', 'disabled', 'places'}.issubset(resp.json['data'].keys())
|
|
assert {'recurrence_days', 'recurrence_week_interval', 'recurrence_end_date'}.isdisjoint(
|
|
resp.json['data'].keys()
|
|
)
|
|
event = Event.objects.filter(agenda=agenda).get(slug='foo-bar-event')
|
|
assert str(event.start_datetime) == '2021-11-15 14:38:00+00:00'
|
|
assert str(event.start_datetime.tzinfo) == 'UTC'
|
|
assert event.places == 10
|
|
assert event.publication_datetime is None
|
|
assert event.custom_fields == {}
|
|
assert AgendaSnapshot.objects.count() == 1
|
|
|
|
# add an event without custom fields
|
|
events_type = EventsType.objects.create(
|
|
label='Foo',
|
|
custom_fields=[
|
|
{'varname': 'text', 'label': 'Text', 'field_type': 'text'},
|
|
{'varname': 'textarea', 'label': 'TextArea', 'field_type': 'textarea'},
|
|
{'varname': 'bool', 'label': 'Bool', 'field_type': 'bool'},
|
|
],
|
|
)
|
|
agenda.events_type = events_type
|
|
agenda.save()
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'places': 10,
|
|
}
|
|
resp = app.post_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event = Event.objects.latest('pk')
|
|
assert event.custom_fields == {
|
|
'text': '',
|
|
'textarea': '',
|
|
'bool': None,
|
|
}
|
|
|
|
# add with almost all optional managed fields
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'duration': 42,
|
|
'publication_datetime': '2021-09-20 10:00',
|
|
'places': 11,
|
|
'waiting_list_places': 3,
|
|
'label': 'FOO camp',
|
|
'description': 'An event',
|
|
'pricing': 'free',
|
|
'url': 'http://example.org/foo/bar/?',
|
|
'custom_field_text': 'foo',
|
|
'custom_field_textarea': 'foo bar',
|
|
'custom_field_bool': True,
|
|
}
|
|
resp = app.post_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
assert resp.json['data']['id'] == 'foo-camp'
|
|
assert {'api', 'disabled', 'places'}.issubset(resp.json['data'].keys())
|
|
assert {'recurrence_days', 'recurrence_week_interval', 'recurrence_end_date'}.isdisjoint(
|
|
resp.json['data'].keys()
|
|
)
|
|
event = Event.objects.filter(agenda=agenda).get(slug='foo-camp')
|
|
assert event.duration == 42
|
|
assert event.waiting_list_places == 3
|
|
assert event.label == 'FOO camp'
|
|
assert event.description == 'An event'
|
|
assert event.pricing == 'free'
|
|
assert event.url == 'http://example.org/foo/bar/?'
|
|
assert str(event.publication_datetime) == '2021-09-20 08:00:00+00:00'
|
|
assert str(event.publication_datetime.tzinfo) == 'UTC'
|
|
assert event.custom_fields == {
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
}
|
|
|
|
# add with errors in bool custom field
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'places': 10,
|
|
'custom_field_bool': 'foobar',
|
|
}
|
|
resp = app.post_json(api_url, params=params, status=400)
|
|
assert resp.json['err']
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['custom_field_bool'][0] == 'Must be a valid boolean.'
|
|
|
|
# add with errors in recurrence_days list
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'places': 10,
|
|
'recurrence_days': 'oups',
|
|
}
|
|
resp = app.post_json(api_url, params=params, status=400)
|
|
assert resp.json['err']
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['recurrence_days']['0'][0] == 'A valid integer is required.'
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'places': 10,
|
|
'recurrence_days': '7',
|
|
}
|
|
resp = app.post_json(api_url, params=params, status=400)
|
|
assert resp.json['err']
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['recurrence_days']['0'][0] == 'Ensure this value is less than or equal to 6.'
|
|
|
|
# add a recurrent event
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'places': 12,
|
|
'recurrence_days': '3',
|
|
'recurrence_week_interval': '2',
|
|
'description': 'A recurrent event',
|
|
}
|
|
assert Event.objects.filter(agenda=agenda).count() == 3
|
|
resp = app.post_json(api_url, params=params)
|
|
assert Event.objects.filter(agenda=agenda).count() == 29
|
|
assert not resp.json['err']
|
|
assert resp.json['data']['id'] == 'foo-bar-event-2'
|
|
assert {'api', 'disabled', 'places'}.isdisjoint(resp.json['data'].keys())
|
|
assert {'recurrence_days', 'recurrence_week_interval', 'recurrence_end_date'}.issubset(
|
|
resp.json['data'].keys()
|
|
)
|
|
event = Event.objects.filter(agenda=agenda).get(slug='foo-bar-event-2')
|
|
assert event.description == 'A recurrent event'
|
|
assert event.recurrence_days == [4]
|
|
assert event.recurrence_week_interval == 2
|
|
assert event.recurrence_end_date is None
|
|
# some occurrences created
|
|
assert event.recurrences.count() == 25
|
|
|
|
# add a recurrent event with end recurrence date creates 9 recurrences
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'places': 13,
|
|
'recurrence_days': '0,3,5', # Monday, Tuesday, Saturday
|
|
'recurrence_week_interval': '2',
|
|
'recurrence_end_date': '2021-12-27',
|
|
'description': 'A recurrent event having recurrences',
|
|
'custom_field_text': 'foo',
|
|
'custom_field_textarea': 'foo bar',
|
|
'custom_field_bool': True,
|
|
}
|
|
resp = app.post_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
assert resp.json['data']['id'] == 'foo-bar-event-3'
|
|
assert {'api', 'disabled', 'places'}.isdisjoint(resp.json['data'].keys())
|
|
assert {'recurrence_days', 'recurrence_week_interval', 'recurrence_end_date'}.issubset(
|
|
resp.json['data'].keys()
|
|
)
|
|
event = Event.objects.filter(agenda=agenda).get(slug='foo-bar-event-3')
|
|
assert Event.objects.filter(agenda=agenda).count() == 39
|
|
assert event.description == 'A recurrent event having recurrences'
|
|
assert event.recurrence_days == [1, 4, 6]
|
|
assert event.recurrence_week_interval == 2
|
|
assert event.recurrence_end_date == datetime.date(2021, 12, 27)
|
|
assert event.custom_fields == {
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
}
|
|
assert event.recurrences.count() == 9
|
|
assert sorted(
|
|
str(x.start_datetime.date()) for x in Event.objects.all() if 'foo-bar-event-3--' in x.slug
|
|
) == [
|
|
'2021-11-15',
|
|
'2021-11-18',
|
|
'2021-11-20',
|
|
'2021-11-29',
|
|
'2021-12-02',
|
|
'2021-12-04',
|
|
'2021-12-13',
|
|
'2021-12-16',
|
|
'2021-12-18',
|
|
]
|
|
for ev in event.recurrences.all():
|
|
assert ev.custom_fields == {
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
}
|
|
|
|
app.delete('/api/agenda/%s/event/' % agenda.slug, status=405) # forbidden
|
|
|
|
|
|
@pytest.mark.freeze_time('2023-03-09')
|
|
def test_add_event_end_datetime(app, user):
|
|
agenda = Agenda.objects.create(label='Foo bar', maximal_booking_delay=0)
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
api_url = '/api/agenda/%s/event/' % (agenda.slug)
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
# add an event
|
|
params = {'start_datetime': '2023-03-10 14:00', 'places': 10, 'duration': 30}
|
|
resp = app.post_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
assert resp.json['data']['id'] == 'foo-bar-event'
|
|
assert resp.json['data']['datetime'] == '2023-03-10 14:00:00'
|
|
assert resp.json['data']['end_datetime'] == '2023-03-10 14:30:00'
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-11-01')
|
|
def test_update_event(app, user):
|
|
api_url = '/api/agenda/%s/event/%s/' % ('nop', 'nop')
|
|
|
|
# no authentication
|
|
resp = app.patch(api_url, status=401)
|
|
assert resp.json['detail'] == 'Authentication credentials were not provided.'
|
|
|
|
# wrong password
|
|
app.authorization = ('Basic', ('john.doe', 'wrong'))
|
|
resp = app.patch(api_url, status=401)
|
|
assert resp.json['detail'] == 'Invalid username/password.'
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
# missing agenda
|
|
resp = app.patch(api_url, status=404)
|
|
assert resp.json['detail'] == 'Not found.'
|
|
|
|
meeting_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='meetings')
|
|
|
|
# using meeting agenda
|
|
api_url = '/api/agenda/%s/event/%s/' % (meeting_agenda.slug, 'nop')
|
|
resp = app.patch(api_url, status=404)
|
|
assert resp.json['detail'] == 'Not found.'
|
|
|
|
events_type = EventsType.objects.create(
|
|
label='Foo',
|
|
custom_fields=[
|
|
{'varname': 'text', 'label': 'Text', 'field_type': 'text'},
|
|
{'varname': 'textarea', 'label': 'TextArea', 'field_type': 'textarea'},
|
|
{'varname': 'bool', 'label': 'Bool', 'field_type': 'bool'},
|
|
],
|
|
)
|
|
agenda = Agenda.objects.create(label='Foo bar', events_type=events_type)
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
|
|
# missing event
|
|
api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, 'nop')
|
|
resp = app.patch(api_url, status=404)
|
|
assert resp.json['detail'] == 'Not found.'
|
|
|
|
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10, waiting_list_places=5)
|
|
api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, event.slug)
|
|
|
|
# update with errors in datetime parts
|
|
params = {
|
|
'start_datetime': '2021-11-15 minuit',
|
|
'recurrence_days': '7, 8',
|
|
}
|
|
resp = app.patch_json(api_url, params=params, status=400)
|
|
assert resp.json['err']
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert 'Datetime has wrong format' in resp.json['errors']['start_datetime'][0]
|
|
assert resp.json['errors']['recurrence_days']['0'][0] == 'Ensure this value is less than or equal to 6.'
|
|
|
|
# update with almost all optional managed fields
|
|
params = {
|
|
'start_datetime': '2021-11-15 15:38',
|
|
'duration': 42,
|
|
'publication_datetime': '2021-09-20 12:00',
|
|
'places': 8,
|
|
'waiting_list_places': 3,
|
|
'label': 'FOO camp',
|
|
'description': 'An event',
|
|
'pricing': 'free',
|
|
'url': 'http://example.org/foo/bar/?',
|
|
}
|
|
resp = app.patch_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
|
|
assert event.duration == 42
|
|
assert event.places == 8
|
|
assert event.waiting_list_places == 3
|
|
assert event.label == 'FOO camp'
|
|
assert event.description == 'An event'
|
|
assert event.pricing == 'free'
|
|
assert event.url == 'http://example.org/foo/bar/?'
|
|
assert str(event.publication_datetime) == '2021-09-20 10:00:00+00:00'
|
|
assert str(event.publication_datetime.tzinfo) == 'UTC'
|
|
assert event.custom_fields == {
|
|
'text': '',
|
|
'textarea': '',
|
|
'bool': None,
|
|
}
|
|
assert AgendaSnapshot.objects.count() == 1
|
|
|
|
# update event as a recurring event
|
|
params = {
|
|
'recurrence_days': '0,3,5',
|
|
'recurrence_week_interval': 2,
|
|
'recurrence_end_date': '2021-12-27',
|
|
# with custom fields
|
|
'custom_field_text': 'foo',
|
|
'custom_field_textarea': 'foo bar',
|
|
'custom_field_bool': True,
|
|
}
|
|
resp = app.patch_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
|
|
assert event.recurrences.count() == 9
|
|
assert event.custom_fields == {
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
}
|
|
assert [x.places for x in event.recurrences.all()] == [8] * 9
|
|
for ev in event.recurrences.all():
|
|
assert ev.custom_fields == {
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
}
|
|
|
|
recurrence_slug = event.recurrences.first().slug
|
|
assert recurrence_slug == 'foo-bar-event--2021-11-15-1538'
|
|
recurrence_url = '/api/agenda/%s/event/%s/' % (agenda.slug, 'foo-bar-event--2021-11-15-1538')
|
|
|
|
# update unprotected fields of one of the event recurrencies
|
|
params = {
|
|
'start_datetime': '2021-11-14 14:00',
|
|
'duration': 43,
|
|
'places': 9,
|
|
'waiting_list_places': 4,
|
|
'label': 'BAR camp',
|
|
'description': 'An occurence of an event recurrence',
|
|
'pricing': '5€',
|
|
'url': 'http://example.org/bar/bar/',
|
|
}
|
|
resp = app.patch_json(recurrence_url, params=params)
|
|
assert not resp.json['err']
|
|
recurrence = Event.objects.filter(agenda=agenda).get(slug=recurrence_slug)
|
|
assert recurrence.duration == 43
|
|
assert recurrence.places == 9
|
|
assert recurrence.waiting_list_places == 4
|
|
assert recurrence.label == 'BAR camp'
|
|
assert recurrence.description == 'An occurence of an event recurrence'
|
|
assert recurrence.pricing == '5€'
|
|
assert recurrence.url == 'http://example.org/bar/bar/'
|
|
|
|
# try to update protected fields of one of the event recurrencies
|
|
params = {
|
|
'publication_datetime': '2021-11-15 12:00',
|
|
}
|
|
resp = app.patch_json(recurrence_url, params=params, status=400)
|
|
assert resp.json['err']
|
|
assert 'cannot be modified' in resp.json['err_desc']
|
|
|
|
# update protected fields of one of the event recurrencies providing same value
|
|
params = {
|
|
'recurrence_week_interval': 1,
|
|
}
|
|
resp = app.patch_json(recurrence_url, params=params)
|
|
assert not resp.json['err']
|
|
|
|
# update of custom field of one of event recurrences is ignored
|
|
params = {
|
|
'custom_field_text': 'foo bar baz',
|
|
}
|
|
resp = app.patch_json(recurrence_url, params=params)
|
|
assert not resp.json['err']
|
|
recurrence.refresh_from_db()
|
|
assert recurrence.custom_fields == {
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
}
|
|
|
|
booking = Booking.objects.create(event=event.recurrences.all()[2])
|
|
|
|
# update unprotected fields
|
|
params = {
|
|
'places': 7,
|
|
}
|
|
resp = app.patch_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
|
|
assert [x.places for x in event.recurrences.all()] == [7] * 9
|
|
|
|
# try to update recurring event protected fields
|
|
params = {
|
|
'recurrence_days': '1,2',
|
|
}
|
|
resp = app.patch_json(api_url, params=params, status=400)
|
|
assert resp.json['err']
|
|
assert 'cannot be modified' in resp.json['err_desc']
|
|
|
|
assert booking.event.start_datetime.date() == datetime.date(2021, 11, 20)
|
|
|
|
# try to reduce recurrence end date before booked event
|
|
params = {
|
|
'recurrence_end_date': '2021-11-20',
|
|
}
|
|
resp = app.patch_json(api_url, params=params, status=400)
|
|
assert resp.json['err']
|
|
assert 'bookings exist after this date.' in resp.json['err_desc']
|
|
|
|
# reduce recurrence end date after booked event
|
|
params = {
|
|
'recurrence_end_date': '2021-11-21',
|
|
}
|
|
resp = app.patch_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
|
|
assert event.recurrences.count() == 3
|
|
|
|
booking.cancel()
|
|
|
|
# update no more protected fields
|
|
params = {
|
|
'recurrence_days': '1,2,3,4,5',
|
|
'recurrence_week_interval': 1,
|
|
}
|
|
resp = app.patch_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
|
|
assert event.recurrences.count() == 5
|
|
|
|
# update just one custom field
|
|
params = {
|
|
'custom_field_textarea': 'foo bar baz',
|
|
}
|
|
resp = app.patch_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event.refresh_from_db()
|
|
assert event.custom_fields == {
|
|
'text': 'foo',
|
|
'textarea': 'foo bar baz',
|
|
'bool': True,
|
|
}
|
|
params = {
|
|
'custom_field_bool': False,
|
|
}
|
|
resp = app.patch_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event.refresh_from_db()
|
|
assert event.custom_fields == {
|
|
'text': 'foo',
|
|
'textarea': 'foo bar baz',
|
|
'bool': False,
|
|
}
|
|
# reset custom fields
|
|
params = {
|
|
'custom_field_text': '',
|
|
'custom_field_textarea': '',
|
|
'custom_field_bool': None,
|
|
}
|
|
resp = app.patch_json(api_url, params=params)
|
|
assert not resp.json['err']
|
|
event.refresh_from_db()
|
|
assert event.custom_fields == {
|
|
'text': '',
|
|
'textarea': '',
|
|
'bool': None,
|
|
}
|
|
|
|
|
|
def test_event_read_only_fields(app, user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
agenda2 = Agenda.objects.create(label='Foo bar 2', kind='events')
|
|
event = Event.objects.create(
|
|
slug='event', start_datetime=now() + datetime.timedelta(days=5), places=1, agenda=agenda
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
api_url = '/api/agenda/%s/event/' % agenda.slug
|
|
params = {
|
|
'slug': 'slug',
|
|
'agenda': agenda2.slug,
|
|
'primary_event': event.slug,
|
|
'start_datetime': now().isoformat(),
|
|
'places': 42,
|
|
}
|
|
resp = app.post(api_url, params=params)
|
|
assert resp.json['err'] == 0
|
|
new_event = Event.objects.latest('pk')
|
|
assert new_event.slug == 'foo-bar-event'
|
|
assert new_event.agenda == agenda
|
|
assert new_event.primary_event is None
|
|
|
|
api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, new_event.slug)
|
|
params = {
|
|
'slug': 'slug',
|
|
'agenda': agenda2.slug,
|
|
'primary_event': event.slug,
|
|
}
|
|
resp = app.patch(api_url, params=params)
|
|
assert resp.json['err'] == 0
|
|
new_event.refresh_from_db()
|
|
assert new_event.slug == 'foo-bar-event'
|
|
assert new_event.agenda == agenda
|
|
assert new_event.primary_event is None
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-11-01 10:00')
|
|
def test_delete_event(app, user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
event = Event.objects.create(
|
|
slug='event', start_datetime=now() + datetime.timedelta(days=5), places=1, agenda=agenda
|
|
)
|
|
|
|
# no authentication
|
|
resp = app.delete('/api/agenda/%s/event/%s/' % (agenda.slug, event.slug), status=401)
|
|
assert Event.objects.count() == 1
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.delete('/api/agenda/%s/event/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['err'] == 0
|
|
assert not Event.objects.exists()
|
|
assert AgendaSnapshot.objects.count() == 1
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-11-01 10:00')
|
|
def test_delete_event_forbidden(app, user, freezer):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
event = Event.objects.create(
|
|
slug='event', start_datetime=now() + datetime.timedelta(days=5), places=1, agenda=agenda
|
|
)
|
|
booking = Booking.objects.create(event=event)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.delete('/api/agenda/%s/event/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['err'] == 1
|
|
assert 'This cannot be removed' in resp.json['err_desc']
|
|
|
|
freezer.move_to('2021-11-10 10:00')
|
|
resp = app.delete('/api/agenda/%s/event/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['err'] == 0
|
|
assert not Event.objects.exists()
|
|
|
|
event = Event.objects.create(
|
|
slug='event', start_datetime=now() + datetime.timedelta(days=5), places=1, agenda=agenda
|
|
)
|
|
booking = Booking.objects.create(event=event)
|
|
|
|
resp = app.delete('/api/agenda/%s/event/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['err'] == 1
|
|
|
|
booking.cancellation_datetime = now()
|
|
booking.save()
|
|
resp = app.delete('/api/agenda/%s/event/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['err'] == 0
|
|
assert not Event.objects.exists()
|
|
|
|
|
|
@pytest.mark.freeze_time('2021-11-01 10:00')
|
|
def test_delete_recurring_event_forbidden(app, user):
|
|
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
|
start_datetime = now() + datetime.timedelta(days=10)
|
|
event = Event.objects.create(
|
|
start_datetime=start_datetime,
|
|
places=10,
|
|
agenda=agenda,
|
|
recurrence_days=[start_datetime.isoweekday()],
|
|
recurrence_end_date=start_datetime + datetime.timedelta(days=7),
|
|
)
|
|
event.create_all_recurrences()
|
|
event_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
|
|
booking = Booking.objects.create(event=event_recurrence)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
resp = app.delete('/api/agenda/%s/event/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['err'] == 1
|
|
assert 'This cannot be removed' in resp.json['err_desc']
|
|
|
|
booking.cancellation_datetime = now()
|
|
booking.save()
|
|
resp = app.delete('/api/agenda/%s/event/%s/' % (agenda.slug, event.slug))
|
|
assert resp.json['err'] == 0
|
|
assert not Event.objects.exists()
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-07-01 14:00')
|
|
def test_events(app, user):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
# missing slots
|
|
resp = app.get(
|
|
'/api/agendas/events/',
|
|
params={},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['slots'] == ['This field is required.']
|
|
|
|
agenda = Agenda.objects.create(label='Foo')
|
|
agenda2 = Agenda.objects.create(label='Bar')
|
|
start_datetime = now()
|
|
# recurring event
|
|
recurring_event = Event.objects.create(
|
|
slug='recurring-event-slug',
|
|
label='Recurring Event Label',
|
|
start_datetime=start_datetime,
|
|
recurrence_days=[start_datetime.isoweekday()],
|
|
recurrence_end_date=start_datetime + datetime.timedelta(days=8),
|
|
places=10,
|
|
agenda=agenda,
|
|
custom_fields={
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
},
|
|
)
|
|
recurring_event.create_all_recurrences()
|
|
Event.objects.create(
|
|
slug='event-slug',
|
|
label='Event Label',
|
|
start_datetime=start_datetime + datetime.timedelta(days=1),
|
|
places=10,
|
|
agenda=agenda2,
|
|
checked=True,
|
|
check_locked=True,
|
|
invoiced=True,
|
|
)
|
|
# cancelled event, not returned
|
|
Event.objects.create(
|
|
slug='cancelled',
|
|
label='Cancelled',
|
|
start_datetime=start_datetime,
|
|
places=10,
|
|
agenda=agenda,
|
|
cancelled=True,
|
|
)
|
|
|
|
# unknown event in list
|
|
resp = app.get(
|
|
'/api/agendas/events/',
|
|
params={'slots': ['foo@event-slug', 'foo@recurring-event-slug--2022-07-01-1600']},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid slugs: foo@event-slug'
|
|
|
|
# cancelled event in list
|
|
resp = app.get(
|
|
'/api/agendas/events/',
|
|
params={'slots': ['bar@event-slug', 'foo@recurring-event-slug--2022-07-01-1600', 'foo@cancelled']},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid slugs: foo@cancelled'
|
|
|
|
# bad event format
|
|
resp = app.get(
|
|
'/api/agendas/events/',
|
|
params={'slots': ['bar']},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid slugs: bar'
|
|
resp = app.get(
|
|
'/api/agendas/events/',
|
|
params={'slots': ['bar@bar@bar']},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid slugs: bar@bar@bar'
|
|
|
|
# ok
|
|
resp = app.get(
|
|
'/api/agendas/events/',
|
|
params={
|
|
'slots': [
|
|
'bar@event-slug',
|
|
'foo@recurring-event-slug--2022-07-01-1600',
|
|
'foo@recurring-event-slug',
|
|
]
|
|
},
|
|
)
|
|
assert resp.json['data'] == [
|
|
{
|
|
'agenda': 'bar',
|
|
'check_locked': True,
|
|
'checked': True,
|
|
'description': None,
|
|
'duration': None,
|
|
'invoiced': True,
|
|
'label': 'Event Label',
|
|
'places': 10,
|
|
'pricing': None,
|
|
'primary_event': None,
|
|
'publication_datetime': None,
|
|
'recurrence_days': None,
|
|
'recurrence_end_date': None,
|
|
'recurrence_week_interval': 1,
|
|
'slug': 'event-slug',
|
|
'start_datetime': '2022-07-02T16:00:00+02:00',
|
|
'url': None,
|
|
'waiting_list_places': 0,
|
|
},
|
|
{
|
|
'agenda': 'foo',
|
|
'check_locked': False,
|
|
'checked': False,
|
|
'description': None,
|
|
'duration': None,
|
|
'invoiced': False,
|
|
'label': 'Recurring Event Label',
|
|
'places': 10,
|
|
'pricing': None,
|
|
'primary_event': 'recurring-event-slug',
|
|
'publication_datetime': None,
|
|
'recurrence_days': None,
|
|
'recurrence_end_date': None,
|
|
'recurrence_week_interval': 1,
|
|
'slug': 'recurring-event-slug--2022-07-01-1600',
|
|
'start_datetime': '2022-07-01T16:00:00+02:00',
|
|
'url': None,
|
|
'waiting_list_places': 0,
|
|
},
|
|
{
|
|
'agenda': 'foo',
|
|
'check_locked': False,
|
|
'checked': False,
|
|
'description': None,
|
|
'duration': None,
|
|
'invoiced': False,
|
|
'label': 'Recurring Event Label',
|
|
'places': 10,
|
|
'pricing': None,
|
|
'primary_event': None,
|
|
'publication_datetime': None,
|
|
'recurrence_days': [4],
|
|
'recurrence_end_date': '2022-07-09',
|
|
'recurrence_week_interval': 1,
|
|
'slug': 'recurring-event-slug',
|
|
'start_datetime': '2022-07-01T16:00:00+02:00',
|
|
'url': None,
|
|
'waiting_list_places': 0,
|
|
},
|
|
]
|
|
# result sorting ?
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(
|
|
'/api/agendas/events/',
|
|
params={
|
|
'slots': [
|
|
'foo@recurring-event-slug--2022-07-01-1600',
|
|
'bar@event-slug',
|
|
'foo@recurring-event-slug--2022-07-08-1600',
|
|
'foo@recurring-event-slug',
|
|
]
|
|
},
|
|
)
|
|
# there's one less query on django 3.2, the ORM has probably
|
|
# been optimized there
|
|
assert len(ctx.captured_queries) in (5, 6)
|
|
assert [(d['agenda'], d['slug']) for d in resp.json['data']] == [
|
|
('foo', 'recurring-event-slug--2022-07-01-1600'),
|
|
('bar', 'event-slug'),
|
|
('foo', 'recurring-event-slug--2022-07-08-1600'),
|
|
('foo', 'recurring-event-slug'),
|
|
]
|
|
|
|
|
|
def test_events_check_status_params(app, user):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
# missing user_external_id
|
|
resp = app.get(
|
|
'/api/agendas/events/check-status/',
|
|
params={'agendas': 'foo', 'date_start': '2022-05-01', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['user_external_id'] == ['This field is required.']
|
|
|
|
# missing agendas
|
|
resp = app.get(
|
|
'/api/agendas/events/check-status/',
|
|
params={'user_external_id': 'child:42', 'date_start': '2022-05-01', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['This field is required.']
|
|
|
|
# unknown agenda
|
|
resp = app.get(
|
|
'/api/agendas/events/check-status/',
|
|
params={
|
|
'user_external_id': 'child:42',
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar, foo']
|
|
Agenda.objects.create(label='Foo')
|
|
resp = app.get(
|
|
'/api/agendas/events/check-status/',
|
|
params={
|
|
'user_external_id': 'child:42',
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar']
|
|
|
|
# wrong kind
|
|
wrong_agenda = Agenda.objects.create(label='Bar')
|
|
for kind in ['meetings', 'virtual']:
|
|
wrong_agenda.kind = kind
|
|
wrong_agenda.save()
|
|
resp = app.get(
|
|
'/api/agendas/events/check-status/',
|
|
params={
|
|
'user_external_id': 'child:42',
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar']
|
|
|
|
# missing date_start
|
|
resp = app.get(
|
|
'/api/agendas/events/check-status/',
|
|
params={'user_external_id': 'child:42', 'agendas': 'foo', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['date_start'] == ['This field is required.']
|
|
|
|
# missing date_end
|
|
resp = app.get(
|
|
'/api/agendas/events/check-status/',
|
|
params={'user_external_id': 'child:42', 'agendas': 'foo', 'date_start': '2022-05-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['date_end'] == ['This field is required.']
|
|
|
|
# bad date format
|
|
resp = app.get(
|
|
'/api/agendas/events/check-status/',
|
|
params={'user_external_id': 'child:42', 'agendas': 'foo', 'date_start': 'wrong', 'date_end': 'wrong'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert 'wrong format' in resp.json['errors']['date_start'][0]
|
|
assert 'wrong format' in resp.json['errors']['date_end'][0]
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_check_status(app, user):
|
|
agenda = Agenda.objects.create(label='Foo')
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
label='Event Label',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda,
|
|
checked=True,
|
|
)
|
|
Subscription.objects.create(
|
|
agenda=agenda,
|
|
user_external_id='child:42',
|
|
date_start=datetime.date(year=2021, month=9, day=1),
|
|
date_end=datetime.date(year=2022, month=9, day=1),
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-status/'
|
|
params = {
|
|
'user_external_id': 'child:42',
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
|
|
# not booked
|
|
resp = app.get(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'status': 'not-booked',
|
|
}
|
|
assert resp.json['data'][0]['booking'] == {}
|
|
|
|
# 2 bookings found, error
|
|
booking = Booking.objects.create(event=event, user_external_id='child:42')
|
|
booking2 = Booking.objects.create(event=event, user_external_id='child:42')
|
|
Booking.objects.create(event=event, user_external_id='other')
|
|
resp = app.get(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'status': 'error',
|
|
'error_reason': 'too-many-bookings-found',
|
|
}
|
|
assert resp.json['data'][0]['booking'] == {}
|
|
|
|
# booking cancelled
|
|
booking2.delete()
|
|
booking.cancellation_datetime = now()
|
|
booking.save()
|
|
resp = app.get(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'status': 'cancelled',
|
|
}
|
|
assert list(resp.json['data'][0]['booking'].keys()) == [
|
|
'id',
|
|
'in_waiting_list',
|
|
'user_first_name',
|
|
'user_last_name',
|
|
'user_email',
|
|
'user_phone_number',
|
|
'user_was_present',
|
|
'user_absence_reason',
|
|
'user_presence_reason',
|
|
'use_color_for',
|
|
'extra_data',
|
|
'creation_datetime',
|
|
'cancellation_datetime',
|
|
'label',
|
|
]
|
|
assert resp.json['data'][0]['booking']['cancellation_datetime'] == localtime(now()).isoformat()
|
|
|
|
# booking not checked
|
|
booking.cancellation_datetime = None
|
|
booking.save()
|
|
resp = app.get(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'status': 'error',
|
|
'error_reason': 'booking-not-checked',
|
|
}
|
|
assert resp.json['data'][0]['booking']['cancellation_datetime'] is None
|
|
|
|
# absence
|
|
booking.mark_user_absence()
|
|
resp = app.get(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'status': 'absence',
|
|
'check_type': None,
|
|
}
|
|
assert resp.json['data'][0]['booking']['user_was_present'] is False
|
|
assert resp.json['data'][0]['booking']['user_absence_reason'] is None
|
|
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
|
|
|
|
# absence with check type
|
|
booking.user_check.type_slug = 'foo-reason'
|
|
booking.user_check.save()
|
|
resp = app.get(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'status': 'absence',
|
|
'check_type': 'foo-reason',
|
|
}
|
|
assert resp.json['data'][0]['booking']['user_was_present'] is False
|
|
assert resp.json['data'][0]['booking']['user_absence_reason'] == 'foo-reason'
|
|
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
|
|
|
|
# presence
|
|
booking.mark_user_presence()
|
|
resp = app.get(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'status': 'presence',
|
|
'check_type': None,
|
|
}
|
|
assert resp.json['data'][0]['booking']['user_was_present'] is True
|
|
assert resp.json['data'][0]['booking']['user_absence_reason'] is None
|
|
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
|
|
|
|
# presence with check type
|
|
booking.user_check.type_slug = 'foo-reason'
|
|
booking.user_check.save()
|
|
resp = app.get(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'status': 'presence',
|
|
'check_type': 'foo-reason',
|
|
}
|
|
assert resp.json['data'][0]['booking']['user_was_present'] is True
|
|
assert resp.json['data'][0]['booking']['user_absence_reason'] is None
|
|
assert resp.json['data'][0]['booking']['user_presence_reason'] == 'foo-reason'
|
|
|
|
|
|
@pytest.mark.parametrize('partial_bookings', [True, False])
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_check_status_events(app, user, partial_bookings):
|
|
events_type = EventsType.objects.create(
|
|
label='Foo',
|
|
custom_fields=[
|
|
{'varname': 'text', 'label': 'Text', 'field_type': 'text'},
|
|
{'varname': 'textarea', 'label': 'TextArea', 'field_type': 'textarea'},
|
|
{'varname': 'bool', 'label': 'Bool', 'field_type': 'bool'},
|
|
],
|
|
)
|
|
agenda = Agenda.objects.create(
|
|
label='Foo',
|
|
events_type=events_type,
|
|
partial_bookings=partial_bookings,
|
|
invoicing_unit='half_hour',
|
|
invoicing_tolerance=10,
|
|
)
|
|
start_datetime = now()
|
|
# recurring event
|
|
recurring_event = Event.objects.create(
|
|
slug='recurring-event-slug',
|
|
label='Recurring Event Label',
|
|
start_datetime=start_datetime,
|
|
recurrence_days=[start_datetime.isoweekday()],
|
|
recurrence_end_date=start_datetime + datetime.timedelta(days=7),
|
|
places=10,
|
|
agenda=agenda,
|
|
custom_fields={
|
|
'text': 'foo',
|
|
'textarea': 'foo bar',
|
|
'bool': True,
|
|
},
|
|
)
|
|
recurring_event.create_all_recurrences()
|
|
first_event = recurring_event.recurrences.get()
|
|
first_event.checked = True
|
|
first_event.save()
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
label='Event Label',
|
|
start_datetime=start_datetime - datetime.timedelta(days=1),
|
|
places=10,
|
|
agenda=agenda,
|
|
checked=True,
|
|
check_locked=True,
|
|
invoiced=True,
|
|
)
|
|
# not checked event
|
|
notchecked_event = Event.objects.create(
|
|
slug='notchecked-event-slug',
|
|
label='Not Checked Event Label',
|
|
start_datetime=start_datetime - datetime.timedelta(days=2),
|
|
places=10,
|
|
agenda=agenda,
|
|
checked=False,
|
|
)
|
|
# cancelled event, not returned
|
|
Event.objects.create(
|
|
slug='cancelled',
|
|
label='Cancelled',
|
|
start_datetime=start_datetime,
|
|
places=10,
|
|
agenda=agenda,
|
|
cancelled=True,
|
|
)
|
|
Subscription.objects.create(
|
|
agenda=agenda,
|
|
user_external_id='child:42',
|
|
date_start=datetime.date(year=2021, month=9, day=1),
|
|
date_end=datetime.date(year=2022, month=9, day=1),
|
|
)
|
|
booking1 = Booking.objects.create(
|
|
event=first_event,
|
|
user_external_id='child:42',
|
|
start_time=datetime.time(8, 0),
|
|
end_time=datetime.time(17, 0),
|
|
)
|
|
booking1.mark_user_presence(
|
|
check_type_slug='foo-reason', start_time=datetime.time(7, 55), end_time=datetime.time(17, 15)
|
|
)
|
|
booking1.refresh_computed_times(commit=True)
|
|
booking1.user_check.refresh_from_db()
|
|
assert booking1.user_check.computed_start_time == datetime.time(8, 0)
|
|
assert booking1.user_check.computed_end_time == datetime.time(17, 30)
|
|
booking2 = Booking.objects.create(event=event, user_external_id='child:42')
|
|
booking2.mark_user_presence(check_type_slug='foo-reason')
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-status/'
|
|
params = {
|
|
'user_external_id': 'child:42',
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(url, params=params)
|
|
assert len(ctx.captured_queries) == 6
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 3
|
|
assert list(resp.json['data'][0].keys()) == ['event', 'check_status', 'booking']
|
|
assert resp.json['data'][0]['event'] == {
|
|
'description': None,
|
|
'duration': None,
|
|
'label': 'Not Checked Event Label',
|
|
'slug': 'notchecked-event-slug',
|
|
'places': 10,
|
|
'pricing': None,
|
|
'publication_datetime': None,
|
|
'recurrence_days': None,
|
|
'recurrence_end_date': None,
|
|
'recurrence_week_interval': 1,
|
|
'start_datetime': localtime(notchecked_event.start_datetime).isoformat(),
|
|
'url': None,
|
|
'waiting_list_places': 0,
|
|
'agenda': agenda.slug,
|
|
'primary_event': None,
|
|
'check_locked': False,
|
|
'checked': False,
|
|
'invoiced': False,
|
|
'custom_field_bool': None,
|
|
'custom_field_text': '',
|
|
'custom_field_textarea': '',
|
|
}
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'error_reason': 'event-not-checked',
|
|
'status': 'error',
|
|
}
|
|
assert resp.json['data'][0]['booking'] == {}
|
|
assert list(resp.json['data'][1].keys()) == ['event', 'check_status', 'booking']
|
|
assert resp.json['data'][1]['event'] == {
|
|
'description': None,
|
|
'duration': None,
|
|
'label': 'Event Label',
|
|
'slug': 'event-slug',
|
|
'places': 10,
|
|
'pricing': None,
|
|
'publication_datetime': None,
|
|
'recurrence_days': None,
|
|
'recurrence_end_date': None,
|
|
'recurrence_week_interval': 1,
|
|
'start_datetime': localtime(event.start_datetime).isoformat(),
|
|
'url': None,
|
|
'waiting_list_places': 0,
|
|
'agenda': agenda.slug,
|
|
'primary_event': None,
|
|
'check_locked': True,
|
|
'checked': True,
|
|
'invoiced': True,
|
|
'custom_field_bool': None,
|
|
'custom_field_text': '',
|
|
'custom_field_textarea': '',
|
|
}
|
|
assert resp.json['data'][1]['check_status'] == {
|
|
'check_type': 'foo-reason',
|
|
'status': 'presence',
|
|
}
|
|
if partial_bookings:
|
|
assert resp.json['data'][1]['booking'] == {
|
|
'cancellation_datetime': None,
|
|
'use_color_for': None,
|
|
'creation_datetime': localtime(now()).isoformat(),
|
|
'extra_data': None,
|
|
'id': booking2.pk,
|
|
'in_waiting_list': False,
|
|
'user_absence_reason': None,
|
|
'user_email': '',
|
|
'user_first_name': '',
|
|
'user_last_name': '',
|
|
'user_phone_number': '',
|
|
'user_presence_reason': 'foo-reason',
|
|
'user_was_present': True,
|
|
'label': '',
|
|
'start_time': None,
|
|
'end_time': None,
|
|
'duration': None,
|
|
'adjusted_start_time': None,
|
|
'adjusted_end_time': None,
|
|
'adjusted_duration': None,
|
|
'user_check_start_time': None,
|
|
'user_check_end_time': None,
|
|
'user_check_duration': None,
|
|
'computed_start_time': None,
|
|
'computed_end_time': None,
|
|
'computed_duration': None,
|
|
}
|
|
else:
|
|
assert resp.json['data'][1]['booking'] == {
|
|
'cancellation_datetime': None,
|
|
'use_color_for': None,
|
|
'creation_datetime': localtime(now()).isoformat(),
|
|
'extra_data': None,
|
|
'id': booking2.pk,
|
|
'in_waiting_list': False,
|
|
'user_absence_reason': None,
|
|
'user_email': '',
|
|
'user_first_name': '',
|
|
'user_last_name': '',
|
|
'user_phone_number': '',
|
|
'user_presence_reason': 'foo-reason',
|
|
'user_was_present': True,
|
|
'label': '',
|
|
}
|
|
assert list(resp.json['data'][2].keys()) == ['event', 'check_status', 'booking']
|
|
assert resp.json['data'][2]['event'] == {
|
|
'description': None,
|
|
'duration': None,
|
|
'label': 'Recurring Event Label',
|
|
'slug': 'recurring-event-slug--2022-05-30-1600',
|
|
'places': 10,
|
|
'pricing': None,
|
|
'publication_datetime': None,
|
|
'recurrence_days': None,
|
|
'recurrence_end_date': None,
|
|
'recurrence_week_interval': 1,
|
|
'start_datetime': localtime(first_event.start_datetime).isoformat(),
|
|
'url': None,
|
|
'waiting_list_places': 0,
|
|
'agenda': agenda.slug,
|
|
'primary_event': recurring_event.slug,
|
|
'check_locked': False,
|
|
'checked': True,
|
|
'invoiced': False,
|
|
'custom_field_text': 'foo',
|
|
'custom_field_textarea': 'foo bar',
|
|
'custom_field_bool': True,
|
|
}
|
|
assert resp.json['data'][2]['check_status'] == {
|
|
'check_type': 'foo-reason',
|
|
'status': 'presence',
|
|
}
|
|
if partial_bookings:
|
|
assert resp.json['data'][2]['booking'] == {
|
|
'cancellation_datetime': None,
|
|
'use_color_for': None,
|
|
'creation_datetime': localtime(now()).isoformat(),
|
|
'extra_data': None,
|
|
'id': booking1.pk,
|
|
'in_waiting_list': False,
|
|
'user_absence_reason': None,
|
|
'user_email': '',
|
|
'user_first_name': '',
|
|
'user_last_name': '',
|
|
'user_phone_number': '',
|
|
'user_presence_reason': 'foo-reason',
|
|
'user_was_present': True,
|
|
'label': '',
|
|
'start_time': '08:00:00',
|
|
'end_time': '17:00:00',
|
|
'duration': 540,
|
|
'adjusted_start_time': '08:00:00',
|
|
'adjusted_end_time': '17:00:00',
|
|
'adjusted_duration': 540,
|
|
'user_check_start_time': '07:55:00',
|
|
'user_check_end_time': '17:15:00',
|
|
'user_check_duration': 560,
|
|
'computed_start_time': '08:00:00',
|
|
'computed_end_time': '17:30:00',
|
|
'computed_duration': 570,
|
|
}
|
|
else:
|
|
assert resp.json['data'][2]['booking'] == {
|
|
'cancellation_datetime': None,
|
|
'use_color_for': None,
|
|
'creation_datetime': localtime(now()).isoformat(),
|
|
'extra_data': None,
|
|
'id': booking1.pk,
|
|
'in_waiting_list': False,
|
|
'user_absence_reason': None,
|
|
'user_email': '',
|
|
'user_first_name': '',
|
|
'user_last_name': '',
|
|
'user_phone_number': '',
|
|
'user_presence_reason': 'foo-reason',
|
|
'user_was_present': True,
|
|
'label': '',
|
|
}
|
|
|
|
if partial_bookings:
|
|
booking1.mark_user_presence(
|
|
check_type_slug='foo-reason', start_time=datetime.time(7, 55), end_time=datetime.time(12, 15)
|
|
)
|
|
BookingCheck.objects.create(
|
|
booking=booking1,
|
|
start_time=datetime.time(13, 00),
|
|
end_time=datetime.time(17, 15),
|
|
presence=False,
|
|
)
|
|
booking1.refresh_computed_times(commit=True)
|
|
user_check1, user_check2 = booking1.user_checks.all().order_by('start_time')
|
|
assert user_check1.computed_start_time == datetime.time(8, 0)
|
|
assert user_check1.computed_end_time == datetime.time(12, 30)
|
|
assert user_check2.computed_start_time == datetime.time(12, 30)
|
|
assert user_check2.computed_end_time == datetime.time(17, 30)
|
|
with CaptureQueriesContext(connection) as ctx:
|
|
resp = app.get(url, params=params)
|
|
assert len(ctx.captured_queries) == 6
|
|
assert resp.json['err'] == 0
|
|
assert len(resp.json['data']) == 4
|
|
assert resp.json['data'][0]['event']['slug'] == 'notchecked-event-slug'
|
|
assert resp.json['data'][0]['check_status'] == {
|
|
'error_reason': 'event-not-checked',
|
|
'status': 'error',
|
|
}
|
|
assert resp.json['data'][0]['booking'] == {}
|
|
assert resp.json['data'][1]['event']['slug'] == 'event-slug'
|
|
assert resp.json['data'][1]['check_status'] == {
|
|
'check_type': 'foo-reason',
|
|
'status': 'presence',
|
|
}
|
|
assert {
|
|
'id': booking2.pk,
|
|
'user_absence_reason': None,
|
|
'user_presence_reason': 'foo-reason',
|
|
'user_was_present': True,
|
|
'start_time': None,
|
|
'end_time': None,
|
|
'duration': None,
|
|
'adjusted_start_time': None,
|
|
'adjusted_end_time': None,
|
|
'adjusted_duration': None,
|
|
'user_check_start_time': None,
|
|
'user_check_end_time': None,
|
|
'user_check_duration': None,
|
|
'computed_start_time': None,
|
|
'computed_end_time': None,
|
|
'computed_duration': None,
|
|
}.items() <= resp.json['data'][1]['booking'].items()
|
|
assert resp.json['data'][2]['event']['slug'] == 'recurring-event-slug--2022-05-30-1600'
|
|
assert resp.json['data'][2]['check_status'] == {
|
|
'check_type': 'foo-reason',
|
|
'status': 'presence',
|
|
}
|
|
assert {
|
|
'id': booking1.pk,
|
|
'user_absence_reason': None,
|
|
'user_presence_reason': 'foo-reason',
|
|
'user_was_present': True,
|
|
'start_time': '08:00:00',
|
|
'end_time': '17:00:00',
|
|
'duration': 540,
|
|
'adjusted_start_time': '08:00:00',
|
|
'adjusted_end_time': '12:30:00',
|
|
'adjusted_duration': 270,
|
|
'user_check_start_time': '07:55:00',
|
|
'user_check_end_time': '12:15:00',
|
|
'user_check_duration': 260,
|
|
'computed_start_time': '08:00:00',
|
|
'computed_end_time': '12:30:00',
|
|
'computed_duration': 270,
|
|
}.items() <= resp.json['data'][2]['booking'].items()
|
|
assert resp.json['data'][3]['event']['slug'] == 'recurring-event-slug--2022-05-30-1600'
|
|
assert resp.json['data'][3]['check_status'] == {
|
|
'check_type': None,
|
|
'status': 'absence',
|
|
}
|
|
assert {
|
|
'id': booking1.pk,
|
|
'user_absence_reason': None,
|
|
'user_presence_reason': None,
|
|
'user_was_present': False,
|
|
'start_time': '08:00:00',
|
|
'end_time': '17:00:00',
|
|
'duration': 540,
|
|
'adjusted_start_time': '12:30:00',
|
|
'adjusted_end_time': '17:00:00',
|
|
'adjusted_duration': 270,
|
|
'user_check_start_time': '13:00:00',
|
|
'user_check_end_time': '17:15:00',
|
|
'user_check_duration': 255,
|
|
'computed_start_time': '12:30:00',
|
|
'computed_end_time': '17:30:00',
|
|
'computed_duration': 300,
|
|
}.items() <= resp.json['data'][3]['booking'].items()
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_check_status_agendas_filter(app, user):
|
|
agenda1 = Agenda.objects.create(label='Foo')
|
|
agenda2 = Agenda.objects.create(label='Foo 2')
|
|
Event.objects.create(
|
|
slug='event-1',
|
|
label='Event 1',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda1,
|
|
)
|
|
Event.objects.create(
|
|
slug='event-2',
|
|
label='Event 2',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda2,
|
|
)
|
|
Subscription.objects.create(
|
|
agenda=agenda1,
|
|
user_external_id='child:42',
|
|
date_start=datetime.date(year=2021, month=9, day=1),
|
|
date_end=datetime.date(year=2022, month=9, day=1),
|
|
)
|
|
Subscription.objects.create(
|
|
agenda=agenda2,
|
|
user_external_id='child:42',
|
|
date_start=datetime.date(year=2021, month=9, day=1),
|
|
date_end=datetime.date(year=2022, month=9, day=1),
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-status/'
|
|
params = {
|
|
'user_external_id': 'child:42',
|
|
'agendas': 'foo, foo-2',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
resp = app.get(url, params=params)
|
|
assert len(resp.json['data']) == 2
|
|
assert resp.json['data'][0]['event']['slug'] == 'event-1'
|
|
assert resp.json['data'][1]['event']['slug'] == 'event-2'
|
|
|
|
params['agendas'] = 'foo'
|
|
resp = app.get(url, params=params)
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['event']['slug'] == 'event-1'
|
|
|
|
params['agendas'] = 'foo-2'
|
|
resp = app.get(url, params=params)
|
|
assert len(resp.json['data']) == 1
|
|
assert resp.json['data'][0]['event']['slug'] == 'event-2'
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'event_date, expected',
|
|
[
|
|
# just before first day
|
|
((2022, 4, 30, 12, 0), False),
|
|
# first day
|
|
((2022, 5, 1, 12, 0), True),
|
|
# last day
|
|
((2022, 5, 31, 12, 0), True),
|
|
# just after last day
|
|
((2022, 6, 1, 12, 0), False),
|
|
],
|
|
)
|
|
def test_events_check_status_date_filter(app, user, event_date, expected):
|
|
agenda = Agenda.objects.create(label='Foo')
|
|
Event.objects.create(
|
|
slug='event',
|
|
label='Event',
|
|
start_datetime=make_aware(datetime.datetime(*event_date)),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
Subscription.objects.create(
|
|
agenda=agenda,
|
|
user_external_id='child:42',
|
|
date_start=datetime.date(year=2021, month=9, day=1),
|
|
date_end=datetime.date(year=2022, month=9, day=1),
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-status/'
|
|
params = {
|
|
'user_external_id': 'child:42',
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
resp = app.get(url, params=params)
|
|
assert len(resp.json['data']) == int(expected)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'event_date, expected',
|
|
[
|
|
# just before first day
|
|
((2022, 4, 30, 12, 0), False),
|
|
# first day
|
|
((2022, 5, 1, 12, 0), True),
|
|
# last day
|
|
((2022, 5, 31, 12, 0), True),
|
|
# just after last day
|
|
((2022, 6, 1, 12, 0), False),
|
|
],
|
|
)
|
|
def test_events_check_status_subscription_filter(app, user, freezer, event_date, expected):
|
|
agenda = Agenda.objects.create(label='Foo')
|
|
Event.objects.create(
|
|
slug='event',
|
|
label='Event',
|
|
start_datetime=make_aware(datetime.datetime(*event_date)),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
Subscription.objects.create(
|
|
agenda=agenda,
|
|
user_external_id='child:42',
|
|
date_start=datetime.date(year=2022, month=5, day=1),
|
|
date_end=datetime.date(year=2022, month=6, day=1),
|
|
)
|
|
Subscription.objects.create(
|
|
agenda=agenda,
|
|
user_external_id='other',
|
|
date_start=datetime.date(year=2022, month=4, day=1),
|
|
date_end=datetime.date(year=2022, month=7, day=1),
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-status/'
|
|
params = {
|
|
'user_external_id': 'child:42',
|
|
'agendas': 'foo',
|
|
'date_start': '2022-04-01',
|
|
'date_end': '2022-07-01',
|
|
}
|
|
resp = app.get(url, params=params)
|
|
assert len(resp.json['data']) == int(expected)
|
|
|
|
|
|
def test_events_check_lock_params(app, user):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
# missing check_locked
|
|
resp = app.post_json(
|
|
'/api/agendas/events/check-lock/',
|
|
params={'agendas': 'foo', 'date_start': '2022-05-01', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['check_locked'] == ['This field is required.']
|
|
|
|
# missing agendas
|
|
resp = app.post_json(
|
|
'/api/agendas/events/check-lock/',
|
|
params={'check_locked': True, 'date_start': '2022-05-01', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['This field is required.']
|
|
|
|
# unknown agenda
|
|
resp = app.post_json(
|
|
'/api/agendas/events/check-lock/',
|
|
params={
|
|
'check_locked': True,
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar, foo']
|
|
Agenda.objects.create(label='Foo')
|
|
resp = app.post_json(
|
|
'/api/agendas/events/check-lock/',
|
|
params={
|
|
'check_locked': True,
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar']
|
|
|
|
# wrong kind
|
|
wrong_agenda = Agenda.objects.create(label='Bar')
|
|
for kind in ['meetings', 'virtual']:
|
|
wrong_agenda.kind = kind
|
|
wrong_agenda.save()
|
|
resp = app.post_json(
|
|
'/api/agendas/events/check-lock/',
|
|
params={
|
|
'check_locked': True,
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar']
|
|
|
|
# missing date_start
|
|
resp = app.post_json(
|
|
'/api/agendas/events/check-lock/',
|
|
params={'check_locked': True, 'agendas': 'foo', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['date_start'] == ['This field is required.']
|
|
|
|
# missing date_end
|
|
resp = app.post_json(
|
|
'/api/agendas/events/check-lock/',
|
|
params={'check_locked': True, 'agendas': 'foo', 'date_start': '2022-05-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['date_end'] == ['This field is required.']
|
|
|
|
# bad date format
|
|
resp = app.post_json(
|
|
'/api/agendas/events/check-lock/',
|
|
params={'check_locked': True, 'agendas': 'foo', 'date_start': 'wrong', 'date_end': 'wrong'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert 'wrong format' in resp.json['errors']['date_start'][0]
|
|
assert 'wrong format' in resp.json['errors']['date_end'][0]
|
|
|
|
|
|
@pytest.mark.parametrize('partial_bookings', [True, False])
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_check_lock(app, user, partial_bookings):
|
|
agenda = Agenda.objects.create(label='Foo', partial_bookings=partial_bookings)
|
|
assert agenda.invoicing_unit == 'hour'
|
|
assert agenda.invoicing_tolerance == 0
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
label='Event Label',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda,
|
|
checked=True,
|
|
)
|
|
booking = Booking.objects.create(
|
|
event=event,
|
|
user_external_id='child:42',
|
|
start_time=datetime.time(8, 0),
|
|
end_time=datetime.time(17, 0),
|
|
)
|
|
booking.mark_user_presence(
|
|
check_type_slug='foo-reason',
|
|
start_time=datetime.time(7, 55),
|
|
end_time=datetime.time(17, 15),
|
|
)
|
|
# computed times are None, because refresh_computed_times was not called in this test
|
|
assert booking.user_check.computed_start_time is None
|
|
assert booking.user_check.computed_end_time is None
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-lock/'
|
|
params = {
|
|
'check_locked': True,
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
resp = app.post_json(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
event.refresh_from_db()
|
|
assert event.check_locked is True
|
|
booking.refresh_from_db()
|
|
# computed times are still None, refresh_computed_times is not called on lock
|
|
assert booking.user_check.computed_start_time is None
|
|
assert booking.user_check.computed_end_time is None
|
|
|
|
params['check_locked'] = False
|
|
resp = app.post_json(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
event.refresh_from_db()
|
|
assert event.check_locked is False
|
|
booking.refresh_from_db()
|
|
if partial_bookings:
|
|
assert booking.user_check.computed_start_time == datetime.time(7, 0)
|
|
assert booking.user_check.computed_end_time == datetime.time(18, 0)
|
|
else:
|
|
# not refreshed, not a partial_bookings agenda
|
|
assert booking.user_check.computed_start_time is None
|
|
assert booking.user_check.computed_end_time is None
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_check_lock_events(app, user):
|
|
events_type = EventsType.objects.create(
|
|
label='Foo',
|
|
)
|
|
agenda = Agenda.objects.create(label='Foo', events_type=events_type)
|
|
start_datetime = now()
|
|
# recurring event
|
|
recurring_event = Event.objects.create(
|
|
slug='recurring-event-slug',
|
|
label='Recurring Event Label',
|
|
start_datetime=start_datetime,
|
|
recurrence_days=[start_datetime.isoweekday()],
|
|
recurrence_end_date=start_datetime + datetime.timedelta(days=7),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
recurring_event.create_all_recurrences()
|
|
first_event = recurring_event.recurrences.get()
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
label='Event Label',
|
|
start_datetime=start_datetime - datetime.timedelta(days=1),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
# cancelled event, not updated
|
|
cancelled_event = Event.objects.create(
|
|
slug='cancelled',
|
|
label='Cancelled',
|
|
start_datetime=start_datetime,
|
|
places=10,
|
|
agenda=agenda,
|
|
cancelled=True,
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-lock/'
|
|
params = {
|
|
'check_locked': True,
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
resp = app.post_json(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
recurring_event.refresh_from_db()
|
|
assert recurring_event.check_locked is False
|
|
first_event.refresh_from_db()
|
|
assert first_event.check_locked is True
|
|
event.refresh_from_db()
|
|
assert event.check_locked is True
|
|
cancelled_event.refresh_from_db()
|
|
assert cancelled_event.check_locked is False
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_check_lock_agendas_filter(app, user):
|
|
agenda1 = Agenda.objects.create(label='Foo')
|
|
agenda2 = Agenda.objects.create(label='Foo 2')
|
|
event1 = Event.objects.create(
|
|
slug='event-1',
|
|
label='Event 1',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda1,
|
|
)
|
|
event2 = Event.objects.create(
|
|
slug='event-2',
|
|
label='Event 2',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda2,
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-lock/'
|
|
params = {
|
|
'check_locked': True,
|
|
'agendas': 'foo, foo-2',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
app.post_json(url, params=params)
|
|
event1.refresh_from_db()
|
|
assert event1.check_locked is True
|
|
event2.refresh_from_db()
|
|
assert event2.check_locked is True
|
|
|
|
params['agendas'] = 'foo'
|
|
params['check_locked'] = False
|
|
app.post_json(url, params=params)
|
|
event1.refresh_from_db()
|
|
assert event1.check_locked is False
|
|
event2.refresh_from_db()
|
|
assert event2.check_locked is True
|
|
|
|
params['agendas'] = 'foo-2'
|
|
app.post_json(url, params=params)
|
|
event1.refresh_from_db()
|
|
assert event1.check_locked is False
|
|
event2.refresh_from_db()
|
|
assert event2.check_locked is False
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'event_date, expected',
|
|
[
|
|
# just before first day
|
|
((2022, 4, 30, 12, 0), False),
|
|
# first day
|
|
((2022, 5, 1, 12, 0), True),
|
|
# last day
|
|
((2022, 5, 31, 12, 0), True),
|
|
# just after last day
|
|
((2022, 6, 1, 12, 0), False),
|
|
],
|
|
)
|
|
def test_events_check_lock_date_filter(app, user, event_date, expected):
|
|
agenda = Agenda.objects.create(label='Foo')
|
|
event = Event.objects.create(
|
|
slug='event',
|
|
label='Event',
|
|
start_datetime=make_aware(datetime.datetime(*event_date)),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/check-lock/'
|
|
params = {
|
|
'check_locked': True,
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
app.post_json(url, params=params)
|
|
event.refresh_from_db()
|
|
assert event.check_locked == expected
|
|
|
|
|
|
def test_events_invoiced_params(app, user):
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
|
|
# missing invoiced
|
|
resp = app.post_json(
|
|
'/api/agendas/events/invoiced/',
|
|
params={'agendas': 'foo', 'date_start': '2022-05-01', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['invoiced'] == ['This field is required.']
|
|
|
|
# missing agendas
|
|
resp = app.post_json(
|
|
'/api/agendas/events/invoiced/',
|
|
params={'invoiced': True, 'date_start': '2022-05-01', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['This field is required.']
|
|
|
|
# unknown agenda
|
|
resp = app.post_json(
|
|
'/api/agendas/events/invoiced/',
|
|
params={
|
|
'invoiced': True,
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar, foo']
|
|
Agenda.objects.create(label='Foo')
|
|
resp = app.post_json(
|
|
'/api/agendas/events/invoiced/',
|
|
params={
|
|
'invoiced': True,
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar']
|
|
|
|
# wrong kind
|
|
wrong_agenda = Agenda.objects.create(label='Bar')
|
|
for kind in ['meetings', 'virtual']:
|
|
wrong_agenda.kind = kind
|
|
wrong_agenda.save()
|
|
resp = app.post_json(
|
|
'/api/agendas/events/invoiced/',
|
|
params={
|
|
'invoiced': True,
|
|
'agendas': 'foo, bar',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['agendas'] == ['invalid slugs: bar']
|
|
|
|
# missing date_start
|
|
resp = app.post_json(
|
|
'/api/agendas/events/invoiced/',
|
|
params={'invoiced': True, 'agendas': 'foo', 'date_end': '2022-06-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['date_start'] == ['This field is required.']
|
|
|
|
# missing date_end
|
|
resp = app.post_json(
|
|
'/api/agendas/events/invoiced/',
|
|
params={'invoiced': True, 'agendas': 'foo', 'date_start': '2022-05-01'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert resp.json['errors']['date_end'] == ['This field is required.']
|
|
|
|
# bad date format
|
|
resp = app.post_json(
|
|
'/api/agendas/events/invoiced/',
|
|
params={'invoiced': True, 'agendas': 'foo', 'date_start': 'wrong', 'date_end': 'wrong'},
|
|
status=400,
|
|
)
|
|
assert resp.json['err'] == 1
|
|
assert resp.json['err_desc'] == 'invalid payload'
|
|
assert 'wrong format' in resp.json['errors']['date_start'][0]
|
|
assert 'wrong format' in resp.json['errors']['date_end'][0]
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_invoiced(app, user):
|
|
agenda = Agenda.objects.create(label='Foo')
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
label='Event Label',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda,
|
|
checked=True,
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/invoiced/'
|
|
params = {
|
|
'invoiced': True,
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
resp = app.post_json(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
event.refresh_from_db()
|
|
assert event.invoiced is True
|
|
|
|
params['invoiced'] = False
|
|
resp = app.post_json(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
event.refresh_from_db()
|
|
assert event.invoiced is False
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_invoiced_events(app, user):
|
|
events_type = EventsType.objects.create(
|
|
label='Foo',
|
|
)
|
|
agenda = Agenda.objects.create(label='Foo', events_type=events_type)
|
|
start_datetime = now()
|
|
# recurring event
|
|
recurring_event = Event.objects.create(
|
|
slug='recurring-event-slug',
|
|
label='Recurring Event Label',
|
|
start_datetime=start_datetime,
|
|
recurrence_days=[start_datetime.isoweekday()],
|
|
recurrence_end_date=start_datetime + datetime.timedelta(days=7),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
recurring_event.create_all_recurrences()
|
|
first_event = recurring_event.recurrences.get()
|
|
event = Event.objects.create(
|
|
slug='event-slug',
|
|
label='Event Label',
|
|
start_datetime=start_datetime - datetime.timedelta(days=1),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
# cancelled event, not updated
|
|
cancelled_event = Event.objects.create(
|
|
slug='cancelled',
|
|
label='Cancelled',
|
|
start_datetime=start_datetime,
|
|
places=10,
|
|
agenda=agenda,
|
|
cancelled=True,
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/invoiced/'
|
|
params = {
|
|
'invoiced': True,
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
resp = app.post_json(url, params=params)
|
|
assert resp.json['err'] == 0
|
|
recurring_event.refresh_from_db()
|
|
assert recurring_event.invoiced is False
|
|
first_event.refresh_from_db()
|
|
assert first_event.invoiced is True
|
|
event.refresh_from_db()
|
|
assert event.invoiced is True
|
|
cancelled_event.refresh_from_db()
|
|
assert cancelled_event.invoiced is False
|
|
|
|
|
|
@pytest.mark.freeze_time('2022-05-30 14:00')
|
|
def test_events_invoiced_agendas_filter(app, user):
|
|
agenda1 = Agenda.objects.create(label='Foo')
|
|
agenda2 = Agenda.objects.create(label='Foo 2')
|
|
event1 = Event.objects.create(
|
|
slug='event-1',
|
|
label='Event 1',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda1,
|
|
)
|
|
event2 = Event.objects.create(
|
|
slug='event-2',
|
|
label='Event 2',
|
|
start_datetime=now(),
|
|
places=10,
|
|
agenda=agenda2,
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/invoiced/'
|
|
params = {
|
|
'invoiced': True,
|
|
'agendas': 'foo, foo-2',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
app.post_json(url, params=params)
|
|
event1.refresh_from_db()
|
|
assert event1.invoiced is True
|
|
event2.refresh_from_db()
|
|
assert event2.invoiced is True
|
|
|
|
params['agendas'] = 'foo'
|
|
params['invoiced'] = False
|
|
app.post_json(url, params=params)
|
|
event1.refresh_from_db()
|
|
assert event1.invoiced is False
|
|
event2.refresh_from_db()
|
|
assert event2.invoiced is True
|
|
|
|
params['agendas'] = 'foo-2'
|
|
app.post_json(url, params=params)
|
|
event1.refresh_from_db()
|
|
assert event1.invoiced is False
|
|
event2.refresh_from_db()
|
|
assert event2.invoiced is False
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'event_date, expected',
|
|
[
|
|
# just before first day
|
|
((2022, 4, 30, 12, 0), False),
|
|
# first day
|
|
((2022, 5, 1, 12, 0), True),
|
|
# last day
|
|
((2022, 5, 31, 12, 0), True),
|
|
# just after last day
|
|
((2022, 6, 1, 12, 0), False),
|
|
],
|
|
)
|
|
def test_events_invoiced_date_filter(app, user, event_date, expected):
|
|
agenda = Agenda.objects.create(label='Foo')
|
|
event = Event.objects.create(
|
|
slug='event',
|
|
label='Event',
|
|
start_datetime=make_aware(datetime.datetime(*event_date)),
|
|
places=10,
|
|
agenda=agenda,
|
|
)
|
|
|
|
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
url = '/api/agendas/events/invoiced/'
|
|
params = {
|
|
'invoiced': True,
|
|
'agendas': 'foo',
|
|
'date_start': '2022-05-01',
|
|
'date_end': '2022-06-01',
|
|
}
|
|
app.post_json(url, params=params)
|
|
event.refresh_from_db()
|
|
assert event.invoiced == expected
|