chrono/tests/manager/test_event.py

3344 lines
130 KiB
Python

import codecs
import datetime
from unittest import mock
import pytest
import requests
from django.core.management import call_command
from django.db import connection
from django.test.utils import CaptureQueriesContext
from django.utils.timezone import localtime, make_aware, now
from webtest import Upload
from chrono.agendas.models import Agenda, Booking, Desk, Event, EventsType, Subscription
from chrono.utils.lingo import CheckType
from tests.utils import login
pytestmark = pytest.mark.django_db
def test_add_event(app, admin_user):
events_type = EventsType.objects.create(
label='Foo', custom_fields=[{'varname': 'foo', 'label': 'Foo', 'field_type': 'text'}]
)
agenda = Agenda.objects.create(label='Foo bar', maximal_booking_delay=0, events_type=events_type)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert "This agenda doesn't have any event yet." in resp.text
year = now().year + 1
resp = resp.click('New Event')
assert 'custom_field_foo' not in resp.context['form'].fields
resp.form['start_datetime_0'] = '%s-02-15' % year
resp.form['start_datetime_1'] = '17:00'
resp.form['places'] = 10
resp = resp.form.submit()
resp = resp.follow()
event = Event.objects.get(places=10)
assert event.publication_datetime is None
assert "This agenda doesn't have any event yet." not in resp.text
assert '/manage/agendas/%s/events/%s/' % (agenda.id, event.id) in resp.text
assert ('Feb. 15, %s, 5 p.m.' % year) in resp.text
resp_datetimes = app.get('/api/agenda/%s/datetimes/' % agenda.id)
assert resp_datetimes.json['data'][0]['text'] == 'Feb. 15, %s, 5 p.m.' % year
assert resp_datetimes.json['data'][0]['datetime'] == '%s-02-15 17:00:00' % year
# add with errors in datetime parts
for parts in (
('', ''),
('invalid', ''),
('', 'invalid'),
('2019-02-24', 'invalid'),
('invalid', '17:00'),
):
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('New Event')
resp.form['start_datetime_0'] = parts[0]
resp.form['start_datetime_1'] = parts[1]
resp.form['places'] = 10
resp = resp.form.submit()
assert (
resp.text.count('Enter a valid date')
or resp.text.count('Enter a valid time') == 1
or resp.text.count('This field is required.') >= 1
)
@pytest.mark.freeze_time('2021-05-06 14:00')
def test_add_recurring_event(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('New Event')
resp.form['start_datetime_0'] = '2021-06-01'
resp.form['start_datetime_1'] = '17:00'
resp.form['places'] = 10
resp.form['frequency'] = 'unique' # not a recurring event
resp.form['recurrence_days'] = [1]
resp.form.submit().follow()
event = Event.objects.get()
assert event.recurrence_days is None
event.delete()
# add recurring event
resp.form['frequency'] = 'recurring'
resp.form.submit().follow()
event = Event.objects.get(primary_event__isnull=True)
assert event.recurrence_days == [1]
assert Event.objects.filter(primary_event=event).count() == 49
event.delete()
# add recurring event with end date
resp.form['recurrence_end_date'] = '2021-07-01'
resp.form.submit().follow()
event = Event.objects.get(primary_event__isnull=True)
assert event.recurrence_days == [1]
assert Event.objects.filter(primary_event=event).count() == 5
# add recurring event with end date in a very long time
resp.form['recurrence_end_date'] = '2030-01-01'
resp = resp.form.submit()
assert 'Recurrence end date cannot be more than 3 years from now' in resp.text
def test_add_event_on_missing_agenda(app, admin_user):
app = login(app)
app.get('/manage/agendas/%s/add-event' % '0', status=404)
def test_add_event_as_manager(app, manager_user):
agenda = Agenda(label='Foo bar')
agenda.view_role = manager_user.groups.all()[0]
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
app = login(app, username='manager', password='manager')
resp = app.get('/manage/agendas/%s/' % agenda.id, status=302)
app.get('/manage/agendas/%s/add-event' % agenda.id, status=403)
agenda.edit_role = manager_user.groups.all()[0]
agenda.save()
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert '<h2>Settings' in resp.text
resp = resp.click('New Event')
resp.form['start_datetime_0'] = '2016-02-15'
resp.form['start_datetime_1'] = '17:00'
resp.form['places'] = 10
resp = resp.form.submit()
resp = resp.follow()
event = Event.objects.get(places=10)
assert "This agenda doesn't have any event yet." not in resp.text
assert '/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id) in resp.text
assert 'Feb. 15, 2016, 5 p.m.' in resp.text
assert event.duration is None
assert event.end_datetime is None
resp = resp.click('New Event')
resp.form['start_datetime_0'] = '2016-02-15'
resp.form['start_datetime_1'] = '17:00'
resp.form['duration'] = 45
resp.form['places'] = 12
resp = resp.form.submit()
resp = resp.follow()
event = Event.objects.get(places=12)
assert event.duration == 45
assert event.end_datetime == event.start_datetime + datetime.timedelta(minutes=45)
def test_edit_event(settings, app, admin_user):
settings.LANGUAGE_CODE = 'fr-fr' # check date initial value format
agenda = Agenda.objects.create(label='Foo bar')
event = Event.objects.create(
label='Foo',
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
places=20,
agenda=agenda,
)
event2 = Event.objects.create(
label='Other',
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
places=20,
agenda=agenda,
)
assert event.duration is None
assert event.end_datetime is None
other_agenda = Agenda.objects.create(label='Foo bar')
other_event = Event.objects.create(
label='Foo',
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
places=20,
agenda=other_agenda,
)
assert event.slug == other_event.slug
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
assert resp.form['start_datetime_0'].value == '2016-02-15'
assert resp.form['start_datetime_1'].value == '17:00'
assert resp.form['publication_datetime_0'].value == ''
assert resp.form['publication_datetime_1'].value == ''
assert resp.form['duration'].value == ''
assert resp.form['description'].value == ''
resp.form['start_datetime_0'] = '2016-02-16'
resp.form['start_datetime_1'] = '17:00'
resp.form['publication_datetime_0'] = '2020-05-11'
resp.form['publication_datetime_1'] = '12:00'
resp.form['duration'].value = 45
resp.form['places'] = 20
resp.form['description'] = 'A description'
resp = resp.form.submit()
settings.LANGUAGE_CODE = 'en'
resp = resp.follow()
assert '/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id) in resp.text
assert 'Feb. 16, 2016, 5 p.m.' in resp.text
event.refresh_from_db()
assert event.places == 20
assert str(event.publication_datetime) == '2020-05-11 10:00:00+00:00'
assert str(event.publication_datetime.tzinfo) == 'UTC'
assert event.duration == 45
assert event.end_datetime == event.start_datetime + datetime.timedelta(minutes=45)
assert event.description == 'A description'
assert event.slug == other_event.slug
# check slug edition
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
resp.form['slug'] = event2.slug
resp = resp.form.submit()
assert resp.context['form'].errors['slug'] == ['Another event exists with the same identifier.']
def test_event_digit_slug(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.maximal_booking_delay = 0
agenda.save()
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['slug'] = 42
resp = resp.form.submit()
assert 'value cannot be a number' in resp.text
def test_edit_missing_event(app, admin_user):
app = login(app)
app.get('/manage/agendas/999/', status=404)
def test_edit_event_as_manager(app, manager_user):
agenda = Agenda(label='Foo bar')
agenda.view_role = manager_user.groups.all()[0]
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
places=20,
agenda=agenda,
publication_datetime=make_aware(datetime.datetime(2020, 5, 11)),
)
app = login(app, username='manager', password='manager')
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id), status=403)
agenda.edit_role = manager_user.groups.all()[0]
agenda.save()
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('Feb. 15, 2016, 5 p.m.')
assert resp.form['start_datetime_0'].value == '2016-02-15'
assert resp.form['start_datetime_1'].value == '17:00'
assert resp.form['publication_datetime_0'].value == '2020-05-11'
assert resp.form['publication_datetime_1'].value == '00:00'
resp.form['start_datetime_0'] = '2016-02-16'
resp.form['start_datetime_1'] = '17:00'
resp.form['publication_datetime_0'] = ''
resp.form['publication_datetime_1'] = ''
resp.form['places'] = 20
resp = resp.form.submit()
resp = resp.follow()
assert '/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id) in resp.text
assert 'Feb. 16, 2016, 5 p.m.' in resp.text
event.refresh_from_db()
assert event.publication_datetime is None
def test_edit_event_with_custom_fields(app, admin_user):
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', kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
assert 'custom_field_text' not in resp.context['form'].fields
assert 'custom_field_textarea' not in resp.context['form'].fields
assert 'custom_field_bool' not in resp.context['form'].fields
agenda.events_type = events_type
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
assert 'custom_field_text' in resp.context['form'].fields
assert 'custom_field_textarea' in resp.context['form'].fields
assert 'custom_field_bool' in resp.context['form'].fields
resp.form.submit().follow()
event.refresh_from_db()
assert event.custom_fields == {
'text': '',
'textarea': '',
'bool': None,
}
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
resp.form['custom_field_text'] = 'foo'
resp.form['custom_field_textarea'] = 'foo bar'
resp.form['custom_field_bool'] = 'true'
resp.form.submit().follow()
event.refresh_from_db()
assert event.custom_fields == {
'text': 'foo',
'textarea': 'foo bar',
'bool': True,
}
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
assert resp.form['custom_field_text'].value == 'foo'
assert resp.form['custom_field_textarea'].value == 'foo bar'
assert resp.form['custom_field_bool'].value == 'true'
resp.form['custom_field_text'] = ''
resp.form['custom_field_textarea'] = ''
resp.form['custom_field_bool'] = 'false'
resp.form.submit().follow()
event.refresh_from_db()
assert event.custom_fields == {
'text': '',
'textarea': '',
'bool': False,
}
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
resp.form['custom_field_bool'] = 'unknown'
resp.form.submit().follow()
event.refresh_from_db()
assert event.custom_fields == {
'text': '',
'textarea': '',
'bool': None,
}
def test_edit_recurring_event(settings, app, admin_user, freezer):
freezer.move_to('2021-01-12 12:10')
events_type = EventsType.objects.create(
label='Foo', custom_fields=[{'varname': 'foo', 'label': 'Foo', 'field_type': 'text'}]
)
agenda = Agenda.objects.create(
label='Foo bar',
kind='events',
minimal_booking_delay=15,
maximal_booking_delay=30,
events_type=events_type,
)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event.objects.create(start_datetime=now(), places=10, agenda=agenda)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['frequency'] = 'recurring'
resp.form['recurrence_days'] = [localtime().weekday()]
resp = resp.form.submit()
# no end date, events are created for the year to come
assert Event.objects.count() == 54
assert Event.objects.last().start_datetime.strftime('%Y-%m-%d') == '2022-01-11'
# specifying end date removes events
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = '2021-06-01'
resp = resp.form.submit()
assert Event.objects.count() == 21
assert Event.objects.last().start_datetime.strftime('%Y-%m-%d') == '2021-05-25'
# detail page doesn't exist
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.id, event.id), status=404)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert 'On Tuesdays at 1:10 p.m.' in resp.text
# event is bookable regardless of minimal_booking_delay, since it has bookable recurrences
assert len(resp.pyquery.find('.bookable')) == 1
# maximal_booking_delay is accounted for, because no recurrences are bookable
freezer.move_to('2020-11-12')
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert len(resp.pyquery.find('.not-bookable')) == 1
# editing recurring event updates event recurrences
event.refresh_from_db()
event_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['places'] = 20
resp.form['custom_field_foo'] = 'bar'
resp = resp.form.submit().follow()
event_recurrence.refresh_from_db()
assert event_recurrence.places == 20
assert event_recurrence.custom_fields == {'foo': 'bar'}
event.refresh_from_db()
assert event.custom_fields == {'foo': 'bar'}
# but some fields should not be updated
assert event_recurrence.slug != event.slug
assert not event_recurrence.recurrence_days
# changing recurrence attribute removes event recurrences
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['frequency'] = 'unique'
resp = resp.form.submit().follow()
assert not Event.objects.filter(primary_event=event).exists()
# same goes with changing slug
event.recurrence_days = [1]
event.save()
event.create_all_recurrences()
event_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
assert Event.objects.filter(primary_event=event, slug__startswith='foo-bar-event').exists()
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['slug'] = 'hop'
resp = resp.form.submit().follow()
assert not Event.objects.filter(primary_event=event, slug__startswith='foo-bar-event').exists()
# changing recurring attribute or slug is forbidden if there are bookings for future recurrences
event_recurrence = Event.objects.get(
primary_event=event, start_datetime=event.start_datetime + datetime.timedelta(days=7)
)
Booking.objects.create(event=event_recurrence)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
assert 'disabled' in resp.form['frequency'].attrs
assert all('disabled' in resp.form.get('recurrence_days', index=i).attrs for i in range(7))
assert 'disabled' in resp.form['recurrence_week_interval'].attrs
assert 'disabled' in resp.form['slug'].attrs
assert 'disabled' in resp.form['start_datetime_0'].attrs
assert 'disabled' in resp.form['start_datetime_1'].attrs
# changing it anyway doesn't work
resp.form['slug'] = 'changed'
resp = resp.form.submit()
assert not Event.objects.filter(slug='changed').exists()
# deletion of event recurrence is not allowed
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.id, event_recurrence.id))
assert 'Delete' not in resp.text
resp = resp.click('Options')
assert 'Delete' not in resp.text
assert {
'slug',
'frequency',
'recurrence_days',
'recurence_weekly_interval',
'recurrence_end_date',
'publication_datetime_0',
'publication_datetime_1',
'custom_field_foo',
}.isdisjoint(resp.form.fields)
resp.form.submit().follow()
# custom fields not changed
event_recurrence.refresh_from_db()
assert event_recurrence.custom_fields == {'foo': 'bar'}
def test_edit_recurring_event_with_end_date(settings, app, admin_user, freezer):
freezer.move_to('2021-01-12 12:10')
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(
start_datetime=now(), places=10, recurrence_days=list(range(7)), agenda=agenda
)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = (localtime() + datetime.timedelta(days=5)).strftime('%Y-%m-%d')
resp = resp.form.submit()
# recurrences are created automatically
event = Event.objects.get(recurrence_days__isnull=False)
assert Event.objects.filter(primary_event=event).count() == 5
assert Event.objects.filter(primary_event=event, start_datetime=now()).exists()
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['start_datetime_1'] = (localtime() + datetime.timedelta(hours=1)).strftime('%H:%M')
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 5
assert Event.objects.filter(
primary_event=event, start_datetime=now() + datetime.timedelta(hours=1)
).exists()
# old recurrences were deleted
assert not Event.objects.filter(primary_event=event, start_datetime=now()).exists()
# if start datetime of a recurrence is edited, it stays that way
recurrence = event.recurrences.first()
recurrence.start_datetime += datetime.timedelta(hours=1)
recurrence.save()
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 5
assert Event.objects.filter(primary_event=event, start_datetime=recurrence.start_datetime).count() == 1
# ensure recurrence_end_date has not been propagated
assert not Event.objects.filter(primary_event=event, recurrence_end_date__isnull=False).exists()
# editing recurrence_end_date is permitted as long as bookings are not impacted
event_recurrence = Event.objects.get(primary_event=event, start_datetime__day=15)
Booking.objects.create(event=event_recurrence)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = (localtime() + datetime.timedelta(days=6)).strftime('%Y-%m-%d')
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 6
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = (localtime() + datetime.timedelta(days=4)).strftime('%Y-%m-%d')
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 4
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp.form['recurrence_end_date'] = (localtime() + datetime.timedelta(days=2)).strftime('%Y-%m-%d')
resp = resp.form.submit()
assert Event.objects.filter(primary_event=event).count() == 4
assert 'Bookings exist after this date' in resp.text
def test_edit_booked_event_disable_frequency_choice(settings, app, admin_user, freezer):
freezer.move_to('2021-01-12 12:10')
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(start_datetime=now(), places=10, agenda=agenda)
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
assert 'disabled' not in resp.form['frequency'].attrs
assert 'This field will not be editable once event has bookings.' in resp.text
Booking.objects.create(event=event)
resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
assert 'disabled' in resp.form['frequency'].attrs
assert 'cannot be modified' in resp.form['frequency'].attrs['title']
assert 'This field will not be editable once event has bookings.' not in resp.text
def test_booked_places(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
event.save()
Booking(event=event).save()
Booking(event=event).save()
app = login(app)
day = event.start_datetime
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month), status=200)
assert '8 remaining places' in resp.text
assert '(2/10 bookings)' in resp.text
def test_event_classes(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
event.save()
for _ in range(2):
Booking(event=event).save()
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert 'full' not in resp.text
assert 'overbooking' not in resp.text
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '<span class="tag">Full</span>' not in resp
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '<span class="tag">Full</span>' not in resp
for _ in range(8):
Booking(event=event).save()
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert 'full' in resp.text
assert 'overbooking' not in resp.text
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '<span class="tag">Full</span>' in resp
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '<span class="tag">Full</span>' in resp
Booking(event=event).save()
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
assert 'full' in resp.text
assert 'overbooking' in resp.text
def test_event_detail_backoffice_url_translation(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
event.save()
Booking.objects.create(event=event, backoffice_url='publik://default/foo/')
app = login(app)
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert 'http://example.org/foo/' in resp.text
def test_delete_event(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
event.save()
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
resp = resp.form.submit()
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
assert Event.objects.count() == 0
def test_delete_busy_event(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event(start_datetime=now() + datetime.timedelta(days=10), places=10, agenda=agenda)
event.save()
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
assert 'Are you sure you want to delete this event?' in resp.text
booking = Booking(event=event)
booking.save()
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
assert 'This cannot be removed' in resp.text
booking.cancellation_datetime = now()
booking.save()
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
assert 'Are you sure you want to delete this event?' in resp.text
# suddenly the booking is no longer cancelled, but the admin clicks on the
# delete button.
booking.cancellation_datetime = None
booking.save()
resp = resp.form.submit(status=403)
def test_delete_recurring_event(app, admin_user, freezer):
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.weekday()],
recurrence_end_date=start_datetime + datetime.timedelta(days=15),
)
event.create_all_recurrences()
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
assert 'Are you sure you want to delete this event?' in resp.text
event_recurrence = Event.objects.get(primary_event=event, start_datetime=event.start_datetime)
booking = Booking.objects.create(event=event_recurrence)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
assert 'This cannot be removed' in resp.text
booking.cancellation_datetime = now()
booking.save()
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
assert 'Are you sure you want to delete this event?' in resp.text
booking.cancellation_datetime = None
booking.save()
freezer.move_to(now() + datetime.timedelta(days=11))
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
assert 'Are you sure you want to delete this event?' in resp.text
def test_delete_event_as_manager(app, manager_user):
agenda = Agenda(label='Foo bar')
agenda.edit_role = manager_user.groups.all()[0]
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event(start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)), places=10, agenda=agenda)
event.save()
app = login(app, username='manager', password='manager')
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click(href='/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id))
resp = resp.click('Delete')
resp = resp.form.submit()
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
assert Event.objects.count() == 0
def test_export_events(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar')
app = login(app)
resp = app.get('/manage/agendas/%s/export-events' % agenda.id)
csv_export = resp.text
assert (
csv_export
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date/time,duration\r\n'
)
resp = app.get('/manage/agendas/%s/import-events' % agenda.id)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,00:30,10', 'text/csv')
resp.form.submit(status=302)
resp = app.get('/manage/agendas/%s/export-events' % agenda.id)
csv_export = resp.text
assert (
csv_export
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date/time,duration\r\n'
'2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n'
)
resp = app.get('/manage/agendas/%s/import-events' % agenda.id)
resp.form['events_csv_file'] = Upload(
't.csv',
b'2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16 00:00,90',
'text/csv',
)
resp.form.submit(status=302)
resp = app.get('/manage/agendas/%s/export-events' % agenda.id)
csv_export = resp.text
assert (
csv_export
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date/time,duration\r\n'
'2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n'
'2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16 00:00,90\r\n'
)
def test_export_events_wrong_kind(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
app = login(app)
app.get('/manage/agendas/%s/export-events' % agenda.id, status=404)
agenda.kind = 'virtual'
agenda.save()
app.get('/manage/agendas/%s/export-events' % agenda.id, status=404)
def test_import_events(app, admin_user):
agenda = Agenda(label='Foo bar')
agenda.save()
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200)
resp = resp.click('Import Events')
sample_csv_resp = resp.click('Download sample file')
assert sample_csv_resp.content_type == 'text/csv'
assert sample_csv_resp.text.startswith('date,time')
resp.form['events_csv_file'] = Upload('t.csv', sample_csv_resp.content, 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'xx', 'text/csv')
resp = resp.form.submit(status=200)
assert 'Invalid file format.' in resp.text
resp.form['events_csv_file'] = Upload('t.csv', b'xxxx\0\0xxxx', 'text/csv')
resp = resp.form.submit(status=200)
assert 'Invalid file format.' in resp.text
resp.form['events_csv_file'] = Upload('t.csv', b'2016-14-16,18:00', 'text/csv')
resp = resp.form.submit(status=200)
assert 'Invalid file format.' in resp.text
resp.form['events_csv_file'] = Upload('t.csv', b'2016-14-16,18:00,10', 'text/csv')
resp = resp.form.submit(status=200)
assert 'Invalid file format. (date/time format' in resp.text
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,blah', 'text/csv')
resp = resp.form.submit(status=200)
assert 'Invalid file format. (number of places,' in resp.text
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,blah', 'text/csv')
resp = resp.form.submit(status=200)
assert 'Invalid file format. (number of places in waiting list,' in resp.text
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,' + b'x' * 151, 'text/csv')
resp = resp.form.submit(status=200)
assert 'Ensure this value has at most 150' in resp.text
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10', 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
assert Event.objects.all()[0].places == 10
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5', 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
assert Event.objects.all()[0].places == 10
assert Event.objects.all()[0].waiting_list_places == 5
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', '2016-09-16,18:00,10,5,éléphant'.encode(), 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
assert Event.objects.all()[0].places == 10
assert Event.objects.all()[0].waiting_list_places == 5
assert Event.objects.all()[0].label == 'éléphant'
Event.objects.all().delete()
# BOM
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv', codecs.BOM_UTF8 + '2016-09-16,18:00,10,5,éléphant'.encode(), 'text/csv'
)
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
assert Event.objects.all()[0].places == 10
assert Event.objects.all()[0].waiting_list_places == 5
assert Event.objects.all()[0].label == 'éléphant'
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv', '2016-09-16,18:00,10,5,éléphant'.encode('iso-8859-15'), 'text/csv'
)
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
assert Event.objects.all()[0].places == 10
assert Event.objects.all()[0].waiting_list_places == 5
assert Event.objects.all()[0].label == 'éléphant'
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv', '2016-09-16,18:00,10,5,éléphant'.encode('eucjp'), 'text/csv'
)
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
assert Event.objects.all()[0].start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
assert Event.objects.all()[0].places == 10
assert Event.objects.all()[0].waiting_list_places == 5
assert Event.objects.all()[0].label == '\x8f«±l\x8f«±phant' # eucjp interpreted as iso-8859-15
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
b'date,time,etc.\n' b'2016-09-16,18:00,10,5,bla bla bla\n' b'\n' b'2016-09-19,18:00,10',
'text/csv',
)
resp = resp.form.submit(status=302)
assert Event.objects.count() == 2
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
'"date"\t"time"\t"etc."\n'
'"2016-09-16"\t"18:00"\t"10"\t"5"\t"éléphant"\n'
'"2016-09-19"\t"18:00"\t"10"'.encode('iso-8859-15'),
'text/csv',
)
resp = resp.form.submit(status=302)
assert Event.objects.count() == 2
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
event = Event.objects.latest('pk')
assert event.start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
assert event.places == 10
assert event.waiting_list_places == 5
assert event.label == 'label'
assert event.slug == 'slug'
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
event = Event.objects.latest('pk')
assert event.slug == 'slug'
# additional optional attributes
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug,,,,,', 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
event = Event.objects.get()
assert event.description == ''
assert event.pricing == ''
assert event.url == ''
assert event.publication_datetime is None
assert event.duration is None
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
b'2016-09-16,18:00,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90',
'text/csv',
)
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
event = Event.objects.get()
assert event.description == 'description\nfoobar'
assert event.pricing == 'pricing'
assert event.url == 'url'
assert str(event.publication_datetime) == '2016-10-15 22:00:00+00:00'
assert str(event.publication_datetime.tzinfo) == 'UTC'
assert event.duration == 90
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
b'2016-09-16,18:00,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16 10:00,90',
'text/csv',
)
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
event = Event.objects.get()
assert event.description == 'description\nfoobar'
assert event.pricing == 'pricing'
assert event.url == 'url'
assert str(event.publication_datetime) == '2016-10-16 08:00:00+00:00'
assert str(event.publication_datetime.tzinfo) == 'UTC'
assert event.duration == 90
# publication date/time bad format
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv', b'2016-09-16,18:00,10,5,label,slug,description,pricing,url,foobar', 'text/csv'
)
resp = resp.form.submit(status=200)
assert 'Invalid file format. (date/time format' in resp.text
# duration bad format
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv', b'2016-09-16,18:00,10,5,label,slug,description,pricing,url,2016-09-16,foobar', 'text/csv'
)
resp = resp.form.submit(status=200)
assert 'Invalid file format. (duration' in resp.text
# import events with empty slugs
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
b'2016-09-16,18:00,10,5,labela,labelb,,pricing,\n'
b'2016-09-17,18:00,10,5,labela,labelb-1,,pricing,\n'
b'2016-09-18,18:00,10,5,labela,labelb-2,,pricing,\n'
b'2016-09-18,18:00,10,5,labelb,,,pricing,\n'
b'2016-09-18,18:00,10,5,labelb,,,pricing,\n',
'text/csv',
)
with CaptureQueriesContext(connection) as ctx:
resp = resp.form.submit(status=302)
assert len(ctx.captured_queries) == 22
assert Event.objects.count() == 5
assert set(Event.objects.values_list('slug', flat=True)) == {
'labelb',
'labelb-1',
'labelb-2',
'labelb-3',
'labelb-4',
}
# forbidden numerical slug
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,1234', 'text/csv')
resp = resp.form.submit(status=200)
assert 'value cannot be a number' in resp.text
assert 'Identifier:' in resp.text # verbose_name is shown, not field name ('slug:')
def test_import_events_existing_event(app, admin_user, freezer):
agenda = Agenda.objects.create(label='Foo bar')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
app = login(app)
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
b'2016-09-16,18:00,10,5,label,slug\n2016-09-16,18:00,10,5,label,slug\n',
'text/csv',
)
resp.form.submit(status=302)
assert agenda.event_set.count() == 1
event = Event.objects.latest('pk')
def check_import(date, time, with_alert):
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
b'%s,%s,10,5,label,slug\n' % (date.encode(), time.encode()),
'text/csv',
)
resp = resp.form.submit(status=302).follow()
assert agenda.event_set.count() == 1
event.refresh_from_db()
if with_alert:
assert (
'<li class="warning">Event &quot;label&quot; start date has changed. Do not forget to notify the registrants.</li>'
in resp.text
)
else:
assert (
'<li class="warning">Event &quot;label&quot; start date has changed. Do not forget to notify the registrants.</li>'
not in resp.text
)
assert event.start_datetime == make_aware(
datetime.datetime(*(int(v) for v in date.split('-')), *(int(v) for v in time.split(':')))
)
# change date or time
# event in the past, no alert, with or without booking
Booking.objects.create(
event=event, cancellation_datetime=make_aware(datetime.datetime(2017, 5, 20, 10, 30))
)
check_import('2016-09-15', '18:00', False) # change date
check_import('2016-09-15', '17:00', False) # change time
# available booking
Booking.objects.create(event=event)
check_import('2016-09-14', '17:00', False) # change date
check_import('2016-09-14', '16:00', False) # change time
# date in the future
freezer.move_to('2016-09-01')
# warn if available booking only
check_import('2016-09-13', '16:00', True) # change date
check_import('2016-09-13', '15:00', True) # change time
# no available booking
Booking.objects.all().delete()
Booking.objects.create(
event=event, cancellation_datetime=make_aware(datetime.datetime(2017, 5, 20, 10, 30))
)
check_import('2016-09-12', '15:00', False) # change date
check_import('2016-09-12', '14:00', False) # change time
# check there is a message per changed event
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
b'2016-09-16,18:00,10,5,label,slug\n2016-09-16,19:00,10,5,label,other_slug\n',
'text/csv',
)
resp.form.submit(status=302)
assert agenda.event_set.count() == 2
event2 = Event.objects.latest('pk')
Booking.objects.create(event=event)
Booking.objects.create(event=event2)
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload(
't.csv',
b'2016-09-17,18:00,10,5,label,slug\n2016-09-17,19:00,10,5,,other_slug\n2016-09-17,20:00,10,5,,other_slug\n',
'text/csv',
)
resp = resp.form.submit(status=302).follow()
assert agenda.event_set.count() == 2
assert (
resp.text.count(
'Event &quot;label&quot; start date has changed. Do not forget to notify the registrants.'
)
== 1
)
assert (
resp.text.count(
'Event &quot;other_slug&quot; start date has changed. Do not forget to notify the registrants.'
)
== 1
)
def test_import_events_wrong_kind(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
app = login(app)
app.get('/manage/agendas/%s/import-events' % agenda.id, status=404)
agenda.kind = 'virtual'
agenda.save()
app.get('/manage/agendas/%s/import-events' % agenda.id, status=404)
@pytest.mark.freeze_time('2022-05-24')
def test_event_detail(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() + datetime.timedelta(days=1),
places=10,
waiting_list_places=2,
agenda=agenda,
)
Booking.objects.create(event=event, user_last_name="User's 1")
Booking.objects.create(event=event, user_last_name='User 2', in_waiting_list=True)
login(app)
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert 'Bookings (1/10)' in resp.text
assert 'User&#39;s 1, May 24, 2022, 2 a.m.' in resp.text
assert 'Waiting List (1/2): 1 remaining place' in resp.text
assert 'User 2, May 24, 2022, 2 a.m.' in resp.text
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
agenda.save()
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert 'Bookings (1/10)' in resp.text
assert '&lt;b&gt;User&#39;s 1&lt;/b&gt; Foo Bar, May 24, 2022, 2 a.m.' in resp.text
assert 'Waiting List (1/2): 1 remaining place' in resp.text
assert '&lt;b&gt;User 2&lt;/b&gt; Foo Bar, May 24, 2022, 2 a.m.' in resp.text
def test_event_cancellation(app, admin_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
)
login(app)
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert 'Bookings (0/10)' in resp.text
resp = resp.click('Cancel', href='/cancel')
assert 'related bookings' not in resp.text
Booking.objects.create(event=event, user_last_name='User 1')
Booking.objects.create(event=event, user_last_name='User 2')
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert 'Bookings (2/10)' in resp.text
resp = resp.click('Cancel', href='manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
assert '2 related bookings will also be cancelled.' in resp.text
resp = resp.form.submit().follow()
assert 'Cancelled' in resp.text
assert 'Bookings (0/10)' in resp.text
assert Booking.objects.filter(event=event, cancellation_datetime__isnull=False).count() == 2
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert '/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk) not in resp.text
def test_event_cancellation_error_report(app, admin_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
)
day = event.start_datetime
def mocked_requests_connection_error(*args, **kwargs):
raise requests.exceptions.ConnectionError('unreachable')
for _ in range(5):
Booking.objects.create(event=event, cancel_callback_url='http://example.org/jump/trigger/')
login(app)
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
resp = resp.click('Cancellation error reports')
assert 'No error report' in resp.text
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
resp = resp.form.submit().follow()
assert 'Cancellation in progress' in resp.text
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
mock_send.side_effect = mocked_requests_connection_error
call_command('cancel_events')
event.refresh_from_db()
assert not event.cancelled and not event.cancellation_scheduled
assert not Booking.objects.filter(cancellation_datetime__isnull=False).exists()
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
assert 'Errors occured during cancellation of event "xyz".' in resp.text
# warning doesn't go away
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
assert 'Errors occured during cancellation of event "xyz".' in resp.text
resp = resp.click('Details')
assert resp.text.count('unreachable') == 5
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
assert 'Errors occured during cancellation of event "xyz".' not in resp.text
resp = resp.click('Cancellation error reports')
assert '(5 failures)' in resp.text
resp = resp.click(str(event))
resp = resp.click('Force cancellation')
resp = resp.form.submit().follow()
event.refresh_from_db()
assert event.cancelled and not event.cancellation_scheduled
assert Booking.objects.filter(cancellation_datetime__isnull=False).count() == 5
def test_event_cancellation_error_report_backofice_url_translation(app, admin_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
)
day = event.start_datetime
def mocked_requests_connection_error(*args, **kwargs):
raise requests.exceptions.ConnectionError('unreachable')
for _ in range(5):
Booking.objects.create(
event=event,
cancel_callback_url='http://example.org/jump/trigger/',
backoffice_url='publik://default/',
)
login(app)
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
resp = resp.click('Cancellation error reports')
assert 'No error report' in resp.text
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
resp = resp.form.submit().follow()
assert 'Cancellation in progress' in resp.text
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
mock_send.side_effect = mocked_requests_connection_error
call_command('cancel_events')
event.refresh_from_db()
assert not event.cancelled and not event.cancellation_scheduled
assert not Booking.objects.filter(cancellation_datetime__isnull=False).exists()
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
assert 'Errors occured during cancellation of event "xyz".' in resp.text
resp = resp.click('Cancellation error reports')
assert '(5 failures)' in resp.text
resp = resp.click(str(event))
assert 'http://example.org/' in resp.text
def test_event_cancellation_forbidden(app, admin_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
)
Booking.objects.create(event=event)
booking = Booking.objects.create(event=event, backoffice_url='http://example.org/backoffice/xx/')
login(app)
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
assert 'event has bookings with no callback url configured' in resp.text
assert 'Proceed with cancellation' not in resp.text
booking.cancel()
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
assert 'event has bookings with no callback url configured' not in resp.text
assert 'Proceed with cancellation' in resp.text
def test_event_booking_form_url(settings, app, admin_user):
settings.TEMPLATE_VARS = {'eservices_url': 'http://demarches/'}
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
)
day = event.start_datetime
login(app)
assert event.get_booking_form_url() is None
resp = app.get('/manage/agendas/%d/%d/%d/' % (agenda.pk, day.year, day.month))
assert 'Booking form' not in resp.text
resp = app.get('/manage/agendas/%d/events/open/' % agenda.pk)
assert 'Booking form' not in resp.text
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert 'Booking form' not in resp.text
agenda.booking_form_url = '{{ eservices_url }}backoffice/submission/inscription-aux-activites/'
agenda.save()
assert (
event.get_booking_form_url()
== 'http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s'
% (agenda.slug, event.slug)
)
resp = app.get('/manage/agendas/%d/%d/%d/' % (agenda.pk, day.year, day.month))
assert (
'<a class="link-action-text" href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s&ReturnURL=%s">Booking form</a>'
% (
agenda.slug,
event.slug,
'http://testserver/manage/agendas/%d/%d/%d/' % (agenda.pk, day.year, day.month),
)
in resp.text
)
resp = app.get('/manage/agendas/%d/events/open/' % agenda.pk)
assert (
'<a class="link-action-text" href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s&ReturnURL=%s">Booking form</a>'
% (agenda.slug, event.slug, 'http://testserver/manage/agendas/%d/events/open/' % agenda.pk)
in resp.text
)
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert (
'<a href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s&ReturnURL=%s">Booking form</a>'
% (agenda.slug, event.slug, 'http://testserver/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
in resp.text
)
def test_booking_cancellation_events_agenda(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event(label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda)
event.save()
booking = Booking.objects.create(event=event)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.id, event.id))
assert 'Bookings (1/10)' in resp.text
resp = resp.click('Cancel', href='bookings/')
resp = resp.form.submit()
assert resp.location.endswith('/manage/agendas/%s/events/%s/' % (agenda.id, event.id))
booking.refresh_from_db()
assert booking.cancellation_datetime
resp = resp.follow()
assert 'Bookings (0/10)' in resp.text
# again
app.get('/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, booking.pk), status=404)
# test secondary booking
primary = Booking.objects.create(event=event)
secondary = Booking.objects.create(event=event, primary_booking=primary)
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert 'Bookings (2/10)' in resp.text
assert '/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, primary.pk) in resp.text
assert '/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, secondary.pk) not in resp.text
app.get('/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, secondary.pk), status=404)
app.get('/manage/agendas/%s/bookings/%s/cancel' % (agenda.pk, primary.pk)).form.submit()
primary.refresh_from_db()
secondary.refresh_from_db()
assert primary.cancellation_datetime
assert secondary.cancellation_datetime
def test_event_check(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
agenda2 = Agenda.objects.create(label='Events', kind='events')
Desk.objects.create(agenda=agenda2, slug='_exceptions_holder')
event = Event.objects.create(
label='xyz',
start_datetime=now() + datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking1 = Booking.objects.create(
event=event, user_external_id='user:1', user_first_name='User', user_last_name='42'
)
Booking.objects.create(
event=event, user_external_id='user:2', user_first_name="User's", user_last_name='01'
)
Booking.objects.create(
event=event, user_external_id='user:3', user_first_name='User', user_last_name='17'
)
Booking.objects.create(
event=event, user_external_id='user:4', user_first_name='User', user_last_name='35'
)
Booking.objects.create(
event=event, user_external_id='user:5', user_first_name='User', user_last_name='05'
)
booking6 = Booking.objects.create(
event=event, user_external_id='user:6', user_first_name='User', user_last_name='12 Cancelled'
)
booking6.cancel()
booking7 = Booking.objects.create(
event=event,
user_external_id='user:7',
user_first_name='User',
user_last_name='Waiting',
in_waiting_list=True,
)
booking8 = Booking.objects.create(
event=event,
user_external_id='user:8',
user_first_name='User',
user_last_name='Waiting and Cancelled',
in_waiting_list=True,
)
booking8.cancel()
booking9 = Booking.objects.create(
event=event,
user_external_id='user:1',
user_first_name='User',
user_last_name='Secondary',
primary_booking=booking1,
)
login(app)
# event not in past
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) not in resp
app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), status=404)
event.start_datetime = localtime(now()).replace(hour=22, minute=0) # it's ok all the day
event.save()
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) in resp
# unknown agenda
app.get('/manage/agendas/%s/events/%s/check' % (0, event.pk), status=404)
# wrong agenda
app.get('/manage/agendas/%s/events/%s/check' % (agenda2.pk, event.pk), status=404)
resp = resp.click('Check')
assert (
resp.text.index('Bookings (6/10)')
< resp.text.index("User&#39;s 01")
< resp.text.index('User 05')
< resp.text.index('User 17')
< resp.text.index('User 35')
< resp.text.index('User 42')
< resp.text.index('Waiting List (1/5)')
< resp.text.index('User Waiting')
)
assert 'User 12 Cancelled' not in resp
assert 'User Waiting and Cancelled' not in resp
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:9',
user_first_name='Subscription',
user_last_name='43',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:10',
user_first_name='Subscription',
user_last_name='14',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:7',
user_first_name='Subscription',
user_last_name='Waiting',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:42',
user_first_name='Subscription',
user_last_name='Too soon',
date_start=now() - datetime.timedelta(days=1),
date_end=now(),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:42',
user_first_name='Subscription',
user_last_name='Too late',
date_start=now() + datetime.timedelta(days=1),
date_end=now() + datetime.timedelta(days=2),
)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert (
resp.text.index('Bookings (6/10)')
< resp.text.index("User&#39;s 01")
< resp.text.index('User 05')
< resp.text.index('User 12 Cancelled')
< resp.text.index('Subscription 14')
< resp.text.index('(Not booked)')
< resp.text.index('User 17')
< resp.text.index('User 35')
< resp.text.index('User 42')
< resp.text.index('Subscription 43')
< resp.text.index('Waiting List (1/5)')
< resp.text.index('User Waiting')
< resp.text.index('User Waiting and Cancelled')
)
assert 'Subscription Waiting' not in resp
assert 'Subscription 42' not in resp
assert 'Subscription too soon' not in resp
assert 'Subscription too late' not in resp
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '&lt;b&gt;User&#39;s 01&lt;/b&gt; Foo Bar' in resp
assert '&lt;b&gt;Subscription 14&lt;/b&gt; Foo Bar' in resp
assert '&lt;b&gt;User Waiting&lt;/b&gt; Foo Bar' in resp
# cancelled booking
token = resp.context['csrf_token']
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking6.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking6.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# booking in waiting list
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking7.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking7.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# secondary booking
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking9.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking9.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# unknown agenda
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (0, booking1.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (0, booking1.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# wrong agenda
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda2.pk, booking1.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda2.pk, booking1.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# cancelled event
event.cancel()
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk) not in resp
app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), status=404)
def test_event_checked(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events', booking_check_filters='foo,bar')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
agenda=agenda,
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark the event as checked' not in resp
Booking.objects.create(event=event, user_first_name='User')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '<span class="tag">Checked</span>' not in resp
assert 'Mark the event as checked' in resp
assert event.checked is False
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
assert 'checked tag' not in resp
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '<span class="tag">Checked</span>' not in resp
token = resp.context['csrf_token']
resp = app.post(
'/manage/agendas/%s/events/%s/checked' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
)
assert resp.location.endswith('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
event.refresh_from_db()
assert event.checked is True
resp = resp.follow()
assert '<span class="tag">Checked</span>' in resp
assert 'Mark the event as checked' not in resp
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
assert 'checked tag' in resp
resp = app.get('/manage/agendas/%s/events/%s/' % (agenda.pk, event.pk))
assert '<span class="tag">Checked</span>' in resp
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_filters(check_types, app, admin_user):
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
agenda = Agenda.objects.create(
label='Events',
kind='events',
booking_check_filters='foo,bar',
)
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
agenda=agenda,
)
Booking.objects.create(
event=event, user_external_id='user:none', user_first_name='User', user_last_name='none'
)
Booking.objects.create(
event=event,
user_external_id='user:empty',
user_first_name='User',
user_last_name='empty',
extra_data={},
)
Booking.objects.create(
event=event,
user_external_id='user:1',
user_first_name='User',
user_last_name='foo-val1 bar-none presence',
extra_data={'foo': 'val1'},
user_was_present=True,
)
Booking.objects.create(
event=event,
user_external_id='user:2',
user_first_name='User',
user_last_name='foo-val2 bar-val1 absence',
extra_data={'foo': 'val2', 'bar': 'val1'},
user_was_present=False,
)
Booking.objects.create(
event=event,
user_external_id='user:3',
user_first_name='User',
user_last_name='foo-val1 bar-val2 not-checked',
extra_data={'foo': 'val1', 'bar': 'val2'},
)
Booking.objects.create(
event=event,
user_external_id='user:4',
user_first_name='User',
user_last_name='foo-none bar-val2 reason-foo',
extra_data={'bar': 'val2'},
user_was_present=False,
user_check_type_slug='foo-reason',
)
Booking.objects.create(
event=event,
user_external_id='user:5',
user_first_name='User',
user_last_name='foo-none bar-val2 reason-bar',
extra_data={'bar': 'val2'},
user_was_present=True,
user_check_type_slug='bar-reason',
)
Booking.objects.create(
event=event,
user_external_id='user:6',
user_first_name='User',
user_last_name='foo-none bar-val2 cancelled-absence',
extra_data={'bar': 'val2'},
user_was_present=False,
user_check_type_slug='foo-reason',
cancellation_datetime=now(),
)
Booking.objects.create(
event=event,
user_external_id='user:7',
user_first_name='User',
user_last_name='foo-none bar-val2 cancelled-presence',
extra_data={'bar': 'val2'},
user_was_present=True,
user_check_type_slug='bar-reason',
cancellation_datetime=now(),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:none',
user_first_name='Subscription',
user_last_name='none',
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:empty',
user_first_name='Subscription',
user_last_name='empty',
extra_data={},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:1',
user_first_name='Subscription',
user_last_name='foo-val1 bar-none',
extra_data={'foo': 'val1'},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:2',
user_first_name='Subscription',
user_last_name='foo-val2 bar-val1',
extra_data={'foo': 'val2', 'bar': 'val1'},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:3',
user_first_name='Subscription',
user_last_name='foo-val1 bar-val2',
extra_data={'foo': 'val1', 'bar': 'val2'},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
Subscription.objects.create(
agenda=agenda,
user_external_id='subscription:4',
user_first_name='Subscription',
user_last_name='foo-none bar-val2',
extra_data={'bar': 'val2'},
date_start=event.start_datetime,
date_end=event.start_datetime + datetime.timedelta(days=1),
)
login(app)
for params in [
{},
{'unknown': 'unknown'},
{'extra-data-unknown': 'unknown'},
{'extra-data-foo': 'unknown'},
]:
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params=params)
assert 'User none' in resp
assert 'User empty' in resp
assert 'User foo-val1 bar-none presence' in resp
assert 'User foo-val2 bar-val1 absence' in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' in resp
assert 'User foo-none bar-val2 reason-bar' in resp
assert 'User foo-none bar-val2 cancelled-absence' in resp
assert 'User foo-none bar-val2 cancelled-presence' in resp
assert 'Subscription none' in resp
assert 'Subscription empty' in resp
assert 'Subscription foo-val1 bar-none' in resp
assert 'Subscription foo-val2 bar-val1' in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' in resp
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'extra-data-foo': 'val1'}
)
assert len(ctx.captured_queries) == 10
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'extra-data-foo': 'val1', 'extra-data-bar': 'val2'},
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'extra-data-foo': 'val2', 'extra-data-bar': 'val2'},
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'booked'}
)
assert 'User none' in resp
assert 'User empty' in resp
assert 'User foo-val1 bar-none presence' in resp
assert 'User foo-val2 bar-val1 absence' in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' in resp
assert 'User foo-none bar-val2 reason-bar' in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'not-booked'}
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' in resp
assert 'Subscription empty' in resp
assert 'Subscription foo-val1 bar-none' in resp
assert 'Subscription foo-val2 bar-val1' in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'cancelled'}
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' in resp
assert 'User foo-none bar-val2 cancelled-presence' in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'not-checked'}
)
assert 'User none' in resp
assert 'User empty' in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'presence'}
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'booking-status': 'absence'}
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'booking-status': 'absence::foo-reason'},
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' in resp
assert 'User foo-none bar-val2 reason-bar' not in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'booking-status': 'presence::bar-reason'},
)
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' not in resp
assert 'User foo-val2 bar-val1 absence' not in resp
assert 'User foo-val1 bar-val2 not-checked' not in resp
assert 'User foo-none bar-val2 reason-foo' not in resp
assert 'User foo-none bar-val2 reason-bar' in resp
assert 'User foo-none bar-val2 cancelled-absence' not in resp
assert 'User foo-none bar-val2 cancelled-presence' not in resp
assert 'Subscription none' not in resp
assert 'Subscription empty' not in resp
assert 'Subscription foo-val1 bar-none' not in resp
assert 'Subscription foo-val2 bar-val1' not in resp
assert 'Subscription foo-val1 bar-val2' not in resp
assert 'Subscription foo-none bar-val2' not in resp
def test_event_check_ordering(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 15, 17, 0)), places=10, agenda=agenda
)
Booking.objects.create(
event=event,
user_first_name='BB',
user_last_name='XX',
user_external_id='user:1',
)
Booking.objects.create(
event=event,
user_first_name='AA',
user_last_name='YY',
user_external_id='user:2',
cancellation_datetime=now(),
)
Subscription.objects.create(
agenda=agenda,
user_first_name='CC',
user_last_name='WW',
user_external_id='user:3',
date_start=datetime.date(2022, 2, 1),
date_end=datetime.date(2022, 3, 1),
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert resp.text.index('CC WW') < resp.text.index('BB XX') < resp.text.index('AA YY')
resp = app.get('/manage/agendas/%s/events/%s/check?sort=lastname,firstname' % (agenda.pk, event.pk))
assert resp.text.index('CC WW') < resp.text.index('BB XX') < resp.text.index('AA YY')
resp = app.get('/manage/agendas/%s/events/%s/check?sort=firstname,lastname' % (agenda.pk, event.pk))
assert resp.text.index('AA YY') < resp.text.index('BB XX') < resp.text.index('CC WW')
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_booking(check_types, app, admin_user):
check_types.return_value = []
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
secondary_booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='42', primary_booking=booking
)
assert agenda.mark_event_checked_auto is False
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert resp.pyquery.find('td.booking-status')[0].text.strip() == '-'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 0
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
# set as present
token = resp.context['csrf_token']
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is False
agenda.mark_event_checked_auto = True
agenda.save()
# set as absent without check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Absence'
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is False
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
]
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
# set as absent with check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
).follow()
assert 'Foo reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type_slug == 'foo-reason'
assert booking.user_check_type_label == 'Foo reason'
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is False
assert secondary_booking.user_check_type_slug == 'foo-reason'
assert secondary_booking.user_check_type_label == 'Foo reason'
# set as present without check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 1
# set as present with check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
).follow()
assert 'Bar reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug == 'bar-reason'
assert booking.user_check_type_label == 'Bar reason'
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug == 'bar-reason'
assert secondary_booking.user_check_type_label == 'Bar reason'
# mark the event as checked
event.checked = True
event.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=302,
)
# now disable check update
agenda.disable_check_update = True
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) not in resp
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_booking_ajax(check_types, app, admin_user):
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
token = resp.context['csrf_token']
# set as present
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present\n \n (Bar reason)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
assert '<option value="bar-reason" selected>Bar reason</option>' in resp
# set as absent
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent\n \n (Foo reason)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text.startswith('Absence')
assert '<option value="foo-reason" selected>Foo reason</option>' in resp
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_all_bookings(check_types, app, admin_user):
check_types.return_value = [
CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
]
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking1 = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
assert agenda.mark_event_checked_auto is False
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
token = resp.context['csrf_token']
assert 'Mark all bookings without status' in resp
assert '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk) in resp
assert '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk) in resp
resp = app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk), params={'csrfmiddlewaretoken': token}
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
event.refresh_from_db()
assert event.checked is False
agenda.mark_event_checked_auto = True
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' not in resp
assert '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk) not in resp
assert '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk) not in resp
booking2 = Booking.objects.create(event=event, user_first_name='User', user_last_name='35')
secondary_booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='35', primary_booking=booking2
)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' in resp
assert '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk) in resp
assert '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk) in resp
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk), params={'csrfmiddlewaretoken': token}
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
# event is checked
booking3 = Booking.objects.create(event=event, user_first_name='User', user_last_name='51')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' in resp
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_check_type_slug == 'foo-reason'
assert booking3.user_check_type_label == 'Foo reason'
booking4 = Booking.objects.create(event=event, user_first_name='User', user_last_name='52')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' in resp
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_check_type_slug == 'foo-reason'
assert booking3.user_check_type_label == 'Foo reason'
booking4.refresh_from_db()
assert booking4.user_was_present is True
assert booking4.user_check_type_slug == 'bar-reason'
assert booking4.user_check_type_label == 'Bar reason'
# now disable check update
agenda.disable_check_update = True
agenda.save()
Booking.objects.create(event=event, user_first_name='User', user_last_name='52')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' not in resp
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
status=404,
)
resp = app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
status=404,
)
resp = app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
def test_event_check_primary_booking(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
Booking.objects.create(event=event, user_first_name='John', user_last_name='Doe')
booking_3 = Booking.objects.create(
event=event, user_first_name='Jane', user_last_name='Doe', in_waiting_list=True
)
# create secondary bookings
Booking.objects.create(event=event, user_first_name='User', user_last_name='42', primary_booking=booking)
Booking.objects.create(event=event, user_first_name='User', user_last_name='42', primary_booking=booking)
Booking.objects.create(
event=event,
user_first_name='Jane',
user_last_name='Doe',
primary_booking=booking_3,
in_waiting_list=True,
)
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Bookings (4/10)' in resp.text
user_bookings = resp.pyquery.find('td.booking-username.main-list')
assert len(user_bookings) == 2
assert user_bookings[0].text == 'User 42 (3 places)'
assert user_bookings[1].text == 'John Doe'
assert 'Waiting List (2/5)' in resp.text
user_bookings = resp.pyquery.find('td.booking-username.waiting')
assert len(user_bookings) == 1
assert user_bookings[0].text == 'Jane Doe (2 places)'
def test_events_timesheet_wrong_kind(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
app = login(app)
app.get('/manage/agendas/%s/events/timesheet' % agenda.id, status=404)
agenda.kind = 'virtual'
agenda.save()
app.get('/manage/agendas/%s/events/timesheet' % agenda.id, status=404)
def test_events_timesheet_form(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-01-01'
resp.form['date_end'] = '2021-12-31'
resp = resp.form.submit()
assert resp.context['form'].errors['date_end'] == ['End date must be greater than start date.']
resp.form['date_end'] = '2022-04-02'
resp = resp.form.submit()
assert resp.context['form'].errors['date_end'] == ['Please select an interval of no more than 3 months.']
resp.form['date_end'] = '2022-04-01'
resp = resp.form.submit()
assert resp.context['form'].errors == {}
@pytest.mark.freeze_time('2022-02-15')
def test_events_timesheet_slots(app, admin_user):
start, end = (
now() - datetime.timedelta(days=15),
now() + datetime.timedelta(days=14),
) # 2022-02-31, 2022-03-01
agenda = Agenda.objects.create(label='Events', kind='events')
Event.objects.create(label='event 1', start_datetime=start, places=10, agenda=agenda)
event2 = Event.objects.create(
label='event 2', start_datetime=start + datetime.timedelta(days=1), places=10, agenda=agenda
)
event3 = Event.objects.create(label='event 3', start_datetime=now(), places=10, agenda=agenda)
Event.objects.create(
label='event cancelled',
start_datetime=now() + datetime.timedelta(days=4),
places=10,
agenda=agenda,
cancelled=True,
)
event4 = Event.objects.create(
label='event 4', start_datetime=end - datetime.timedelta(days=1), places=10, agenda=agenda
)
Event.objects.create(label='event 5', start_datetime=end, places=10, agenda=agenda)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=start,
date_end=end + datetime.timedelta(days=1),
)
recurring_event1 = Event.objects.create(
label='recurring 1',
start_datetime=start,
places=10,
agenda=agenda,
recurrence_days=[0, 1],
recurrence_end_date=end,
)
recurring_event1.create_all_recurrences()
recurring_event2 = Event.objects.create(
label='recurring 2',
start_datetime=start,
places=10,
agenda=agenda,
recurrence_days=[1, 2],
recurrence_end_date=end,
)
recurring_event2.create_all_recurrences()
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-02-01'
resp.form['date_end'] = '2022-02-28'
with CaptureQueriesContext(connection) as ctx:
resp = resp.form.submit()
assert len(ctx.captured_queries) == 7
slots = resp.context['form'].get_slots()
assert slots['dates'] == [
[
datetime.date(2022, 2, 1),
datetime.date(2022, 2, 2),
datetime.date(2022, 2, 7),
datetime.date(2022, 2, 8),
datetime.date(2022, 2, 9),
datetime.date(2022, 2, 14),
datetime.date(2022, 2, 15),
datetime.date(2022, 2, 16),
datetime.date(2022, 2, 21),
datetime.date(2022, 2, 22),
datetime.date(2022, 2, 23),
datetime.date(2022, 2, 28),
]
]
assert slots['events'] == [
event2,
recurring_event1,
recurring_event2,
event3,
event4,
]
assert slots['users'][0]['users'] == [
{
'user_id': 'user:1',
'user_first_name': 'Subscription',
'user_last_name': '42',
'extra_data': {},
'events': [
{
'event': event2,
'dates': {date: False for date in slots['dates'][0] if date == datetime.date(2022, 2, 1)},
},
{
'event': recurring_event1,
'dates': {date: False for date in slots['dates'][0] if date.weekday() in [0, 1]},
},
{
'event': recurring_event2,
'dates': {date: False for date in slots['dates'][0] if date.weekday() in [1, 2]},
},
{
'event': event3,
'dates': {
date: False for date in slots['dates'][0] if date == datetime.date(2022, 2, 15)
},
},
{
'event': event4,
'dates': {
date: False for date in slots['dates'][0] if date == datetime.date(2022, 2, 28)
},
},
],
},
]
assert slots['extra_data'] == []
@pytest.mark.freeze_time('2022-02-15')
def test_events_timesheet_subscription_limits(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event1 = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 1, 17, 0)), places=10, agenda=agenda
)
event2 = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 15, 17, 0)), places=10, agenda=agenda
)
event3 = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 28, 17, 0)), places=10, agenda=agenda
)
dates = [
('2022-01-31', '2022-02-01'),
('2022-02-01', '2022-02-02'),
('2022-02-01', '2022-02-15'),
('2022-02-01', '2022-02-16'),
('2022-02-15', '2022-02-28'),
('2022-02-15', '2022-03-01'),
('2022-02-16', '2022-03-01'),
('2022-02-01', '2022-03-01'),
('2022-02-28', '2022-03-01'),
('2022-03-01', '2022-03-02'),
]
for start, end in dates:
Subscription.objects.create(
agenda=agenda,
user_external_id='user:%s-%s' % (start, end),
user_first_name='Subscription',
user_last_name='%s - %s' % (start, end),
date_start=datetime.datetime.strptime(start, '%Y-%m-%d'),
date_end=datetime.datetime.strptime(end, '%Y-%m-%d'),
)
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-02-01'
resp.form['date_end'] = '2022-02-28'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['dates'] == [
[
datetime.date(2022, 2, 1),
datetime.date(2022, 2, 15),
datetime.date(2022, 2, 28),
]
]
assert slots['events'] == [
event1,
event2,
event3,
]
users = slots['users'][0]['users']
assert len(users) == 8
assert users[0]['user_id'] == 'user:2022-02-01-2022-02-02'
assert users[1]['user_id'] == 'user:2022-02-01-2022-02-15'
assert users[2]['user_id'] == 'user:2022-02-01-2022-02-16'
assert users[3]['user_id'] == 'user:2022-02-01-2022-03-01'
assert users[4]['user_id'] == 'user:2022-02-15-2022-02-28'
assert users[5]['user_id'] == 'user:2022-02-15-2022-03-01'
assert users[6]['user_id'] == 'user:2022-02-16-2022-03-01'
assert users[7]['user_id'] == 'user:2022-02-28-2022-03-01'
def test_events_timesheet_users(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 15, 17, 0)), places=10, agenda=agenda
)
booking1 = Booking.objects.create(
event=event, user_external_id='user:1', user_first_name='User', user_last_name='42'
)
Booking.objects.create(
event=event, user_external_id='user:2', user_first_name='User', user_last_name='01'
)
Booking.objects.create(
event=event, user_external_id='user:3', user_first_name='User', user_last_name='17'
)
Booking.objects.create(
event=event, user_external_id='user:4', user_first_name='User', user_last_name='35'
)
Booking.objects.create(
event=event, user_external_id='user:5', user_first_name='User', user_last_name='05'
)
booking6 = Booking.objects.create(
event=event, user_external_id='user:6', user_first_name='User', user_last_name='12 Cancelled'
)
booking6.cancel()
Booking.objects.create(
event=event,
user_external_id='user:7',
user_first_name='User',
user_last_name='Waiting',
in_waiting_list=True,
)
booking8 = Booking.objects.create(
event=event,
user_external_id='user:8',
user_first_name='User',
user_last_name='Waiting and Cancelled',
in_waiting_list=True,
)
booking8.cancel()
Booking.objects.create(
event=event,
user_external_id='user:1',
user_first_name='User',
user_last_name='Secondary',
primary_booking=booking1,
)
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-02-01'
resp.form['date_end'] = '2022-02-28'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert [u['user_id'] for u in slots['users'][0]['users']] == [
'user:2',
'user:5',
'user:3',
'user:4',
'user:1',
]
start = datetime.date(2022, 2, 1)
end = datetime.date(2022, 3, 1)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=start,
date_end=end,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:9',
user_first_name='Subscription',
user_last_name='43',
date_start=start,
date_end=end,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:10',
user_first_name='Subscription',
user_last_name='14',
date_start=start,
date_end=end,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:7',
user_first_name='Subscription',
user_last_name='Waiting',
date_start=start,
date_end=end,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:42',
user_first_name='Subscription',
user_last_name='Too soon',
date_start=start - datetime.timedelta(days=1),
date_end=start,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:43',
user_first_name='Subscription',
user_last_name='Too late',
date_start=end + datetime.timedelta(days=1),
date_end=end + datetime.timedelta(days=2),
)
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert [u['user_id'] for u in slots['users'][0]['users']] == [
'user:2',
'user:5',
'user:6',
'user:10',
'user:3',
'user:4',
'user:1',
'user:9',
'user:7',
]
def test_events_timesheet_user_ids(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 15, 17, 0)), places=10, agenda=agenda
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-02-01'
resp.form['date_end'] = '2022-02-28'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
# no user_id found
assert [u['user_id'] for u in slots['users'][0]['users']] == []
assert [u['user_first_name'] for u in slots['users'][0]['users']] == []
assert [u['user_last_name'] for u in slots['users'][0]['users']] == []
booking.user_external_id = 'user:1'
booking.save()
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert [u['user_id'] for u in slots['users'][0]['users']] == [
'user:1',
]
assert [u['user_first_name'] for u in slots['users'][0]['users']] == ['User']
assert [u['user_last_name'] for u in slots['users'][0]['users']] == ['42']
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='41',
date_start=datetime.date(2022, 2, 1),
date_end=datetime.date(2022, 3, 1),
)
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert [u['user_id'] for u in slots['users'][0]['users']] == [
'user:1',
]
assert [u['user_first_name'] for u in slots['users'][0]['users']] == [
'Subscription',
]
assert [u['user_last_name'] for u in slots['users'][0]['users']] == [
'41',
]
@pytest.mark.freeze_time('2022-02-01')
def test_events_timesheet_booked(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event_date = make_aware(datetime.datetime(2022, 2, 15, 17, 0))
event1 = Event.objects.create(label='event 1', start_datetime=event_date, places=10, agenda=agenda)
event2 = Event.objects.create(label='event 2', start_datetime=event_date, places=10, agenda=agenda)
event3 = Event.objects.create(label='event 3', start_datetime=event_date, places=10, agenda=agenda)
recurring_event1 = Event.objects.create(
label='recurring 1',
start_datetime=event_date,
places=10,
agenda=agenda,
recurrence_days=[1],
recurrence_end_date=event_date + datetime.timedelta(days=1),
)
recurring_event1.create_all_recurrences()
recurring_event1_occurence = recurring_event1.recurrences.first()
recurring_event2 = Event.objects.create(
label='recurring 2',
start_datetime=event_date,
places=10,
agenda=agenda,
recurrence_days=[1],
recurrence_end_date=event_date + datetime.timedelta(days=1),
)
recurring_event2.create_all_recurrences()
recurring_event2_occurence = recurring_event2.recurrences.first()
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=datetime.date(2022, 2, 1),
date_end=datetime.date(2022, 3, 1),
)
Booking.objects.create(
event=event1,
user_external_id='user:1',
user_first_name='User',
user_last_name='42',
)
Booking.objects.create(
event=event2,
user_external_id='user:1',
user_first_name='User',
user_last_name='42',
cancellation_datetime=now(),
)
Booking.objects.create(
event=recurring_event1_occurence,
user_external_id='user:1',
user_first_name='User',
user_last_name='42',
)
Booking.objects.create(
event=recurring_event2_occurence,
user_external_id='user:1',
user_first_name='User',
user_last_name='42',
cancellation_datetime=now(),
)
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-02-01'
resp.form['date_end'] = '2022-02-28'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['events'] == [
event1,
event2,
event3,
recurring_event1,
recurring_event2,
]
assert len(slots['users'][0]['users']) == 1
assert slots['users'][0]['users'][0]['events'] == [
{
'event': event1,
'dates': {datetime.date(2022, 2, 15): True},
},
{
'event': event2,
'dates': {datetime.date(2022, 2, 15): False},
},
{
'event': event3,
'dates': {datetime.date(2022, 2, 15): False},
},
{
'event': recurring_event1,
'dates': {datetime.date(2022, 2, 15): True},
},
{
'event': recurring_event2,
'dates': {datetime.date(2022, 2, 15): False},
},
]
def test_events_timesheet_extra_data(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 15, 17, 0)), places=10, agenda=agenda
)
Booking.objects.create(
event=event,
user_first_name='User',
user_last_name='42',
user_external_id='user:1',
extra_data={'foo': 'bar', 'baz': 'blah'},
)
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-02-01'
resp.form['date_end'] = '2022-02-28'
resp.form['extra_data'] = ' foo '
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert resp.text.count('<div class="page_break">') == 0
assert len(slots['users']) == 1
assert slots['users'][0]['grouper'] == ''
assert len(slots['users'][0]['users']) == 1
assert slots['extra_data'] == ['foo']
assert slots['users'][0]['users'][0]['extra_data']['foo'] == 'bar'
resp.form['extra_data'] = ' foo ,baz,,'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert len(slots['users'][0]['users']) == 1
assert slots['extra_data'] == ['foo', 'baz']
assert slots['users'][0]['users'][0]['extra_data']['foo'] == 'bar'
assert slots['users'][0]['users'][0]['extra_data']['baz'] == 'blah'
resp.form['extra_data'] = 'unknown'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert len(slots['users'][0]['users']) == 1
assert slots['extra_data'] == ['unknown']
assert slots['users'][0]['users'][0]['extra_data']['unknown'] == ''
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='41',
date_start=datetime.date(2022, 2, 1),
date_end=datetime.date(2022, 3, 1),
extra_data={'foo': 'baz'},
)
resp.form['extra_data'] = ' foo '
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert len(slots['users'][0]['users']) == 1
assert slots['extra_data'] == ['foo']
assert slots['users'][0]['users'][0]['extra_data']['foo'] == 'baz'
resp.form['extra_data'] = ' foo ,baz,,'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert len(slots['users'][0]['users']) == 1
assert slots['extra_data'] == ['foo', 'baz']
assert slots['users'][0]['users'][0]['extra_data']['foo'] == 'baz'
assert slots['users'][0]['users'][0]['extra_data']['baz'] == ''
Booking.objects.create(
event=event,
user_first_name='User',
user_last_name='43',
user_external_id='user:2',
extra_data={'foo': 'bar', 'baz': 'aa'},
)
Booking.objects.create(
event=event,
user_first_name='User',
user_last_name='44',
user_external_id='user:3',
extra_data={'foo': 'bar2', 'baz': 'aa'},
)
resp.form['extra_data'] = ''
resp.form['group_by'] = 'foo'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert resp.text.count('<div class="page_break">') == 0
assert len(slots['users']) == 3
assert slots['users'][0]['grouper'] == 'bar'
assert len(slots['users'][0]['users']) == 1
assert slots['users'][0]['users'][0]['user_id'] == 'user:2'
assert slots['users'][1]['grouper'] == 'bar2'
assert len(slots['users'][1]['users']) == 1
assert slots['users'][1]['users'][0]['user_id'] == 'user:3'
assert slots['users'][2]['grouper'] == 'baz'
assert len(slots['users'][2]['users']) == 1
assert slots['users'][2]['users'][0]['user_id'] == 'user:1'
resp.form['with_page_break'] = True
resp = resp.form.submit()
assert resp.text.count('<div class="page_break">') == 2
resp.form['group_by'] = 'baz'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert len(slots['users']) == 2
assert slots['users'][0]['grouper'] == 'aa'
assert len(slots['users'][0]['users']) == 2
assert slots['users'][0]['users'][0]['user_id'] == 'user:2'
assert slots['users'][0]['users'][1]['user_id'] == 'user:3'
assert slots['users'][1]['grouper'] == ''
assert len(slots['users'][1]['users']) == 1
assert slots['users'][1]['users'][0]['user_id'] == 'user:1'
Subscription.objects.update(extra_data={'foo': 'baz', 'baz': 'blah'})
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert len(slots['users']) == 2
assert slots['users'][0]['grouper'] == 'aa'
assert len(slots['users'][0]['users']) == 2
assert slots['users'][0]['users'][0]['user_id'] == 'user:2'
assert slots['users'][0]['users'][1]['user_id'] == 'user:3'
assert slots['users'][1]['grouper'] == 'blah'
assert len(slots['users'][1]['users']) == 1
assert slots['users'][1]['users'][0]['user_id'] == 'user:1'
resp.form['group_by'] = 'unknown'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert len(slots['users']) == 1
assert slots['users'][0]['grouper'] == ''
assert len(slots['users'][0]['users']) == 3
def test_events_timesheet_ordering(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
start_datetime=make_aware(datetime.datetime(2022, 2, 15, 17, 0)), places=10, agenda=agenda
)
Booking.objects.create(
event=event,
user_first_name='BB',
user_last_name='XX',
user_external_id='user:1',
)
Booking.objects.create(
event=event,
user_first_name='AA',
user_last_name='YY',
user_external_id='user:2',
cancellation_datetime=now(),
)
Subscription.objects.create(
agenda=agenda,
user_first_name='CC',
user_last_name='WW',
user_external_id='user:3',
date_start=datetime.date(2022, 2, 1),
date_end=datetime.date(2022, 3, 1),
)
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-02-01'
resp.form['date_end'] = '2022-02-28'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['users'][0]['users'][0]['user_id'] == 'user:3'
assert slots['users'][0]['users'][1]['user_id'] == 'user:1'
assert slots['users'][0]['users'][2]['user_id'] == 'user:2'
resp.form['sort'] = 'lastname,firstname'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['users'][0]['users'][0]['user_id'] == 'user:3'
assert slots['users'][0]['users'][1]['user_id'] == 'user:1'
assert slots['users'][0]['users'][2]['user_id'] == 'user:2'
resp.form['sort'] = 'firstname,lastname'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['users'][0]['users'][0]['user_id'] == 'user:2'
assert slots['users'][0]['users'][1]['user_id'] == 'user:1'
assert slots['users'][0]['users'][2]['user_id'] == 'user:3'
@pytest.mark.freeze_time('2022-04-01')
def test_events_timesheet_date_display(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
recurring_event = Event.objects.create(
label='recurring 1',
start_datetime=make_aware(datetime.datetime(2022, 1, 1, 12, 0)),
places=10,
agenda=agenda,
recurrence_days=[0],
recurrence_end_date=datetime.date(2022, 4, 1),
)
recurring_event.create_all_recurrences()
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=datetime.date(2022, 1, 1),
date_end=datetime.date(2022, 4, 1),
extra_data={'foo': 'bar'},
)
login(app)
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
resp.form['date_start'] = '2022-01-01'
resp.form['date_end'] = '2022-03-31'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['dates'] == [
[
datetime.date(2022, 1, 3),
datetime.date(2022, 1, 10),
datetime.date(2022, 1, 17),
datetime.date(2022, 1, 24),
datetime.date(2022, 1, 31),
datetime.date(2022, 2, 7),
datetime.date(2022, 2, 14),
datetime.date(2022, 2, 21),
datetime.date(2022, 2, 28),
datetime.date(2022, 3, 7),
datetime.date(2022, 3, 14),
datetime.date(2022, 3, 21),
datetime.date(2022, 3, 28),
]
]
resp.form['date_display'] = 'month'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['dates'] == [
[
datetime.date(2022, 1, 3),
datetime.date(2022, 1, 10),
datetime.date(2022, 1, 17),
datetime.date(2022, 1, 24),
datetime.date(2022, 1, 31),
],
[
datetime.date(2022, 2, 7),
datetime.date(2022, 2, 14),
datetime.date(2022, 2, 21),
datetime.date(2022, 2, 28),
],
[
datetime.date(2022, 3, 7),
datetime.date(2022, 3, 14),
datetime.date(2022, 3, 21),
datetime.date(2022, 3, 28),
],
]
resp.form['date_display'] = 'week'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert resp.text.count('<div class="page_break">') == 12
assert slots['dates'] == [
[datetime.date(2022, 1, 3)],
[datetime.date(2022, 1, 10)],
[datetime.date(2022, 1, 17)],
[datetime.date(2022, 1, 24)],
[datetime.date(2022, 1, 31)],
[datetime.date(2022, 2, 7)],
[datetime.date(2022, 2, 14)],
[datetime.date(2022, 2, 21)],
[datetime.date(2022, 2, 28)],
[datetime.date(2022, 3, 7)],
[datetime.date(2022, 3, 14)],
[datetime.date(2022, 3, 21)],
[datetime.date(2022, 3, 28)],
]
resp.form['date_display'] = 'custom'
resp = resp.form.submit()
assert resp.context['form'].errors['custom_nb_dates_per_page'] == ['This field is required.']
resp.form['custom_nb_dates_per_page'] = 10
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['dates'] == [
[
datetime.date(2022, 1, 3),
datetime.date(2022, 1, 10),
datetime.date(2022, 1, 17),
datetime.date(2022, 1, 24),
datetime.date(2022, 1, 31),
datetime.date(2022, 2, 7),
datetime.date(2022, 2, 14),
datetime.date(2022, 2, 21),
datetime.date(2022, 2, 28),
datetime.date(2022, 3, 7),
],
[
datetime.date(2022, 3, 14),
datetime.date(2022, 3, 21),
datetime.date(2022, 3, 28),
],
]
resp.form['custom_nb_dates_per_page'] = 3
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert slots['dates'] == [
[
datetime.date(2022, 1, 3),
datetime.date(2022, 1, 10),
datetime.date(2022, 1, 17),
],
[
datetime.date(2022, 1, 24),
datetime.date(2022, 1, 31),
datetime.date(2022, 2, 7),
],
[
datetime.date(2022, 2, 14),
datetime.date(2022, 2, 21),
datetime.date(2022, 2, 28),
],
[
datetime.date(2022, 3, 7),
datetime.date(2022, 3, 14),
datetime.date(2022, 3, 21),
],
[
datetime.date(2022, 3, 28),
],
]
Subscription.objects.create(
agenda=agenda,
user_external_id='user:2',
user_first_name='Subscription',
user_last_name='43',
date_start=datetime.date(2022, 1, 1),
date_end=datetime.date(2022, 4, 1),
extra_data={'foo': 'baz'},
)
resp.form['date_display'] = 'week'
resp.form['group_by'] = 'foo'
resp = resp.form.submit()
slots = resp.context['form'].get_slots()
assert resp.text.count('<div class="page_break">') == 12
resp.form['with_page_break'] = True
resp = resp.form.submit()
assert resp.text.count('<div class="page_break">') == 25
def test_events_timesheet_pdf(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
login(app)
resp = app.get(
'/manage/agendas/%s/events/timesheet?pdf=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname&date_display=all&orientation=portrait'
% agenda.pk
)
assert resp.headers['Content-Type'] == 'application/pdf'
assert (
resp.headers['Content-Disposition']
== 'attachment; filename="timesheet_events_2022-02-01_2022-02-28.pdf"'
)
# form invalid
resp = app.get(
'/manage/agendas/%s/events/timesheet?pdf=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname&date_display=all'
% agenda.pk
)
assert resp.context['form'].errors['orientation'] == ['This field is required.']