api: return status in multiple agendas datetimes (#63268)

This commit is contained in:
Lauréline Guérin 2022-03-29 16:25:07 +02:00
parent db5b7f3be7
commit 094cba528d
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
4 changed files with 197 additions and 3 deletions

View File

@ -1514,8 +1514,8 @@ class Event(models.Model):
return self.start_datetime.date() <= now().date()
@staticmethod
def annotate_queryset_for_user(qs, user_external_id):
return qs.annotate(
def annotate_queryset_for_user(qs, user_external_id, with_status=False):
qs = qs.annotate(
user_places_count=Count(
'booking',
filter=Q(
@ -1533,6 +1533,25 @@ class Event(models.Model):
),
),
)
if with_status:
qs = qs.annotate(
user_absence_count=Count(
'booking',
filter=Q(
booking__cancellation_datetime__isnull=True,
booking__user_was_present=False,
booking__user_external_id=user_external_id,
),
),
user_cancelled_count=Count(
'booking',
filter=Q(
booking__cancellation_datetime__isnull=False,
booking__user_external_id=user_external_id,
),
),
)
return qs
@property
def remaining_places(self):

View File

@ -262,6 +262,18 @@ class AgendaOrSubscribedSlugsMixin(DateRangeMixin):
class MultipleAgendasDatetimesSerializer(AgendaOrSubscribedSlugsMixin, DatetimesSerializer):
show_past_events = serializers.BooleanField(default=False)
guardian_external_id = serializers.CharField(max_length=250, required=False)
with_status = serializers.BooleanField(default=False)
guardian_external_id = serializers.CharField(max_length=250, required=False)
def validate(self, attrs):
super().validate(attrs)
user_external_id = attrs.get('user_external_id')
if attrs.get('with_status') and not user_external_id:
raise ValidationError(
{'user_external_id': _('This field is required when using "with_status" parameter.')}
)
return attrs
class AgendaOrSubscribedSlugsSerializer(AgendaOrSubscribedSlugsMixin, serializers.Serializer):

View File

@ -474,6 +474,7 @@ def get_event_text(event, agenda, day=None):
return event_text
# pylint: disable=too-many-arguments
def get_event_detail(
request,
event,
@ -485,6 +486,7 @@ def get_event_detail(
multiple_agendas=False,
disable_booked=True,
bypass_delays=False,
with_status=False,
):
agenda = agenda or event.agenda
details = {
@ -576,6 +578,15 @@ def get_event_detail(
details['booked_for_external_user'] = 'main-list'
elif getattr(event, 'user_waiting_places_count', 0) > 0:
details['booked_for_external_user'] = 'waiting-list'
if with_status and booked_user_external_id:
if getattr(event, 'user_absence_count', 0) > 0:
details['status'] = 'absence'
elif getattr(event, 'user_places_count', 0) > 0 or getattr(event, 'user_waiting_places_count', 0) > 0:
details['status'] = 'booked'
elif getattr(event, 'user_cancelled_count', 0) > 0:
details['status'] = 'cancelled'
else:
details['status'] = 'free'
return details
@ -885,6 +896,7 @@ class MultipleAgendasDatetimes(APIView):
guardian_external_id = payload.get('guardian_external_id')
show_past_events = bool(payload.get('show_past_events'))
show_only_subscribed = bool('subscribed' in payload)
with_status = bool(payload.get('with_status'))
entries = Event.objects.none()
for agenda in agendas:
@ -899,7 +911,7 @@ class MultipleAgendasDatetimes(APIView):
bypass_delays=payload.get('bypass_delays'),
show_out_of_minimal_delay=show_past_events,
)
entries = Event.annotate_queryset_for_user(entries, user_external_id)
entries = Event.annotate_queryset_for_user(entries, user_external_id, with_status=with_status)
if show_only_subscribed:
entries = entries.filter(
agenda__subscriptions__user_external_id=user_external_id,
@ -943,6 +955,7 @@ class MultipleAgendasDatetimes(APIView):
multiple_agendas=True,
disable_booked=disable_booked,
bypass_delays=payload.get('bypass_delays'),
with_status=with_status,
)
for x in entries
],

View File

@ -1176,3 +1176,153 @@ def test_datetimes_multiple_agendas_shared_custody_holiday_rules(app):
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
)
assert len(resp.json['data']) == 1
def test_datetimes_multiple_agendas_with_status(app):
agenda = Agenda.objects.create(label='agenda', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
event_booked = Event.objects.create(
slug='event-booked',
start_datetime=now() - datetime.timedelta(days=15),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_booked, user_external_id='xxx')
Event.objects.create(
slug='event-free',
start_datetime=now() - datetime.timedelta(days=14),
places=5,
agenda=agenda,
)
event_cancelled = Event.objects.create(
slug='event-cancelled',
start_datetime=now() - datetime.timedelta(days=13),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_cancelled, user_external_id='xxx', cancellation_datetime=now())
event_absence = Event.objects.create(
slug='event-absence',
start_datetime=now() - datetime.timedelta(days=12),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_absence, user_external_id='xxx', user_was_present=False)
event_absence_with_reason = Event.objects.create(
slug='event-absence_with_reason',
start_datetime=now() - datetime.timedelta(days=11),
places=5,
agenda=agenda,
)
Booking.objects.create(
event=event_absence_with_reason,
user_external_id='xxx',
user_was_present=False,
user_absence_reason='foobar',
)
event_presence = Event.objects.create(
slug='event-presence',
start_datetime=now() - datetime.timedelta(days=10),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_presence, user_external_id='xxx', user_was_present=True)
event_booked_future = Event.objects.create(
slug='event-booked-future',
start_datetime=now() + datetime.timedelta(days=1),
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_booked_future, user_external_id='xxx')
Event.objects.create(
slug='event-free-future',
start_datetime=now() + datetime.timedelta(days=2),
places=5,
agenda=agenda,
)
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': 'agenda', 'show_past_events': True, 'user_external_id': 'xxx'},
)
assert [d['id'] for d in resp.json['data']] == [
'agenda@event-booked',
'agenda@event-free',
'agenda@event-cancelled',
'agenda@event-absence',
'agenda@event-absence_with_reason',
'agenda@event-presence',
'agenda@event-booked-future',
'agenda@event-free-future',
]
for d in resp.json['data']:
assert 'status' not in d
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': 'agenda',
'show_past_events': True,
'user_external_id': 'xxx',
'with_status': True,
},
)
assert [d['id'] for d in resp.json['data']] == [
'agenda@event-booked',
'agenda@event-free',
'agenda@event-cancelled',
'agenda@event-absence',
'agenda@event-absence_with_reason',
'agenda@event-presence',
'agenda@event-booked-future',
'agenda@event-free-future',
]
assert [d['status'] for d in resp.json['data']] == [
'booked',
'free',
'cancelled',
'absence',
'absence',
'booked',
'booked',
'free',
]
# other user
resp = app.get(
'/api/agendas/datetimes/',
params={
'agendas': 'agenda',
'show_past_events': True,
'user_external_id': 'yyy',
'with_status': True,
},
)
assert [d['id'] for d in resp.json['data']] == [
'agenda@event-booked',
'agenda@event-free',
'agenda@event-cancelled',
'agenda@event-absence',
'agenda@event-absence_with_reason',
'agenda@event-presence',
'agenda@event-booked-future',
'agenda@event-free-future',
]
assert [d['status'] for d in resp.json['data']] == [
'free',
'free',
'free',
'free',
'free',
'free',
'free',
'free',
]
# check errors
resp = app.get(
'/api/agendas/datetimes/',
params={'agendas': 'agenda', 'show_past_events': True, 'with_status': True},
status=400,
)
assert 'required' in resp.json['errors']['user_external_id'][0]