agendas: rename absence reason into check type (#63810)

This commit is contained in:
Lauréline Guérin 2022-04-12 15:31:42 +02:00
parent 1c1e18a45b
commit b1c85499df
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
29 changed files with 694 additions and 656 deletions

View File

@ -0,0 +1,50 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agendas', '0118_booking_out_of_min_delay'),
]
operations = [
migrations.RenameModel(
old_name='AbsenceReason',
new_name='CheckType',
),
migrations.RenameModel(
old_name='AbsenceReasonGroup',
new_name='CheckTypeGroup',
),
migrations.RenameField(
model_name='agenda',
old_name='absence_reasons_group',
new_name='check_type_group',
),
migrations.AlterField(
model_name='agenda',
name='check_type_group',
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to='agendas.CheckTypeGroup',
verbose_name='Check type group',
),
),
migrations.AlterField(
model_name='checktype',
name='group',
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name='check_types',
to='agendas.CheckTypeGroup',
),
),
migrations.RenameField(
model_name='booking',
old_name='user_absence_reason',
new_name='user_check_type',
),
]

View File

@ -254,9 +254,9 @@ class Agenda(models.Model):
category = models.ForeignKey(
'Category', verbose_name=_('Category'), blank=True, null=True, on_delete=models.SET_NULL
)
absence_reasons_group = models.ForeignKey(
'AbsenceReasonGroup',
verbose_name=_('Absence reasons group'),
check_type_group = models.ForeignKey(
'CheckTypeGroup',
verbose_name=_('Check type group'),
blank=True,
null=True,
on_delete=models.SET_NULL,
@ -445,9 +445,7 @@ class Agenda(models.Model):
agenda['events'] = [x.export_json() for x in self.event_set.filter(primary_event__isnull=True)]
if hasattr(self, 'notifications_settings'):
agenda['notifications_settings'] = self.notifications_settings.export_json()
agenda['absence_reasons_group'] = (
self.absence_reasons_group.slug if self.absence_reasons_group else None
)
agenda['check_type_group'] = self.check_type_group.slug if self.check_type_group else None
agenda['exceptions_desk'] = self.desk_set.get().export_json()
agenda['minimal_booking_delay_in_working_days'] = self.minimal_booking_delay_in_working_days
agenda['booking_user_block_template'] = self.booking_user_block_template
@ -494,15 +492,11 @@ class Agenda(models.Model):
data['category'] = Category.objects.get(slug=data['category'])
except Category.DoesNotExist:
del data['category']
if data.get('absence_reasons_group'):
if data.get('check_type_group'):
try:
data['absence_reasons_group'] = AbsenceReasonGroup.objects.get(
slug=data['absence_reasons_group']
)
except AbsenceReasonGroup.DoesNotExist:
raise AgendaImportError(
_('Missing "%s" absence reasons group') % data['absence_reasons_group']
)
data['check_type_group'] = CheckTypeGroup.objects.get(slug=data['check_type_group'])
except CheckTypeGroup.DoesNotExist:
raise AgendaImportError(_('Missing "%s" check type group') % data['check_type_group'])
if data.get('events_type'):
try:
data['events_type'] = EventsType.objects.get(slug=data['events_type'])
@ -1936,7 +1930,7 @@ class Booking(models.Model):
user_email = models.EmailField(blank=True)
user_phone_number = models.CharField(max_length=16, blank=True)
user_was_present = models.NullBooleanField()
user_absence_reason = models.CharField(max_length=250, blank=True)
user_check_type = models.CharField(max_length=250, blank=True)
out_of_min_delay = models.BooleanField(default=False)
extra_emails = ArrayField(models.EmailField(), default=list)
@ -1987,20 +1981,20 @@ class Booking(models.Model):
self.secondary_booking_set.update(in_waiting_list=True)
self.save()
def mark_user_absence(self, reason=None):
self.user_absence_reason = reason
def mark_user_absence(self, check_type=None):
self.user_check_type = check_type
self.user_was_present = False
with transaction.atomic():
self.secondary_booking_set.update(user_absence_reason=reason)
self.secondary_booking_set.update(user_check_type=check_type)
self.secondary_booking_set.update(user_was_present=False)
self.save()
self.event.set_is_checked()
def mark_user_presence(self):
self.user_absence_reason = ''
self.user_check_type = ''
self.user_was_present = True
with transaction.atomic():
self.secondary_booking_set.update(user_absence_reason='')
self.secondary_booking_set.update(user_check_type='')
self.secondary_booking_set.update(user_was_present=True)
self.save()
self.event.set_is_checked()
@ -3039,7 +3033,7 @@ class AgendaReminderSettings(models.Model):
return new_settings
class AbsenceReasonGroup(models.Model):
class CheckTypeGroup(models.Model):
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
label = models.CharField(_('Label'), max_length=150)
@ -3060,16 +3054,16 @@ class AbsenceReasonGroup(models.Model):
@classmethod
def import_json(cls, data, overwrite=False):
absence_reasons = data.pop('absence_reasons', [])
check_types = data.pop('check_types', [])
data = clean_import_data(cls, data)
group, created = cls.objects.update_or_create(slug=data['slug'], defaults=data)
if overwrite:
AbsenceReason.objects.filter(group=group).delete()
CheckType.objects.filter(group=group).delete()
for absence_reason in absence_reasons:
absence_reason['group'] = group
AbsenceReason.import_json(absence_reason)
for check_type in check_types:
check_type['group'] = group
CheckType.import_json(check_type)
return created, group
@ -3077,12 +3071,12 @@ class AbsenceReasonGroup(models.Model):
return {
'label': self.label,
'slug': self.slug,
'absence_reasons': [a.export_json() for a in self.absence_reasons.all()],
'check_types': [a.export_json() for a in self.check_types.all()],
}
class AbsenceReason(models.Model):
group = models.ForeignKey(AbsenceReasonGroup, on_delete=models.CASCADE, related_name='absence_reasons')
class CheckType(models.Model):
group = models.ForeignKey(CheckTypeGroup, on_delete=models.CASCADE, related_name='check_types')
slug = models.SlugField(_('Identifier'), max_length=160)
label = models.CharField(_('Label'), max_length=150)

View File

@ -5,7 +5,7 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from chrono.agendas.models import AbsenceReason, Agenda, Booking, Category, Event, EventsType, Subscription
from chrono.agendas.models import Agenda, Booking, Category, CheckType, Event, EventsType, Subscription
def get_objects_from_slugs(slugs, qs):
@ -138,27 +138,27 @@ class RecurringFillslotsSerializer(MultipleAgendasEventsSlotsSerializer):
class BookingSerializer(serializers.ModelSerializer):
user_absence_reason = serializers.CharField(required=False, allow_blank=True, allow_null=True)
user_check_type = serializers.CharField(required=False, allow_blank=True, allow_null=True)
class Meta:
model = Booking
fields = ['id', 'in_waiting_list', 'user_was_present', 'user_absence_reason', 'extra_data']
fields = ['id', 'in_waiting_list', 'user_was_present', 'user_check_type', 'extra_data']
read_only_fields = ['id', 'in_waiting_list', 'extra_data']
def validate_user_absence_reason(self, value):
def validate_user_check_type(self, value):
if not value:
return ''
if not self.instance.event.agenda.absence_reasons_group:
raise serializers.ValidationError(_('unknown absence reason'))
if not self.instance.event.agenda.check_type_group:
raise serializers.ValidationError(_('unknown check type'))
reasons_qs = self.instance.event.agenda.absence_reasons_group.absence_reasons
check_types_qs = self.instance.event.agenda.check_type_group.check_types
try:
reason = reasons_qs.get(slug=value)
value = reason.label
except AbsenceReason.DoesNotExist:
if not reasons_qs.filter(label=value).exists():
raise serializers.ValidationError(_('unknown absence reason'))
check_type = check_types_qs.get(slug=value)
value = check_type.label
except CheckType.DoesNotExist:
if not check_types_qs.filter(label=value).exists():
raise serializers.ValidationError(_('unknown check type'))
return value

View File

@ -379,10 +379,10 @@ def get_agenda_detail(request, agenda, check_events=False):
}
if check_events:
agenda_detail['opened_events_available'] = bool(agenda.get_open_events().filter(full=False))
if agenda.absence_reasons_group:
if agenda.check_type_group:
agenda_detail['absence_reasons'] = [
{'id': r.slug, 'slug': r.slug, 'text': r.label, 'label': r.label}
for r in agenda.absence_reasons_group.absence_reasons.all()
for r in agenda.check_type_group.check_types.all()
]
elif agenda.accept_meetings():
agenda_detail['api'] = {
@ -733,8 +733,8 @@ class Agendas(APIView):
def get(self, request, format=None):
agendas_queryset = (
Agenda.objects.all()
.select_related('absence_reasons_group', 'category', 'edit_role', 'view_role', 'events_type')
.prefetch_related('resources', 'absence_reasons_group__absence_reasons')
.select_related('check_type_group', 'category', 'edit_role', 'view_role', 'events_type')
.prefetch_related('resources', 'check_type_group__check_types')
.order_by('label')
)
@ -2239,7 +2239,7 @@ class BookingFilter(filters.FilterSet):
'date_start',
'date_end',
'user_was_present',
'user_absence_reason',
'user_check_type',
'in_waiting_list',
]
@ -2320,7 +2320,7 @@ class BookingAPI(APIView):
if (
self.booking.event.checked
and self.booking.event.agenda.disable_check_update
and ('user_was_present' in request.data or 'user_absence_reason' in request.data)
and ('user_was_present' in request.data or 'user_check_type' in request.data)
):
raise APIErrorBadRequest(N_('event is marked as checked'), err=5)
@ -2334,8 +2334,8 @@ class BookingAPI(APIView):
if 'user_was_present' in request.data:
self.booking.secondary_booking_set.update(user_was_present=self.booking.user_was_present)
self.booking.event.set_is_checked()
if 'user_absence_reason' in request.data:
self.booking.secondary_booking_set.update(user_absence_reason=self.booking.user_absence_reason)
if 'user_check_type' in request.data:
self.booking.secondary_booking_set.update(user_check_type=self.booking.user_check_type)
if extra_data:
self.booking.secondary_booking_set.update(extra_data=self.booking.extra_data)

View File

@ -40,12 +40,12 @@ from chrono.agendas.models import (
WEEK_CHOICES,
WEEKDAY_CHOICES,
WEEKDAYS_LIST,
AbsenceReason,
AbsenceReasonGroup,
Agenda,
AgendaNotificationsSettings,
AgendaReminderSettings,
Booking,
CheckType,
CheckTypeGroup,
Desk,
Event,
EventsType,
@ -69,16 +69,16 @@ from . import widgets
from .widgets import SplitDateTimeField, WeekdaysWidget
class AbsenceReasonForm(forms.ModelForm):
class CheckTypeForm(forms.ModelForm):
class Meta:
model = AbsenceReason
model = CheckType
fields = ['label', 'slug']
def clean_slug(self):
slug = self.cleaned_data['slug']
if self.instance.group.absence_reasons.filter(slug=slug).exclude(pk=self.instance.pk).exists():
raise ValidationError(_('Another absence reason exists with the same identifier.'))
if self.instance.group.check_types.filter(slug=slug).exclude(pk=self.instance.pk).exists():
raise ValidationError(_('Another check type exists with the same identifier.'))
return slug
@ -444,10 +444,10 @@ class BookingCheckFilterSet(django_filters.FilterSet):
('presence', _('Presence')),
('absence', _('Absence')),
]
if self.agenda.absence_reasons_group:
if self.agenda.check_type_group:
status_choices += [
('absence-%s' % r.label, _('Absence (%s)') % r.label)
for r in self.agenda.absence_reasons_group.absence_reasons.all()
for r in self.agenda.check_type_group.check_types.all()
]
self.filters['booking-status'] = django_filters.ChoiceFilter(
label=_('Filter by status'),
@ -473,7 +473,7 @@ class BookingCheckFilterSet(django_filters.FilterSet):
if value == 'absence':
return queryset.filter(user_was_present=False)
if value.startswith('absence-'):
return queryset.filter(user_was_present=False, user_absence_reason=value[8:])
return queryset.filter(user_was_present=False, user_check_type=value[8:])
return queryset
def do_nothing(self, queryset, name, value):
@ -491,15 +491,15 @@ class SubscriptionCheckFilterSet(BookingCheckFilterSet):
return queryset
class BookingAbsenceReasonForm(forms.Form):
reason = forms.ChoiceField(required=False)
class BookingCheckAbsenceForm(forms.Form):
check_type = forms.ChoiceField(required=False)
def __init__(self, *args, **kwargs):
agenda = kwargs.pop('agenda')
super().__init__(*args, **kwargs)
if agenda.absence_reasons_group:
self.fields['reason'].choices = [('', '---------')] + [
(r.label, r.label) for r in agenda.absence_reasons_group.absence_reasons.all()
if agenda.check_type_group:
self.fields['check_type'].choices = [('', '---------')] + [
(r.label, r.label) for r in agenda.check_type_group.check_types.all()
]
@ -1267,7 +1267,7 @@ class AgendaBookingCheckSettingsForm(forms.ModelForm):
class Meta:
model = Agenda
fields = [
'absence_reasons_group',
'check_type_group',
'booking_check_filters',
'booking_user_block_template',
'mark_event_checked_auto',
@ -1277,8 +1277,8 @@ class AgendaBookingCheckSettingsForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not AbsenceReasonGroup.objects.exists():
del self.fields['absence_reasons_group']
if not CheckTypeGroup.objects.exists():
del self.fields['check_type_group']
class AgendaNotificationsForm(forms.ModelForm):
@ -1378,7 +1378,7 @@ class AgendasExportForm(forms.Form):
label=_('Unavailability calendars'), required=False, initial=True
)
categories = forms.BooleanField(label=_('Categories'), required=False, initial=True)
absence_reason_groups = forms.BooleanField(label=_('Absence reason groups'), required=False, initial=True)
check_type_groups = forms.BooleanField(label=_('Check type groups'), required=False, initial=True)
events_types = forms.BooleanField(label=_('Events types'), required=False, initial=True)

View File

@ -75,8 +75,8 @@ h2 span.identifier {
}
.timeperiods .timeperiod a.add::before,
.absence-reason-group h3 a.delete::before,
.absence-reason-group a.add::before {
.check-type-group h3 a.delete::before,
.check-type-group a.add::before {
content: "\f055"; /* plus-circle */
font-family: FontAwesome;
padding-right: 1ex;
@ -90,7 +90,7 @@ a.timeperiod-exception-all {
content: "\f0ad"; /* wrench */
}
.absence-reason-group h3 a.delete {
.check-type-group h3 a.delete {
width: 1em;
overflow: hidden;
&::before {

View File

@ -35,8 +35,8 @@ $(function() {
var formData = {
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]', $form).val()
};
if ($('select[name=reason]', $form)) {
formData['reason'] = $('select[name=reason]', $form).val();
if ($('select[name=check_type]', $form)) {
formData['check_type'] = $('select[name=check_type]', $form).val();
}
$.ajax({

View File

@ -1,31 +0,0 @@
{% extends "chrono/manager_absence_reason_list.html" %}
{% load i18n %}
{% block breadcrumb %}
{{ block.super }}
{% if form.instance.pk %}
<a href="{% url 'chrono-manager-absence-reason-edit' form.instance.group_id form.instance.pk %}">{{ form.instance }}</a>
{% else %}
<a href="{% url 'chrono-manager-absence-reason-add' form.instance.group_id %}">{% trans "New absence reason" %}</a>
{% endif %}
{% endblock %}
{% block appbar %}
{% if form.instance.pk %}
<h2>{{ form.instance.group }} - {% trans "Edit absence reason" %}</h2>
{% else %}
<h2>{{ form.instance.group }} - {% trans "New absence reason" %}</h2>
{% endif %}
{% endblock %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div class="buttons">
<button class="submit-button">{% trans "Save" %}</button>
<a class="cancel" href="{% url 'chrono-manager-absence-reason-list' %}">{% trans 'Cancel' %}</a>
</div>
</form>
{% endblock %}

View File

@ -1,31 +0,0 @@
{% extends "chrono/manager_absence_reason_list.html" %}
{% load i18n %}
{% block breadcrumb %}
{{ block.super }}
{% if object.pk %}
<a href="{# url 'chrono-manager-absence-reason-group-edit' object.pk #}">{{ object }}</a>
{% else %}
<a href="{% url 'chrono-manager-absence-reason-group-add' %}">{% trans "New absence reason group" %}</a>
{% endif %}
{% endblock %}
{% block appbar %}
{% if object.pk %}
<h2>{% trans "Edit absence reason group" %}</h2>
{% else %}
<h2>{% trans "New absence reason group" %}</h2>
{% endif %}
{% endblock %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div class="buttons">
<button class="submit-button">{% trans "Save" %}</button>
<a class="cancel" href="{% url 'chrono-manager-absence-reason-list' %}">{% trans 'Cancel' %}</a>
</div>
</form>
{% endblock %}

View File

@ -1,49 +0,0 @@
{% extends "chrono/manager_base.html" %}
{% load i18n %}
{% block breadcrumb %}
{{ block.super }}
<a href="{% url 'chrono-manager-absence-reason-list' %}">{% trans "Absence reasons" %}</a>
{% endblock %}
{% block appbar %}
<h2>{% trans 'Absence reasons' %}</h2>
<span class="actions">
<a rel="popup" href="{% url 'chrono-manager-absence-reason-group-add' %}">{% trans 'New group' %}</a>
</span>
{% endblock %}
{% block content %}
<div class="pk-information">
<p>{% trans "Define here absence reasons used in events agendas to check bookings." %}</p>
</div>
{% for object in object_list %}
<div class="section absence-reason-group">
<h3>
<a rel="popup" href="{% url 'chrono-manager-absence-reason-group-edit' object.pk %}">{{ object }}</a>
<span>
<a class="button" href="{% url 'chrono-manager-absence-reason-group-export' object.pk %}">{% trans "Export"%}</a>
<a class="button" rel="popup" href="{% url 'chrono-manager-absence-reason-group-delete' object.pk %}">{% trans "Delete"%}</a>
</span>
</h3>
<div>
<ul class="objects-list single-links">
{% for reason in object.absence_reasons.all %}
<li>
<a rel="popup" href="{% url 'chrono-manager-absence-reason-edit' object.pk reason.pk %}">{{ reason }}</a>
<a class="delete" rel="popup" href="{% url 'chrono-manager-absence-reason-delete' object.pk reason.pk %}">{% trans "delete"%}</a>
</li>
{% endfor %}
<li><a class="add" rel="popup" href="{% url 'chrono-manager-absence-reason-add' object.pk %}">{% trans "Add an absence reason" %}</a></li>
</ul>
</div>
</div>
{% empty %}
<div class="big-msg-info">
{% blocktrans %}
This site doesn't have any absence reason group yet. Click on the "New group" button in the top
right of the page to add a first one.
{% endblocktrans %}
</div>
{% endfor %}
{% endblock %}

View File

@ -0,0 +1,31 @@
{% extends "chrono/manager_check_type_list.html" %}
{% load i18n %}
{% block breadcrumb %}
{{ block.super }}
{% if form.instance.pk %}
<a href="{% url 'chrono-manager-check-type-edit' form.instance.group_id form.instance.pk %}">{{ form.instance }}</a>
{% else %}
<a href="{% url 'chrono-manager-check-type-add' form.instance.group_id %}">{% trans "New check type" %}</a>
{% endif %}
{% endblock %}
{% block appbar %}
{% if form.instance.pk %}
<h2>{{ form.instance.group }} - {% trans "Edit check type" %}</h2>
{% else %}
<h2>{{ form.instance.group }} - {% trans "New check type" %}</h2>
{% endif %}
{% endblock %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div class="buttons">
<button class="submit-button">{% trans "Save" %}</button>
<a class="cancel" href="{% url 'chrono-manager-check-type-list' %}">{% trans 'Cancel' %}</a>
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,31 @@
{% extends "chrono/manager_check_type_list.html" %}
{% load i18n %}
{% block breadcrumb %}
{{ block.super }}
{% if object.pk %}
<a href="{% url 'chrono-manager-check-type-group-edit' object.pk %}">{{ object }}</a>
{% else %}
<a href="{% url 'chrono-manager-check-type-group-add' %}">{% trans "New check type group" %}</a>
{% endif %}
{% endblock %}
{% block appbar %}
{% if object.pk %}
<h2>{% trans "Edit check type group" %}</h2>
{% else %}
<h2>{% trans "New check type group" %}</h2>
{% endif %}
{% endblock %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div class="buttons">
<button class="submit-button">{% trans "Save" %}</button>
<a class="cancel" href="{% url 'chrono-manager-check-type-list' %}">{% trans 'Cancel' %}</a>
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,49 @@
{% extends "chrono/manager_base.html" %}
{% load i18n %}
{% block breadcrumb %}
{{ block.super }}
<a href="{% url 'chrono-manager-check-type-list' %}">{% trans "Check types" %}</a>
{% endblock %}
{% block appbar %}
<h2>{% trans 'Check types' %}</h2>
<span class="actions">
<a rel="popup" href="{% url 'chrono-manager-check-type-group-add' %}">{% trans 'New group' %}</a>
</span>
{% endblock %}
{% block content %}
<div class="pk-information">
<p>{% trans "Define here check types used in events agendas to check bookings." %}</p>
</div>
{% for object in object_list %}
<div class="section check-type-group">
<h3>
<a rel="popup" href="{% url 'chrono-manager-check-type-group-edit' object.pk %}">{{ object }}</a>
<span>
<a class="button" href="{% url 'chrono-manager-check-type-group-export' object.pk %}">{% trans "Export"%}</a>
<a class="button" rel="popup" href="{% url 'chrono-manager-check-type-group-delete' object.pk %}">{% trans "Delete"%}</a>
</span>
</h3>
<div>
<ul class="objects-list single-links">
{% for check_type in object.check_types.all %}
<li>
<a rel="popup" href="{% url 'chrono-manager-check-type-edit' object.pk check_type.pk %}">{{ check_type }}</a>
<a class="delete" rel="popup" href="{% url 'chrono-manager-check-type-delete' object.pk check_type.pk %}">{% trans "delete"%}</a>
</li>
{% endfor %}
<li><a class="add" rel="popup" href="{% url 'chrono-manager-check-type-add' object.pk %}">{% trans "Add a check type" %}</a></li>
</ul>
</div>
</div>
{% empty %}
<div class="big-msg-info">
{% blocktrans %}
This site doesn't have any check type group yet. Click on the "New group" button in the top
right of the page to add a first one.
{% endblocktrans %}
</div>
{% endfor %}
{% endblock %}

View File

@ -49,7 +49,7 @@
<form method="post" action="{% url 'chrono-manager-event-absence' pk=agenda.pk event_pk=object.pk %}" id="all-bookings-absence">
{% csrf_token %}
<button class="submit-button">{% trans "Absence" %}</button>
{% if absence_form.reason.field.choices.1 %}{{ absence_form.reason }}{% endif %}
{% if absence_form.check_type.field.choices.1 %}{{ absence_form.check_type }}{% endif %}
<script>
$(function() {
$('#all-bookings-absence select').on('change',

View File

@ -3,8 +3,8 @@
<td class="booking-username main-list">{{ booking.get_user_block }}{% if booking.places_count > 1 %} ({{ booking.places_count }} {% trans "places" %}){% endif %}</td>
<td class="booking-status {% if booking.user_was_present is None %}without-status{% endif %}">
{{ booking.user_was_present|yesno:_('Present,Absent,-') }}
{% if booking.user_was_present is False and booking.user_absence_reason %}
({{ booking.user_absence_reason }})
{% if booking.user_was_present is False and booking.user_check_type %}
({{ booking.user_check_type }})
{% endif %}
</td>
{% if not event.checked or not agenda.disable_check_update %}

View File

@ -36,17 +36,17 @@
</h3>
<div>
<ul>
{% if has_absence_reasons %}
{% if agenda.absence_reasons_group %}
<li>{% trans "Absence reasons group:" %} {{ agenda.absence_reasons_group }}
{% if has_check_types %}
{% if agenda.check_type_group %}
<li>{% trans "Check type group:" %} {{ agenda.check_type_group }}
<ul>
{% for reason in agenda.absence_reasons_group.absence_reasons.all %}
<li>{{ reason }}</li>
{% for check_type in agenda.check_type_group.check_types.all %}
<li>{{ check_type }}</li>
{% endfor %}
</ul>
</li>
{% else %}
<li>{% trans "No absence reasons configured for this agenda." %}</li>
<li>{% trans "No check types configured for this agenda." %}</li>
{% endif %}
{% endif %}

View File

@ -11,7 +11,7 @@
<li><a rel="popup" href="{% url 'chrono-manager-agendas-import' %}">{% trans 'Import' %}</a></li>
<li><a rel="popup" href="{% url 'chrono-manager-agendas-export' %}" data-autoclose-dialog="true">{% trans 'Export' %}</a></li>
<li><a href="{% url 'chrono-manager-events-type-list' %}">{% trans 'Events types' %}</a></li>
<li><a href="{% url 'chrono-manager-absence-reason-list' %}">{% trans 'Absence reasons' %}</a></li>
<li><a href="{% url 'chrono-manager-check-type-list' %}">{% trans 'Check types' %}</a></li>
{% endif %}
{% if has_access_to_unavailability_calendars %}
<li><a href="{% url 'chrono-manager-unavailability-calendar-list' %}">{% trans 'Unavailability calendars' %}</a></li>

View File

@ -84,41 +84,41 @@ urlpatterns = [
url(r'^category/add/$', views.category_add, name='chrono-manager-category-add'),
url(r'^category/(?P<pk>\d+)/edit/$', views.category_edit, name='chrono-manager-category-edit'),
url(r'^category/(?P<pk>\d+)/delete/$', views.category_delete, name='chrono-manager-category-delete'),
url(r'^absence-reasons/$', views.absence_reason_list, name='chrono-manager-absence-reason-list'),
url(r'^check-types/$', views.check_type_list, name='chrono-manager-check-type-list'),
url(
r'^absence-reason/group/add/$',
views.absence_reason_group_add,
name='chrono-manager-absence-reason-group-add',
r'^check-type/group/add/$',
views.check_type_group_add,
name='chrono-manager-check-type-group-add',
),
url(
r'^absence-reason/group/(?P<pk>\d+)/edit/$',
views.absence_reason_group_edit,
name='chrono-manager-absence-reason-group-edit',
r'^check-type/group/(?P<pk>\d+)/edit/$',
views.check_type_group_edit,
name='chrono-manager-check-type-group-edit',
),
url(
r'^absence-reason/group/(?P<pk>\d+)/delete/$',
views.absence_reason_group_delete,
name='chrono-manager-absence-reason-group-delete',
r'^check-type/group/(?P<pk>\d+)/delete/$',
views.check_type_group_delete,
name='chrono-manager-check-type-group-delete',
),
url(
r'^absence-reason/group/(?P<pk>\d+)/export/$',
views.absence_reason_group_export,
name='chrono-manager-absence-reason-group-export',
r'^check-type/group/(?P<pk>\d+)/export/$',
views.check_type_group_export,
name='chrono-manager-check-type-group-export',
),
url(
r'^absence-reason/group/(?P<group_pk>\d+)/add/$',
views.absence_reason_add,
name='chrono-manager-absence-reason-add',
r'^check-type/group/(?P<group_pk>\d+)/add/$',
views.check_type_add,
name='chrono-manager-check-type-add',
),
url(
r'^absence-reason/group/(?P<group_pk>\d+)/(?P<pk>\d+)/edit/$',
views.absence_reason_edit,
name='chrono-manager-absence-reason-edit',
r'^check-type/group/(?P<group_pk>\d+)/(?P<pk>\d+)/edit/$',
views.check_type_edit,
name='chrono-manager-check-type-edit',
),
url(
r'^absence-reason/group/(?P<group_pk>\d+)/(?P<pk>\d+)/delete/$',
views.absence_reason_delete,
name='chrono-manager-absence-reason-delete',
r'^check-type/group/(?P<group_pk>\d+)/(?P<pk>\d+)/delete/$',
views.check_type_delete,
name='chrono-manager-check-type-delete',
),
url(r'^events-types/$', views.events_type_list, name='chrono-manager-events-type-list'),
url(r'^events-type/add/$', views.events_type_add, name='chrono-manager-events-type-add'),

View File

@ -22,10 +22,10 @@ from django.db import transaction
from django.db.models import Q
from chrono.agendas.models import (
AbsenceReasonGroup,
Agenda,
AgendaImportError,
Category,
CheckTypeGroup,
EventsType,
Resource,
UnavailabilityCalendar,
@ -35,7 +35,7 @@ from chrono.agendas.models import (
def export_site(
agendas=True,
unavailability_calendars=True,
absence_reason_groups=True,
check_type_groups=True,
events_types=True,
resources=True,
categories=True,
@ -48,8 +48,8 @@ def export_site(
data['resources'] = [x.export_json() for x in Resource.objects.all()]
if events_types:
data['events_types'] = [x.export_json() for x in EventsType.objects.all()]
if absence_reason_groups:
data['absence_reason_groups'] = [x.export_json() for x in AbsenceReasonGroup.objects.all()]
if check_type_groups:
data['check_type_groups'] = [x.export_json() for x in CheckTypeGroup.objects.all()]
if unavailability_calendars:
data['unavailability_calendars'] = [x.export_json() for x in UnavailabilityCalendar.objects.all()]
if agendas:
@ -64,7 +64,7 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
if if_empty and (
Agenda.objects.exists()
or UnavailabilityCalendar.objects.exists()
or AbsenceReasonGroup.objects.exists()
or CheckTypeGroup.objects.exists()
or EventsType.objects.exists()
or Resource.objects.exists()
or Category.objects.exists()
@ -74,7 +74,7 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
if clean:
Agenda.objects.all().delete()
UnavailabilityCalendar.objects.all().delete()
AbsenceReasonGroup.objects.all().delete()
CheckTypeGroup.objects.all().delete()
EventsType.objects.all().delete()
Resource.objects.all().delete()
Category.objects.all().delete()
@ -84,7 +84,7 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
for key in [
'agendas',
'unavailability_calendars',
'absence_reason_groups',
'check_type_groups',
'events_types',
'resources',
'categories',
@ -108,7 +108,7 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
(Category, 'categories'),
(Resource, 'resources'),
(EventsType, 'events_types'),
(AbsenceReasonGroup, 'absence_reason_groups'),
(CheckTypeGroup, 'check_type_groups'),
(UnavailabilityCalendar, 'unavailability_calendars'),
(Agenda, 'agendas'),
):

View File

@ -60,8 +60,6 @@ from weasyprint import HTML
from chrono.agendas.management.commands.utils import send_reminder
from chrono.agendas.models import (
AbsenceReason,
AbsenceReasonGroup,
Agenda,
AgendaImportError,
AgendaNotificationsSettings,
@ -69,6 +67,8 @@ from chrono.agendas.models import (
Booking,
BookingColor,
Category,
CheckType,
CheckTypeGroup,
Desk,
Event,
EventCancellationReport,
@ -89,7 +89,6 @@ from chrono.agendas.models import (
from chrono.utils.date import get_weekday_index
from .forms import (
AbsenceReasonForm,
AgendaAddForm,
AgendaBookingCheckSettingsForm,
AgendaBookingDelaysForm,
@ -102,9 +101,10 @@ from .forms import (
AgendaRolesForm,
AgendasExportForm,
AgendasImportForm,
BookingAbsenceReasonForm,
BookingCancelForm,
BookingCheckAbsenceForm,
BookingCheckFilterSet,
CheckTypeForm,
CustomFieldFormSet,
DeskExceptionsImportForm,
DeskForm,
@ -654,9 +654,9 @@ class CategoryDeleteView(DeleteView):
category_delete = CategoryDeleteView.as_view()
class AbsenceReasonListView(ListView):
template_name = 'chrono/manager_absence_reason_list.html'
model = AbsenceReasonGroup
class CheckTypeListView(ListView):
template_name = 'chrono/manager_check_type_list.html'
model = CheckTypeGroup
def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
@ -664,15 +664,15 @@ class AbsenceReasonListView(ListView):
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return AbsenceReasonGroup.objects.prefetch_related('absence_reasons')
return CheckTypeGroup.objects.prefetch_related('check_types')
absence_reason_list = AbsenceReasonListView.as_view()
check_type_list = CheckTypeListView.as_view()
class AbsenceReasonGroupAddView(CreateView):
template_name = 'chrono/manager_absence_reason_group_form.html'
model = AbsenceReasonGroup
class CheckTypeGroupAddView(CreateView):
template_name = 'chrono/manager_check_type_group_form.html'
model = CheckTypeGroup
fields = ['label']
def dispatch(self, request, *args, **kwargs):
@ -681,15 +681,15 @@ class AbsenceReasonGroupAddView(CreateView):
return super().dispatch(request, *args, **kwargs)
def get_success_url(self):
return reverse('chrono-manager-absence-reason-list')
return reverse('chrono-manager-check-type-list')
absence_reason_group_add = AbsenceReasonGroupAddView.as_view()
check_type_group_add = CheckTypeGroupAddView.as_view()
class AbsenceReasonGroupEditView(UpdateView):
template_name = 'chrono/manager_absence_reason_group_form.html'
model = AbsenceReasonGroup
class CheckTypeGroupEditView(UpdateView):
template_name = 'chrono/manager_check_type_group_form.html'
model = CheckTypeGroup
fields = ['label', 'slug']
def dispatch(self, request, *args, **kwargs):
@ -698,15 +698,15 @@ class AbsenceReasonGroupEditView(UpdateView):
return super().dispatch(request, *args, **kwargs)
def get_success_url(self):
return reverse('chrono-manager-absence-reason-list')
return reverse('chrono-manager-check-type-list')
absence_reason_group_edit = AbsenceReasonGroupEditView.as_view()
check_type_group_edit = CheckTypeGroupEditView.as_view()
class AbsenceReasonGroupDeleteView(DeleteView):
class CheckTypeGroupDeleteView(DeleteView):
template_name = 'chrono/manager_confirm_delete.html'
model = AbsenceReasonGroup
model = CheckTypeGroup
def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
@ -714,14 +714,14 @@ class AbsenceReasonGroupDeleteView(DeleteView):
return super().dispatch(request, *args, **kwargs)
def get_success_url(self):
return reverse('chrono-manager-absence-reason-list')
return reverse('chrono-manager-check-type-list')
absence_reason_group_delete = AbsenceReasonGroupDeleteView.as_view()
check_type_group_delete = CheckTypeGroupDeleteView.as_view()
class AbsenceReasonGroupExport(DetailView):
model = AbsenceReasonGroup
class CheckTypeGroupExport(DetailView):
model = CheckTypeGroup
def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
@ -731,20 +731,20 @@ class AbsenceReasonGroupExport(DetailView):
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='application/json')
today = datetime.date.today()
attachment = 'attachment; filename="export_absence_reason_group_{}_{}.json"'.format(
attachment = 'attachment; filename="export_check_type_group_{}_{}.json"'.format(
self.get_object().slug, today.strftime('%Y%m%d')
)
response['Content-Disposition'] = attachment
json.dump({'absence_reason_groups': [self.get_object().export_json()]}, response, indent=2)
json.dump({'check_type_groups': [self.get_object().export_json()]}, response, indent=2)
return response
absence_reason_group_export = AbsenceReasonGroupExport.as_view()
check_type_group_export = CheckTypeGroupExport.as_view()
class AbsenceReasonAddView(CreateView):
template_name = 'chrono/manager_absence_reason_form.html'
model = AbsenceReason
class CheckTypeAddView(CreateView):
template_name = 'chrono/manager_check_type_form.html'
model = CheckType
fields = ['label']
def dispatch(self, request, *args, **kwargs):
@ -761,16 +761,16 @@ class AbsenceReasonAddView(CreateView):
return kwargs
def get_success_url(self):
return reverse('chrono-manager-absence-reason-list')
return reverse('chrono-manager-check-type-list')
absence_reason_add = AbsenceReasonAddView.as_view()
check_type_add = CheckTypeAddView.as_view()
class AbsenceReasonEditView(UpdateView):
template_name = 'chrono/manager_absence_reason_form.html'
model = AbsenceReason
form_class = AbsenceReasonForm
class CheckTypeEditView(UpdateView):
template_name = 'chrono/manager_check_type_form.html'
model = CheckType
form_class = CheckTypeForm
def dispatch(self, request, *args, **kwargs):
self.group_pk = kwargs.pop('group_pk')
@ -779,18 +779,18 @@ class AbsenceReasonEditView(UpdateView):
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return AbsenceReason.objects.filter(group=self.group_pk)
return CheckType.objects.filter(group=self.group_pk)
def get_success_url(self):
return reverse('chrono-manager-absence-reason-list')
return reverse('chrono-manager-check-type-list')
absence_reason_edit = AbsenceReasonEditView.as_view()
check_type_edit = CheckTypeEditView.as_view()
class AbsenceReasonDeleteView(DeleteView):
class CheckTypeDeleteView(DeleteView):
template_name = 'chrono/manager_confirm_delete.html'
model = AbsenceReason
model = CheckType
def dispatch(self, request, *args, **kwargs):
self.group_pk = kwargs.pop('group_pk')
@ -799,13 +799,13 @@ class AbsenceReasonDeleteView(DeleteView):
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return AbsenceReason.objects.filter(group=self.group_pk)
return CheckType.objects.filter(group=self.group_pk)
def get_success_url(self):
return reverse('chrono-manager-absence-reason-list')
return reverse('chrono-manager-check-type-list')
absence_reason_delete = AbsenceReasonDeleteView.as_view()
check_type_delete = CheckTypeDeleteView.as_view()
class EventsTypeListView(ListView):
@ -981,17 +981,17 @@ class AgendasImportView(FormView):
x,
),
},
'absence_reason_groups': {
'create_noop': _('No absence reason group created.'),
'check_type_groups': {
'create_noop': _('No check type group created.'),
'create': lambda x: ungettext(
'An absence reason group has been created.',
'%(count)d absence reason groups have been created.',
'An check type group has been created.',
'%(count)d check type groups have been created.',
x,
),
'update_noop': _('No absence reason group updated.'),
'update_noop': _('No check type group updated.'),
'update': lambda x: ungettext(
'An absence reason group has been updated.',
'%(count)d absence reason groups have been updated.',
'An check type group has been updated.',
'%(count)d check type groups have been updated.',
x,
),
},
@ -1060,7 +1060,7 @@ class AgendasImportView(FormView):
a_count, uc_count, arg_count = (
len(results['agendas']['all']),
len(results['unavailability_calendars']['all']),
len(results['absence_reason_groups']['all']),
len(results['check_type_groups']['all']),
)
if (a_count, uc_count, arg_count) == (1, 0, 0):
# only one agenda imported, redirect to settings page
@ -1076,15 +1076,15 @@ class AgendasImportView(FormView):
)
)
if (a_count, uc_count, arg_count) == (0, 0, 1):
# only one absence reason group imported, redirect to group page
return HttpResponseRedirect(reverse('chrono-manager-absence-reason-list'))
# only one check type group imported, redirect to group page
return HttpResponseRedirect(reverse('chrono-manager-check-type-list'))
if global_noop:
messages.info(self.request, _('No data found.'))
else:
messages.info(self.request, results['agendas']['messages'])
messages.info(self.request, results['unavailability_calendars']['messages'])
messages.info(self.request, results['absence_reason_groups']['messages'])
messages.info(self.request, results['check_type_groups']['messages'])
messages.info(self.request, results['events_types']['messages'])
messages.info(self.request, results['resources']['messages'])
messages.info(self.request, results['categories']['messages'])
@ -1786,7 +1786,7 @@ class AgendaSettings(ManagedAgendaMixin, DetailView):
def set_agenda(self, **kwargs):
self.agenda = get_object_or_404(
Agenda.objects.select_related('edit_role', 'view_role', 'absence_reasons_group'),
Agenda.objects.select_related('edit_role', 'view_role', 'check_type_group'),
pk=kwargs.get('pk'),
)
@ -1813,7 +1813,7 @@ class AgendaSettings(ManagedAgendaMixin, DetailView):
else False
)
if self.agenda.kind == 'events':
context['has_absence_reasons'] = AbsenceReasonGroup.objects.exists()
context['has_check_types'] = CheckTypeGroup.objects.exists()
context['has_recurring_events'] = self.agenda.event_set.filter(
recurrence_days__isnull=False
).exists()
@ -2257,7 +2257,7 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
def set_agenda(self, **kwargs):
self.agenda = get_object_or_404(
Agenda.objects.prefetch_related('absence_reasons_group__absence_reasons'),
Agenda.objects.prefetch_related('check_type_group__check_types'),
pk=kwargs.get('pk'),
kind='events',
)
@ -2335,8 +2335,8 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
for booking in booked_filterset.qs:
if booking.cancellation_datetime is None and booking.user_was_present is None:
booked_without_status = True
booking.form = BookingAbsenceReasonForm(
agenda=self.agenda, initial={'reason': booking.user_absence_reason}
booking.form = BookingCheckAbsenceForm(
agenda=self.agenda, initial={'check_type': booking.user_check_type}
)
booking.kind = 'booking'
results.append(booking)
@ -2356,7 +2356,7 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
# set context
context['booked_without_status'] = booked_without_status
if context['booked_without_status']:
context['absence_form'] = BookingAbsenceReasonForm(agenda=self.agenda)
context['absence_form'] = BookingCheckAbsenceForm(agenda=self.agenda)
context['filterset'] = booked_filterset
context['results'] = results
context['waiting'] = waiting_qs
@ -2405,7 +2405,7 @@ class EventCheckMixin:
class EventPresenceView(EventCheckMixin, ViewableAgendaMixin, View):
def post(self, request, *args, **kwargs):
bookings = self.get_bookings()
bookings.update(user_absence_reason='', user_was_present=True)
bookings.update(user_check_type='', user_was_present=True)
self.event.set_is_checked()
return self.response(request)
@ -2414,7 +2414,7 @@ event_presence = EventPresenceView.as_view()
class EventAbsenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
form_class = BookingAbsenceReasonForm
form_class = BookingCheckAbsenceForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
@ -2425,7 +2425,7 @@ class EventAbsenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
form = self.get_form()
qs_kwargs = {}
if form.is_valid():
qs_kwargs['user_absence_reason'] = form.cleaned_data['reason']
qs_kwargs['user_check_type'] = form.cleaned_data['check_type']
bookings = self.get_bookings()
bookings.update(user_was_present=False, **qs_kwargs)
self.event.set_is_checked()
@ -3121,8 +3121,8 @@ class BookingCheckMixin:
def response(self, request, booking):
if request.is_ajax():
booking.form = BookingAbsenceReasonForm(
agenda=self.agenda, initial={'reason': booking.user_absence_reason}
booking.form = BookingCheckAbsenceForm(
agenda=self.agenda, initial={'check_type': booking.user_check_type}
)
return render(
request,
@ -3148,7 +3148,7 @@ booking_presence = BookingPresenceView.as_view()
class BookingAbsenceView(ViewableAgendaMixin, BookingCheckMixin, FormView):
form_class = BookingAbsenceReasonForm
form_class = BookingCheckAbsenceForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
@ -3158,10 +3158,10 @@ class BookingAbsenceView(ViewableAgendaMixin, BookingCheckMixin, FormView):
def post(self, request, *args, **kwargs):
booking = self.get_booking(**kwargs)
form = self.get_form()
reason = None
check_type = None
if form.is_valid():
reason = form.cleaned_data['reason']
booking.mark_user_absence(reason=reason)
check_type = form.cleaned_data['check_type']
booking.mark_user_absence(check_type=check_type)
return self.response(request, booking)

View File

@ -1222,7 +1222,7 @@ def test_datetimes_multiple_agendas_with_status(app):
event=event_absence_with_reason,
user_external_id='xxx',
user_was_present=False,
user_absence_reason='foobar',
user_check_type='foobar',
)
event_presence = Event.objects.create(
slug='event-presence',

View File

@ -7,11 +7,11 @@ from django.test.utils import CaptureQueriesContext
from django.utils.timezone import localtime, now
from chrono.agendas.models import (
AbsenceReason,
AbsenceReasonGroup,
Agenda,
Booking,
Category,
CheckType,
CheckTypeGroup,
Desk,
Event,
EventsType,
@ -27,22 +27,22 @@ def test_agendas_api(app):
view_group = Group.objects.create(name='View')
category_a = Category.objects.create(label='Category A')
category_b = Category.objects.create(label='Category B')
group = AbsenceReasonGroup.objects.create(label='Foo')
reason = AbsenceReason.objects.create(group=group, label='Foo bar')
reason2 = AbsenceReason.objects.create(group=group, label='Foo bar baz')
group = CheckTypeGroup.objects.create(label='Foo')
reason = CheckType.objects.create(group=group, label='Foo bar')
reason2 = CheckType.objects.create(group=group, label='Foo bar baz')
events_type = EventsType.objects.create(label='Type A')
events_type2 = EventsType.objects.create(label='Type B')
event_agenda = Agenda.objects.create(
label='Foo bar',
category=category_a,
absence_reasons_group=group,
check_type_group=group,
events_type=events_type,
edit_role=edit_group,
)
Desk.objects.create(agenda=event_agenda, slug='_exceptions_holder')
event_agenda2 = Agenda.objects.create(label='Foo bar 2', category=category_a, events_type=events_type2)
Desk.objects.create(agenda=event_agenda2, slug='_exceptions_holder')
event_agenda3 = Agenda.objects.create(label='Foo bar 3', absence_reasons_group=group)
event_agenda3 = Agenda.objects.create(label='Foo bar 3', check_type_group=group)
Desk.objects.create(agenda=event_agenda3, slug='_exceptions_holder')
meetings_agenda1 = Agenda.objects.create(
label='Foo bar Meeting', kind='meetings', category=category_b, view_role=view_group

View File

@ -7,11 +7,11 @@ from django.test.utils import CaptureQueriesContext
from django.utils.timezone import make_aware, now
from chrono.agendas.models import (
AbsenceReason,
AbsenceReasonGroup,
Agenda,
Booking,
Category,
CheckType,
CheckTypeGroup,
Desk,
Event,
MeetingType,
@ -146,14 +146,14 @@ def test_bookings_api(app, user):
'id': meetings_booking1.pk,
'in_waiting_list': False,
'user_was_present': None,
'user_absence_reason': '',
'user_check_type': '',
'extra_data': None,
},
{
'id': events_booking1.pk,
'in_waiting_list': False,
'user_was_present': None,
'user_absence_reason': '',
'user_check_type': '',
'extra_data': None,
'event': resp.json['data'][1]['event'],
},
@ -161,7 +161,7 @@ def test_bookings_api(app, user):
'id': events_booking2.pk,
'in_waiting_list': False,
'user_was_present': None,
'user_absence_reason': '',
'user_check_type': '',
'extra_data': None,
'event': resp.json['data'][1]['event'],
},
@ -298,19 +298,19 @@ def test_bookings_api_filter_user_was_present(app, user):
assert [b['id'] for b in resp.json['data']] == [booking3.pk]
def test_bookings_api_filter_user_absence_reason(app, user):
def test_bookings_api_filter_user_check_type(app, user):
agenda = Agenda.objects.create(label='Foo bar')
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')
booking2 = Booking.objects.create(event=event, user_external_id='42', user_absence_reason='foo-bar')
booking2 = Booking.objects.create(event=event, user_external_id='42', user_check_type='foo-bar')
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': 'foo'})
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_check_type': 'foo'})
assert resp.json['err'] == 0
assert [b['id'] for b in resp.json['data']] == []
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': 'foo-bar'})
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_check_type': 'foo-bar'})
assert resp.json['err'] == 0
assert [b['id'] for b in resp.json['data']] == [booking2.pk]
@ -385,13 +385,13 @@ 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_absence_reason='foobar')
booking = Booking.objects.create(event=event, user_was_present=flag, user_check_type='foobar')
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/booking/%s/' % booking.pk)
assert resp.json['booking_id'] == booking.pk
assert resp.json['user_was_present'] == flag
assert resp.json['user_absence_reason'] == 'foobar'
assert resp.json['user_check_type'] == 'foobar'
@pytest.mark.parametrize('flag', [True, False])
@ -527,39 +527,35 @@ def test_booking_patch_api_absence_reason(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
# reasons not defined on agenda
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'foobar'}, status=400
)
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'user_check_type': 'foobar'}, status=400)
assert resp.json['err'] == 4
assert resp.json['err_desc'] == 'invalid payload'
group = AbsenceReasonGroup.objects.create(label='Foo')
reason = AbsenceReason.objects.create(group=group, label='Foo bar')
group = CheckTypeGroup.objects.create(label='Foo')
reason = CheckType.objects.create(group=group, label='Foo bar')
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'foobar'}, status=400
)
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'user_check_type': 'foobar'}, status=400)
assert resp.json['err'] == 4
assert resp.json['err_desc'] == 'invalid payload'
# set reason
agenda.absence_reasons_group = group
agenda.check_type_group = group
agenda.save()
# it works with label
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'Foo bar'})
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_check_type': 'Foo bar'})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_absence_reason == 'Foo bar'
assert booking.user_check_type == 'Foo bar'
# reset
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': ''})
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_check_type': ''})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_absence_reason == ''
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': None})
assert booking.user_check_type == ''
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_check_type': None})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_absence_reason == ''
assert booking.user_check_type == ''
# make secondary bookings
Booking.objects.create(event=event, primary_booking=booking, user_was_present=False)
@ -568,12 +564,12 @@ def test_booking_patch_api_absence_reason(app, user):
other_booking = Booking.objects.create(event=event)
# it works also with slug
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': reason.slug})
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_check_type': reason.slug})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_absence_reason == 'Foo bar'
assert booking.user_check_type == 'Foo bar'
# all secondary bookings are upadted
assert list(booking.secondary_booking_set.values_list('user_absence_reason', flat=True)) == [
assert list(booking.secondary_booking_set.values_list('user_check_type', flat=True)) == [
'Foo bar',
'Foo bar',
]
@ -582,19 +578,19 @@ def test_booking_patch_api_absence_reason(app, user):
False,
] # not changed
other_booking.refresh_from_db()
assert other_booking.user_absence_reason == '' # not changed
assert other_booking.user_check_type == '' # not changed
# mark the event as checked
event.checked = True
event.save()
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': reason.slug})
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'user_check_type': reason.slug})
assert resp.json['err'] == 0
# now disable check update
agenda.disable_check_update = True
agenda.save()
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': reason.slug}, status=400
'/api/booking/%s/' % booking.pk, params={'user_check_type': reason.slug}, status=400
)
assert resp.json['err'] == 5
assert resp.json['err_desc'] == 'event is marked as checked'

View File

@ -1,205 +0,0 @@
import pytest
from chrono.agendas.models import AbsenceReason, AbsenceReasonGroup, Agenda, Desk
from tests.utils import login
pytestmark = pytest.mark.django_db
@pytest.fixture
def agenda_with_restrictions(manager_user):
agenda = Agenda(label='Foo Bar')
agenda.view_role = manager_user.groups.all()[0]
agenda.save()
return agenda
def test_list_reasons_as_manager(app, manager_user, agenda_with_restrictions):
app = login(app, username='manager', password='manager')
app.get('/manage/absence-reasons/', status=403)
resp = app.get('/manage/')
assert 'Absence reasons' not in resp.text
def test_add_group(app, admin_user):
app = login(app)
resp = app.get('/manage/')
resp = resp.click('Absence reasons')
resp = resp.click('New group')
resp.form['label'] = 'Foo bar'
resp = resp.form.submit()
group = AbsenceReasonGroup.objects.latest('pk')
assert resp.location.endswith('/manage/absence-reasons/')
assert group.label == 'Foo bar'
assert group.slug == 'foo-bar'
def test_add_group_as_manager(app, manager_user, agenda_with_restrictions):
app = login(app, username='manager', password='manager')
app.get('/manage/absence-reason/group/add/', status=403)
def test_edit_group(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
group2 = AbsenceReasonGroup.objects.create(label='baz')
app = login(app)
resp = app.get('/manage/absence-reasons/')
resp = resp.click(href='/manage/absence-reason/group/%s/edit/' % group.pk)
resp.form['label'] = 'Foo bar baz'
resp.form['slug'] = group2.slug
resp = resp.form.submit()
assert resp.context['form'].errors['slug'] == [
'Absence reason group with this Identifier already exists.'
]
resp.form['slug'] = 'baz2'
resp = resp.form.submit()
assert resp.location.endswith('/manage/absence-reasons/')
group.refresh_from_db()
assert group.label == 'Foo bar baz'
assert group.slug == 'baz2'
def test_edit_group_as_manager(app, manager_user, agenda_with_restrictions):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
app = login(app, username='manager', password='manager')
app.get('/manage/absence-reason/group/%s/edit/' % group.pk, status=403)
def test_delete_group(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
AbsenceReason.objects.create(label='Foo reason', group=group)
app = login(app)
resp = app.get('/manage/absence-reasons/')
resp = resp.click(href='/manage/absence-reason/group/%s/delete/' % group.pk)
resp = resp.form.submit()
assert resp.location.endswith('/manage/absence-reasons/')
assert AbsenceReasonGroup.objects.exists() is False
assert AbsenceReason.objects.exists() is False
def test_delete_group_as_manager(app, manager_user, agenda_with_restrictions):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
app = login(app, username='manager', password='manager')
app.get('/manage/absence-reason/group/%s/delete/' % group.pk, status=403)
def test_add_reason(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
app = login(app)
resp = app.get('/manage/')
resp = resp.click('Absence reasons')
resp = resp.click('Add an absence reason')
resp.form['label'] = 'Foo reason'
resp = resp.form.submit()
reason = AbsenceReason.objects.latest('pk')
assert resp.location.endswith('/manage/absence-reasons/')
assert reason.label == 'Foo reason'
assert reason.group == group
assert reason.slug == 'foo-reason'
def test_add_reason_as_manager(app, manager_user, agenda_with_restrictions):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
app = login(app, username='manager', password='manager')
app.get('/manage/absence-reason/group/%s/add/' % group.pk, status=403)
def test_edit_reason(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
reason = AbsenceReason.objects.create(label='Foo reason', group=group)
reason2 = AbsenceReason.objects.create(label='Baz', group=group)
group2 = AbsenceReasonGroup.objects.create(label='Foo bar')
reason3 = AbsenceReason.objects.create(label='Foo bar reason', group=group2)
app = login(app)
resp = app.get('/manage/absence-reasons/')
resp = resp.click(href='/manage/absence-reason/group/%s/%s/edit/' % (group.pk, reason.pk))
resp.form['label'] = 'Foo bar reason'
resp.form['slug'] = reason2.slug
resp = resp.form.submit()
assert resp.context['form'].errors['slug'] == ['Another absence reason exists with the same identifier.']
resp.form['slug'] = reason3.slug
resp = resp.form.submit()
assert resp.location.endswith('/manage/absence-reasons/')
reason.refresh_from_db()
assert reason.label == 'Foo bar reason'
assert reason.slug == 'foo-bar-reason'
app.get('/manage/absence-reason/group/%s/%s/edit/' % (group2.pk, reason.pk), status=404)
def test_edit_reason_as_manager(app, manager_user, agenda_with_restrictions):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
reason = AbsenceReason.objects.create(label='Foo reason', group=group)
app = login(app, username='manager', password='manager')
app.get('/manage/absence-reason/group/%s/%s/edit/' % (group.pk, reason.pk), status=403)
def test_delete_reason(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
reason = AbsenceReason.objects.create(label='Foo reason', group=group)
app = login(app)
resp = app.get('/manage/absence-reasons/')
resp = resp.click(href='/manage/absence-reason/group/%s/%s/delete/' % (group.pk, reason.pk))
resp = resp.form.submit()
assert resp.location.endswith('/manage/absence-reasons/')
assert AbsenceReasonGroup.objects.exists() is True
assert AbsenceReason.objects.exists() is False
group2 = AbsenceReasonGroup.objects.create(label='Foo bar baz')
app.get('/manage/absence-reason/group/%s/%s/delete/' % (group2.pk, reason.pk), status=404)
def test_delete_reason_as_manager(app, manager_user, agenda_with_restrictions):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
reason = AbsenceReason.objects.create(label='Foo reason', group=group)
app = login(app, username='manager', password='manager')
app.get('/manage/absence-reason/group/%s/%s/delete/' % (group.pk, reason.pk), status=403)
def test_meetings_agenda_group(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
AbsenceReasonGroup.objects.create(label='Foo bar')
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert 'has_absence_reasons' not in resp.context
# not for meetings agenda
app.get('/manage/agendas/%s/absence-reasons' % agenda.pk, status=404)
def test_agenda_group(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert 'has_absence_reasons' in resp.context
assert resp.context['has_absence_reasons'] is False
assert 'No absence reasons configured for this agenda.' not in resp
assert '/manage/agendas/%s/absence-reasons' % agenda.pk not in resp
resp = resp.click(href='/manage/agendas/%s/check-options' % agenda.pk)
assert 'absence_reasons_group' not in resp.context['form'].fields
group = AbsenceReasonGroup.objects.create(label='Foo bar')
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert 'has_absence_reasons' in resp.context
assert resp.context['has_absence_reasons'] is True
assert 'No absence reasons configured for this agenda.' in resp
resp = resp.click(href='/manage/agendas/%s/check-options' % agenda.pk)
resp.form['absence_reasons_group'] = group.pk
resp = resp.form.submit().follow()
assert 'Absence reasons group: Foo bar' in resp

View File

@ -0,0 +1,203 @@
import pytest
from chrono.agendas.models import Agenda, CheckType, CheckTypeGroup, Desk
from tests.utils import login
pytestmark = pytest.mark.django_db
@pytest.fixture
def agenda_with_restrictions(manager_user):
agenda = Agenda(label='Foo Bar')
agenda.view_role = manager_user.groups.all()[0]
agenda.save()
return agenda
def test_list_types_as_manager(app, manager_user, agenda_with_restrictions):
app = login(app, username='manager', password='manager')
app.get('/manage/check-types/', status=403)
resp = app.get('/manage/')
assert 'Check types' not in resp.text
def test_add_group(app, admin_user):
app = login(app)
resp = app.get('/manage/')
resp = resp.click('Check types')
resp = resp.click('New group')
resp.form['label'] = 'Foo bar'
resp = resp.form.submit()
group = CheckTypeGroup.objects.latest('pk')
assert resp.location.endswith('/manage/check-types/')
assert group.label == 'Foo bar'
assert group.slug == 'foo-bar'
def test_add_group_as_manager(app, manager_user, agenda_with_restrictions):
app = login(app, username='manager', password='manager')
app.get('/manage/check-type/group/add/', status=403)
def test_edit_group(app, admin_user):
group = CheckTypeGroup.objects.create(label='Foo bar')
group2 = CheckTypeGroup.objects.create(label='baz')
app = login(app)
resp = app.get('/manage/check-types/')
resp = resp.click(href='/manage/check-type/group/%s/edit/' % group.pk)
resp.form['label'] = 'Foo bar baz'
resp.form['slug'] = group2.slug
resp = resp.form.submit()
assert resp.context['form'].errors['slug'] == ['Check type group with this Identifier already exists.']
resp.form['slug'] = 'baz2'
resp = resp.form.submit()
assert resp.location.endswith('/manage/check-types/')
group.refresh_from_db()
assert group.label == 'Foo bar baz'
assert group.slug == 'baz2'
def test_edit_group_as_manager(app, manager_user, agenda_with_restrictions):
group = CheckTypeGroup.objects.create(label='Foo bar')
app = login(app, username='manager', password='manager')
app.get('/manage/check-type/group/%s/edit/' % group.pk, status=403)
def test_delete_group(app, admin_user):
group = CheckTypeGroup.objects.create(label='Foo bar')
CheckType.objects.create(label='Foo reason', group=group)
app = login(app)
resp = app.get('/manage/check-types/')
resp = resp.click(href='/manage/check-type/group/%s/delete/' % group.pk)
resp = resp.form.submit()
assert resp.location.endswith('/manage/check-types/')
assert CheckTypeGroup.objects.exists() is False
assert CheckType.objects.exists() is False
def test_delete_group_as_manager(app, manager_user, agenda_with_restrictions):
group = CheckTypeGroup.objects.create(label='Foo bar')
app = login(app, username='manager', password='manager')
app.get('/manage/check-type/group/%s/delete/' % group.pk, status=403)
def test_add_check_type(app, admin_user):
group = CheckTypeGroup.objects.create(label='Foo bar')
app = login(app)
resp = app.get('/manage/')
resp = resp.click('Check types')
resp = resp.click('Add a check type')
resp.form['label'] = 'Foo reason'
resp = resp.form.submit()
check_type = CheckType.objects.latest('pk')
assert resp.location.endswith('/manage/check-types/')
assert check_type.label == 'Foo reason'
assert check_type.group == group
assert check_type.slug == 'foo-reason'
def test_add_check_type_as_manager(app, manager_user, agenda_with_restrictions):
group = CheckTypeGroup.objects.create(label='Foo bar')
app = login(app, username='manager', password='manager')
app.get('/manage/check-type/group/%s/add/' % group.pk, status=403)
def test_edit_check_type(app, admin_user):
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group)
check_type2 = CheckType.objects.create(label='Baz', group=group)
group2 = CheckTypeGroup.objects.create(label='Foo bar')
check_type3 = CheckType.objects.create(label='Foo bar reason', group=group2)
app = login(app)
resp = app.get('/manage/check-types/')
resp = resp.click(href='/manage/check-type/group/%s/%s/edit/' % (group.pk, check_type.pk))
resp.form['label'] = 'Foo bar reason'
resp.form['slug'] = check_type2.slug
resp = resp.form.submit()
assert resp.context['form'].errors['slug'] == ['Another check type exists with the same identifier.']
resp.form['slug'] = check_type3.slug
resp = resp.form.submit()
assert resp.location.endswith('/manage/check-types/')
check_type.refresh_from_db()
assert check_type.label == 'Foo bar reason'
assert check_type.slug == 'foo-bar-reason'
app.get('/manage/check-type/group/%s/%s/edit/' % (group2.pk, check_type.pk), status=404)
def test_edit_check_type_as_manager(app, manager_user, agenda_with_restrictions):
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group)
app = login(app, username='manager', password='manager')
app.get('/manage/check-type/group/%s/%s/edit/' % (group.pk, check_type.pk), status=403)
def test_delete_check_type(app, admin_user):
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group)
app = login(app)
resp = app.get('/manage/check-types/')
resp = resp.click(href='/manage/check-type/group/%s/%s/delete/' % (group.pk, check_type.pk))
resp = resp.form.submit()
assert resp.location.endswith('/manage/check-types/')
assert CheckTypeGroup.objects.exists() is True
assert CheckType.objects.exists() is False
group2 = CheckTypeGroup.objects.create(label='Foo bar baz')
app.get('/manage/check-type/group/%s/%s/delete/' % (group2.pk, check_type.pk), status=404)
def test_delete_check_type_as_manager(app, manager_user, agenda_with_restrictions):
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group)
app = login(app, username='manager', password='manager')
app.get('/manage/check-type/group/%s/%s/delete/' % (group.pk, check_type.pk), status=403)
def test_meetings_agenda_group(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
CheckTypeGroup.objects.create(label='Foo bar')
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert 'has_check_types' not in resp.context
# not for meetings agenda
app.get('/manage/agendas/%s/check-types' % agenda.pk, status=404)
def test_agenda_group(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert 'has_check_types' in resp.context
assert resp.context['has_check_types'] is False
assert 'No check types configured for this agenda.' not in resp
assert '/manage/agendas/%s/check-types' % agenda.pk not in resp
resp = resp.click(href='/manage/agendas/%s/check-options' % agenda.pk)
assert 'check_type_group' not in resp.context['form'].fields
group = CheckTypeGroup.objects.create(label='Foo bar')
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert 'has_check_types' in resp.context
assert resp.context['has_check_types'] is True
assert 'No check types configured for this agenda.' in resp
resp = resp.click(href='/manage/agendas/%s/check-options' % agenda.pk)
resp.form['check_type_group'] = group.pk
resp = resp.form.submit().follow()
assert 'Check type group: Foo bar' in resp

View File

@ -11,10 +11,10 @@ from django.utils.timezone import localtime, make_aware, now
from webtest import Upload
from chrono.agendas.models import (
AbsenceReason,
AbsenceReasonGroup,
Agenda,
Booking,
CheckType,
CheckTypeGroup,
Desk,
Event,
EventsType,
@ -1620,10 +1620,10 @@ def test_event_checked(app, admin_user):
def test_event_check_filters(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
reason = AbsenceReason.objects.create(label='Foo reason', group=group)
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group)
agenda = Agenda.objects.create(
label='Events', kind='events', booking_check_filters='foo,bar', absence_reasons_group=group
label='Events', kind='events', booking_check_filters='foo,bar', check_type_group=group
)
event = Event.objects.create(
label='xyz',
@ -1671,7 +1671,7 @@ def test_event_check_filters(app, admin_user):
user_last_name='foo-none bar-val2 reason-foo',
extra_data={'bar': 'val2'},
user_was_present=False,
user_absence_reason=reason.label,
user_check_type=check_type.label,
)
Booking.objects.create(
event=event,
@ -1680,7 +1680,7 @@ def test_event_check_filters(app, admin_user):
user_last_name='foo-none bar-val2 cancelled',
extra_data={'bar': 'val2'},
user_was_present=False,
user_absence_reason=reason.label,
user_check_type=check_type.label,
cancellation_datetime=now(),
)
@ -1973,7 +1973,7 @@ def test_event_check_ordering(app, admin_user):
def test_event_check_booking(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
group = CheckTypeGroup.objects.create(label='Foo bar')
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
@ -2006,17 +2006,17 @@ def test_event_check_booking(app, admin_user):
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_absence_reason == ''
assert booking.user_check_type == ''
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_absence_reason == ''
assert secondary_booking.user_check_type == ''
event.refresh_from_db()
assert event.checked is False
agenda.mark_event_checked_auto = True
agenda.save()
# set as absent without reason
# set as absent without check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
@ -2026,34 +2026,34 @@ def test_event_check_booking(app, admin_user):
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_absence_reason == ''
assert booking.user_check_type == ''
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is False
assert secondary_booking.user_absence_reason == ''
assert secondary_booking.user_check_type == ''
event.refresh_from_db()
assert event.checked is True
agenda.absence_reasons_group = group
agenda.check_type_group = group
agenda.save()
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-actions select')) == 0
AbsenceReason.objects.create(label='Foo reason', group=group)
CheckType.objects.create(label='Foo reason', group=group)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-actions select')) == 1
# set as absent with reason
# set as absent with check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'reason': 'Foo reason'},
params={'csrfmiddlewaretoken': token, 'check_type': 'Foo reason'},
).follow()
assert 'Foo reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_absence_reason == 'Foo reason'
assert booking.user_check_type == 'Foo reason'
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is False
assert secondary_booking.user_absence_reason == 'Foo reason'
assert secondary_booking.user_check_type == 'Foo reason'
# set as present
app.post(
@ -2062,10 +2062,10 @@ def test_event_check_booking(app, admin_user):
)
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_absence_reason == ''
assert booking.user_check_type == ''
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_absence_reason == ''
assert secondary_booking.user_check_type == ''
# mark the event as checked
event.checked = True
@ -2103,9 +2103,9 @@ def test_event_check_booking(app, admin_user):
def test_event_check_booking_ajax(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
AbsenceReason.objects.create(label='Foo reason', group=group)
agenda = Agenda.objects.create(label='Events', kind='events', absence_reasons_group=group)
group = CheckTypeGroup.objects.create(label='Foo bar')
CheckType.objects.create(label='Foo reason', group=group)
agenda = Agenda.objects.create(label='Events', kind='events', check_type_group=group)
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
@ -2133,7 +2133,7 @@ def test_event_check_booking_ajax(app, admin_user):
# set as absent
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'reason': 'Foo reason'},
params={'csrfmiddlewaretoken': token, 'check_type': 'Foo reason'},
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
@ -2143,9 +2143,9 @@ def test_event_check_booking_ajax(app, admin_user):
def test_event_check_all_bookings(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
AbsenceReason.objects.create(label='Foo reason', group=group)
agenda = Agenda.objects.create(label='Events', kind='events', absence_reasons_group=group)
group = CheckTypeGroup.objects.create(label='Foo bar')
CheckType.objects.create(label='Foo reason', group=group)
agenda = Agenda.objects.create(label='Events', kind='events', check_type_group=group)
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
@ -2168,7 +2168,7 @@ def test_event_check_all_bookings(app, admin_user):
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_absence_reason == ''
assert booking1.user_check_type == ''
event.refresh_from_db()
assert event.checked is False
@ -2194,13 +2194,13 @@ def test_event_check_all_bookings(app, admin_user):
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_absence_reason == ''
assert booking1.user_check_type == ''
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_absence_reason == ''
assert booking2.user_check_type == ''
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_absence_reason == ''
assert secondary_booking.user_check_type == ''
event.refresh_from_db()
assert event.checked is True
@ -2210,17 +2210,17 @@ def test_event_check_all_bookings(app, admin_user):
assert 'Mark all bookings without status' in resp
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'reason': 'Foo reason'},
params={'csrfmiddlewaretoken': token, 'check_type': 'Foo reason'},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_absence_reason == ''
assert booking1.user_check_type == ''
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_absence_reason == ''
assert booking2.user_check_type == ''
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_absence_reason == 'Foo reason'
assert booking3.user_check_type == 'Foo reason'
# now disable check update
agenda.disable_check_update = True
@ -2230,7 +2230,7 @@ def test_event_check_all_bookings(app, admin_user):
assert 'Mark all bookings without status' not in resp
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'reason': 'Foo reason'},
params={'csrfmiddlewaretoken': token, 'check_type': 'Foo reason'},
status=404,
)
resp = app.post(

View File

@ -8,10 +8,10 @@ from django.utils.timezone import now
from webtest import Upload
from chrono.agendas.models import (
AbsenceReason,
AbsenceReasonGroup,
Agenda,
Booking,
CheckType,
CheckTypeGroup,
Desk,
Event,
MeetingType,
@ -36,7 +36,7 @@ def test_export_site(app, admin_user):
assert site_json == {
'unavailability_calendars': [],
'agendas': [],
'absence_reason_groups': [],
'check_type_groups': [],
'events_types': [],
'resources': [],
'categories': [],
@ -51,14 +51,14 @@ def test_export_site(app, admin_user):
site_json = json.loads(resp.text)
assert len(site_json['agendas']) == 1
assert len(site_json['unavailability_calendars']) == 1
assert len(site_json['absence_reason_groups']) == 0
assert len(site_json['check_type_groups']) == 0
assert len(site_json['events_types']) == 0
assert len(site_json['resources']) == 0
assert len(site_json['categories']) == 0
resp = app.get('/manage/agendas/export/')
resp.form['agendas'] = False
resp.form['absence_reason_groups'] = False
resp.form['check_type_groups'] = False
resp.form['events_types'] = False
resp.form['resources'] = False
resp.form['categories'] = False
@ -67,7 +67,7 @@ def test_export_site(app, admin_user):
site_json = json.loads(resp.text)
assert 'agendas' not in site_json
assert 'unavailability_calendars' in site_json
assert 'absence_reason_groups' not in site_json
assert 'check_type_groups' not in site_json
assert 'events_types' not in site_json
assert 'resources' not in site_json
assert 'categories' not in site_json
@ -294,17 +294,17 @@ def test_import_unavailability_calendar(app, admin_user):
@pytest.mark.freeze_time('2021-07-08')
def test_import_absence_reason_group(app, admin_user):
group = AbsenceReasonGroup.objects.create(label='Foo bar')
AbsenceReason.objects.create(label='Foo reason', group=group)
AbsenceReason.objects.create(label='Baz', group=group)
def test_import_check_type_group(app, admin_user):
group = CheckTypeGroup.objects.create(label='Foo bar')
CheckType.objects.create(label='Foo reason', group=group)
CheckType.objects.create(label='Baz', group=group)
app = login(app)
resp = app.get('/manage/absence-reason/group/%s/export/' % group.id)
resp = app.get('/manage/check-type/group/%s/export/' % group.id)
assert resp.headers['content-type'] == 'application/json'
assert (
resp.headers['content-disposition']
== 'attachment; filename="export_absence_reason_group_foo-bar_20210708.json"'
== 'attachment; filename="export_check_type_group_foo-bar_20210708.json"'
)
group_export = resp.text
@ -313,32 +313,32 @@ def test_import_absence_reason_group(app, admin_user):
resp = resp.click('Import')
resp.form['agendas_json'] = Upload('export.json', group_export.encode('utf-8'), 'application/json')
resp = resp.form.submit()
assert resp.location.endswith('/manage/absence-reasons/')
assert resp.location.endswith('/manage/check-types/')
resp = resp.follow()
assert 'No absence reason group created. An absence reason group has been updated.' not in resp.text
assert AbsenceReasonGroup.objects.count() == 1
assert AbsenceReason.objects.count() == 2
assert 'No check type group created. An check type group has been updated.' not in resp.text
assert CheckTypeGroup.objects.count() == 1
assert CheckType.objects.count() == 2
# new group
AbsenceReasonGroup.objects.all().delete()
CheckTypeGroup.objects.all().delete()
resp = app.get('/manage/', status=200)
resp = resp.click('Import')
resp.form['agendas_json'] = Upload('export.json', group_export.encode('utf-8'), 'application/json')
resp = resp.form.submit()
assert resp.location.endswith('/manage/absence-reasons/')
assert resp.location.endswith('/manage/check-types/')
resp = resp.follow()
assert 'An absence reason group has been created. No absence reason group updated.' not in resp.text
assert AbsenceReasonGroup.objects.count() == 1
assert AbsenceReason.objects.count() == 2
assert 'An check type group has been created. No check type group updated.' not in resp.text
assert CheckTypeGroup.objects.count() == 1
assert CheckType.objects.count() == 2
# multiple groups
groups = json.loads(group_export)
groups['absence_reason_groups'].append(copy.copy(groups['absence_reason_groups'][0]))
groups['absence_reason_groups'].append(copy.copy(groups['absence_reason_groups'][0]))
groups['absence_reason_groups'][1]['label'] = 'Foo bar 2'
groups['absence_reason_groups'][1]['slug'] = 'foo-bar-2'
groups['absence_reason_groups'][2]['label'] = 'Foo bar 3'
groups['absence_reason_groups'][2]['slug'] = 'foo-bar-3'
groups['check_type_groups'].append(copy.copy(groups['check_type_groups'][0]))
groups['check_type_groups'].append(copy.copy(groups['check_type_groups'][0]))
groups['check_type_groups'][1]['label'] = 'Foo bar 2'
groups['check_type_groups'][1]['slug'] = 'foo-bar-2'
groups['check_type_groups'][2]['label'] = 'Foo bar 3'
groups['check_type_groups'][2]['slug'] = 'foo-bar-3'
resp = app.get('/manage/', status=200)
resp = resp.click('Import')
@ -346,15 +346,15 @@ def test_import_absence_reason_group(app, admin_user):
resp = resp.form.submit()
assert resp.location.endswith('/manage/')
resp = resp.follow()
assert '2 absence reason groups have been created. An absence reason group has been updated.' in resp.text
assert AbsenceReasonGroup.objects.count() == 3
assert AbsenceReason.objects.count() == 6
assert '2 check type groups have been created. An check type group has been updated.' in resp.text
assert CheckTypeGroup.objects.count() == 3
assert CheckType.objects.count() == 6
AbsenceReasonGroup.objects.all().delete()
CheckTypeGroup.objects.all().delete()
resp = app.get('/manage/', status=200)
resp = resp.click('Import')
resp.form['agendas_json'] = Upload('export.json', json.dumps(groups).encode('utf-8'), 'application/json')
resp = resp.form.submit().follow()
assert '3 absence reason groups have been created. No absence reason group updated.' in resp.text
assert AbsenceReasonGroup.objects.count() == 3
assert AbsenceReason.objects.count() == 6
assert '3 check type groups have been created. No check type group updated.' in resp.text
assert CheckTypeGroup.objects.count() == 3
assert CheckType.objects.count() == 6

View File

@ -13,12 +13,12 @@ from django.test import override_settings
from django.utils.timezone import localtime, make_aware, now
from chrono.agendas.models import (
AbsenceReasonGroup,
Agenda,
AgendaNotificationsSettings,
AgendaReminderSettings,
Booking,
Category,
CheckTypeGroup,
Desk,
Event,
EventCancellationReport,
@ -187,22 +187,22 @@ def test_category_duplicate_slugs():
assert category.slug == 'foo-baz-2'
def test_absence_reason_group_slug():
group = AbsenceReasonGroup.objects.create(label='Foo bar')
def test_check_type_group_slug():
group = CheckTypeGroup.objects.create(label='Foo bar')
assert group.slug == 'foo-bar'
def test_absence_reason_group_existing_slug():
group = AbsenceReasonGroup.objects.create(label='Foo bar', slug='bar')
def test_check_type_group_existing_slug():
group = CheckTypeGroup.objects.create(label='Foo bar', slug='bar')
assert group.slug == 'bar'
def test_absence_reason_group_duplicate_slugs():
group = AbsenceReasonGroup.objects.create(label='Foo baz')
def test_check_type_group_duplicate_slugs():
group = CheckTypeGroup.objects.create(label='Foo baz')
assert group.slug == 'foo-baz'
group = AbsenceReasonGroup.objects.create(label='Foo baz')
group = CheckTypeGroup.objects.create(label='Foo baz')
assert group.slug == 'foo-baz-1'
group = AbsenceReasonGroup.objects.create(label='Foo baz')
group = CheckTypeGroup.objects.create(label='Foo baz')
assert group.slug == 'foo-baz-2'

View File

@ -16,13 +16,13 @@ from django.utils.encoding import force_bytes
from django.utils.timezone import make_aware, now
from chrono.agendas.models import (
AbsenceReason,
AbsenceReasonGroup,
Agenda,
AgendaImportError,
AgendaNotificationsSettings,
AgendaReminderSettings,
Category,
CheckType,
CheckTypeGroup,
Desk,
Event,
EventsType,
@ -431,31 +431,31 @@ def test_import_export_agenda_with_category(app):
assert agenda.category == category
def test_import_export_agenda_with_absence_reasons(app):
group = AbsenceReasonGroup.objects.create(label='foo')
agenda = Agenda.objects.create(label='Foo Bar', kind='events', absence_reasons_group=group)
def test_import_export_agenda_with_check_types(app):
group = CheckTypeGroup.objects.create(label='foo')
agenda = Agenda.objects.create(label='Foo Bar', kind='events', check_type_group=group)
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
output = get_output_of_command('export_site')
import_site(data={}, clean=True)
assert Agenda.objects.count() == 0
assert AbsenceReasonGroup.objects.count() == 0
assert CheckTypeGroup.objects.count() == 0
data = json.loads(output)
del data['absence_reason_groups']
del data['check_type_groups']
with pytest.raises(AgendaImportError) as excinfo:
import_site(data, overwrite=True)
assert str(excinfo.value) == 'Missing "foo" absence reasons group'
assert str(excinfo.value) == 'Missing "foo" check type group'
AbsenceReasonGroup.objects.create(label='foobar')
CheckTypeGroup.objects.create(label='foobar')
with pytest.raises(AgendaImportError) as excinfo:
import_site(data, overwrite=True)
assert str(excinfo.value) == 'Missing "foo" absence reasons group'
assert str(excinfo.value) == 'Missing "foo" check type group'
group = AbsenceReasonGroup.objects.create(label='foo')
group = CheckTypeGroup.objects.create(label='foo')
import_site(data, overwrite=True)
agenda = Agenda.objects.get(slug=agenda.slug)
assert agenda.absence_reasons_group == group
assert agenda.check_type_group == group
def test_import_export_agenda_with_events_type(app):
@ -932,35 +932,35 @@ def test_import_export_unavailability_calendar(app):
assert calendar.label == 'Calendar Updated'
def test_import_export_absence_reason_group(app):
def test_import_export_check_type_group(app):
output = get_output_of_command('export_site')
payload = json.loads(output)
assert len(payload['absence_reason_groups']) == 0
assert len(payload['check_type_groups']) == 0
group = AbsenceReasonGroup.objects.create(label='Foo bar')
AbsenceReason.objects.create(label='Foo reason', group=group)
AbsenceReason.objects.create(label='Baz', group=group)
group = CheckTypeGroup.objects.create(label='Foo bar')
CheckType.objects.create(label='Foo reason', group=group)
CheckType.objects.create(label='Baz', group=group)
output = get_output_of_command('export_site')
payload = json.loads(output)
assert len(payload['absence_reason_groups']) == 1
assert len(payload['check_type_groups']) == 1
group.delete()
assert not AbsenceReasonGroup.objects.exists()
assert not AbsenceReason.objects.exists()
assert not CheckTypeGroup.objects.exists()
assert not CheckType.objects.exists()
import_site(copy.deepcopy(payload))
assert AbsenceReasonGroup.objects.count() == 1
group = AbsenceReasonGroup.objects.first()
assert CheckTypeGroup.objects.count() == 1
group = CheckTypeGroup.objects.first()
assert group.label == 'Foo bar'
assert group.slug == 'foo-bar'
assert group.absence_reasons.count() == 2
assert AbsenceReason.objects.get(group=group, label='Foo reason', slug='foo-reason')
assert AbsenceReason.objects.get(group=group, label='Baz', slug='baz')
assert group.check_types.count() == 2
assert CheckType.objects.get(group=group, label='Foo reason', slug='foo-reason')
assert CheckType.objects.get(group=group, label='Baz', slug='baz')
# update
update_payload = copy.deepcopy(payload)
update_payload['absence_reason_groups'][0]['label'] = 'Foo bar Updated'
update_payload['check_type_groups'][0]['label'] = 'Foo bar Updated'
import_site(update_payload)
group.refresh_from_db()
assert group.label == 'Foo bar Updated'
@ -969,24 +969,24 @@ def test_import_export_absence_reason_group(app):
group.slug = 'foo-bar-updated'
group.save()
import_site(copy.deepcopy(payload))
assert AbsenceReasonGroup.objects.count() == 2
group = AbsenceReasonGroup.objects.latest('pk')
assert CheckTypeGroup.objects.count() == 2
group = CheckTypeGroup.objects.latest('pk')
assert group.label == 'Foo bar'
assert group.slug == 'foo-bar'
assert group.absence_reasons.count() == 2
assert AbsenceReason.objects.get(group=group, label='Foo reason', slug='foo-reason')
assert AbsenceReason.objects.get(group=group, label='Baz', slug='baz')
assert group.check_types.count() == 2
assert CheckType.objects.get(group=group, label='Foo reason', slug='foo-reason')
assert CheckType.objects.get(group=group, label='Baz', slug='baz')
# with overwrite
AbsenceReason.objects.create(group=group, label='Baz2')
CheckType.objects.create(group=group, label='Baz2')
import_site(copy.deepcopy(payload), overwrite=True)
assert AbsenceReasonGroup.objects.count() == 2
group = AbsenceReasonGroup.objects.latest('pk')
assert CheckTypeGroup.objects.count() == 2
group = CheckTypeGroup.objects.latest('pk')
assert group.label == 'Foo bar'
assert group.slug == 'foo-bar'
assert group.absence_reasons.count() == 2
assert AbsenceReason.objects.get(group=group, label='Foo reason', slug='foo-reason')
assert AbsenceReason.objects.get(group=group, label='Baz', slug='baz')
assert group.check_types.count() == 2
assert CheckType.objects.get(group=group, label='Foo reason', slug='foo-reason')
assert CheckType.objects.get(group=group, label='Baz', slug='baz')
def test_import_export_category(app):