manager: filter timesheet by booking status (#84260)
gitea/chrono/pipeline/head This commit looks good
Details
gitea/chrono/pipeline/head This commit looks good
Details
This commit is contained in:
parent
d02210ab66
commit
698bbfc7a4
|
@ -772,17 +772,29 @@ class EventsTimesheetForm(forms.Form):
|
|||
],
|
||||
initial='portrait',
|
||||
)
|
||||
booking_filter = forms.ChoiceField(
|
||||
label=_('Filter by status'),
|
||||
choices=[
|
||||
('all', _('All')),
|
||||
('with_booking', _('With booking')),
|
||||
('without_booking', _('Without booking')),
|
||||
],
|
||||
initial='all',
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.agenda = kwargs.pop('agenda')
|
||||
self.event = kwargs.pop('event', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.with_subscriptions = self.agenda.subscriptions.exists()
|
||||
if self.event is not None:
|
||||
del self.fields['date_start']
|
||||
del self.fields['date_end']
|
||||
del self.fields['date_display']
|
||||
del self.fields['custom_nb_dates_per_page']
|
||||
del self.fields['activity_display']
|
||||
if not self.with_subscriptions:
|
||||
del self.fields['booking_filter']
|
||||
|
||||
def get_slots(self):
|
||||
extra_data = self.cleaned_data['extra_data'].split(',')
|
||||
|
@ -850,20 +862,21 @@ class EventsTimesheetForm(forms.Form):
|
|||
)
|
||||
|
||||
users = {}
|
||||
subscriptions = self.agenda.subscriptions.filter(date_start__lt=max_start, date_end__gt=min_start)
|
||||
for subscription in subscriptions:
|
||||
if subscription.user_external_id in users:
|
||||
continue
|
||||
users[subscription.user_external_id] = {
|
||||
'user_id': subscription.user_external_id,
|
||||
'user_first_name': subscription.user_first_name,
|
||||
'user_last_name': subscription.user_last_name,
|
||||
'extra_data': {k: (subscription.extra_data or {}).get(k) or '' for k in all_extra_data},
|
||||
'events': copy.deepcopy(event_slots),
|
||||
}
|
||||
if self.with_subscriptions:
|
||||
subscriptions = self.agenda.subscriptions.filter(date_start__lt=max_start, date_end__gt=min_start)
|
||||
for subscription in subscriptions:
|
||||
if subscription.user_external_id in users:
|
||||
continue
|
||||
users[subscription.user_external_id] = {
|
||||
'user_id': subscription.user_external_id,
|
||||
'user_first_name': subscription.user_first_name,
|
||||
'user_last_name': subscription.user_last_name,
|
||||
'extra_data': {k: (subscription.extra_data or {}).get(k) or '' for k in all_extra_data},
|
||||
'events': copy.deepcopy(event_slots),
|
||||
}
|
||||
|
||||
booking_qs_kwargs = {}
|
||||
if not self.agenda.subscriptions.exists():
|
||||
if not self.with_subscriptions:
|
||||
booking_qs_kwargs = {'cancellation_datetime__isnull': True}
|
||||
booked_qs = (
|
||||
Booking.objects.filter(
|
||||
|
@ -899,6 +912,19 @@ class EventsTimesheetForm(forms.Form):
|
|||
participants += 1
|
||||
break
|
||||
|
||||
if self.cleaned_data.get('booking_filter') == 'with_booking':
|
||||
# remove subscribed users without booking
|
||||
users = {
|
||||
k: user for k, user in users.items() if any(any(e['dates'].values()) for e in user['events'])
|
||||
}
|
||||
elif self.cleaned_data.get('booking_filter') == 'without_booking':
|
||||
# remove subscribed users with booking
|
||||
users = {
|
||||
k: user
|
||||
for k, user in users.items()
|
||||
if not any(any(e['dates'].values()) for e in user['events'])
|
||||
}
|
||||
|
||||
if self.cleaned_data['sort'] == 'lastname,firstname':
|
||||
sort_fields = ['user_last_name', 'user_first_name']
|
||||
else:
|
||||
|
|
|
@ -266,6 +266,113 @@ def test_events_timesheet_subscription_limits(app, admin_user):
|
|||
assert users[7]['user_id'] == 'user:2022-02-28-2022-03-01'
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2022-02-15')
|
||||
def test_events_timesheet_filter_with_booking(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
|
||||
)
|
||||
|
||||
Booking.objects.create(
|
||||
event=event1, user_external_id='user:1', user_first_name='User', user_last_name='1'
|
||||
)
|
||||
Booking.objects.create(
|
||||
event=event1, user_external_id='user:2', user_first_name='User', user_last_name='2'
|
||||
)
|
||||
Booking.objects.create(
|
||||
event=event2, user_external_id='user:2', user_first_name='User', user_last_name='2'
|
||||
)
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
|
||||
assert 'booking_filter' not in resp.context['form'].fields
|
||||
|
||||
start = datetime.date(2022, 2, 1)
|
||||
end = datetime.date(2022, 3, 1)
|
||||
for user_id in [1, 2, 3, 4, 5, 6]:
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='user:%s' % user_id,
|
||||
user_first_name='Subscription',
|
||||
user_last_name=str(user_id),
|
||||
date_start=start,
|
||||
date_end=end,
|
||||
)
|
||||
|
||||
resp = app.get('/manage/agendas/%s/events/timesheet' % agenda.pk)
|
||||
resp.form['date_start'] = '2022-02-01'
|
||||
resp.form['date_end'] = '2022-02-28'
|
||||
assert resp.form['booking_filter'].value == 'all'
|
||||
resp = resp.form.submit()
|
||||
slots = resp.context['form'].get_slots()
|
||||
assert len(slots['dates']) == 1
|
||||
assert [d[0] for d in slots['dates'][0]] == [
|
||||
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) == 6
|
||||
assert users[0]['user_id'] == 'user:1'
|
||||
assert users[1]['user_id'] == 'user:2'
|
||||
assert users[2]['user_id'] == 'user:3'
|
||||
assert users[3]['user_id'] == 'user:4'
|
||||
assert users[4]['user_id'] == 'user:5'
|
||||
assert users[5]['user_id'] == 'user:6'
|
||||
|
||||
resp.form['booking_filter'] = 'with_booking'
|
||||
resp = resp.form.submit()
|
||||
slots = resp.context['form'].get_slots()
|
||||
assert len(slots['dates']) == 1
|
||||
assert [d[0] for d in slots['dates'][0]] == [
|
||||
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) == 2
|
||||
assert users[0]['user_id'] == 'user:1'
|
||||
assert users[1]['user_id'] == 'user:2'
|
||||
|
||||
resp.form['booking_filter'] = 'without_booking'
|
||||
resp = resp.form.submit()
|
||||
slots = resp.context['form'].get_slots()
|
||||
assert len(slots['dates']) == 1
|
||||
assert [d[0] for d in slots['dates'][0]] == [
|
||||
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) == 4
|
||||
assert users[0]['user_id'] == 'user:3'
|
||||
assert users[1]['user_id'] == 'user:4'
|
||||
assert users[2]['user_id'] == 'user:5'
|
||||
assert users[3]['user_id'] == 'user:6'
|
||||
|
||||
|
||||
def test_events_timesheet_users(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Events', kind='events')
|
||||
event = Event.objects.create(
|
||||
|
@ -959,7 +1066,7 @@ def test_events_timesheet_pdf(app, admin_user):
|
|||
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&activity_display=row&orientation=portrait' % agenda.pk
|
||||
'&date_display=all&activity_display=row&orientation=portrait&booking_filter=all' % agenda.pk
|
||||
)
|
||||
assert resp.headers['Content-Type'] == 'application/pdf'
|
||||
assert (
|
||||
|
@ -969,8 +1076,8 @@ def test_events_timesheet_pdf(app, admin_user):
|
|||
|
||||
# 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&activity_display=row'
|
||||
% agenda.pk
|
||||
'/manage/agendas/%s/events/timesheet?pdf=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname&date_display=all'
|
||||
'&activity_display=row&booking_filter=all' % agenda.pk
|
||||
)
|
||||
assert resp.context['form'].errors['orientation'] == ['This field is required.']
|
||||
|
||||
|
@ -981,7 +1088,7 @@ def test_events_timesheet_csv(app, admin_user):
|
|||
login(app)
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname'
|
||||
'&date_display=all&activity_display=row&orientation=portrait' % agenda.pk
|
||||
'&date_display=all&activity_display=row&orientation=portrait&booking_filter=all' % agenda.pk
|
||||
)
|
||||
assert resp.headers['Content-Type'] == 'text/csv'
|
||||
assert (
|
||||
|
@ -991,8 +1098,8 @@ def test_events_timesheet_csv(app, admin_user):
|
|||
|
||||
# form invalid
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname&date_display=all&activity_display=row'
|
||||
% agenda.pk
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname&date_display=all'
|
||||
'&activity_display=row&booking_filter=all' % agenda.pk
|
||||
)
|
||||
assert resp.context['form'].errors['orientation'] == ['This field is required.']
|
||||
|
||||
|
@ -1034,7 +1141,7 @@ def test_events_timesheet_csv(app, admin_user):
|
|||
# display row
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname'
|
||||
'&date_display=all&activity_display=row&orientation=portrait' % agenda.pk
|
||||
'&date_display=all&activity_display=row&orientation=portrait&booking_filter=all' % agenda.pk
|
||||
)
|
||||
assert resp.text == (
|
||||
'First name,Last name,Mon 07/02,Mon 14/02,Mon 21/02,Mon 28/02\r\n'
|
||||
|
@ -1044,7 +1151,7 @@ def test_events_timesheet_csv(app, admin_user):
|
|||
# display col
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname'
|
||||
'&date_display=all&activity_display=col&orientation=portrait' % agenda.pk
|
||||
'&date_display=all&activity_display=col&orientation=portrait&booking_filter=all' % agenda.pk
|
||||
)
|
||||
assert resp.text == (
|
||||
'First name,Last name,recurring 1 of 07-02,recurring 1 of 14-02,recurring 1 of 21-02,recurring 1 of 28-02\r\n'
|
||||
|
@ -1067,7 +1174,7 @@ def test_events_timesheet_csv(app, admin_user):
|
|||
# display row
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname'
|
||||
'&date_display=all&activity_display=row&orientation=portrait' % agenda.pk
|
||||
'&date_display=all&activity_display=row&orientation=portrait&booking_filter=all' % agenda.pk
|
||||
)
|
||||
assert resp.text == (
|
||||
'First name,Last name,Activity,Mon 07/02,Mon 14/02,Tue 15/02,Mon 21/02,Mon 28/02\r\n'
|
||||
|
@ -1079,7 +1186,7 @@ def test_events_timesheet_csv(app, admin_user):
|
|||
# display col
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname'
|
||||
'&date_display=all&activity_display=col&orientation=portrait' % agenda.pk
|
||||
'&date_display=all&activity_display=col&orientation=portrait&booking_filter=all' % agenda.pk
|
||||
)
|
||||
assert resp.text == (
|
||||
'First name,Last name,recurring 1 of 07-02,recurring 1 of 14-02,"Feb. 15, 2022, 5 p.m. of 15-02",recurring 1 of 21-02,recurring 1 of 28-02\r\n'
|
||||
|
@ -1091,7 +1198,8 @@ def test_events_timesheet_csv(app, admin_user):
|
|||
# display row
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname'
|
||||
'&date_display=all&activity_display=row&orientation=portrait&extra_data=foo&group_by=foo' % agenda.pk
|
||||
'&date_display=all&activity_display=row&orientation=portrait&booking_filter=all&extra_data=foo&group_by=foo'
|
||||
% agenda.pk
|
||||
)
|
||||
assert resp.text == (
|
||||
'foo: bar\r\n'
|
||||
|
@ -1104,7 +1212,8 @@ def test_events_timesheet_csv(app, admin_user):
|
|||
# display col
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/timesheet?csv=&date_start=2022-02-01&date_end=2022-02-28&sort=lastname,firstname'
|
||||
'&date_display=all&activity_display=col&orientation=portrait&extra_data=foo&group_by=foo' % agenda.pk
|
||||
'&date_display=all&activity_display=col&orientation=portrait&booking_filter=all&extra_data=foo&group_by=foo'
|
||||
% agenda.pk
|
||||
)
|
||||
assert resp.text == (
|
||||
'foo: bar\r\n'
|
||||
|
@ -1277,6 +1386,85 @@ def test_event_timesheet_subscription_limits(app, admin_user):
|
|||
assert users[3]['user_id'] == 'user:2022-02-15-2022-03-01'
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2022-02-15')
|
||||
def test_event_timesheet_filter_with_booking(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_external_id='user:1', user_first_name='User', user_last_name='1')
|
||||
Booking.objects.create(event=event, user_external_id='user:2', user_first_name='User', user_last_name='2')
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/events/%s/timesheet' % (agenda.pk, event.pk))
|
||||
assert 'booking_filter' not in resp.context['form'].fields
|
||||
|
||||
start = datetime.date(2022, 2, 1)
|
||||
end = datetime.date(2022, 3, 1)
|
||||
for user_id in [1, 2, 3, 4, 5, 6]:
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='user:%s' % user_id,
|
||||
user_first_name='Subscription',
|
||||
user_last_name=str(user_id),
|
||||
date_start=start,
|
||||
date_end=end,
|
||||
)
|
||||
|
||||
resp = app.get('/manage/agendas/%s/events/%s/timesheet' % (agenda.pk, event.pk))
|
||||
assert resp.form['booking_filter'].value == 'all'
|
||||
resp = resp.form.submit()
|
||||
slots = resp.context['form'].get_slots()
|
||||
assert len(slots['dates']) == 1
|
||||
assert [d[0] for d in slots['dates'][0]] == [
|
||||
datetime.date(2022, 2, 15),
|
||||
]
|
||||
assert slots['events'] == [
|
||||
event,
|
||||
]
|
||||
users = slots['users'][0]['users']
|
||||
assert len(users) == 6
|
||||
assert users[0]['user_id'] == 'user:1'
|
||||
assert users[1]['user_id'] == 'user:2'
|
||||
assert users[2]['user_id'] == 'user:3'
|
||||
assert users[3]['user_id'] == 'user:4'
|
||||
assert users[4]['user_id'] == 'user:5'
|
||||
assert users[5]['user_id'] == 'user:6'
|
||||
|
||||
resp.form['booking_filter'] = 'with_booking'
|
||||
resp = resp.form.submit()
|
||||
slots = resp.context['form'].get_slots()
|
||||
assert len(slots['dates']) == 1
|
||||
assert [d[0] for d in slots['dates'][0]] == [
|
||||
datetime.date(2022, 2, 15),
|
||||
]
|
||||
|
||||
assert slots['events'] == [
|
||||
event,
|
||||
]
|
||||
users = slots['users'][0]['users']
|
||||
assert len(users) == 2
|
||||
assert users[0]['user_id'] == 'user:1'
|
||||
assert users[1]['user_id'] == 'user:2'
|
||||
|
||||
resp.form['booking_filter'] = 'without_booking'
|
||||
resp = resp.form.submit()
|
||||
slots = resp.context['form'].get_slots()
|
||||
assert len(slots['dates']) == 1
|
||||
assert [d[0] for d in slots['dates'][0]] == [
|
||||
datetime.date(2022, 2, 15),
|
||||
]
|
||||
assert slots['events'] == [
|
||||
event,
|
||||
]
|
||||
users = slots['users'][0]['users']
|
||||
assert len(users) == 4
|
||||
assert users[0]['user_id'] == 'user:3'
|
||||
assert users[1]['user_id'] == 'user:4'
|
||||
assert users[2]['user_id'] == 'user:5'
|
||||
assert users[3]['user_id'] == 'user:6'
|
||||
|
||||
|
||||
def test_event_timesheet_pdf(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Foo', kind='events')
|
||||
event = Event.objects.create(
|
||||
|
@ -1288,7 +1476,7 @@ def test_event_timesheet_pdf(app, admin_user):
|
|||
|
||||
login(app)
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/%s/timesheet?pdf=&sort=lastname,firstname&date_display=all&orientation=portrait'
|
||||
'/manage/agendas/%s/events/%s/timesheet?pdf=&sort=lastname,firstname&date_display=all&orientation=portrait&booking_filter=all'
|
||||
% (agenda.pk, event.pk)
|
||||
)
|
||||
assert resp.headers['Content-Type'] == 'application/pdf'
|
||||
|
@ -1296,7 +1484,7 @@ def test_event_timesheet_pdf(app, admin_user):
|
|||
|
||||
# form invalid
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/%s/timesheet?pdf=&sort=lastname,firstname&date_display=all'
|
||||
'/manage/agendas/%s/events/%s/timesheet?pdf=&sort=lastname,firstname&date_display=all&booking_filter=all'
|
||||
% (agenda.pk, event.pk)
|
||||
)
|
||||
assert resp.context['form'].errors['orientation'] == ['This field is required.']
|
||||
|
@ -1313,7 +1501,7 @@ def test_event_timesheet_csv(app, admin_user):
|
|||
|
||||
login(app)
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/%s/timesheet?csv=&sort=lastname,firstname&date_display=all&orientation=portrait'
|
||||
'/manage/agendas/%s/events/%s/timesheet?csv=&sort=lastname,firstname&date_display=all&orientation=portrait&booking_filter=all'
|
||||
% (agenda.pk, event.pk)
|
||||
)
|
||||
assert resp.headers['Content-Type'] == 'text/csv'
|
||||
|
@ -1321,7 +1509,7 @@ def test_event_timesheet_csv(app, admin_user):
|
|||
|
||||
# form invalid
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/%s/timesheet?csv=&sort=lastname,firstname&date_display=all'
|
||||
'/manage/agendas/%s/events/%s/timesheet?csv=&sort=lastname,firstname&date_display=all&booking_filter=all'
|
||||
% (agenda.pk, event.pk)
|
||||
)
|
||||
assert resp.context['form'].errors['orientation'] == ['This field is required.']
|
||||
|
@ -1351,14 +1539,14 @@ def test_event_timesheet_csv(app, admin_user):
|
|||
user_last_name='02',
|
||||
)
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/%s/timesheet?csv=&sort=lastname,firstname&date_display=all&orientation=portrait'
|
||||
'/manage/agendas/%s/events/%s/timesheet?csv=&sort=lastname,firstname&date_display=all&orientation=portrait&booking_filter=all'
|
||||
% (agenda.pk, event.pk)
|
||||
)
|
||||
assert resp.text == ('First name,Last name,Tue 15/02\r\n' 'Subscription,01,\r\n' 'Subscription,02,☐\r\n')
|
||||
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/%s/timesheet?csv=&sort=lastname,firstname&date_display=all&orientation=portrait&extra_data=foo&group_by=foo'
|
||||
% (agenda.pk, event.pk)
|
||||
'/manage/agendas/%s/events/%s/timesheet?csv=&sort=lastname,firstname&date_display=all&orientation=portrait'
|
||||
'&booking_filter=all&extra_data=foo&group_by=foo' % (agenda.pk, event.pk)
|
||||
)
|
||||
assert resp.text == (
|
||||
'foo: bar\r\n'
|
||||
|
|
Loading…
Reference in New Issue