diff --git a/tests/manager/test_event.py b/tests/manager/test_event.py index a60d9f49..7bf891dc 100644 --- a/tests/manager/test_event.py +++ b/tests/manager/test_event.py @@ -2454,890 +2454,3 @@ def test_event_check_primary_booking(app, admin_user): 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('
') == 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('
') == 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('
') == 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('
') == 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('
') == 12 - - resp.form['with_page_break'] = True - resp = resp.form.submit() - assert resp.text.count('
') == 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.'] diff --git a/tests/manager/test_event_timesheet.py b/tests/manager/test_event_timesheet.py new file mode 100644 index 00000000..40f1ed22 --- /dev/null +++ b/tests/manager/test_event_timesheet.py @@ -0,0 +1,898 @@ +import datetime + +import pytest +from django.db import connection +from django.test.utils import CaptureQueriesContext +from django.utils.timezone import make_aware, now + +from chrono.agendas.models import Agenda, Booking, Event, Subscription +from tests.utils import login + +pytestmark = pytest.mark.django_db + + +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('
') == 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('
') == 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('
') == 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('
') == 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('
') == 12 + + resp.form['with_page_break'] = True + resp = resp.form.submit() + assert resp.text.count('
') == 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.']