manager: display link to booking form on events (#45417)
This commit is contained in:
parent
66b71a6d84
commit
0a7bdd9882
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import chrono.agendas.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0063_auto_20200928_1445'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='agenda',
|
||||
name='booking_form_url',
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
max_length=200,
|
||||
validators=[chrono.agendas.models.django_template_validator],
|
||||
verbose_name='Booking form URL',
|
||||
),
|
||||
),
|
||||
]
|
|
@ -35,6 +35,7 @@ from django.core.exceptions import ValidationError
|
|||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models, transaction
|
||||
from django.db.models import Count, Q, Case, When
|
||||
from django.template import engines, Context, Template, TemplateSyntaxError, VariableDoesNotExist
|
||||
from django.urls import reverse
|
||||
from django.utils import functional
|
||||
from django.utils.dates import WEEKDAYS
|
||||
|
@ -115,6 +116,13 @@ def validate_not_digit(value):
|
|||
raise ValidationError(_('This value cannot be a number.'))
|
||||
|
||||
|
||||
def django_template_validator(value):
|
||||
try:
|
||||
engines['django'].from_string(value)
|
||||
except TemplateSyntaxError as e:
|
||||
raise ValidationError(_('syntax error: %s') % e)
|
||||
|
||||
|
||||
class ICSError(Exception):
|
||||
pass
|
||||
|
||||
|
@ -179,6 +187,9 @@ class Agenda(models.Model):
|
|||
'Category', verbose_name=_('Category'), blank=True, null=True, on_delete=models.SET_NULL
|
||||
)
|
||||
default_view = models.CharField(_('Default view'), max_length=20, choices=AGENDA_VIEWS, default='month')
|
||||
booking_form_url = models.CharField(
|
||||
_('Booking form URL'), max_length=200, blank=True, validators=[django_template_validator]
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['label']
|
||||
|
@ -297,6 +308,8 @@ class Agenda(models.Model):
|
|||
if hasattr(self, 'reminder_settings'):
|
||||
agenda['reminder_settings'] = self.reminder_settings.export_json()
|
||||
if self.kind == 'events':
|
||||
agenda['default_view'] = self.default_view
|
||||
agenda['booking_form_url'] = self.booking_form_url
|
||||
agenda['events'] = [x.export_json() for x in self.event_set.all()]
|
||||
if hasattr(self, 'notifications_settings'):
|
||||
agenda['notifications_settings'] = self.notifications_settings.export_json()
|
||||
|
@ -502,6 +515,15 @@ class Agenda(models.Model):
|
|||
entries = entries.filter(start_datetime__lt=max_start)
|
||||
return entries
|
||||
|
||||
def get_booking_form_url(self):
|
||||
if not self.booking_form_url:
|
||||
return
|
||||
template_vars = Context(settings.TEMPLATE_VARS)
|
||||
try:
|
||||
return Template(self.booking_form_url).render(template_vars)
|
||||
except (VariableDoesNotExist, TemplateSyntaxError):
|
||||
return
|
||||
|
||||
|
||||
class VirtualMember(models.Model):
|
||||
'''Trough model to link virtual agendas to their real agendas.
|
||||
|
|
|
@ -76,6 +76,7 @@ class AgendaEditForm(AgendaAddForm):
|
|||
'maximal_booking_delay',
|
||||
'anonymize_delay',
|
||||
'default_view',
|
||||
'booking_form_url',
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -85,6 +86,7 @@ class AgendaEditForm(AgendaAddForm):
|
|||
self.fields['maximal_booking_delay'].required = True
|
||||
if kwargs['instance'].kind != 'events':
|
||||
del self.fields['default_view']
|
||||
del self.fields['booking_form_url']
|
||||
|
||||
|
||||
class ResourceAddForm(forms.ModelForm):
|
||||
|
|
|
@ -44,8 +44,8 @@
|
|||
</a>
|
||||
{% if settings_view %}
|
||||
<a rel="popup" class="delete" href="{% url 'chrono-manager-event-delete' pk=agenda.pk event_pk=event.pk %}?next=settings">{% trans "remove" %}</a>
|
||||
{% elif not event.cancellation_status %}
|
||||
<a rel="popup" class="link-action-text cancel" href="{% url 'chrono-manager-event-cancel' pk=agenda.pk event_pk=event.pk %}?next={{ request.path }}">{% trans "Cancel" %}</a>
|
||||
{% elif agenda.booking_form_url %}
|
||||
<a class="link-action-text" href="{{ agenda.get_booking_form_url }}?agenda={{ agenda.slug }}&event={{ event.slug }}">{% trans "Booking form" %}</a>
|
||||
{% endif %}
|
||||
<span class="occupation-bar"></span>
|
||||
</li>
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
{% endif %}
|
||||
<a href="{% url 'chrono-manager-event-edit' pk=agenda.id event_pk=object.id %}">{% trans "Options" %}</a>
|
||||
{% endif %}
|
||||
{% if object.agenda.booking_form_url %}
|
||||
<a href="{{ object.agenda.get_booking_form_url }}?agenda={{ object.agenda.slug }}&event={{ event.slug }}">{% trans "Booking form" %}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -134,6 +134,29 @@ def test_import_export(app):
|
|||
shutil.rmtree(tempdir)
|
||||
|
||||
|
||||
def test_import_export_events_agenda_options(app):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Foo Bar',
|
||||
kind='events',
|
||||
default_view='open_events',
|
||||
booking_form_url='{{ eservices_url }}backoffice/submission/inscription-aux-activites/',
|
||||
)
|
||||
|
||||
output = get_output_of_command('export_site')
|
||||
assert len(json.loads(output)['agendas']) == 1
|
||||
import_site(data={}, clean=True)
|
||||
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
f.write(force_bytes(output))
|
||||
f.flush()
|
||||
call_command('import_site', f.name)
|
||||
|
||||
assert Agenda.objects.count() == 1
|
||||
agenda = Agenda.objects.first()
|
||||
assert agenda.default_view == 'open_events'
|
||||
assert agenda.booking_form_url == '{{ eservices_url }}backoffice/submission/inscription-aux-activites/'
|
||||
|
||||
|
||||
def test_import_export_event_details(app):
|
||||
agenda = Agenda.objects.create(label='Foo Bar', kind='events')
|
||||
Event.objects.create(
|
||||
|
|
|
@ -892,6 +892,7 @@ def test_options_agenda(app, admin_user):
|
|||
resp.form['label'] = 'Foo baz'
|
||||
resp.form['anonymize_delay'] = 365
|
||||
assert 'default_view' in resp.context['form'].fields
|
||||
assert 'booking_form_url' in resp.context['form'].fields
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda_events.pk)
|
||||
resp = resp.follow()
|
||||
|
@ -903,8 +904,10 @@ def test_options_agenda(app, admin_user):
|
|||
|
||||
resp = app.get('/manage/agendas/%s/edit' % agenda_meetings.pk)
|
||||
assert 'default_view' not in resp.context['form'].fields
|
||||
assert 'booking_form_url' not in resp.context['form'].fields
|
||||
resp = app.get('/manage/agendas/%s/edit' % agenda_virtual.pk)
|
||||
assert 'default_view' not in resp.context['form'].fields
|
||||
assert 'booking_form_url' not in resp.context['form'].fields
|
||||
|
||||
|
||||
def test_options_agenda_cant_unset_delays(app, admin_user):
|
||||
|
@ -4056,11 +4059,10 @@ def test_event_cancellation(app, admin_user):
|
|||
event = Event.objects.create(
|
||||
label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda
|
||||
)
|
||||
day = event.start_datetime
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
|
||||
assert '0/10 bookings' in resp.text
|
||||
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
||||
assert 'Bookings (0/10)' in resp.text
|
||||
|
||||
resp = resp.click('Cancel', href='/cancel')
|
||||
assert 'related bookings' not in resp.text
|
||||
|
@ -4068,15 +4070,15 @@ def test_event_cancellation(app, admin_user):
|
|||
Booking.objects.create(event=event)
|
||||
Booking.objects.create(event=event)
|
||||
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
|
||||
assert '2/10 bookings' in resp.text
|
||||
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
||||
assert 'Bookings (2/10)' in resp.text
|
||||
|
||||
resp = resp.click('Cancel', href='/cancel')
|
||||
resp = resp.click('Cancel', href='manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
|
||||
assert '2 related bookings will also be cancelled.' in resp.text
|
||||
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Cancelled' in resp.text
|
||||
assert '0/10 bookings' in resp.text
|
||||
assert 'Bookings (0/10)' in resp.text
|
||||
assert Booking.objects.filter(event=event, cancellation_datetime__isnull=False).count() == 2
|
||||
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
||||
assert '/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk) not in resp.text
|
||||
|
@ -4100,8 +4102,7 @@ def test_event_cancellation_error_report(app, admin_user):
|
|||
resp = resp.click('Cancellation error reports')
|
||||
assert 'No error report' in resp.text
|
||||
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
|
||||
resp = resp.click('Cancel', href='/cancel')
|
||||
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Cancellation in progress' in resp.text
|
||||
|
||||
|
@ -4144,15 +4145,56 @@ def test_event_cancellation_forbidden(app, admin_user):
|
|||
event = Event.objects.create(
|
||||
label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda
|
||||
)
|
||||
booking = Booking.objects.create(event=event)
|
||||
booking2 = Booking.objects.create(event=event, backoffice_url='http://example.org/backoffice/xx/')
|
||||
Booking.objects.create(event=event)
|
||||
Booking.objects.create(event=event, backoffice_url='http://example.org/backoffice/xx/')
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%d/events/%d/cancel' % (agenda.pk, event.pk))
|
||||
assert 'event has bookings with no callback url configured' in resp.text
|
||||
assert 'Proceed with cancellation' not in resp.text
|
||||
|
||||
|
||||
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 = event.start_datetime
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
|
||||
resp = resp.click('Cancel', href='/cancel')
|
||||
assert 'event has bookings with no callback url configured' in resp.text
|
||||
assert 'Proceed with cancellation' not in resp.text
|
||||
|
||||
assert agenda.get_booking_form_url() is None
|
||||
resp = app.get('/manage/agendas/%d/%d/%d/' % (agenda.pk, day.year, day.month))
|
||||
assert 'Booking form' not in resp.text
|
||||
resp = app.get('/manage/agendas/%d/events/open/' % agenda.pk)
|
||||
assert 'Booking form' not in resp.text
|
||||
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
||||
assert 'Booking form' not in resp.text
|
||||
|
||||
agenda.booking_form_url = '{{ eservices_url }}backoffice/submission/inscription-aux-activites/'
|
||||
agenda.save()
|
||||
assert (
|
||||
agenda.get_booking_form_url() == 'http://demarches/backoffice/submission/inscription-aux-activites/'
|
||||
)
|
||||
resp = app.get('/manage/agendas/%d/%d/%d/' % (agenda.pk, day.year, day.month))
|
||||
assert (
|
||||
'<a class="link-action-text" href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s">Booking form</a>'
|
||||
% (agenda.slug, event.slug)
|
||||
in resp.text
|
||||
)
|
||||
resp = app.get('/manage/agendas/%d/events/open/' % agenda.pk)
|
||||
assert (
|
||||
'<a class="link-action-text" href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s">Booking form</a>'
|
||||
% (agenda.slug, event.slug)
|
||||
in resp.text
|
||||
)
|
||||
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
|
||||
assert (
|
||||
'<a href="http://demarches/backoffice/submission/inscription-aux-activites/?agenda=%s&event=%s">Booking form</a>'
|
||||
% (agenda.slug, event.slug)
|
||||
in resp.text
|
||||
)
|
||||
|
||||
|
||||
def test_agenda_notifications(app, admin_user, managers_group):
|
||||
|
|
Loading…
Reference in New Issue