Compare commits
11 Commits
f6792b339f
...
f7c87dd0c9
Author | SHA1 | Date |
---|---|---|
Valentin Deniaud | f7c87dd0c9 | |
Frédéric Péters | 031961ad80 | |
Lauréline Guérin | 5b8419efe5 | |
Lauréline Guérin | cff4ce0861 | |
Lauréline Guérin | 737ba6f0bb | |
Lauréline Guérin | 72be0166f3 | |
Lauréline Guérin | dae40958f4 | |
Lauréline Guérin | 05703dddb1 | |
Frédéric Péters | 78928bc760 | |
Thomas NOËL | a548753f2a | |
Emmanuel Cazenave | 8a7f83a02d |
|
@ -2182,28 +2182,44 @@ class Event(models.Model):
|
|||
self.notify_checked()
|
||||
|
||||
def notify_checked(self):
|
||||
for booking in self.booking_set.filter(user_checks__isnull=False).prefetch_related('user_checks'):
|
||||
if booking.user_check.presence is True and booking.presence_callback_url:
|
||||
url = booking.presence_callback_url
|
||||
elif booking.user_check.presence is False and booking.absence_callback_url:
|
||||
url = booking.absence_callback_url
|
||||
partial_bookings = self.agenda.partial_bookings
|
||||
for user_check in BookingCheck.objects.filter(booking__event=self).select_related('booking'):
|
||||
if user_check.presence is True and user_check.booking.presence_callback_url:
|
||||
url = user_check.booking.presence_callback_url
|
||||
elif user_check.presence is False and user_check.booking.absence_callback_url:
|
||||
url = user_check.booking.absence_callback_url
|
||||
else:
|
||||
continue
|
||||
payload = {
|
||||
'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,
|
||||
'user_was_present': user_check.presence,
|
||||
'user_check_type_slug': user_check.type_slug,
|
||||
'user_check_type_label': user_check.type_label,
|
||||
}
|
||||
if partial_bookings:
|
||||
payload.update(
|
||||
{
|
||||
'start_time': user_check.start_time.isoformat() if user_check.start_time else None,
|
||||
'end_time': user_check.end_time.isoformat() if user_check.end_time else None,
|
||||
'computed_start_time': user_check.computed_start_time.isoformat()
|
||||
if user_check.computed_start_time
|
||||
else None,
|
||||
'computed_end_time': user_check.computed_end_time.isoformat()
|
||||
if user_check.computed_end_time
|
||||
else None,
|
||||
}
|
||||
)
|
||||
try:
|
||||
response = requests_wrapper.post(url, json=payload, remote_service='auto', timeout=15)
|
||||
if response and not response.ok:
|
||||
logging.error(
|
||||
'error (HTTP %s) notifying checked booking (%s)', response.status_code, booking.id
|
||||
'error (HTTP %s) notifying checked booking (%s)',
|
||||
response.status_code,
|
||||
user_check.booking_id,
|
||||
)
|
||||
except requests.Timeout:
|
||||
logging.error('error (timeout) notifying checked booking (%s)', booking.id)
|
||||
logging.error('error (timeout) notifying checked booking (%s)', user_check.booking_id)
|
||||
except Exception as e: # noqa pylint: disable=broad-except
|
||||
logging.error('error (%s) notifying checked booking (%s)', e, booking.id)
|
||||
logging.error('error (%s) notifying checked booking (%s)', e, user_check.booking_id)
|
||||
|
||||
def async_refresh_booking_computed_times(self):
|
||||
if self.agenda.kind != 'events' or not self.agenda.partial_bookings:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import collections
|
||||
import datetime
|
||||
import re
|
||||
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db import models, transaction
|
||||
|
@ -42,6 +43,15 @@ class StringOrListField(serializers.ListField):
|
|||
return super().to_internal_value(data)
|
||||
|
||||
|
||||
class PhoneNumbersStringOrListField(serializers.ListField):
|
||||
def to_internal_value(self, data):
|
||||
if isinstance(data, str):
|
||||
data = [s.strip() for s in data.split(',') if s.strip()]
|
||||
# strip white spaces and dots
|
||||
data = [re.sub(r'[\s\.]', '', x) for x in data]
|
||||
return super().to_internal_value(data)
|
||||
|
||||
|
||||
class CommaSeparatedStringField(serializers.ListField):
|
||||
def get_value(self, dictionary):
|
||||
return super(serializers.ListField, self).get_value(dictionary)
|
||||
|
@ -91,7 +101,7 @@ class FillSlotSerializer(serializers.Serializer):
|
|||
extra_emails = StringOrListField(
|
||||
required=False, child=serializers.EmailField(max_length=250, allow_blank=False)
|
||||
)
|
||||
extra_phone_numbers = StringOrListField(
|
||||
extra_phone_numbers = PhoneNumbersStringOrListField(
|
||||
required=False, child=serializers.CharField(max_length=16, allow_blank=False)
|
||||
)
|
||||
check_overlaps = serializers.BooleanField(default=False)
|
||||
|
|
|
@ -7,8 +7,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: chrono 0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-09 10:54+0200\n"
|
||||
"PO-Revision-Date: 2023-10-09 10:58+0200\n"
|
||||
"POT-Creation-Date: 2023-11-02 13:47+0000\n"
|
||||
"PO-Revision-Date: 2023-11-02 14:47+0100\n"
|
||||
"Last-Translator: Frederic Peters <fpeters@entrouvert.com>\n"
|
||||
"Language: French\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
@ -291,6 +291,17 @@ msgstr "À la minute"
|
|||
msgid "Tolerance"
|
||||
msgstr "Tolérance"
|
||||
|
||||
#: agendas/models.py api/views.py apps/ants_hub/models.py
|
||||
msgid "Agenda"
|
||||
msgstr "Agenda"
|
||||
|
||||
#: agendas/models.py apps/ants_hub/templates/chrono/manager_ants_hub_place.html
|
||||
#: manager/forms.py manager/templates/chrono/manager_base.html
|
||||
#: manager/templates/chrono/manager_home.html
|
||||
#: manager/templates/chrono/manager_no_access.html manager/views.py
|
||||
msgid "Agendas"
|
||||
msgstr "Agendas"
|
||||
|
||||
#: agendas/models.py manager/forms.py
|
||||
msgid "Partial bookings"
|
||||
msgstr "Plages libres"
|
||||
|
@ -519,6 +530,12 @@ msgstr "%(Every_x_days)s, à partir du %(date)s"
|
|||
msgid "%(Every_x_days)s, until %(date)s"
|
||||
msgstr "%(Every_x_days)s, jusqu’au %(date)s"
|
||||
|
||||
#: agendas/models.py manager/forms.py
|
||||
#: manager/templates/chrono/manager_events_type_list.html
|
||||
#: manager/templates/chrono/manager_home.html
|
||||
msgid "Events types"
|
||||
msgstr "Types d’évènements"
|
||||
|
||||
#: agendas/models.py
|
||||
msgid "Label displayed to user"
|
||||
msgstr "Libellé affiché à l’usager"
|
||||
|
@ -541,6 +558,25 @@ msgstr "Le calendrier d’indisponibilités « %s » n’existe pas."
|
|||
msgid "Optional description."
|
||||
msgstr "Description optionnelle."
|
||||
|
||||
#: agendas/models.py manager/forms.py
|
||||
msgid "Resource"
|
||||
msgstr "Ressource"
|
||||
|
||||
#: agendas/models.py manager/forms.py
|
||||
#: manager/templates/chrono/manager_home.html
|
||||
#: manager/templates/chrono/manager_meetings_agenda_settings.html
|
||||
#: manager/templates/chrono/manager_resource_list.html
|
||||
msgid "Resources"
|
||||
msgstr "Ressources"
|
||||
|
||||
#: agendas/models.py
|
||||
msgid "Category (agendas)"
|
||||
msgstr "Catégorie (agendas)"
|
||||
|
||||
#: agendas/models.py
|
||||
msgid "Categories (agendas)"
|
||||
msgstr "Catégories (agendas)"
|
||||
|
||||
#: agendas/models.py
|
||||
#, python-format
|
||||
msgid ""
|
||||
|
@ -572,6 +608,15 @@ msgstr "L’évènement « %s » n’a pas de date de début."
|
|||
msgid "Exception"
|
||||
msgstr "Exception"
|
||||
|
||||
#: agendas/models.py
|
||||
msgid "Unavailability calendar"
|
||||
msgstr "Calendrier d’indisponibilités"
|
||||
|
||||
#: agendas/models.py manager/forms.py
|
||||
#: manager/templates/chrono/manager_home.html
|
||||
msgid "Unavailability calendars"
|
||||
msgstr "Calendrier d’indisponibilités"
|
||||
|
||||
#: agendas/models.py
|
||||
msgid "Optional Label"
|
||||
msgstr "Libellé optionnel"
|
||||
|
@ -1402,10 +1447,6 @@ msgstr "Nombre de réservations"
|
|||
msgid "Interval"
|
||||
msgstr "Intervalle"
|
||||
|
||||
#: api/views.py apps/ants_hub/models.py
|
||||
msgid "Agenda"
|
||||
msgstr "Agenda"
|
||||
|
||||
#: api/views.py manager/forms.py
|
||||
msgctxt "agendas"
|
||||
msgid "All"
|
||||
|
@ -1743,13 +1784,6 @@ msgstr "Géolocalisation :"
|
|||
msgid "URLs"
|
||||
msgstr "URLs"
|
||||
|
||||
#: apps/ants_hub/templates/chrono/manager_ants_hub_place.html manager/forms.py
|
||||
#: manager/templates/chrono/manager_base.html
|
||||
#: manager/templates/chrono/manager_home.html
|
||||
#: manager/templates/chrono/manager_no_access.html manager/views.py
|
||||
msgid "Agendas"
|
||||
msgstr "Agendas"
|
||||
|
||||
#: apps/ants_hub/templates/chrono/manager_ants_hub_place.html
|
||||
msgid "Add"
|
||||
msgstr "Ajouter"
|
||||
|
@ -2051,10 +2085,6 @@ msgstr "La date de fin doit venir après la date de début."
|
|||
msgid "Please select an interval of no more than 3 months."
|
||||
msgstr "Veuillez choisir un intervalle d’au plus 3 mois."
|
||||
|
||||
#: manager/forms.py
|
||||
msgid "Resource"
|
||||
msgstr "Ressource"
|
||||
|
||||
#: manager/forms.py
|
||||
msgid ""
|
||||
"Can't add a meetingtype to an agenda that is included in a virtual agenda."
|
||||
|
@ -2252,26 +2282,11 @@ msgstr ""
|
|||
"Le rappel sera envoyé vers ce numéro, à la place de celui lié à la "
|
||||
"réservation."
|
||||
|
||||
#: manager/forms.py manager/templates/chrono/manager_home.html
|
||||
#: manager/templates/chrono/manager_meetings_agenda_settings.html
|
||||
#: manager/templates/chrono/manager_resource_list.html
|
||||
msgid "Resources"
|
||||
msgstr "Ressources"
|
||||
|
||||
#: manager/forms.py manager/templates/chrono/manager_home.html
|
||||
msgid "Unavailability calendars"
|
||||
msgstr "Calendrier d’indisponibilités"
|
||||
|
||||
#: manager/forms.py manager/templates/chrono/manager_category_list.html
|
||||
#: manager/templates/chrono/manager_home.html
|
||||
msgid "Categories"
|
||||
msgstr "Catégories"
|
||||
|
||||
#: manager/forms.py manager/templates/chrono/manager_events_type_list.html
|
||||
#: manager/templates/chrono/manager_home.html
|
||||
msgid "Events types"
|
||||
msgstr "Types d’évènements"
|
||||
|
||||
#: manager/forms.py manager/templates/chrono/manager_home.html
|
||||
msgid "Shared custody"
|
||||
msgstr "Garde partagée"
|
||||
|
@ -2838,6 +2853,17 @@ msgstr "Pointage"
|
|||
msgid "Bookings (%(booked_places)s/%(places)s)"
|
||||
msgstr "Réservations (%(booked_places)s/%(places)s)"
|
||||
|
||||
#: manager/templates/chrono/manager_event_check.html
|
||||
#: manager/templates/chrono/manager_partial_bookings_day_view.html
|
||||
msgid "Filtering options"
|
||||
msgstr "Paramètres de filtrage"
|
||||
|
||||
#: manager/templates/chrono/manager_event_check.html
|
||||
#: manager/templates/chrono/manager_partial_bookings_day_view.html
|
||||
msgctxt "form filtering action"
|
||||
msgid "Apply"
|
||||
msgstr "Appliquer"
|
||||
|
||||
#: manager/templates/chrono/manager_event_check.html
|
||||
#: manager/templates/chrono/manager_partial_bookings_day_view.html
|
||||
msgid "Mark the event as checked"
|
||||
|
@ -3335,6 +3361,10 @@ msgstr "Période réservée"
|
|||
msgid "Booked period:"
|
||||
msgstr "Période réservée :"
|
||||
|
||||
#: manager/templates/chrono/manager_partial_bookings_day_view.html
|
||||
msgid "Checked period"
|
||||
msgstr "Période pointée"
|
||||
|
||||
#: manager/templates/chrono/manager_partial_bookings_day_view.html
|
||||
msgid "Checked period:"
|
||||
msgstr "Période pointée :"
|
||||
|
|
|
@ -15,71 +15,71 @@
|
|||
</h3>
|
||||
<div>
|
||||
<form class="check-bookings-filters">
|
||||
{{ filterset.form.as_p }}
|
||||
<script>
|
||||
$(function() {
|
||||
$('form.check-bookings-filters input').on('change',
|
||||
function() {
|
||||
$(this).parents('form').submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<fieldset class="gadjo-foldable gadjo-folded" id="filters">
|
||||
<legend class="gadjo-foldable-widget">{% trans "Filtering options" %}</legend>
|
||||
<div class="gadjo-folding">
|
||||
{{ filterset.form.as_p }}
|
||||
<button class="submit-button">{% trans "Apply" context 'form filtering action' %}</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<table class="main check-bookings">
|
||||
<tbody>
|
||||
{% if results and not event.checked and not event.check_locked %}
|
||||
<tr class="booking">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<table class="main check-bookings">
|
||||
<tbody>
|
||||
{% if results and not event.checked and not event.check_locked %}
|
||||
<tr class="booking">
|
||||
<td class="booking-actions" colspan="3">
|
||||
<form method="post" action="{% url 'chrono-manager-event-checked' pk=agenda.pk event_pk=object.pk %}">
|
||||
{% csrf_token %}
|
||||
<button class="submit-button">{% trans "Mark the event as checked" %}</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if booked_without_status %}
|
||||
{% if not event.checked or not agenda.disable_check_update %}
|
||||
<tr class="booking all-bookings">
|
||||
<td colspan="2"><b>{% trans "Mark all bookings without status:" %}</b></td>
|
||||
<td class="booking-actions">
|
||||
<form method="post" action="{% url 'chrono-manager-event-checked' pk=agenda.pk event_pk=object.pk %}">
|
||||
<form method="post" action="{% url 'chrono-manager-event-presence' pk=agenda.pk event_pk=object.pk %}" id="all-bookings-presence">
|
||||
{% csrf_token %}
|
||||
<button class="submit-button">{% trans "Mark the event as checked" %}</button>
|
||||
<button class="submit-button">{% trans "Presence" %}</button>
|
||||
{% if presence_form.check_type.field.choices.1 %}{{ presence_form.check_type }}{% endif %}
|
||||
<script>
|
||||
$(function() {
|
||||
$('#all-bookings-presence select').on('change',
|
||||
function() {
|
||||
$('#all-bookings-presence').submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</form>
|
||||
<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.check_type.field.choices.1 %}{{ absence_form.check_type }}{% endif %}
|
||||
<script>
|
||||
$(function() {
|
||||
$('#all-bookings-absence select').on('change',
|
||||
function() {
|
||||
$('#all-bookings-absence').submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if booked_without_status %}
|
||||
{% if not event.checked or not agenda.disable_check_update %}
|
||||
<tr class="booking all-bookings">
|
||||
<td colspan="2"><b>{% trans "Mark all bookings without status:" %}</b></td>
|
||||
<td class="booking-actions">
|
||||
<form method="post" action="{% url 'chrono-manager-event-presence' pk=agenda.pk event_pk=object.pk %}" id="all-bookings-presence">
|
||||
{% csrf_token %}
|
||||
<button class="submit-button">{% trans "Presence" %}</button>
|
||||
{% if presence_form.check_type.field.choices.1 %}{{ presence_form.check_type }}{% endif %}
|
||||
<script>
|
||||
$(function() {
|
||||
$('#all-bookings-presence select').on('change',
|
||||
function() {
|
||||
$('#all-bookings-presence').submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</form>
|
||||
<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.check_type.field.choices.1 %}{{ absence_form.check_type }}{% endif %}
|
||||
<script>
|
||||
$(function() {
|
||||
$('#all-bookings-absence select').on('change',
|
||||
function() {
|
||||
$('#all-bookings-absence').submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% for result in results %}
|
||||
<tr class="booking {% if agenda.booking_extra_user_block_template %}untoggled{% endif %}">
|
||||
{% include "chrono/manager_event_check_booking_fragment.html" with booking=result %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for result in results %}
|
||||
<tr class="booking {% if agenda.booking_extra_user_block_template %}untoggled{% endif %}">
|
||||
{% include "chrono/manager_event_check_booking_fragment.html" with booking=result %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if object.waiting_list_places %}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block page-title-extra-label %}
|
||||
- {% firstof agenda.label event.label %}
|
||||
{% firstof agenda.label event.label %}
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
|
|
|
@ -19,23 +19,29 @@
|
|||
<p>{% trans "No opening hours this day." %}</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<form class="check-bookings-filters">
|
||||
{{ filterset.form.as_p }}
|
||||
<script>
|
||||
$(function() {
|
||||
$('form.check-bookings-filters input').on('change',
|
||||
function() {
|
||||
$(this).parents('form').submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</form>
|
||||
<div class="section">
|
||||
<div>
|
||||
<form class="check-bookings-filters">
|
||||
<fieldset class="gadjo-foldable gadjo-folded" id="filters">
|
||||
<legend class="gadjo-foldable-widget">{% trans "Filtering options" %}</legend>
|
||||
<div class="gadjo-folding">
|
||||
{{ filterset.form.as_p }}
|
||||
<button class="submit-button">{% trans "Apply" context 'form filtering action' %}</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if results and not event.checked and not event.check_locked %}
|
||||
<form method="post" action="{% url 'chrono-manager-event-checked' pk=agenda.pk event_pk=event.pk %}">
|
||||
{% csrf_token %}
|
||||
<button class="submit-button">{% trans "Mark the event as checked" %}</button>
|
||||
</form>
|
||||
<div class="section">
|
||||
<div>
|
||||
<form method="post" action="{% url 'chrono-manager-event-checked' pk=agenda.pk event_pk=event.pk %}">
|
||||
{% csrf_token %}
|
||||
<button class="submit-button">{% trans "Mark the event as checked" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="partial-booking" style="--nb-hours: {{ hours|length }}">
|
||||
|
|
|
@ -4,6 +4,7 @@ After=network.target postgresql.service
|
|||
Wants=postgresql.service
|
||||
|
||||
[Service]
|
||||
SyslogIdentifier=uwsgi/%p
|
||||
Environment=CHRONO_SETTINGS_FILE=/usr/lib/%p/debian_config.py
|
||||
Environment=LANG=C.UTF-8
|
||||
User=%p
|
||||
|
|
|
@ -79,7 +79,7 @@ def test_booking_api(app, user):
|
|||
'user_phone_number': '+33 (0) 6 12 34 56 78', # long phone number
|
||||
'form_url': 'http://example.net/',
|
||||
'extra_emails': ['baz@baz.com', 'hop@hop.com'],
|
||||
'extra_phone_numbers': ['+33123456789', '+33123456789'],
|
||||
'extra_phone_numbers': ['+33123456789', '+33 1 23 45 67 89'],
|
||||
'presence_callback_url': 'http://example.net/jump/trigger2/',
|
||||
'absence_callback_url': 'http://example.net/jump/trigger3/',
|
||||
},
|
||||
|
@ -292,7 +292,7 @@ def test_booking_api_extra_emails(app, user):
|
|||
fillslot_url,
|
||||
params={
|
||||
'extra_emails': 'bar.com',
|
||||
'extra_phone_numbers': 'too loooooooooong',
|
||||
'extra_phone_numbers': 'too loooooooooooong',
|
||||
},
|
||||
status=400,
|
||||
)
|
||||
|
|
|
@ -1431,10 +1431,8 @@ def test_event_cancellation_forbidden(app, admin_user):
|
|||
def test_event_booking_form_url(settings, app, admin_user):
|
||||
settings.TEMPLATE_VARS = {'eservices_url': 'http://demarches/'}
|
||||
agenda = Agenda.objects.create(label='Events', kind='events')
|
||||
event = Event.objects.create(
|
||||
label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda
|
||||
)
|
||||
day = localtime(event.start_datetime)
|
||||
day = localtime(now()) + datetime.timedelta(days=1)
|
||||
event = Event.objects.create(label='xyz', start_datetime=day, places=10, agenda=agenda)
|
||||
|
||||
login(app)
|
||||
|
||||
|
@ -1522,7 +1520,7 @@ def test_event_check(app, admin_user):
|
|||
Desk.objects.create(agenda=agenda2, slug='_exceptions_holder')
|
||||
event = Event.objects.create(
|
||||
label='xyz',
|
||||
start_datetime=now() + datetime.timedelta(days=1),
|
||||
start_datetime=localtime(now()) + datetime.timedelta(days=1),
|
||||
places=10,
|
||||
waiting_list_places=5,
|
||||
agenda=agenda,
|
||||
|
@ -1617,48 +1615,48 @@ def test_event_check(app, admin_user):
|
|||
user_external_id='user:1',
|
||||
user_first_name='Subscription',
|
||||
user_last_name='42',
|
||||
date_start=now(),
|
||||
date_end=now() + datetime.timedelta(days=1),
|
||||
date_start=datetime.date.today(),
|
||||
date_end=datetime.date.today() + datetime.timedelta(days=1),
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='user:9',
|
||||
user_first_name='Subscription',
|
||||
user_last_name='43',
|
||||
date_start=now(),
|
||||
date_end=now() + datetime.timedelta(days=1),
|
||||
date_start=datetime.date.today(),
|
||||
date_end=datetime.date.today() + datetime.timedelta(days=1),
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='user:10',
|
||||
user_first_name='Subscription',
|
||||
user_last_name='14',
|
||||
date_start=now(),
|
||||
date_end=now() + datetime.timedelta(days=1),
|
||||
date_start=datetime.date.today(),
|
||||
date_end=datetime.date.today() + datetime.timedelta(days=1),
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='user:7',
|
||||
user_first_name='Subscription',
|
||||
user_last_name='Waiting',
|
||||
date_start=now(),
|
||||
date_end=now() + datetime.timedelta(days=1),
|
||||
date_start=datetime.date.today(),
|
||||
date_end=datetime.date.today() + datetime.timedelta(days=1),
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='user:42',
|
||||
user_first_name='Subscription',
|
||||
user_last_name='Too soon',
|
||||
date_start=now() - datetime.timedelta(days=1),
|
||||
date_end=now(),
|
||||
date_start=datetime.date.today() - datetime.timedelta(days=1),
|
||||
date_end=datetime.date.today(),
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='user:42',
|
||||
user_first_name='Subscription',
|
||||
user_last_name='Too late',
|
||||
date_start=now() + datetime.timedelta(days=1),
|
||||
date_end=now() + datetime.timedelta(days=2),
|
||||
date_start=datetime.date.today() + datetime.timedelta(days=1),
|
||||
date_end=datetime.date.today() + datetime.timedelta(days=2),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
|
||||
assert (
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import datetime
|
||||
import json
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from chrono.agendas.models import Agenda, Booking, Event, Subscription
|
||||
from chrono.agendas.models import Agenda, Booking, BookingCheck, Event, Subscription
|
||||
from chrono.utils.lingo import CheckType
|
||||
from chrono.utils.timezone import make_aware, now
|
||||
from tests.utils import login
|
||||
|
@ -760,8 +761,18 @@ def test_manager_partial_bookings_event_checked(app, admin_user):
|
|||
event=event,
|
||||
start_time=datetime.time(8, 00),
|
||||
end_time=datetime.time(10, 00),
|
||||
presence_callback_url='https://example.invalid/presence/%s' % i,
|
||||
absence_callback_url='https://example.invalid/absence/%s' % i,
|
||||
)
|
||||
if i < 3:
|
||||
if i == 0:
|
||||
booking.mark_user_presence(start_time=datetime.time(8, 00), end_time=datetime.time(9, 00))
|
||||
BookingCheck.objects.create(
|
||||
booking=booking,
|
||||
start_time=datetime.time(9, 00),
|
||||
end_time=datetime.time(10, 00),
|
||||
presence=False,
|
||||
)
|
||||
elif 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))
|
||||
|
@ -776,10 +787,13 @@ def test_manager_partial_bookings_event_checked(app, admin_user):
|
|||
assert 'invoiced' not in resp
|
||||
|
||||
token = resp.context['csrf_token']
|
||||
resp = app.post(
|
||||
'/manage/agendas/%s/events/%s/checked' % (agenda.pk, event.pk),
|
||||
params={'csrfmiddlewaretoken': token},
|
||||
)
|
||||
with mock.patch('chrono.utils.requests_wrapper.RequestsSession.send') as mock_send:
|
||||
mock_response = mock.Mock(status_code=200)
|
||||
mock_send.return_value = mock_response
|
||||
resp = app.post(
|
||||
'/manage/agendas/%s/events/%s/checked' % (agenda.pk, event.pk),
|
||||
params={'csrfmiddlewaretoken': token},
|
||||
)
|
||||
event.refresh_from_db()
|
||||
assert event.checked is True
|
||||
resp = resp.follow()
|
||||
|
@ -792,6 +806,25 @@ def test_manager_partial_bookings_event_checked(app, admin_user):
|
|||
assert '<span class="checked tag">Checked</span>' in resp
|
||||
assert 'check-locked' not in resp
|
||||
assert 'invoiced' not in resp
|
||||
assert {x[0][0].url for x in mock_send.call_args_list} == {
|
||||
'https://example.invalid/presence/0',
|
||||
'https://example.invalid/presence/1',
|
||||
'https://example.invalid/presence/2',
|
||||
'https://example.invalid/absence/0',
|
||||
'https://example.invalid/absence/3',
|
||||
'https://example.invalid/absence/4',
|
||||
'https://example.invalid/absence/5',
|
||||
'https://example.invalid/absence/6',
|
||||
}
|
||||
assert set(json.loads(mock_send.call_args_list[0][0][0].body).keys()) == {
|
||||
'user_check_type_label',
|
||||
'user_check_type_slug',
|
||||
'user_was_present',
|
||||
'start_time',
|
||||
'end_time',
|
||||
'computed_start_time',
|
||||
'computed_end_time',
|
||||
}
|
||||
|
||||
# event not in past
|
||||
agenda.disable_check_update = False
|
||||
|
|
Loading…
Reference in New Issue