all: use new BookingCheck model (#80371)

This commit is contained in:
Valentin Deniaud 2023-09-19 11:18:54 +02:00
parent bcae843c0d
commit ec497c66d9
16 changed files with 518 additions and 428 deletions

View File

@ -0,0 +1,32 @@
# Generated by Django 3.2.18 on 2023-08-22 15:51
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('agendas', '0162_migrate_booking_check_data'),
]
operations = [
migrations.RemoveField(
model_name='booking',
name='user_check_end_time',
),
migrations.RemoveField(
model_name='booking',
name='user_check_start_time',
),
migrations.RemoveField(
model_name='booking',
name='user_check_type_label',
),
migrations.RemoveField(
model_name='booking',
name='user_check_type_slug',
),
migrations.RemoveField(
model_name='booking',
name='user_was_present',
),
]

View File

@ -2138,7 +2138,7 @@ class Event(models.Model):
booking_qs = self.booking_set.filter(
cancellation_datetime__isnull=True,
in_waiting_list=False,
user_was_present__isnull=True,
user_check__isnull=True,
primary_booking__isnull=True,
)
if booking_qs.exists():
@ -2162,17 +2162,17 @@ class Event(models.Model):
self.notify_checked()
def notify_checked(self):
for booking in self.booking_set.filter(user_was_present__isnull=False):
if booking.user_was_present is True and booking.presence_callback_url:
for booking in self.booking_set.filter(user_check__isnull=False).select_related('user_check'):
if booking.user_check.presence is True and booking.presence_callback_url:
url = booking.presence_callback_url
elif booking.user_was_present is False and booking.absence_callback_url:
elif booking.user_check.presence is False and booking.absence_callback_url:
url = booking.absence_callback_url
else:
continue
payload = {
'user_was_present': booking.user_was_present,
'user_check_type_slug': booking.user_check_type_slug,
'user_check_type_label': booking.user_check_type_label,
'user_was_present': booking.user_check.presence,
'user_check_type_slug': booking.user_check.type_slug,
'user_check_type_label': booking.user_check.type_label,
}
try:
response = requests_wrapper.post(url, json=payload, remote_service='auto', timeout=15)
@ -2274,7 +2274,7 @@ class Event(models.Model):
'booking',
filter=Q(
booking__cancellation_datetime__isnull=True,
booking__user_was_present=False,
booking__user_check__presence=False,
booking__user_external_id=user_external_id,
),
),
@ -2393,10 +2393,14 @@ class Event(models.Model):
.order_by()
.values('event')
)
present_count = bookings.filter(user_was_present=True).annotate(count=Count('event')).values('count')
absent_count = bookings.filter(user_was_present=False).annotate(count=Count('event')).values('count')
present_count = (
bookings.filter(user_check__presence=True).annotate(count=Count('event')).values('count')
)
absent_count = (
bookings.filter(user_check__presence=False).annotate(count=Count('event')).values('count')
)
notchecked_count = (
bookings.filter(user_was_present__isnull=True).annotate(count=Count('event')).values('count')
bookings.filter(user_check__isnull=True).annotate(count=Count('event')).values('count')
)
return qs.annotate(
present_count=Coalesce(Subquery(present_count, output_field=IntegerField()), Value(0)),
@ -2792,11 +2796,6 @@ class Booking(models.Model):
user_first_name = models.CharField(max_length=250, blank=True)
user_email = models.EmailField(blank=True)
user_phone_number = models.CharField(max_length=30, blank=True)
user_was_present = models.BooleanField(null=True)
user_check_type_slug = models.CharField(max_length=160, blank=True, null=True)
user_check_type_label = models.CharField(max_length=150, blank=True, null=True)
user_check_start_time = models.TimeField(_('Arrival'), null=True)
user_check_end_time = models.TimeField(_('Departure'), null=True)
out_of_min_delay = models.BooleanField(default=False)
extra_emails = ArrayField(models.EmailField(), default=list)
@ -2855,30 +2854,41 @@ class Booking(models.Model):
self.save()
def reset_user_was_present(self):
self.user_check_type_slug = None
self.user_check_type_label = None
self.user_was_present = None
with transaction.atomic():
self.save()
if hasattr(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):
self.user_check_type_slug = check_type_slug
self.user_check_type_label = check_type_label
self.user_was_present = False
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'):
self.user_check = BookingCheck(booking=self)
self.user_check.presence = False
self.user_check.type_slug = check_type_slug
self.user_check.type_label = check_type_label
self.user_check.start_time = start_time
self.user_check.end_time = end_time
self.cancellation_datetime = None
with transaction.atomic():
self.user_check.save()
self.secondary_booking_set.update(cancellation_datetime=None)
self.save()
self.event.set_is_checked()
def mark_user_presence(self, check_type_slug=None, check_type_label=None):
self.user_check_type_slug = check_type_slug
self.user_check_type_label = check_type_label
self.user_was_present = True
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'):
self.user_check = BookingCheck(booking=self)
self.user_check.presence = True
self.user_check.type_slug = check_type_slug
self.user_check.type_label = check_type_label
self.user_check.start_time = start_time
self.user_check.end_time = end_time
self.cancellation_datetime = None
with transaction.atomic():
self.user_check.save()
self.secondary_booking_set.update(cancellation_datetime=None)
self.save()
self.event.set_is_checked()
@ -2988,10 +2998,10 @@ class Booking(models.Model):
return previous_slot, next_slot
def get_computed_start_time(self):
if self.user_check_start_time is None:
if not hasattr(self, 'user_check') or self.user_check.start_time is None:
return None
start_time = self.user_check_start_time
start_time = self.user_check.start_time
if self.start_time:
start_time = min(start_time, self.start_time)
if self.event.agenda.invoicing_unit == 'minute':
@ -3010,10 +3020,10 @@ class Booking(models.Model):
return previous_slot
def get_computed_end_time(self):
if self.user_check_end_time is None:
if not hasattr(self, 'user_check') or self.user_check.end_time is None:
return None
end_time = self.user_check_end_time
end_time = self.user_check.end_time
if self.end_time:
end_time = max(end_time, self.end_time)
if self.event.agenda.invoicing_unit == 'minute':

View File

@ -282,6 +282,7 @@ class RecurringFillslotsByDaySerializer(FillSlotSerializer):
class BookingSerializer(serializers.ModelSerializer):
user_was_present = serializers.BooleanField(required=False, allow_null=True)
user_absence_reason = serializers.CharField(required=False, allow_blank=True, allow_null=True)
user_presence_reason = serializers.CharField(required=False, allow_blank=True, allow_null=True)
use_color_for = serializers.CharField(required=False, allow_blank=True, allow_null=True, source='color')
@ -330,13 +331,19 @@ 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
)
ret['user_was_present'] = user_was_present
ret['user_absence_reason'] = (
self.instance.user_check_type_slug if self.instance.user_was_present is False else None
self.instance.user_check.type_slug if user_was_present is False else None
)
ret['user_presence_reason'] = (
self.instance.user_check_type_slug if self.instance.user_was_present is True else None
self.instance.user_check.type_slug if user_was_present is True else None
)
if self.instance.event.agenda.kind == 'events' and self.instance.event.agenda.partial_bookings:
self.instance.user_check_start_time = self.instance.user_check.start_time
self.instance.user_check_end_time = self.instance.user_check.end_time
for key in ['', 'user_check_', 'computed_']:
start_key, end_key, minutes_key = (
'%sstart_time' % key,

View File

@ -46,6 +46,7 @@ from chrono.agendas.models import (
ISO_WEEKDAYS,
Agenda,
Booking,
BookingCheck,
BookingColor,
Desk,
Event,
@ -2203,7 +2204,7 @@ class MultipleAgendasEventsCheckStatus(APIView):
booking_queryset = Booking.objects.filter(
event__in=events,
user_external_id=user_external_id,
)
).select_related('user_check')
bookings_by_event_id = collections.defaultdict(list)
for booking in booking_queryset:
bookings_by_event_id[booking.event_id].append(booking)
@ -2224,12 +2225,12 @@ class MultipleAgendasEventsCheckStatus(APIView):
booking.event = event # prevent db calls
if booking.cancellation_datetime is not None:
check_status = {'status': 'cancelled'}
elif booking.user_was_present is None:
elif not hasattr(booking, 'user_check'):
check_status = {'status': 'error', 'error_reason': 'booking-not-checked'}
else:
check_status = {
'status': 'presence' if booking.user_was_present else 'absence',
'check_type': booking.user_check_type_slug,
'status': 'presence' if booking.user_check.presence else 'absence',
'check_type': booking.user_check.type_slug,
}
data.append(
{
@ -2509,6 +2510,7 @@ class BookingFilter(filters.FilterSet):
category = filters.CharFilter(field_name='event__agenda__category__slug', lookup_expr='exact')
date_start = filters.DateFilter(field_name='event__start_datetime', lookup_expr='gte')
date_end = filters.DateFilter(field_name='event__start_datetime', lookup_expr='lt')
user_was_present = filters.CharFilter(method='filter_user_was_present')
user_absence_reason = filters.CharFilter(method='filter_user_absence_reason')
user_presence_reason = filters.CharFilter(method='filter_user_presence_reason')
@ -2516,16 +2518,19 @@ class BookingFilter(filters.FilterSet):
# we want to include bookings of event recurrences
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)
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_was_present=False,
Q(user_check__type_slug=value) | Q(user_check__type_label=value),
user_check__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_was_present=True,
Q(user_check__type_slug=value) | Q(user_check__type_label=value),
user_check__presence=True,
)
class Meta:
@ -2569,7 +2574,7 @@ 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')
.select_related('event', 'event__agenda', 'event__desk', 'user_check')
.order_by('event__start_datetime', 'event__slug', 'event__agenda__slug', 'pk')
)
@ -2657,7 +2662,10 @@ class BookingAPI(APIView):
):
raise APIErrorBadRequest(N_('event is marked as checked'), err=5)
user_was_present = serializer.validated_data.get('user_was_present', self.booking.user_was_present)
user_was_present = serializer.validated_data.get(
'user_was_present',
self.booking.user_check.presence if hasattr(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)
if user_was_present is False and 'user_presence_reason' in request.data:
@ -2670,6 +2678,21 @@ class BookingAPI(APIView):
self.booking.extra_data.update(extra_data)
self.booking.save()
if user_was_present is None:
if hasattr(self.booking, 'user_check'):
self.booking.user_check.delete()
self.booking.user_check = None
else:
if not hasattr(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'):
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()
secondary_bookings_update = {}
for key in [
'user_first_name',
@ -3238,8 +3261,8 @@ class BookingsStatistics(APIView):
if 'user_was_present' in group_by:
bookings = bookings.annotate(
presence=Case(
When(primary_booking__isnull=True, then=F('user_was_present')),
When(primary_booking__isnull=False, then=F('primary_booking__user_was_present')),
When(primary_booking__isnull=True, then=F('user_check__presence')),
When(primary_booking__isnull=False, then=F('primary_booking__user_check__presence')),
)
)
lookups.append('presence')

View File

@ -47,6 +47,7 @@ from chrono.agendas.models import (
AgendaNotificationsSettings,
AgendaReminderSettings,
Booking,
BookingCheck,
Category,
Desk,
Event,
@ -530,15 +531,15 @@ class BookingCheckFilterSet(django_filters.FilterSet):
if value == 'booked':
return queryset
if value == 'not-checked':
return queryset.filter(user_was_present__isnull=True)
return queryset.filter(user_check__isnull=True)
if value == 'presence':
return queryset.filter(user_was_present=True)
return queryset.filter(user_check__presence=True)
if value == 'absence':
return queryset.filter(user_was_present=False)
return queryset.filter(user_check__presence=False)
if value.startswith('absence::'):
return queryset.filter(user_was_present=False, user_check_type_slug=value.split('::')[1])
return queryset.filter(user_check__presence=False, user_check__type_slug=value.split('::')[1])
if value.startswith('presence::'):
return queryset.filter(user_was_present=True, user_check_type_slug=value.split('::')[1])
return queryset.filter(user_check__presence=True, user_check__type_slug=value.split('::')[1])
return queryset
def do_nothing(self, queryset, name, value):
@ -583,7 +584,7 @@ class BookingCheckPresenceForm(forms.Form):
class PartialBookingCheckForm(forms.ModelForm):
user_was_present = forms.NullBooleanField(
presence = forms.NullBooleanField(
label=_('Status'),
widget=forms.RadioSelect(
choices=(
@ -598,15 +599,15 @@ class PartialBookingCheckForm(forms.ModelForm):
absence_check_type = forms.ChoiceField(label=_('Type'), required=False)
class Meta:
model = Booking
fields = ['user_check_start_time', 'user_check_end_time', 'user_was_present']
model = BookingCheck
fields = ['start_time', 'end_time', 'presence', 'type_label', 'type_slug']
widgets = {
'user_check_start_time': widgets.TimeWidgetWithButton(
'start_time': widgets.TimeWidgetWithButton(
step=60, button_label=_('Fill with booking start time')
),
'user_check_end_time': widgets.TimeWidgetWithButton(
step=60, button_label=_('Fill with booking end time')
),
'end_time': widgets.TimeWidgetWithButton(step=60, button_label=_('Fill with booking end time')),
'type_label': forms.HiddenInput(),
'type_slug': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
@ -618,40 +619,46 @@ class PartialBookingCheckForm(forms.ModelForm):
if presence_check_types:
self.fields['presence_check_type'].choices = [(None, '---------')] + presence_check_types
self.fields['presence_check_type'].initial = self.instance.user_check_type_slug
self.fields['presence_check_type'].initial = self.instance.type_slug
else:
del self.fields['presence_check_type']
if absence_check_types:
self.fields['absence_check_type'].choices = [(None, '---------')] + absence_check_types
self.fields['absence_check_type'].initial = self.instance.user_check_type_slug
self.fields['absence_check_type'].initial = self.instance.type_slug
else:
del self.fields['absence_check_type']
if not self.instance.start_time:
self.fields['user_check_start_time'].widget = widgets.TimeWidget(step=60)
self.fields['user_check_end_time'].widget = widgets.TimeWidget(step=60)
self.fields['user_was_present'].widget.choices = ((None, _('Not checked')), (True, _('Present')))
if not self.instance.booking.start_time:
self.fields['start_time'].widget = widgets.TimeWidget(step=60)
self.fields['end_time'].widget = widgets.TimeWidget(step=60)
self.fields['presence'].widget.choices = ((None, _('Not checked')), (True, _('Present')))
self.fields.pop('absence_check_type', None)
def clean(self):
if self.cleaned_data['user_check_end_time'] <= self.cleaned_data['user_check_start_time']:
if self.cleaned_data['end_time'] <= self.cleaned_data['start_time']:
raise ValidationError(_('Arrival must be before departure.'))
if self.cleaned_data['user_was_present'] is not None:
kind = 'presence' if self.cleaned_data['user_was_present'] else 'absence'
if self.cleaned_data['presence'] is not None:
kind = 'presence' if self.cleaned_data['presence'] else 'absence'
if f'{kind}_check_type' in self.cleaned_data:
self.check_type_slug = self.cleaned_data[f'{kind}_check_type']
self.check_type_label = dict(self.fields[f'{kind}_check_type'].choices).get(
self.check_type_slug
self.cleaned_data['type_slug'] = self.cleaned_data[f'{kind}_check_type']
self.cleaned_data['type_label'] = dict(self.fields[f'{kind}_check_type'].choices).get(
self.cleaned_data['type_slug']
)
def save(self):
if hasattr(self, 'check_type_slug'):
self.instance.user_check_type_slug = self.check_type_slug
self.instance.user_check_type_label = self.check_type_label
self.instance.refresh_computed_times()
return super().save()
if self.cleaned_data['presence'] is None:
self.instance.delete()
return self.instance
super().save()
self.instance.booking.refresh_from_db()
if self.instance.booking.refresh_computed_times():
self.instance.booking.save()
return self.instance
class EventsTimesheetForm(forms.Form):

View File

@ -4,19 +4,19 @@
{% if agenda.booking_extra_user_block_template %}<span class="togglable"></span>{% endif %}
{{ booking.get_user_block }}{% if booking.places_count > 1 %} ({{ booking.places_count }} {% trans "places" %}){% endif %}
</td>
<td class="booking-status {% if booking.kind != "subscription" and booking.cancellation_datetime is None and booking.user_was_present is None %}without-status{% endif %}" data-{{ booking.kind }}-id="{{ booking.id }}">
<td class="booking-status {% if booking.kind != "subscription" and booking.cancellation_datetime is None and booking.user_check %}without-status{% endif %}" data-{{ booking.kind }}-id="{{ booking.id }}">
{% if booking.kind == "subscription" %}
({% trans "Not booked" %})
{% elif booking.cancellation_datetime is None %}
{{ booking.user_was_present|yesno:_('Present,Absent,-') }}
{% if booking.user_was_present is not None and booking.user_check_type_label %}
({{ booking.user_check_type_label }})
{% if booking.user_check %}{{ booking.user_check.presence|yesno:_('Present,Absent') }}{% else %}-{% endif %}
{% if booking.user_check.type_label %}
({{ booking.user_check.type_label }})
{% endif %}
{% else %}
({% trans "Cancelled" %})
{% endif %}
{% if not event.checked or not agenda.disable_check_update %}
{% if booking.user_was_present is not None and not event.check_locked %}
{% if booking.user_check and not event.check_locked %}
<form method="post" action="{% url 'chrono-manager-booking-reset' pk=agenda.pk booking_pk=booking.pk %}" class="with-ajax reset">
{% csrf_token %}
<a href="#">{% trans "Reset" context "check" %}</a>
@ -43,7 +43,7 @@
{% endif %}
{% csrf_token %}
<button class="submit-button"
{% if booking.user_was_present is True %}disabled{% endif %}
{% if booking.user_check.presence %}disabled{% endif %}
>{% trans "Presence" %}</button>
{% if booking.presence_form.check_type.field.choices.1 %}{{ booking.presence_form.check_type }}{% endif %}
<script>
@ -62,7 +62,7 @@
{% endif %}
{% csrf_token %}
<button class="submit-button"
{% if booking.user_was_present is False %}disabled{% endif %}
{% if booking.user_check.presence is False %}disabled{% endif %}
>{% trans "Absence" %}</button>
{% if booking.absence_form.check_type.field.choices.1 %}{{ booking.absence_form.check_type }}{% endif %}
<script>

View File

@ -14,8 +14,8 @@
<form
method="post"
enctype="multipart/form-data"
data-fill-user_check_start_time="{{ booking.start_time|time:"H:i" }}"
data-fill-user_check_end_time="{{ booking.end_time|time:"H:i" }}"
data-fill-start_time="{{ object.booking.start_time|time:"H:i" }}"
data-fill-end_time="{{ object.booking.end_time|time:"H:i" }}"
>
{% csrf_token %}
{{ form|with_template }}
@ -28,7 +28,7 @@
$(function () {
presence_check_type_select = $('.widget[id=id_presence_check_type_p]');
absence_check_type_select = $('.widget[id=id_absence_check_type_p]');
$('input[type=radio][name=user_was_present]').change(function() {
$('input[type=radio][name=presence]').change(function() {
if (!this.checked)
return;
if (this.value == 'True') {

View File

@ -83,7 +83,7 @@
{% if user.bookings %}
<div class="registrant--bar-container">
{% for booking in user.bookings %}
{% if booking.user_was_present is not None %}
{% if booking.user_check %}
<a
class="registrant--bar clearfix check {{ booking.check_css_class }}"
title="{% trans "Checked period:" %}"
@ -94,16 +94,16 @@
{% endif %}
>
<strong class="sr-only">{% trans "Checked period:" %}</strong>
<time class="start-time" datetime="{{ booking.user_check_start_time|time:"H:i" }}">{{ booking.user_check_start_time|time:"H:i" }}</time>
<time class="end-time" datetime="{{ booking.user_check_end_time|time:"H:i" }}">{{ booking.user_check_end_time|time:"H:i" }}</time>
{% if booking.user_check_type_label %}<span>{{ booking.user_check_type_label }}</span>{% endif %}
<time class="start-time" datetime="{{ booking.user_check.start_time|time:"H:i" }}">{{ booking.user_check.start_time|time:"H:i" }}</time>
<time class="end-time" datetime="{{ booking.user_check.end_time|time:"H:i" }}">{{ booking.user_check.end_time|time:"H:i" }}</time>
{% if booking.user_check.type_label %}<span>{{ booking.user_check.type_label }}</span>{% endif %}
</a>
{% endif %}
{% endfor %}
</div>
<div class="registrant--bar-container">
{% for booking in user.bookings %}
{% if booking.user_was_present is not None and booking.computed_start_time != None and booking.computed_end_time != None %}
{% if booking.user_check and booking.computed_start_time != None and booking.computed_end_time != None %}
<p
class="registrant--bar clearfix computed {{ booking.check_css_class }}"
title="{% trans "Computed period" %}"

View File

@ -67,6 +67,7 @@ from chrono.agendas.models import (
AgendaNotificationsSettings,
AgendaReminderSettings,
Booking,
BookingCheck,
BookingColor,
Category,
Desk,
@ -1398,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
booking_qs = event.booking_set.select_related('user_check').order_by('start_time')
booked_qs = booking_qs.filter(
in_waiting_list=False, primary_booking__isnull=True, **booking_qs_kwargs
)
@ -1440,15 +1441,19 @@ class EventChecksMixin:
results = []
booked_without_status = False
for booking in booked_filterset.qs:
if booking.cancellation_datetime is None and booking.user_was_present is None:
if booking.cancellation_datetime is None and not hasattr(booking, 'user_check'):
booked_without_status = True
booking.absence_form = BookingCheckAbsenceForm(
agenda=self.agenda,
initial={'check_type': booking.user_check_type_slug},
initial={
'check_type': booking.user_check.type_slug if hasattr(booking, 'user_check') else None
},
)
booking.presence_form = BookingCheckPresenceForm(
agenda=self.agenda,
initial={'check_type': booking.user_check_type_slug},
initial={
'check_type': booking.user_check.type_slug if hasattr(booking, 'user_check') else None
},
)
booking.kind = 'booking'
results.append(booking)
@ -1651,11 +1656,11 @@ 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 booking.user_was_present is not None:
booking.check_css_class = 'present' if booking.user_was_present else 'absent'
booking.check_css_left = get_time_ratio(booking.user_check_start_time, start_time)
if hasattr(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(
booking.user_check_end_time, booking.user_check_start_time
booking.user_check.end_time, booking.user_check.start_time
)
if booking.computed_start_time is not None and booking.computed_end_time is not None:
booking.computed_css_left = get_time_ratio(booking.computed_start_time, start_time)
@ -1915,7 +1920,7 @@ class AgendaWeekMonthMixin:
]
booking_info_by_user = {}
bookings = Booking.objects.filter(event__in=self.events)
bookings = Booking.objects.filter(event__in=self.events).select_related('user_check')
for booking in bookings:
booking_info = booking_info_by_user.setdefault(
booking.user_external_id,
@ -1928,8 +1933,8 @@ class AgendaWeekMonthMixin:
)
user_bookings = booking_info['bookings']
if booking.user_was_present is not None:
booking.check_css_class = 'present' if booking.user_was_present else 'absent'
if hasattr(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
@ -2739,15 +2744,21 @@ class EventDetailView(ViewableAgendaMixin, DetailView):
context = super().get_context_data(**kwargs)
context['user_can_manage'] = self.agenda.can_be_managed(self.request.user)
event = self.object
context['booked'] = event.booking_set.filter(
cancellation_datetime__isnull=True, in_waiting_list=False
).order_by('creation_datetime')
context['booked'] = (
event.booking_set.filter(cancellation_datetime__isnull=True, in_waiting_list=False)
.select_related('user_check')
.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 b.user_was_present is True])
event.absent_count = len([b for b in context['booked'] if b.user_was_present is False])
event.notchecked_count = len([b for b in context['booked'] if b.user_was_present is None])
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')])
return context
@ -2886,7 +2897,7 @@ class EventCheckMixin:
event__cancelled=False,
cancellation_datetime__isnull=True,
in_waiting_list=False,
user_was_present__isnull=True,
user_check__isnull=True,
)
def get_check_type(self, kind):
@ -2930,10 +2941,19 @@ class EventPresenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
def post(self, request, *args, **kwargs):
qs_kwargs = {}
check_type = self.get_check_type(kind='presence')
qs_kwargs['user_check_type_slug'] = check_type.slug if check_type else None
qs_kwargs['user_check_type_label'] = check_type.label if check_type else None
qs_kwargs['type_slug'] = check_type.slug if check_type else None
qs_kwargs['type_label'] = check_type.label if check_type else None
bookings = self.get_bookings()
bookings.update(user_was_present=True, **qs_kwargs)
booking_checks_to_create = []
for booking in bookings:
if hasattr(booking, 'user_check'):
continue
booking_check = BookingCheck(booking=booking, presence=True, **qs_kwargs)
booking_checks_to_create.append(booking_check)
BookingCheck.objects.filter(booking__in=bookings).update(presence=True, **qs_kwargs)
BookingCheck.objects.bulk_create(booking_checks_to_create)
self.event.set_is_checked()
return self.response(request)
@ -2952,10 +2972,19 @@ class EventAbsenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
def post(self, request, *args, **kwargs):
qs_kwargs = {}
check_type = self.get_check_type(kind='absence')
qs_kwargs['user_check_type_slug'] = check_type.slug if check_type else None
qs_kwargs['user_check_type_label'] = check_type.label if check_type else None
qs_kwargs['type_slug'] = check_type.slug if check_type else None
qs_kwargs['type_label'] = check_type.label if check_type else None
bookings = self.get_bookings()
bookings.update(user_was_present=False, **qs_kwargs)
booking_checks_to_create = []
for booking in bookings:
if hasattr(booking, 'user_check'):
continue
booking_check = BookingCheck(booking=booking, presence=False, **qs_kwargs)
booking_checks_to_create.append(booking_check)
BookingCheck.objects.filter(booking__in=bookings).update(presence=False, **qs_kwargs)
BookingCheck.objects.bulk_create(booking_checks_to_create)
self.event.set_is_checked()
return self.response(request)
@ -3735,10 +3764,16 @@ class BookingCheckMixin:
def response(self, request, booking):
if is_ajax(request):
booking.absence_form = BookingCheckAbsenceForm(
agenda=self.agenda, initial={'check_type': booking.user_check_type_slug}
agenda=self.agenda,
initial={
'check_type': booking.user_check.type_slug if hasattr(booking, 'user_check') else None
},
)
booking.presence_form = BookingCheckPresenceForm(
agenda=self.agenda, initial={'check_type': booking.user_check_type_slug}
agenda=self.agenda,
initial={
'check_type': booking.user_check.type_slug if hasattr(booking, 'user_check') else None
},
)
booking.kind = 'booking'
return render(
@ -4493,10 +4528,11 @@ class PartialBookingCheckMixin(ViewableAgendaMixin):
form_class = PartialBookingCheckForm
def get_object(self):
return self.get_booking(**self.kwargs)
booking = self.get_booking(**self.kwargs)
return getattr(booking, 'user_check', BookingCheck(booking=booking))
def get_success_url(self):
date = self.object.event.start_datetime
date = self.object.booking.event.start_datetime
return reverse(
'chrono-manager-agenda-day-view',
kwargs={'pk': self.agenda.pk, 'year': date.year, 'month': date.month, 'day': date.day},
@ -4520,7 +4556,7 @@ class PartialBookingSubscriptionCheckView(PartialBookingCheckMixin, Subscription
if self.request.method == 'POST':
return super().get_object()
else:
return Booking()
return BookingCheck(booking=Booking())
partial_booking_subscription_check_view = PartialBookingSubscriptionCheckView.as_view()

View File

@ -1494,38 +1494,33 @@ def test_datetimes_multiple_agendas_with_status(app):
places=5,
agenda=agenda,
)
Booking.objects.create(event=event_absence, user_external_id='xxx', user_was_present=False)
booking = Booking.objects.create(event=event_absence, user_external_id='xxx')
booking.mark_user_absence()
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_check_type_slug='foo-reason',
)
booking = Booking.objects.create(event=event_absence_with_reason, user_external_id='xxx')
booking.mark_user_absence(check_type_slug='foo-reason')
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)
booking = Booking.objects.create(event=event_presence, user_external_id='xxx')
booking.mark_user_presence()
event_presence_with_reason = Event.objects.create(
slug='event-presence_with_reason',
start_datetime=now() - datetime.timedelta(days=9),
places=5,
agenda=agenda,
)
Booking.objects.create(
event=event_presence_with_reason,
user_external_id='xxx',
user_was_present=True,
user_check_type_slug='foo-reason',
)
booking = Booking.objects.create(event=event_presence_with_reason, user_external_id='xxx')
booking.mark_user_presence(check_type_slug='foo-reason')
event_booked_future = Event.objects.create(
slug='event-booked-future',
start_datetime=now() + datetime.timedelta(days=1),

View File

@ -5,7 +5,16 @@ import pytest
from django.db import connection
from django.test.utils import CaptureQueriesContext
from chrono.agendas.models import Agenda, Booking, BookingColor, Category, Desk, Event, MeetingType
from chrono.agendas.models import (
Agenda,
Booking,
BookingCheck,
BookingColor,
Category,
Desk,
Event,
MeetingType,
)
from chrono.utils.lingo import CheckType
from chrono.utils.timezone import localtime, make_aware, now
@ -353,8 +362,10 @@ def test_bookings_api_filter_user_was_present(app, user):
agenda=agenda, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 0, 0)), places=10
)
Booking.objects.create(event=event, user_external_id='42')
booking2 = Booking.objects.create(event=event, user_external_id='42', user_was_present=True)
booking3 = Booking.objects.create(event=event, user_external_id='42', user_was_present=False)
booking2 = Booking.objects.create(event=event, user_external_id='42')
booking2.mark_user_presence()
booking3 = Booking.objects.create(event=event, user_external_id='42')
booking3.mark_user_absence()
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_was_present': True})
@ -370,21 +381,12 @@ def test_bookings_api_filter_user_absence_reason(app, user):
event = Event.objects.create(
agenda=agenda, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 0, 0)), places=10
)
Booking.objects.create(event=event, user_external_id='42', user_was_present=False)
booking2 = Booking.objects.create(
event=event,
user_external_id='42',
user_was_present=False,
user_check_type_slug='foo-bar',
user_check_type_label='Foo bar',
)
Booking.objects.create(
event=event,
user_external_id='42',
user_was_present=True,
user_check_type_slug='foo-bar-2',
user_check_type_label='Foo bar 2',
)
booking = Booking.objects.create(event=event, user_external_id='42')
booking.mark_user_absence()
booking2 = Booking.objects.create(event=event, user_external_id='42')
booking2.mark_user_absence(check_type_slug='foo-bar', check_type_label='Foo bar')
booking3 = Booking.objects.create(event=event, user_external_id='42')
booking3.mark_user_presence(check_type_slug='foo-bar-2', check_type_label='Foo bar 2')
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': 'foo'})
@ -399,7 +401,7 @@ def test_bookings_api_filter_user_absence_reason(app, user):
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': 'foo-bar-2'})
assert resp.json['err'] == 0
assert [b['id'] for b in resp.json['data']] == []
Booking.objects.update(user_was_present=True)
BookingCheck.objects.update(presence=True)
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': 'Foo bar 2'})
assert resp.json['err'] == 0
assert [b['id'] for b in resp.json['data']] == []
@ -410,21 +412,12 @@ def test_bookings_api_filter_user_presence_reason(app, user):
event = Event.objects.create(
agenda=agenda, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 0, 0)), places=10
)
Booking.objects.create(event=event, user_external_id='42', user_was_present=True)
booking2 = Booking.objects.create(
event=event,
user_external_id='42',
user_was_present=True,
user_check_type_slug='foo-bar',
user_check_type_label='Foo bar',
)
Booking.objects.create(
event=event,
user_external_id='42',
user_was_present=False,
user_check_type_slug='foo-bar-2',
user_check_type_label='Foo bar 2',
)
booking = Booking.objects.create(event=event, user_external_id='42')
booking.mark_user_presence()
booking2 = Booking.objects.create(event=event, user_external_id='42')
booking2.mark_user_presence(check_type_slug='foo-bar', check_type_label='Foo bar')
booking3 = Booking.objects.create(event=event, user_external_id='42')
booking3.mark_user_absence(check_type_slug='foo-bar-2', check_type_label='Foo bar 2')
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': 'foo'})
@ -439,7 +432,7 @@ def test_bookings_api_filter_user_presence_reason(app, user):
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': 'foo-bar-2'})
assert resp.json['err'] == 0
assert [b['id'] for b in resp.json['data']] == []
Booking.objects.update(user_was_present=False)
BookingCheck.objects.update(presence=False)
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': 'Foo bar 2'})
assert resp.json['err'] == 0
assert [b['id'] for b in resp.json['data']] == []
@ -515,7 +508,11 @@ def test_bookings_api_filter_event(app, user):
def test_booking_api_present(app, user, flag):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
booking = Booking.objects.create(event=event, user_was_present=flag, user_check_type_slug='foo-bar')
booking = Booking.objects.create(event=event)
if flag is True:
booking.mark_user_presence(check_type_slug='foo-bar')
elif flag is False:
booking.mark_user_absence(check_type_slug='foo-bar')
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/booking/%s/' % booking.pk)
@ -614,8 +611,13 @@ def test_booking_patch_api_present(app, user, flag):
# set flag
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag})
booking.refresh_from_db()
assert booking.user_was_present == flag
if flag is not None:
assert booking.user_check.presence == flag
else:
assert not hasattr(booking, 'user_check')
event.refresh_from_db()
assert event.checked is False
@ -623,14 +625,17 @@ def test_booking_patch_api_present(app, user, flag):
agenda.save()
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag})
booking.refresh_from_db()
assert booking.user_was_present == flag
if flag is not None:
assert booking.user_check.presence == flag
else:
assert not hasattr(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 booking.user_was_present is None
assert not hasattr(booking, 'user_check')
# make secondary bookings
Booking.objects.create(event=event, primary_booking=booking)
@ -640,11 +645,14 @@ def test_booking_patch_api_present(app, user, flag):
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag})
booking.refresh_from_db()
assert booking.user_was_present == flag
if flag is not None:
assert booking.user_check.presence == flag
else:
assert not hasattr(booking, 'user_check')
# secondary bookings are left untouched
assert list(booking.secondary_booking_set.values_list('user_was_present', flat=True)) == [None, None]
assert list(booking.secondary_booking_set.values_list('user_check', flat=True)) == [None, None]
other_booking.refresh_from_db()
assert other_booking.user_was_present is None # not changed
assert not hasattr(other_booking, 'user_check') # not changed
# mark the event as checked
event.checked = True
@ -673,7 +681,8 @@ def test_booking_patch_api_absence_reason(check_types, app, user):
check_types.return_value = []
agenda = Agenda.objects.create(kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
booking = Booking.objects.create(event=event, user_was_present=False)
booking = Booking.objects.create(event=event)
booking.mark_user_absence()
app.authorization = ('Basic', ('john.doe', 'password'))
@ -698,8 +707,8 @@ def test_booking_patch_api_absence_reason(check_types, app, user):
# it works with label
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'Foo bar'})
booking.refresh_from_db()
assert booking.user_check_type_slug == 'foo-bar'
assert booking.user_check_type_label == 'Foo bar'
assert booking.user_check.type_slug == 'foo-bar'
assert booking.user_check.type_label == 'Foo bar'
# unknown
resp = app.patch_json(
@ -713,12 +722,12 @@ def test_booking_patch_api_absence_reason(check_types, app, user):
# reset
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': ''})
booking.refresh_from_db()
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
assert booking.user_check.type_slug is None
assert booking.user_check.type_label is None
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': None})
booking.refresh_from_db()
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
assert booking.user_check.type_slug is None
assert booking.user_check.type_label is None
# make secondary bookings
Booking.objects.create(event=event, primary_booking=booking)
@ -729,32 +738,31 @@ def test_booking_patch_api_absence_reason(check_types, app, user):
# it works also with slug
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'foo-bar'})
booking.refresh_from_db()
assert booking.user_check_type_slug == 'foo-bar'
assert booking.user_check_type_label == 'Foo bar'
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_type_slug', flat=True)) == [None, None]
assert list(booking.secondary_booking_set.values_list('user_check', flat=True)) == [None, None]
other_booking.refresh_from_db()
assert other_booking.user_check_type_slug is None # not changed
assert other_booking.user_check_type_label is None # not changed
assert not hasattr(other_booking, 'user_check') # not changed
# user_was_present is True, can not set user_absence_reason
Booking.objects.update(user_was_present=True)
# presence is True, can not set user_absence_reason
BookingCheck.objects.update(presence=True)
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'foo-bar'}, status=400
)
assert resp.json['err'] == 6
assert resp.json['err_desc'] == 'user is marked as present, can not set absence reason'
# but it's ok if user_was_present is set to False
# but it's ok if presence is set to False
resp = app.patch_json(
'/api/booking/%s/' % booking.pk,
params={'user_absence_reason': 'foo-bar', 'user_was_present': False},
)
assert resp.json['err'] == 0
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type_slug == 'foo-bar'
assert booking.user_check_type_label == 'Foo bar'
assert booking.user_check.presence is False
assert booking.user_check.type_slug == 'foo-bar'
assert booking.user_check.type_label == 'Foo bar'
# mark the event as checked
event.checked = True
@ -787,7 +795,8 @@ def test_booking_patch_api_presence_reason(check_types, app, user):
check_types.return_value = []
agenda = Agenda.objects.create(kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
booking = Booking.objects.create(event=event, user_was_present=True)
booking = Booking.objects.create(event=event)
booking.mark_user_presence()
app.authorization = ('Basic', ('john.doe', 'password'))
@ -812,8 +821,8 @@ def test_booking_patch_api_presence_reason(check_types, app, user):
# it works with label
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': 'Foo bar'})
booking.refresh_from_db()
assert booking.user_check_type_slug == 'foo-bar'
assert booking.user_check_type_label == 'Foo bar'
assert booking.user_check.type_slug == 'foo-bar'
assert booking.user_check.type_label == 'Foo bar'
# unknown
resp = app.patch_json(
@ -827,12 +836,12 @@ def test_booking_patch_api_presence_reason(check_types, app, user):
# reset
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': ''})
booking.refresh_from_db()
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
assert booking.user_check.type_slug is None
assert booking.user_check.type_label is None
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': None})
booking.refresh_from_db()
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
assert booking.user_check.type_slug is None
assert booking.user_check.type_label is None
# make secondary bookings
Booking.objects.create(event=event, primary_booking=booking)
@ -843,32 +852,31 @@ def test_booking_patch_api_presence_reason(check_types, app, user):
# it works also with slug
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': 'foo-bar'})
booking.refresh_from_db()
assert booking.user_check_type_slug == 'foo-bar'
assert booking.user_check_type_label == 'Foo bar'
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_type_slug', flat=True)) == [None, None]
assert list(booking.secondary_booking_set.values_list('user_check', flat=True)) == [None, None]
other_booking.refresh_from_db()
assert other_booking.user_check_type_slug is None # not changed
assert other_booking.user_check_type_label is None # not changed
assert not hasattr(other_booking, 'user_check') # not changed
# user_was_present is False, can not set user_presence_reason
Booking.objects.update(user_was_present=False)
# presence is False, can not set user_presence_reason
BookingCheck.objects.update(presence=False)
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_presence_reason': 'foo-bar'}, status=400
)
assert resp.json['err'] == 6
assert resp.json['err_desc'] == 'user is marked as absent, can not set presence reason'
# but it's ok if user_was_present is set to True
# but it's ok if presence is set to True
resp = app.patch_json(
'/api/booking/%s/' % booking.pk,
params={'user_presence_reason': 'foo-bar', 'user_was_present': True},
)
assert resp.json['err'] == 0
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug == 'foo-bar'
assert booking.user_check_type_label == 'Foo bar'
assert booking.user_check.presence is True
assert booking.user_check.type_slug == 'foo-bar'
assert booking.user_check.type_label == 'Foo bar'
# mark the event as checked
event.checked = True
@ -999,28 +1007,29 @@ def test_booking_patch_api_user_fields(app, user):
def test_booking_patch_api_extra_data(app, user):
agenda = Agenda.objects.create(kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
booking = Booking.objects.create(event=event, user_was_present=True)
booking = Booking.objects.create(event=event)
booking.mark_user_presence()
app.authorization = ('Basic', ('john.doe', 'password'))
app.patch_json('/api/booking/%s/' % booking.pk, params={'foo': 'bar'})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check.presence is True # not changed
assert booking.extra_data == {'foo': 'bar'}
app.patch_json('/api/booking/%s/' % booking.pk, params={'foo': 'baz'})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check.presence is True # not changed
assert booking.extra_data == {'foo': 'baz'}
app.patch_json('/api/booking/%s/' % booking.pk, params={'foooo': 'bar'})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check.presence is True # not changed
assert booking.extra_data == {'foo': 'baz', 'foooo': 'bar'}
app.patch_json('/api/booking/%s/' % booking.pk, params={'foooo': 'baz', 'foo': None})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check.presence is True # not changed
assert booking.extra_data == {'foo': None, 'foooo': 'baz'}
# make secondary bookings
@ -1030,7 +1039,7 @@ def test_booking_patch_api_extra_data(app, user):
other_booking = Booking.objects.create(event=event)
app.patch_json('/api/booking/%s/' % booking.pk, params={'foooo': 'baz', 'foo': None})
assert booking.user_was_present is True # not changed
assert booking.user_check.presence is True # not changed
assert booking.extra_data == {'foo': None, 'foooo': 'baz'}
# all secondary bookings are upadted
assert list(booking.secondary_booking_set.values_list('extra_data', flat=True)) == [
@ -1042,7 +1051,7 @@ def test_booking_patch_api_extra_data(app, user):
app.patch_json('/api/booking/%s/' % booking.pk, params={})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check.presence is True # not changed
assert booking.extra_data == {'foo': None, 'foooo': 'baz'} # not changed
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'foo': ['bar', 'baz']}, status=400)

View File

@ -201,17 +201,15 @@ def test_event_notify_checked(app, user):
assert event.checked is False
for i in range(8):
user_was_present = None
if i < 3:
user_was_present = True
elif i < 7:
user_was_present = False
Booking.objects.create(
booking = Booking.objects.create(
event=event,
user_was_present=user_was_present,
presence_callback_url='https://example.invalid/presence/%s' % i,
absence_callback_url='https://example.invalid/absence/%s' % i,
)
if i < 3:
booking.mark_user_presence()
elif i < 7:
booking.mark_user_absence()
app.authorization = ('Basic', ('john.doe', 'password'))
@ -1265,8 +1263,7 @@ def test_events_check_status(app, user):
assert resp.json['data'][0]['booking']['cancellation_datetime'] is None
# absence
booking.user_was_present = False
booking.save()
booking.mark_user_absence()
resp = app.get(url, params=params)
assert resp.json['err'] == 0
assert len(resp.json['data']) == 1
@ -1279,8 +1276,8 @@ def test_events_check_status(app, user):
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
# absence with check type
booking.user_check_type_slug = 'foo-reason'
booking.save()
booking.user_check.type_slug = 'foo-reason'
booking.user_check.save()
resp = app.get(url, params=params)
assert resp.json['err'] == 0
assert len(resp.json['data']) == 1
@ -1293,9 +1290,7 @@ def test_events_check_status(app, user):
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
# presence
booking.user_check_type_slug = None
booking.user_was_present = True
booking.save()
booking.mark_user_presence()
resp = app.get(url, params=params)
assert resp.json['err'] == 0
assert len(resp.json['data']) == 1
@ -1308,8 +1303,8 @@ def test_events_check_status(app, user):
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
# presence with check type
booking.user_check_type_slug = 'foo-reason'
booking.save()
booking.user_check.type_slug = 'foo-reason'
booking.user_check.save()
resp = app.get(url, params=params)
assert resp.json['err'] == 0
assert len(resp.json['data']) == 1
@ -1397,20 +1392,18 @@ def test_events_check_status_events(app, user, partial_bookings):
booking1 = Booking.objects.create(
event=first_event,
user_external_id='child:42',
user_was_present=True,
user_check_type_slug='foo-reason',
start_time=datetime.time(8, 0),
end_time=datetime.time(17, 0),
user_check_start_time=datetime.time(7, 55),
user_check_end_time=datetime.time(17, 15),
)
booking1.mark_user_presence(
check_type_slug='foo-reason', start_time=datetime.time(7, 55), end_time=datetime.time(17, 15)
)
booking1.refresh_computed_times()
booking1.save()
assert booking1.computed_start_time == datetime.time(8, 0)
assert booking1.computed_end_time == datetime.time(17, 30)
booking2 = Booking.objects.create(
event=event, user_external_id='child:42', user_was_present=True, user_check_type_slug='foo-reason'
)
booking2 = Booking.objects.create(event=event, user_external_id='child:42')
booking2.mark_user_presence(check_type_slug='foo-reason')
app.authorization = ('Basic', ('john.doe', 'password'))
url = '/api/agendas/events/check-status/'
@ -1861,12 +1854,13 @@ def test_events_check_lock(app, user, partial_bookings):
booking = Booking.objects.create(
event=event,
user_external_id='child:42',
user_was_present=True,
user_check_type_slug='foo-reason',
start_time=datetime.time(8, 0),
end_time=datetime.time(17, 0),
user_check_start_time=datetime.time(7, 55),
user_check_end_time=datetime.time(17, 15),
)
booking.mark_user_presence(
check_type_slug='foo-reason',
start_time=datetime.time(7, 55),
end_time=datetime.time(17, 15),
)
# computed times are None, because refresh_computed_times was not called in this test
assert booking.computed_start_time is None

View File

@ -121,10 +121,15 @@ def test_statistics_bookings(app, user, freezer):
# absence/presence
for i in range(10):
Booking.objects.create(event=event3, user_was_present=bool(i % 2))
booking = Booking.objects.create(event=event3)
if i % 2:
booking.mark_user_presence()
else:
booking.mark_user_absence()
event4 = Event.objects.create(start_datetime=now().replace(month=11, day=1), places=5, agenda=agenda)
booking = Booking.objects.create(event=event4, user_was_present=True)
booking = Booking.objects.create(event=event4)
booking.mark_user_presence()
Booking.objects.create(event=event4, primary_booking=booking)
resp = app.get(url + '?group_by=user_was_present')
@ -136,13 +141,17 @@ def test_statistics_bookings(app, user, freezer):
]
for i in range(9):
Booking.objects.create(
event=event3 if i % 2 else event4, extra_data={'menu': 'vegetables'}, user_was_present=bool(i % 3)
)
booking = Booking.objects.create(event=event3 if i % 2 else event4, extra_data={'menu': 'vegetables'})
if i % 3:
booking.mark_user_presence()
else:
booking.mark_user_absence()
for i in range(5):
Booking.objects.create(
event=event3 if i % 2 else event4, extra_data={'menu': 'meet'}, user_was_present=bool(i % 3)
)
booking = Booking.objects.create(event=event3 if i % 2 else event4, extra_data={'menu': 'meet'})
if i % 3:
booking.mark_user_presence()
else:
booking.mark_user_absence()
resp = app.get(url + '?group_by=menu')
assert resp.json['data']['x_labels'] == ['2020-10-10', '2020-10-15', '2020-10-25', '2020-11-01']

View File

@ -1765,15 +1765,12 @@ def test_event_checked(app, admin_user):
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark the event as checked' not in resp
for i in range(8):
user_was_present = None
booking = Booking.objects.create(event=event)
if i < 3:
user_was_present = True
booking.mark_user_presence()
elif i < 7:
user_was_present = False
Booking.objects.create(
event=event,
user_was_present=user_was_present,
)
booking.mark_user_absence()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark the event as checked' in resp
assert event.checked is False
@ -1810,7 +1807,8 @@ 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
Booking.objects.filter(user_was_present__isnull=True).update(user_was_present=True)
for booking in Booking.objects.filter(user_check__isnull=True):
booking.mark_user_presence()
for url in urls:
resp = app.get(url)
assert '<span class="checked tag">Checked</span>' in resp
@ -1885,17 +1883,16 @@ def test_event_notify_checked(app, admin_user):
login(app)
for i in range(8):
user_was_present = None
if i < 3:
user_was_present = True
elif i < 7:
user_was_present = False
Booking.objects.create(
booking = Booking.objects.create(
event=event,
user_was_present=user_was_present,
presence_callback_url='https://example.invalid/presence/%s' % i,
absence_callback_url='https://example.invalid/absence/%s' % i,
)
if i < 3:
booking.mark_user_presence()
elif i < 7:
booking.mark_user_absence()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
with mock.patch('chrono.utils.requests_wrapper.RequestsSession.send') as mock_send:
@ -1948,22 +1945,22 @@ def test_event_check_filters(check_types, app, admin_user):
user_last_name='empty',
extra_data={},
)
Booking.objects.create(
booking = Booking.objects.create(
event=event,
user_external_id='user:1',
user_first_name='User',
user_last_name='foo-val1 bar-none presence',
extra_data={'foo': 'val1', 'bar': ['val1']}, # bar is ignored, wrong value
user_was_present=True,
)
Booking.objects.create(
booking.mark_user_presence()
booking = Booking.objects.create(
event=event,
user_external_id='user:2',
user_first_name='User',
user_last_name='foo-val2 bar-val1 absence',
extra_data={'foo': 'val2', 'bar': 'val1'},
user_was_present=False,
)
booking.mark_user_absence()
Booking.objects.create(
event=event,
user_external_id='user:3',
@ -1971,44 +1968,42 @@ def test_event_check_filters(check_types, app, admin_user):
user_last_name='foo-val1 bar-val2 not-checked',
extra_data={'foo': 'val1', 'bar': 'val2'},
)
Booking.objects.create(
booking = Booking.objects.create(
event=event,
user_external_id='user:4',
user_first_name='User',
user_last_name='foo-none bar-val2 reason-foo',
extra_data={'bar': 'val2', 'foo': None}, # foo is ignored, empty value
user_was_present=False,
user_check_type_slug='foo-reason',
)
Booking.objects.create(
booking.mark_user_absence(check_type_slug='foo-reason')
booking = Booking.objects.create(
event=event,
user_external_id='user:5',
user_first_name='User',
user_last_name='foo-none bar-val2 reason-bar',
extra_data={'bar': 'val2', 'foo': ''}, # foo is ignored, empty value
user_was_present=True,
user_check_type_slug='bar-reason',
)
Booking.objects.create(
booking.mark_user_presence(check_type_slug='bar-reason')
booking = Booking.objects.create(
event=event,
user_external_id='user:6',
user_first_name='User',
user_last_name='foo-none bar-val2 cancelled-absence',
extra_data={'bar': 'val2'},
user_was_present=False,
user_check_type_slug='foo-reason',
cancellation_datetime=now(),
)
Booking.objects.create(
booking.mark_user_absence(check_type_slug='foo-reason')
booking.cancellation_datetime = now()
booking.save()
booking = Booking.objects.create(
event=event,
user_external_id='user:7',
user_first_name='User',
user_last_name='foo-none bar-val2 cancelled-presence',
extra_data={'bar': 'val2'},
user_was_present=True,
user_check_type_slug='bar-reason',
cancellation_datetime=now(),
)
booking.mark_user_presence(check_type_slug='bar-reason')
booking.cancellation_datetime = now()
booking.save()
Subscription.objects.create(
agenda=agenda,
@ -2368,13 +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 booking.user_was_present is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
assert not hasattr(booking, 'user_check')
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
assert not hasattr(secondary_booking, 'user_check')
event.refresh_from_db()
assert event.checked is False
@ -2399,13 +2390,11 @@ 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) in resp
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
assert booking.user_check.presence is True
assert booking.user_check.type_slug is None
assert booking.user_check.type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
assert not hasattr(secondary_booking, 'user_check')
event.refresh_from_db()
assert event.checked is False
@ -2424,13 +2413,11 @@ def test_event_check_booking(check_types, app, admin_user):
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Absence'
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
assert booking.user_check.presence is False
assert booking.user_check.type_slug is None
assert booking.user_check.type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
assert not hasattr(secondary_booking, 'user_check')
event.refresh_from_db()
assert event.checked is True
@ -2451,13 +2438,11 @@ def test_event_check_booking(check_types, app, admin_user):
).follow()
assert 'Foo reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type_slug == 'foo-reason'
assert booking.user_check_type_label == 'Foo reason'
assert booking.user_check.presence is False
assert booking.user_check.type_slug == 'foo-reason'
assert booking.user_check.type_label == 'Foo reason'
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
assert not hasattr(secondary_booking, 'user_check')
event.refresh_from_db()
assert event.checked is True
@ -2473,13 +2458,11 @@ def test_event_check_booking(check_types, app, admin_user):
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
assert booking.user_check.presence is True
assert booking.user_check.type_slug is None
assert booking.user_check.type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
assert not hasattr(secondary_booking, 'user_check')
event.refresh_from_db()
assert event.checked is True
@ -2505,13 +2488,11 @@ def test_event_check_booking(check_types, app, admin_user):
).follow()
assert 'Bar reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type_slug == 'bar-reason'
assert booking.user_check_type_label == 'Bar reason'
assert booking.user_check.presence is True
assert booking.user_check.type_slug == 'bar-reason'
assert booking.user_check.type_label == 'Bar reason'
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
assert not hasattr(secondary_booking, 'user_check')
event.refresh_from_db()
assert event.checked is True
@ -2687,10 +2668,10 @@ def test_event_check_cancelled_booking(check_types, app, admin_user):
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.cancellation_datetime is None
assert booking.user_was_present is True
assert booking.user_check.presence is True
secondary_booking.refresh_from_db()
assert secondary_booking.cancellation_datetime is None
assert secondary_booking.user_was_present is None
assert not hasattr(secondary_booking, 'user_check')
booking.cancel()
resp = app.post(
@ -2702,10 +2683,10 @@ def test_event_check_cancelled_booking(check_types, app, admin_user):
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Absence'
booking.refresh_from_db()
assert booking.cancellation_datetime is None
assert booking.user_was_present is False
assert booking.user_check.presence is False
secondary_booking.refresh_from_db()
assert secondary_booking.cancellation_datetime is None
assert secondary_booking.user_was_present is None
assert not hasattr(secondary_booking, 'user_check')
@mock.patch('chrono.manager.forms.get_agenda_check_types')
@ -2847,9 +2828,9 @@ def test_event_check_subscription(check_types, app, admin_user):
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
)
booking = Booking.objects.latest('pk')
assert booking.user_was_present is True
assert booking.user_check_type_slug == 'bar-reason'
assert booking.user_check_type_label == 'Bar reason'
assert booking.user_check.presence is True
assert booking.user_check.type_slug == 'bar-reason'
assert booking.user_check.type_label == 'Bar reason'
assert booking.event == event
assert booking.user_external_id == subscription.user_external_id
assert booking.user_first_name == subscription.user_first_name
@ -2869,9 +2850,9 @@ def test_event_check_subscription(check_types, app, admin_user):
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
)
booking = Booking.objects.latest('pk')
assert booking.user_was_present is False
assert booking.user_check_type_slug == 'foo-reason'
assert booking.user_check_type_label == 'Foo reason'
assert booking.user_check.presence is False
assert booking.user_check.type_slug == 'foo-reason'
assert booking.user_check.type_label == 'Foo reason'
assert booking.event == event
assert booking.user_external_id == subscription.user_external_id
assert booking.user_first_name == subscription.user_first_name
@ -3144,9 +3125,9 @@ def test_event_check_all_bookings(check_types, app, admin_user):
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk), params={'csrfmiddlewaretoken': token}
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
assert booking1.user_check.presence is False
assert booking1.user_check.type_slug is None
assert booking1.user_check.type_label is None
event.refresh_from_db()
assert event.checked is False
@ -3171,17 +3152,17 @@ def test_event_check_all_bookings(check_types, app, admin_user):
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk), params={'csrfmiddlewaretoken': token}
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
assert booking1.user_check.presence is False
assert booking1.user_check.type_slug is None
assert booking1.user_check.type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
assert booking2.user_check.presence is True
assert booking2.user_check.type_slug is None
assert booking2.user_check.type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
assert secondary_booking.user_check.presence is True
assert secondary_booking.user_check.type_slug is None
assert secondary_booking.user_check.type_label is None
event.refresh_from_db()
assert event.checked is True
@ -3194,17 +3175,17 @@ def test_event_check_all_bookings(check_types, app, admin_user):
params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
assert booking1.user_check.presence is False
assert booking1.user_check.type_slug is None
assert booking1.user_check.type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
assert booking2.user_check.presence is True
assert booking2.user_check.type_slug is None
assert booking2.user_check.type_label is None
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_check_type_slug == 'foo-reason'
assert booking3.user_check_type_label == 'Foo reason'
assert booking3.user_check.presence is False
assert booking3.user_check.type_slug == 'foo-reason'
assert booking3.user_check.type_label == 'Foo reason'
booking4 = Booking.objects.create(event=event, user_first_name='User', user_last_name='52')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
@ -3214,21 +3195,21 @@ def test_event_check_all_bookings(check_types, app, admin_user):
params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
assert booking1.user_check.presence is False
assert booking1.user_check.type_slug is None
assert booking1.user_check.type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
assert booking2.user_check.presence is True
assert booking2.user_check.type_slug is None
assert booking2.user_check.type_label is None
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_check_type_slug == 'foo-reason'
assert booking3.user_check_type_label == 'Foo reason'
assert booking3.user_check.presence is False
assert booking3.user_check.type_slug == 'foo-reason'
assert booking3.user_check.type_label == 'Foo reason'
booking4.refresh_from_db()
assert booking4.user_was_present is True
assert booking4.user_check_type_slug == 'bar-reason'
assert booking4.user_check_type_label == 'Bar reason'
assert booking4.user_check.presence is True
assert booking4.user_check.type_slug == 'bar-reason'
assert booking4.user_check.type_label == 'Bar reason'
# now disable check update
agenda.disable_check_update = True

View File

@ -51,10 +51,9 @@ def test_options_partial_bookings_invoicing_settings(app, admin_user):
user_last_name='Doe',
start_time=datetime.time(11, 00),
end_time=datetime.time(13, 30),
user_check_start_time=datetime.time(10, 55),
user_check_end_time=datetime.time(14, 5),
event=event,
)
booking.mark_user_presence(start_time=datetime.time(10, 55), end_time=datetime.time(14, 4))
agenda.refresh_booking_computed_times()
booking.refresh_from_db()
assert booking.computed_start_time == datetime.time(10, 0)
@ -280,9 +279,9 @@ def test_manager_partial_bookings_day_view_multiple_bookings(app, admin_user, fr
# check first booking
resp = resp.click('Booked period', index=0)
resp.form['user_check_start_time'] = '09:30'
resp.form['user_check_end_time'] = '12:00'
resp.form['user_was_present'] = 'True'
resp.form['start_time'] = '09:30'
resp.form['end_time'] = '12:00'
resp.form['presence'] = 'True'
resp = resp.form.submit().follow()
assert len(resp.pyquery('.partial-booking--registrant')) == 1
@ -294,9 +293,9 @@ def test_manager_partial_bookings_day_view_multiple_bookings(app, admin_user, fr
# check second booking
resp = resp.click('Booked period', index=1)
resp.form['user_check_start_time'] = '15:00'
resp.form['user_check_end_time'] = '17:00'
resp.form['user_was_present'] = 'True'
resp.form['start_time'] = '15:00'
resp.form['end_time'] = '17:00'
resp.form['presence'] = 'True'
resp = resp.form.submit().follow()
assert len(resp.pyquery('.partial-booking--registrant')) == 1
@ -339,25 +338,25 @@ def test_manager_partial_bookings_check(check_types, app, admin_user):
assert 'presence_check_type' not in resp.form.fields
assert 'absence_check_type' not in resp.form.fields
assert resp.pyquery('form').attr('data-fill-user_check_start_time') == '11:00'
assert resp.pyquery('form').attr('data-fill-user_check_end_time') == '13:30'
assert resp.pyquery('form').attr('data-fill-start_time') == '11:00'
assert resp.pyquery('form').attr('data-fill-end_time') == '13:30'
assert resp.pyquery('.time-widget-button')[0].text == 'Fill with booking start time'
assert resp.pyquery('.time-widget-button')[1].text == 'Fill with booking end time'
resp.form['user_check_start_time'] = '11:01'
resp.form['user_check_end_time'] = '11:00'
resp.form['user_was_present'] = 'True'
resp.form['start_time'] = '11:01'
resp.form['end_time'] = '11:00'
resp.form['presence'] = 'True'
resp = resp.form.submit()
assert 'Arrival must be before departure.' in resp.text
resp.form['user_check_start_time'] = '11:01'
resp.form['user_check_end_time'] = '13:15'
resp.form['user_was_present'] = 'True'
resp.form['start_time'] = '11:01'
resp.form['end_time'] = '13:15'
resp.form['presence'] = 'True'
resp = resp.form.submit().follow()
booking.refresh_from_db()
assert booking.user_check_start_time == datetime.time(11, 1)
assert booking.user_check_end_time == datetime.time(13, 15)
assert booking.user_check.start_time == datetime.time(11, 1)
assert booking.user_check.end_time == datetime.time(13, 15)
assert booking.computed_start_time == datetime.time(11, 0)
assert booking.computed_end_time == datetime.time(14, 0)
@ -378,8 +377,8 @@ def test_manager_partial_bookings_check(check_types, app, admin_user):
agenda.save()
agenda.refresh_booking_computed_times()
booking.refresh_from_db()
assert booking.user_check_start_time == datetime.time(11, 1)
assert booking.user_check_end_time == datetime.time(13, 15)
assert booking.user_check.start_time == datetime.time(11, 1)
assert booking.user_check.end_time == datetime.time(13, 15)
assert booking.computed_start_time == datetime.time(11, 0)
assert booking.computed_end_time == datetime.time(13, 30)
@ -416,7 +415,7 @@ def test_manager_partial_bookings_check(check_types, app, admin_user):
resp = resp.click('Booked period')
assert resp.form['presence_check_type'].value == 'bar-reason'
resp.form['user_was_present'] = 'False'
resp.form['presence'] = 'False'
resp = resp.form.submit().follow()
assert len(resp.pyquery('.registrant--bar')) == 3
@ -426,7 +425,7 @@ def test_manager_partial_bookings_check(check_types, app, admin_user):
assert resp.pyquery('.registrant--bar span').text() == ''
resp = resp.click('Booked period')
resp.form['user_was_present'] = ''
resp.form['presence'] = ''
resp = resp.form.submit().follow()
assert len(resp.pyquery('.registrant--bar')) == 1
assert len(resp.pyquery('.registrant--bar.booking')) == 1
@ -491,15 +490,15 @@ def test_manager_partial_bookings_check_subscription(check_types, app, admin_use
resp = resp.click('Jane Doe')
assert 'Fill with booking start time' not in resp.text
assert 'absence_check_type' not in resp.form.fields
assert resp.form['user_was_present'].options == [
assert resp.form['presence'].options == [
('', True, None),
('True', False, None),
] # no 'False' option
assert not Booking.objects.exists()
resp.form['user_check_start_time'] = '10:00'
resp.form['user_check_end_time'] = '16:00'
resp.form['user_was_present'] = 'True'
resp.form['start_time'] = '10:00'
resp.form['end_time'] = '16:00'
resp.form['presence'] = 'True'
resp = resp.form.submit().follow()
assert len(resp.pyquery('.registrant--name a')) == 0
@ -517,12 +516,12 @@ def test_manager_partial_bookings_check_subscription(check_types, app, admin_use
resp = resp.click('Checked period')
assert 'Fill with booking start time' not in resp.text
assert 'absence_check_type' not in resp.form.fields
assert resp.form['user_was_present'].options == [
assert resp.form['presence'].options == [
('', False, None),
('True', True, None),
] # no 'False' option
resp.form['user_was_present'] = ''
resp.form['presence'] = ''
resp = resp.form.submit().follow()
assert len(resp.pyquery('.registrant--bar')) == 0
@ -552,30 +551,27 @@ def test_manager_partial_bookings_check_filters(check_types, app, admin_user):
end_time=datetime.time(13, 30),
event=event,
)
Booking.objects.create(
booking = Booking.objects.create(
user_external_id='user:2',
user_first_name='User',
user_last_name='Present Vegan',
start_time=datetime.time(8, 00),
end_time=datetime.time(10, 00),
user_check_start_time=datetime.time(8, 00),
user_check_end_time=datetime.time(10, 00),
event=event,
extra_data={'menu': 'vegan'},
user_was_present=True,
)
Booking.objects.create(
booking.mark_user_presence(start_time=datetime.time(8, 00), end_time=datetime.time(10, 00))
booking = Booking.objects.create(
user_external_id='user:3',
user_first_name='User',
user_last_name='Absent Meat Foo Reason',
start_time=datetime.time(12, 00),
end_time=datetime.time(14, 00),
user_check_start_time=datetime.time(12, 30),
user_check_end_time=datetime.time(14, 30),
event=event,
extra_data={'menu': 'meat'},
user_was_present=False,
user_check_type_slug='foo-reason',
)
booking.mark_user_absence(
check_type_slug='foo-reason', start_time=datetime.time(12, 30), end_time=datetime.time(14, 30)
)
Subscription.objects.create(
agenda=agenda,
@ -645,19 +641,15 @@ def test_manager_partial_bookings_event_checked(app, admin_user):
resp = app.get(url)
assert 'Mark the event as checked' not in resp
for i in range(8):
user_was_present = None
if i < 3:
user_was_present = True
elif i < 7:
user_was_present = False
Booking.objects.create(
booking = Booking.objects.create(
event=event,
user_was_present=user_was_present,
start_time=datetime.time(8, 00),
end_time=datetime.time(10, 00),
user_check_start_time=datetime.time(8, 00),
user_check_end_time=datetime.time(10, 00),
)
if i < 3:
booking.mark_user_presence(start_time=datetime.time(8, 00), end_time=datetime.time(10, 00))
elif i < 7:
booking.mark_user_absence(start_time=datetime.time(8, 00), end_time=datetime.time(10, 00))
resp = app.get(url)
assert 'Mark the event as checked' in resp
assert event.checked is False
@ -679,7 +671,8 @@ 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
Booking.objects.filter(user_was_present__isnull=True).update(user_was_present=True)
for booking in Booking.objects.filter(user_check__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
assert 'check-locked' not in resp
@ -753,28 +746,24 @@ def test_manager_partial_bookings_month_view(app, admin_user, freezer):
end_time=datetime.time(13, 30),
event=e,
)
Booking.objects.create(
booking = Booking.objects.create(
user_external_id='user:2',
user_first_name='User',
user_last_name='Present',
start_time=datetime.time(8, 00),
end_time=datetime.time(10, 00),
user_check_start_time=datetime.time(8, 00),
user_check_end_time=datetime.time(10, 00),
event=event,
user_was_present=True,
)
Booking.objects.create(
booking.mark_user_presence(start_time=datetime.time(8, 00), end_time=datetime.time(10, 00))
booking = Booking.objects.create(
user_external_id='user:3',
user_first_name='User',
user_last_name='Absent',
start_time=datetime.time(12, 00),
end_time=datetime.time(14, 00),
user_check_start_time=datetime.time(12, 30),
user_check_end_time=datetime.time(14, 30),
event=event,
user_was_present=False,
)
booking.mark_user_absence(start_time=datetime.time(12, 30), end_time=datetime.time(14, 30))
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',

View File

@ -3971,9 +3971,8 @@ def test_booking_get_computed_start_time(start_time, user_check_start_time, tole
places=10,
)
booking = Booking.objects.create(
event=event, start_time=start_time, user_check_start_time=user_check_start_time
)
booking = Booking.objects.create(event=event, start_time=start_time)
booking.mark_user_presence(start_time=user_check_start_time)
assert booking.get_computed_start_time() == expected
@ -4029,7 +4028,8 @@ def test_booking_get_computed_end_time(end_time, user_check_end_time, tolerance,
places=10,
)
booking = Booking.objects.create(event=event, end_time=end_time, user_check_end_time=user_check_end_time)
booking = Booking.objects.create(event=event, end_time=end_time)
booking.mark_user_presence(end_time=user_check_end_time)
assert booking.get_computed_end_time() == expected
@ -4051,9 +4051,8 @@ def test_agenda_refresh_booking_computed_times():
event=event,
start_time=datetime.time(8, 0),
end_time=datetime.time(17, 0),
user_check_start_time=datetime.time(7, 55),
user_check_end_time=datetime.time(17, 15),
)
booking.mark_user_presence(start_time=datetime.time(7, 55), end_time=datetime.time(17, 15))
def reset_booking():
booking.computed_start_time = None
@ -4149,9 +4148,8 @@ def test_event_refresh_booking_computed_times():
event=event,
start_time=datetime.time(8, 0),
end_time=datetime.time(17, 0),
user_check_start_time=datetime.time(7, 55),
user_check_end_time=datetime.time(17, 15),
)
booking.mark_user_presence(start_time=datetime.time(7, 55), end_time=datetime.time(17, 15))
def reset_booking():
booking.computed_start_time = None