agendas: allow multiple checks by booking (#80371)
This commit is contained in:
parent
3cb80d478a
commit
81e93dd4c5
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.2.21 on 2023-10-05 11:41
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('agendas', '0163_remove_booking_check_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='bookingcheck',
|
||||
name='booking',
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, related_name='user_checks', to='agendas.booking'
|
||||
),
|
||||
),
|
||||
]
|
|
@ -2141,7 +2141,7 @@ class Event(models.Model):
|
|||
booking_qs = self.booking_set.filter(
|
||||
cancellation_datetime__isnull=True,
|
||||
in_waiting_list=False,
|
||||
user_check__isnull=True,
|
||||
user_checks__isnull=True,
|
||||
primary_booking__isnull=True,
|
||||
)
|
||||
if booking_qs.exists():
|
||||
|
@ -2165,7 +2165,7 @@ class Event(models.Model):
|
|||
self.notify_checked()
|
||||
|
||||
def notify_checked(self):
|
||||
for booking in self.booking_set.filter(user_check__isnull=False).select_related('user_check'):
|
||||
for booking in self.booking_set.filter(user_checks__isnull=False).prefetch_related('user_checks'):
|
||||
if booking.user_check.presence is True and booking.presence_callback_url:
|
||||
url = booking.presence_callback_url
|
||||
elif booking.user_check.presence is False and booking.absence_callback_url:
|
||||
|
@ -2278,7 +2278,7 @@ class Event(models.Model):
|
|||
'booking',
|
||||
filter=Q(
|
||||
booking__cancellation_datetime__isnull=True,
|
||||
booking__user_check__presence=False,
|
||||
booking__user_checks__presence=False,
|
||||
booking__user_external_id=user_external_id,
|
||||
),
|
||||
),
|
||||
|
@ -2398,13 +2398,13 @@ class Event(models.Model):
|
|||
.values('event')
|
||||
)
|
||||
present_count = (
|
||||
bookings.filter(user_check__presence=True).annotate(count=Count('event')).values('count')
|
||||
bookings.filter(user_checks__presence=True).annotate(count=Count('event')).values('count')
|
||||
)
|
||||
absent_count = (
|
||||
bookings.filter(user_check__presence=False).annotate(count=Count('event')).values('count')
|
||||
bookings.filter(user_checks__presence=False).annotate(count=Count('event')).values('count')
|
||||
)
|
||||
notchecked_count = (
|
||||
bookings.filter(user_check__isnull=True).annotate(count=Count('event')).values('count')
|
||||
bookings.filter(user_checks__isnull=True).annotate(count=Count('event')).values('count')
|
||||
)
|
||||
return qs.annotate(
|
||||
present_count=Coalesce(Subquery(present_count, output_field=IntegerField()), Value(0)),
|
||||
|
@ -2819,6 +2819,15 @@ class Booking(models.Model):
|
|||
def user_name(self):
|
||||
return ('%s %s' % (self.user_first_name, self.user_last_name)).strip()
|
||||
|
||||
@cached_property
|
||||
def user_check(self): # pylint: disable=method-hidden
|
||||
user_checks = list(self.user_checks.all())
|
||||
|
||||
if len(user_checks) > 1:
|
||||
raise AttributeError('booking has multiple checks')
|
||||
|
||||
return user_checks[0] if user_checks else None
|
||||
|
||||
@cached_property
|
||||
def emails(self):
|
||||
emails = set(self.extra_emails)
|
||||
|
@ -2833,6 +2842,11 @@ class Booking(models.Model):
|
|||
phone_numbers.add(self.user_phone_number)
|
||||
return list(phone_numbers)
|
||||
|
||||
def refresh_from_db(self, *args, **kwargs):
|
||||
if hasattr(self, 'user_check'):
|
||||
del self.user_check
|
||||
return super().refresh_from_db(*args, **kwargs)
|
||||
|
||||
def cancel(self, trigger_callback=False):
|
||||
timestamp = now()
|
||||
with transaction.atomic():
|
||||
|
@ -2857,14 +2871,14 @@ class Booking(models.Model):
|
|||
|
||||
def reset_user_was_present(self):
|
||||
with transaction.atomic():
|
||||
if hasattr(self, 'user_check'):
|
||||
if self.user_check:
|
||||
self.user_check.delete()
|
||||
self.user_check = None
|
||||
self.event.checked = False
|
||||
self.event.save(update_fields=['checked'])
|
||||
|
||||
def mark_user_absence(self, check_type_slug=None, check_type_label=None, start_time=None, end_time=None):
|
||||
if not hasattr(self, 'user_check'):
|
||||
if not self.user_check:
|
||||
self.user_check = BookingCheck(booking=self)
|
||||
self.user_check.presence = False
|
||||
self.user_check.type_slug = check_type_slug
|
||||
|
@ -2880,7 +2894,7 @@ class Booking(models.Model):
|
|||
self.event.set_is_checked()
|
||||
|
||||
def mark_user_presence(self, check_type_slug=None, check_type_label=None, start_time=None, end_time=None):
|
||||
if not hasattr(self, 'user_check'):
|
||||
if not self.user_check:
|
||||
self.user_check = BookingCheck(booking=self)
|
||||
self.user_check.presence = True
|
||||
self.user_check.type_slug = check_type_slug
|
||||
|
@ -2988,7 +3002,7 @@ class Booking(models.Model):
|
|||
|
||||
|
||||
class BookingCheck(models.Model):
|
||||
booking = models.OneToOneField(Booking, on_delete=models.CASCADE, related_name='user_check')
|
||||
booking = models.ForeignKey(Booking, on_delete=models.CASCADE, related_name='user_checks')
|
||||
|
||||
presence = models.BooleanField()
|
||||
|
||||
|
|
|
@ -331,9 +331,7 @@ class BookingSerializer(serializers.ModelSerializer):
|
|||
ret.pop('user_absence_reason', None)
|
||||
ret.pop('user_presence_reason', None)
|
||||
else:
|
||||
user_was_present = (
|
||||
self.instance.user_check.presence if hasattr(self.instance, 'user_check') else None
|
||||
)
|
||||
user_was_present = self.instance.user_check.presence if self.instance.user_check else None
|
||||
ret['user_was_present'] = user_was_present
|
||||
ret['user_absence_reason'] = (
|
||||
self.instance.user_check.type_slug if user_was_present is False else None
|
||||
|
|
|
@ -2204,7 +2204,7 @@ class MultipleAgendasEventsCheckStatus(APIView):
|
|||
booking_queryset = Booking.objects.filter(
|
||||
event__in=events,
|
||||
user_external_id=user_external_id,
|
||||
).select_related('user_check')
|
||||
).prefetch_related('user_checks')
|
||||
bookings_by_event_id = collections.defaultdict(list)
|
||||
for booking in booking_queryset:
|
||||
bookings_by_event_id[booking.event_id].append(booking)
|
||||
|
@ -2225,7 +2225,7 @@ class MultipleAgendasEventsCheckStatus(APIView):
|
|||
booking.event = event # prevent db calls
|
||||
if booking.cancellation_datetime is not None:
|
||||
check_status = {'status': 'cancelled'}
|
||||
elif not hasattr(booking, 'user_check'):
|
||||
elif not booking.user_check:
|
||||
check_status = {'status': 'error', 'error_reason': 'booking-not-checked'}
|
||||
else:
|
||||
check_status = {
|
||||
|
@ -2519,18 +2519,18 @@ class BookingFilter(filters.FilterSet):
|
|||
return queryset.filter(Q(event__slug=value) | Q(event__primary_event__slug=value))
|
||||
|
||||
def filter_user_was_present(self, queryset, name, value):
|
||||
return queryset.filter(user_check__presence=value)
|
||||
return queryset.filter(user_checks__presence=value)
|
||||
|
||||
def filter_user_absence_reason(self, queryset, name, value):
|
||||
return queryset.filter(
|
||||
Q(user_check__type_slug=value) | Q(user_check__type_label=value),
|
||||
user_check__presence=False,
|
||||
Q(user_checks__type_slug=value) | Q(user_checks__type_label=value),
|
||||
user_checks__presence=False,
|
||||
)
|
||||
|
||||
def filter_user_presence_reason(self, queryset, name, value):
|
||||
return queryset.filter(
|
||||
Q(user_check__type_slug=value) | Q(user_check__type_label=value),
|
||||
user_check__presence=True,
|
||||
Q(user_checks__type_slug=value) | Q(user_checks__type_label=value),
|
||||
user_checks__presence=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
@ -2574,7 +2574,8 @@ class BookingsAPI(ListAPIView):
|
|||
def get_queryset(self):
|
||||
return (
|
||||
Booking.objects.filter(primary_booking__isnull=True, cancellation_datetime__isnull=True)
|
||||
.select_related('event', 'event__agenda', 'event__desk', 'user_check')
|
||||
.select_related('event', 'event__agenda', 'event__desk')
|
||||
.prefetch_related('user_checks')
|
||||
.order_by('event__start_datetime', 'event__slug', 'event__agenda__slug', 'pk')
|
||||
)
|
||||
|
||||
|
@ -2664,7 +2665,7 @@ class BookingAPI(APIView):
|
|||
|
||||
user_was_present = serializer.validated_data.get(
|
||||
'user_was_present',
|
||||
self.booking.user_check.presence if hasattr(self.booking, 'user_check') else None,
|
||||
self.booking.user_check.presence if self.booking.user_check else None,
|
||||
)
|
||||
if user_was_present is True and 'user_absence_reason' in request.data:
|
||||
raise APIErrorBadRequest(N_('user is marked as present, can not set absence reason'), err=6)
|
||||
|
@ -2679,16 +2680,16 @@ class BookingAPI(APIView):
|
|||
self.booking.save()
|
||||
|
||||
if user_was_present is None:
|
||||
if hasattr(self.booking, 'user_check'):
|
||||
if self.booking.user_check:
|
||||
self.booking.user_check.delete()
|
||||
self.booking.user_check = None
|
||||
else:
|
||||
if not hasattr(self.booking, 'user_check'):
|
||||
if not self.booking.user_check:
|
||||
self.booking.user_check = BookingCheck(booking=self.booking)
|
||||
self.booking.user_check.presence = user_was_present
|
||||
self.booking.user_check.save()
|
||||
|
||||
if 'user_check_type_slug' in serializer.validated_data and hasattr(self.booking, 'user_check'):
|
||||
if 'user_check_type_slug' in serializer.validated_data and self.booking.user_check:
|
||||
self.booking.user_check.type_slug = serializer.validated_data['user_check_type_slug']
|
||||
self.booking.user_check.type_label = serializer.validated_data['user_check_type_label']
|
||||
self.booking.user_check.save()
|
||||
|
@ -3261,8 +3262,8 @@ class BookingsStatistics(APIView):
|
|||
if 'user_was_present' in group_by:
|
||||
bookings = bookings.annotate(
|
||||
presence=Case(
|
||||
When(primary_booking__isnull=True, then=F('user_check__presence')),
|
||||
When(primary_booking__isnull=False, then=F('primary_booking__user_check__presence')),
|
||||
When(primary_booking__isnull=True, then=F('user_checks__presence')),
|
||||
When(primary_booking__isnull=False, then=F('primary_booking__user_checks__presence')),
|
||||
)
|
||||
)
|
||||
lookups.append('presence')
|
||||
|
|
|
@ -531,15 +531,15 @@ class BookingCheckFilterSet(django_filters.FilterSet):
|
|||
if value == 'booked':
|
||||
return queryset
|
||||
if value == 'not-checked':
|
||||
return queryset.filter(user_check__isnull=True)
|
||||
return queryset.filter(user_checks__isnull=True)
|
||||
if value == 'presence':
|
||||
return queryset.filter(user_check__presence=True)
|
||||
return queryset.filter(user_checks__presence=True)
|
||||
if value == 'absence':
|
||||
return queryset.filter(user_check__presence=False)
|
||||
return queryset.filter(user_checks__presence=False)
|
||||
if value.startswith('absence::'):
|
||||
return queryset.filter(user_check__presence=False, user_check__type_slug=value.split('::')[1])
|
||||
return queryset.filter(user_checks__presence=False, user_checks__type_slug=value.split('::')[1])
|
||||
if value.startswith('presence::'):
|
||||
return queryset.filter(user_check__presence=True, user_check__type_slug=value.split('::')[1])
|
||||
return queryset.filter(user_checks__presence=True, user_checks__type_slug=value.split('::')[1])
|
||||
return queryset
|
||||
|
||||
def do_nothing(self, queryset, name, value):
|
||||
|
|
|
@ -1399,7 +1399,7 @@ class EventChecksMixin:
|
|||
booking_qs_kwargs = {}
|
||||
if not self.agenda.subscriptions.exists():
|
||||
booking_qs_kwargs = {'cancellation_datetime__isnull': True}
|
||||
booking_qs = event.booking_set.select_related('user_check').order_by('start_time')
|
||||
booking_qs = event.booking_set.prefetch_related('user_checks').order_by('start_time')
|
||||
booked_qs = booking_qs.filter(
|
||||
in_waiting_list=False, primary_booking__isnull=True, **booking_qs_kwargs
|
||||
)
|
||||
|
@ -1441,19 +1441,15 @@ class EventChecksMixin:
|
|||
results = []
|
||||
booked_without_status = False
|
||||
for booking in booked_filterset.qs:
|
||||
if booking.cancellation_datetime is None and not hasattr(booking, 'user_check'):
|
||||
if booking.cancellation_datetime is None and not booking.user_check:
|
||||
booked_without_status = True
|
||||
booking.absence_form = BookingCheckAbsenceForm(
|
||||
agenda=self.agenda,
|
||||
initial={
|
||||
'check_type': booking.user_check.type_slug if hasattr(booking, 'user_check') else None
|
||||
},
|
||||
initial={'check_type': booking.user_check.type_slug if booking.user_check else None},
|
||||
)
|
||||
booking.presence_form = BookingCheckPresenceForm(
|
||||
agenda=self.agenda,
|
||||
initial={
|
||||
'check_type': booking.user_check.type_slug if hasattr(booking, 'user_check') else None
|
||||
},
|
||||
initial={'check_type': booking.user_check.type_slug if booking.user_check else None},
|
||||
)
|
||||
booking.kind = 'booking'
|
||||
results.append(booking)
|
||||
|
@ -1656,7 +1652,7 @@ class AgendaDayView(EventChecksMixin, AgendaDateView, DayArchiveView):
|
|||
booking.css_left = get_time_ratio(booking.start_time, start_time)
|
||||
booking.css_width = get_time_ratio(booking.end_time, booking.start_time)
|
||||
|
||||
if hasattr(booking, 'user_check'):
|
||||
if booking.user_check:
|
||||
booking.check_css_class = 'present' if booking.user_check.presence else 'absent'
|
||||
booking.check_css_left = get_time_ratio(booking.user_check.start_time, start_time)
|
||||
booking.check_css_width = get_time_ratio(
|
||||
|
@ -1922,7 +1918,7 @@ class AgendaWeekMonthMixin:
|
|||
]
|
||||
|
||||
booking_info_by_user = {}
|
||||
bookings = Booking.objects.filter(event__in=self.events).select_related('user_check')
|
||||
bookings = Booking.objects.filter(event__in=self.events).prefetch_related('user_checks')
|
||||
for booking in bookings:
|
||||
booking_info = booking_info_by_user.setdefault(
|
||||
booking.user_external_id,
|
||||
|
@ -1935,7 +1931,7 @@ class AgendaWeekMonthMixin:
|
|||
)
|
||||
user_bookings = booking_info['bookings']
|
||||
|
||||
if hasattr(booking, 'user_check'):
|
||||
if booking.user_check:
|
||||
booking.check_css_class = 'present' if booking.user_check.presence else 'absent'
|
||||
|
||||
user_bookings[localtime(booking.event.start_datetime).day - 1] = booking
|
||||
|
@ -2748,19 +2744,15 @@ class EventDetailView(ViewableAgendaMixin, DetailView):
|
|||
event = self.object
|
||||
context['booked'] = (
|
||||
event.booking_set.filter(cancellation_datetime__isnull=True, in_waiting_list=False)
|
||||
.select_related('user_check')
|
||||
.prefetch_related('user_checks')
|
||||
.order_by('creation_datetime')
|
||||
)
|
||||
context['waiting'] = event.booking_set.filter(
|
||||
cancellation_datetime__isnull=True, in_waiting_list=True
|
||||
).order_by('creation_datetime')
|
||||
event.present_count = len(
|
||||
[b for b in context['booked'] if hasattr(b, 'user_check') and b.user_check.presence]
|
||||
)
|
||||
event.absent_count = len(
|
||||
[b for b in context['booked'] if hasattr(b, 'user_check') and not b.user_check.presence]
|
||||
)
|
||||
event.notchecked_count = len([b for b in context['booked'] if not hasattr(b, 'user_check')])
|
||||
event.present_count = len([b for b in context['booked'] if b.user_check and b.user_check.presence])
|
||||
event.absent_count = len([b for b in context['booked'] if b.user_check and not b.user_check.presence])
|
||||
event.notchecked_count = len([b for b in context['booked'] if not b.user_check])
|
||||
return context
|
||||
|
||||
|
||||
|
@ -2899,7 +2891,7 @@ class EventCheckMixin:
|
|||
event__cancelled=False,
|
||||
cancellation_datetime__isnull=True,
|
||||
in_waiting_list=False,
|
||||
user_check__isnull=True,
|
||||
user_checks__isnull=True,
|
||||
)
|
||||
|
||||
def get_check_type(self, kind):
|
||||
|
@ -2948,7 +2940,7 @@ class EventPresenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
|
|||
bookings = self.get_bookings()
|
||||
booking_checks_to_create = []
|
||||
for booking in bookings:
|
||||
if hasattr(booking, 'user_check'):
|
||||
if booking.user_check:
|
||||
continue
|
||||
|
||||
booking_check = BookingCheck(booking=booking, presence=True, **qs_kwargs)
|
||||
|
@ -2979,7 +2971,7 @@ class EventAbsenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
|
|||
bookings = self.get_bookings()
|
||||
booking_checks_to_create = []
|
||||
for booking in bookings:
|
||||
if hasattr(booking, 'user_check'):
|
||||
if booking.user_check:
|
||||
continue
|
||||
|
||||
booking_check = BookingCheck(booking=booking, presence=False, **qs_kwargs)
|
||||
|
@ -3767,15 +3759,11 @@ class BookingCheckMixin:
|
|||
if is_ajax(request):
|
||||
booking.absence_form = BookingCheckAbsenceForm(
|
||||
agenda=self.agenda,
|
||||
initial={
|
||||
'check_type': booking.user_check.type_slug if hasattr(booking, 'user_check') else None
|
||||
},
|
||||
initial={'check_type': booking.user_check.type_slug if booking.user_check else None},
|
||||
)
|
||||
booking.presence_form = BookingCheckPresenceForm(
|
||||
agenda=self.agenda,
|
||||
initial={
|
||||
'check_type': booking.user_check.type_slug if hasattr(booking, 'user_check') else None
|
||||
},
|
||||
initial={'check_type': booking.user_check.type_slug if booking.user_check else None},
|
||||
)
|
||||
booking.kind = 'booking'
|
||||
return render(
|
||||
|
@ -4531,7 +4519,7 @@ class PartialBookingCheckMixin(ViewableAgendaMixin):
|
|||
|
||||
def get_object(self):
|
||||
booking = self.get_booking(**self.kwargs)
|
||||
return getattr(booking, 'user_check', BookingCheck(booking=booking))
|
||||
return booking.user_check or BookingCheck(booking=booking)
|
||||
|
||||
def get_success_url(self):
|
||||
date = self.object.booking.event.start_datetime
|
||||
|
|
|
@ -186,7 +186,7 @@ def test_bookings_api(app, user):
|
|||
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/api/bookings/', params={'user_external_id': 'enfant-1234'})
|
||||
assert len(ctx.captured_queries) == 2
|
||||
assert len(ctx.captured_queries) == 3
|
||||
|
||||
assert resp.json['err'] == 0
|
||||
assert resp.json['data'] == [
|
||||
|
@ -616,7 +616,7 @@ def test_booking_patch_api_present(app, user, flag):
|
|||
if flag is not None:
|
||||
assert booking.user_check.presence == flag
|
||||
else:
|
||||
assert not hasattr(booking, 'user_check')
|
||||
assert not booking.user_check
|
||||
|
||||
event.refresh_from_db()
|
||||
assert event.checked is False
|
||||
|
@ -628,14 +628,14 @@ def test_booking_patch_api_present(app, user, flag):
|
|||
if flag is not None:
|
||||
assert booking.user_check.presence == flag
|
||||
else:
|
||||
assert not hasattr(booking, 'user_check')
|
||||
assert not booking.user_check
|
||||
event.refresh_from_db()
|
||||
assert event.checked == (flag is not None)
|
||||
|
||||
# reset
|
||||
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': None})
|
||||
booking.refresh_from_db()
|
||||
assert not hasattr(booking, 'user_check')
|
||||
assert not booking.user_check
|
||||
|
||||
# make secondary bookings
|
||||
Booking.objects.create(event=event, primary_booking=booking)
|
||||
|
@ -648,11 +648,11 @@ def test_booking_patch_api_present(app, user, flag):
|
|||
if flag is not None:
|
||||
assert booking.user_check.presence == flag
|
||||
else:
|
||||
assert not hasattr(booking, 'user_check')
|
||||
assert not booking.user_check
|
||||
# secondary bookings are left untouched
|
||||
assert list(booking.secondary_booking_set.values_list('user_check', flat=True)) == [None, None]
|
||||
assert list(booking.secondary_booking_set.values_list('user_checks', flat=True)) == [None, None]
|
||||
other_booking.refresh_from_db()
|
||||
assert not hasattr(other_booking, 'user_check') # not changed
|
||||
assert not other_booking.user_check # not changed
|
||||
|
||||
# mark the event as checked
|
||||
event.checked = True
|
||||
|
@ -741,9 +741,9 @@ def test_booking_patch_api_absence_reason(check_types, app, user):
|
|||
assert booking.user_check.type_slug == 'foo-bar'
|
||||
assert booking.user_check.type_label == 'Foo bar'
|
||||
# secondary bookings are left unchanged
|
||||
assert list(booking.secondary_booking_set.values_list('user_check', flat=True)) == [None, None]
|
||||
assert list(booking.secondary_booking_set.values_list('user_checks', flat=True)) == [None, None]
|
||||
other_booking.refresh_from_db()
|
||||
assert not hasattr(other_booking, 'user_check') # not changed
|
||||
assert not other_booking.user_check # not changed
|
||||
|
||||
# presence is True, can not set user_absence_reason
|
||||
BookingCheck.objects.update(presence=True)
|
||||
|
@ -855,9 +855,9 @@ def test_booking_patch_api_presence_reason(check_types, app, user):
|
|||
assert booking.user_check.type_slug == 'foo-bar'
|
||||
assert booking.user_check.type_label == 'Foo bar'
|
||||
# secondary bookings are left unchanged
|
||||
assert list(booking.secondary_booking_set.values_list('user_check', flat=True)) == [None, None]
|
||||
assert list(booking.secondary_booking_set.values_list('user_checks', flat=True)) == [None, None]
|
||||
other_booking.refresh_from_db()
|
||||
assert not hasattr(other_booking, 'user_check') # not changed
|
||||
assert not other_booking.user_check # not changed
|
||||
|
||||
# presence is False, can not set user_presence_reason
|
||||
BookingCheck.objects.update(presence=False)
|
||||
|
|
|
@ -1415,7 +1415,7 @@ def test_events_check_status_events(app, user, partial_bookings):
|
|||
}
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get(url, params=params)
|
||||
assert len(ctx.captured_queries) == 5
|
||||
assert len(ctx.captured_queries) == 6
|
||||
assert resp.json['err'] == 0
|
||||
assert len(resp.json['data']) == 3
|
||||
assert list(resp.json['data'][0].keys()) == ['event', 'check_status', 'booking']
|
||||
|
|
|
@ -1807,7 +1807,7 @@ def test_event_checked(app, admin_user):
|
|||
assert 'Mark the event as checked' not in resp
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
||||
assert 'checked tag' in resp
|
||||
for booking in Booking.objects.filter(user_check__isnull=True):
|
||||
for booking in Booking.objects.filter(user_checks__isnull=True):
|
||||
booking.mark_user_presence()
|
||||
for url in urls:
|
||||
resp = app.get(url)
|
||||
|
@ -2087,7 +2087,7 @@ def test_event_check_filters(check_types, app, admin_user):
|
|||
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 len(ctx.captured_queries) == 11
|
||||
assert 'User none' not in resp
|
||||
assert 'User empty' not in resp
|
||||
assert 'User foo-val1 bar-none presence' in resp
|
||||
|
@ -2363,9 +2363,9 @@ def test_event_check_booking(check_types, app, admin_user):
|
|||
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
|
||||
assert '/manage/agendas/%s/bookings/%s/reset' % (agenda.pk, booking.pk) not in resp
|
||||
booking.refresh_from_db()
|
||||
assert not hasattr(booking, 'user_check')
|
||||
assert not booking.user_check
|
||||
secondary_booking.refresh_from_db()
|
||||
assert not hasattr(secondary_booking, 'user_check')
|
||||
assert not secondary_booking.user_check
|
||||
event.refresh_from_db()
|
||||
assert event.checked is False
|
||||
|
||||
|
@ -2394,7 +2394,7 @@ def test_event_check_booking(check_types, app, admin_user):
|
|||
assert booking.user_check.type_slug is None
|
||||
assert booking.user_check.type_label is None
|
||||
secondary_booking.refresh_from_db()
|
||||
assert not hasattr(secondary_booking, 'user_check')
|
||||
assert not secondary_booking.user_check
|
||||
event.refresh_from_db()
|
||||
assert event.checked is False
|
||||
|
||||
|
@ -2417,7 +2417,7 @@ def test_event_check_booking(check_types, app, admin_user):
|
|||
assert booking.user_check.type_slug is None
|
||||
assert booking.user_check.type_label is None
|
||||
secondary_booking.refresh_from_db()
|
||||
assert not hasattr(secondary_booking, 'user_check')
|
||||
assert not secondary_booking.user_check
|
||||
event.refresh_from_db()
|
||||
assert event.checked is True
|
||||
|
||||
|
@ -2442,7 +2442,7 @@ def test_event_check_booking(check_types, app, admin_user):
|
|||
assert booking.user_check.type_slug == 'foo-reason'
|
||||
assert booking.user_check.type_label == 'Foo reason'
|
||||
secondary_booking.refresh_from_db()
|
||||
assert not hasattr(secondary_booking, 'user_check')
|
||||
assert not secondary_booking.user_check
|
||||
event.refresh_from_db()
|
||||
assert event.checked is True
|
||||
|
||||
|
@ -2462,7 +2462,7 @@ def test_event_check_booking(check_types, app, admin_user):
|
|||
assert booking.user_check.type_slug is None
|
||||
assert booking.user_check.type_label is None
|
||||
secondary_booking.refresh_from_db()
|
||||
assert not hasattr(secondary_booking, 'user_check')
|
||||
assert not secondary_booking.user_check
|
||||
event.refresh_from_db()
|
||||
assert event.checked is True
|
||||
|
||||
|
@ -2492,7 +2492,7 @@ def test_event_check_booking(check_types, app, admin_user):
|
|||
assert booking.user_check.type_slug == 'bar-reason'
|
||||
assert booking.user_check.type_label == 'Bar reason'
|
||||
secondary_booking.refresh_from_db()
|
||||
assert not hasattr(secondary_booking, 'user_check')
|
||||
assert not secondary_booking.user_check
|
||||
event.refresh_from_db()
|
||||
assert event.checked is True
|
||||
|
||||
|
@ -2671,7 +2671,7 @@ def test_event_check_cancelled_booking(check_types, app, admin_user):
|
|||
assert booking.user_check.presence is True
|
||||
secondary_booking.refresh_from_db()
|
||||
assert secondary_booking.cancellation_datetime is None
|
||||
assert not hasattr(secondary_booking, 'user_check')
|
||||
assert not secondary_booking.user_check
|
||||
|
||||
booking.cancel()
|
||||
resp = app.post(
|
||||
|
@ -2686,7 +2686,7 @@ def test_event_check_cancelled_booking(check_types, app, admin_user):
|
|||
assert booking.user_check.presence is False
|
||||
secondary_booking.refresh_from_db()
|
||||
assert secondary_booking.cancellation_datetime is None
|
||||
assert not hasattr(secondary_booking, 'user_check')
|
||||
assert not secondary_booking.user_check
|
||||
|
||||
|
||||
@mock.patch('chrono.manager.forms.get_agenda_check_types')
|
||||
|
|
|
@ -671,7 +671,7 @@ def test_manager_partial_bookings_event_checked(app, admin_user):
|
|||
assert 'Mark the event as checked' not in resp
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.id)
|
||||
assert 'checked tag' in resp
|
||||
for booking in Booking.objects.filter(user_check__isnull=True):
|
||||
for booking in Booking.objects.filter(user_checks__isnull=True):
|
||||
booking.mark_user_presence(start_time=datetime.time(8, 00), end_time=datetime.time(10, 00))
|
||||
resp = app.get('/manage/agendas/%s/day/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
||||
assert '<span class="checked tag">Checked</span>' in resp
|
||||
|
|
|
@ -17,6 +17,7 @@ from chrono.agendas.models import (
|
|||
AgendaNotificationsSettings,
|
||||
AgendaReminderSettings,
|
||||
Booking,
|
||||
BookingCheck,
|
||||
Category,
|
||||
Desk,
|
||||
Event,
|
||||
|
@ -4222,3 +4223,19 @@ def test_event_refresh_booking_computed_times():
|
|||
booking.cancellation_datetime = None
|
||||
booking.save()
|
||||
test_booking(True)
|
||||
|
||||
|
||||
def test_agenda_booking_user_check_property():
|
||||
agenda = Agenda.objects.create(label='Agenda', kind='events')
|
||||
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
|
||||
booking = Booking.objects.create(event=event)
|
||||
|
||||
booking_check = BookingCheck.objects.create(booking=booking, presence=True)
|
||||
assert booking.user_check == booking_check
|
||||
|
||||
BookingCheck.objects.create(booking=booking, presence=False)
|
||||
booking.refresh_from_db()
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
# pylint: disable=pointless-statement
|
||||
booking.user_check
|
||||
|
|
Loading…
Reference in New Issue