Projet

Général

Profil

0001-manager-add-event-cancellation-44157.patch

Valentin Deniaud, 09 juillet 2020 18:26

Télécharger (11,8 ko)

Voir les différences:

Subject: [PATCH] manager: add event cancellation (#44157)

 .../migrations/0052_event_cancelled.py        | 22 ++++++++++++++
 chrono/agendas/models.py                      | 11 +++++++
 chrono/api/views.py                           |  4 +++
 chrono/manager/forms.py                       |  4 +--
 chrono/manager/static/css/style.scss          |  4 +++
 .../chrono/manager_agenda_event_fragment.html | 15 ++++++++--
 .../manager_confirm_event_cancellation.html   | 24 +++++++++++++++
 chrono/manager/urls.py                        |  5 ++++
 chrono/manager/views.py                       | 29 +++++++++++++++++++
 tests/test_manager.py                         | 28 ++++++++++++++++++
 10 files changed, 142 insertions(+), 4 deletions(-)
 create mode 100644 chrono/agendas/migrations/0052_event_cancelled.py
 create mode 100644 chrono/manager/templates/chrono/manager_confirm_event_cancellation.html
chrono/agendas/migrations/0052_event_cancelled.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-07-09 09:54
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations, models
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    dependencies = [
11
        ('agendas', '0051_booking_cancel_callback_url'),
12
    ]
13

  
14
    operations = [
15
        migrations.AddField(
16
            model_name='event',
17
            name='cancelled',
18
            field=models.BooleanField(
19
                default=False, help_text="Cancel this event so that it won't be bookable anymore."
20
            ),
21
        ),
22
    ]
chrono/agendas/models.py
413 413
        assert self.kind == 'events'
414 414

  
415 415
        entries = self.event_set.all()
416
        entries = self.event_set.filter(cancelled=False)
416 417
        # we never want to allow booking for past events.
417 418
        entries = entries.filter(start_datetime__gte=localtime(now()))
418 419
        # exclude non published events
......
752 753
    pricing = models.CharField(_('Pricing'), max_length=150, null=True, blank=True)
753 754
    url = models.CharField(_('URL'), max_length=200, null=True, blank=True)
754 755
    full = models.BooleanField(default=False)
756
    cancelled = models.BooleanField(
757
        default=False, help_text=_("Cancel this event so that it won't be bookable anymore.")
758
    )
755 759
    meeting_type = models.ForeignKey(MeetingType, null=True, on_delete=models.CASCADE)
756 760
    desk = models.ForeignKey('Desk', null=True, on_delete=models.CASCADE)
757 761
    resources = models.ManyToManyField('Resource')
......
899 903

  
900 904
        return new_event
901 905

  
906
    def cancel(self):
907
        with transaction.atomic():
908
            for booking in self.booking_set.filter(cancellation_datetime__isnull=True).all():
909
                booking.cancel()
910
            self.cancelled = True
911
            self.save()
912

  
902 913

  
903 914
class Booking(models.Model):
904 915
    event = models.ForeignKey(Event, on_delete=models.CASCADE)
chrono/api/views.py
927 927
                    return Response(
928 928
                        {'err': 1, 'err_class': 'event not bookable', 'err_desc': _('event not bookable')}
929 929
                    )
930
                if event.cancelled:
931
                    return Response(
932
                        {'err': 1, 'err_class': 'event is cancelled', 'err_desc': _('event is cancelled')}
933
                    )
930 934

  
931 935
            if not events.count():
932 936
                return Response(
chrono/manager/forms.py
90 90
            'start_datetime': DateTimeWidget(),
91 91
            'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
92 92
        }
93
        exclude = ['full', 'meeting_type', 'desk', 'slug', 'resources']
93
        exclude = ['full', 'meeting_type', 'desk', 'slug', 'resources', 'cancelled']
94 94

  
95 95

  
96 96
class EventForm(forms.ModelForm):
......
101 101
            'start_datetime': DateTimeWidget(),
102 102
            'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
103 103
        }
104
        exclude = ['full', 'meeting_type', 'desk', 'resources']
104
        exclude = ['full', 'meeting_type', 'desk', 'resources', 'cancelled']
105 105

  
106 106

  
107 107
class AgendaResourceForm(forms.Form):
chrono/manager/static/css/style.scss
25 25
	background: #f8f8fe;
26 26
}
27 27

  
28
li.cancelled span.event-info {
29
	text-decoration: line-through;
30
}
31

  
28 32
li span.duration {
29 33
	font-size: 80%;
30 34
}
chrono/manager/templates/chrono/manager_agenda_event_fragment.html
1 1
{% load i18n %}
2 2
<li class="{% if event.booked_places_count > event.places %}overbooking{% endif %}
3 3
           {% if event.main_list_full %}full{% endif %}
4
             {% if event.cancelled %}cancelled{% endif %}
4 5
           {% if not event.in_bookable_period %}not-{% endif %}bookable"
5 6
    {% if event.places %}
6 7
      data-total="{{ event.places }}" data-booked="{{ event.booked_places_count }}"
......
8 9
      data-total="{{ event.waiting_list_places }}" data-booked="{{ event.waiting_list_count }}"
9 10
    {% endif %}
10 11
    ><a href="{% if settings_view %}{% url 'chrono-manager-event-edit' pk=agenda.pk event_pk=event.pk %}?next=settings{% else %}{% url 'chrono-manager-event-view' pk=agenda.pk event_pk=event.pk %}{% endif %}">
11
    {% if event.main_list_full %}<span class="full tag">{% trans "Full" %}</span>{% endif %}
12
    {% if event.cancelled %}
13
    <span class="cancelled tag">{% trans "Cancelled" %}</span>
14
    {% elif event.main_list_full %}
15
    <span class="full tag">{% trans "Full" %}</span>
16
    {% endif %}
17
    <span class="event-info">
12 18
    {% if settings_view %}
13 19
      {% if event.label %}{{ event.label }} {% endif %}[{% trans "identifier:" %} {{ event.slug }}]
14 20
    {% else %}
......
32 38
    {% if not event.in_bookable_period %}
33 39
    ({% trans "out of bookable period" %})
34 40
    {% endif %}
41
    </span>
35 42
        </a>
36
    {% 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>{% endif %}
43
    {% if settings_view %}
44
    <a rel="popup" class="delete" href="{% url 'chrono-manager-event-delete' pk=agenda.pk event_pk=event.pk %}?next=settings">{% trans "remove" %}</a>
45
    {% elif not event.cancelled %}
46
    <a rel="popup" class="link-action-text cancel" href="{% url 'chrono-manager-event-cancel' pk=agenda.pk event_pk=event.pk %}">{% trans "Cancel" %}</a>
47
    {% endif %}
37 48
    <span class="occupation-bar"></span>
38 49
</li>
chrono/manager/templates/chrono/manager_confirm_event_cancellation.html
1
{% extends "chrono/manager_home.html" %}
2
{% load i18n %}
3

  
4
{% block appbar %}
5
<h2>{{ view.model.get_verbose_name }}</h2>
6
{% endblock %}
7

  
8
{% block content %}
9

  
10
<form method="post">
11
  {% csrf_token %}
12
  <p>
13
  {% trans "Are you sure you want to cancel this event?" %}
14
  {% if bookings_count %}
15
  {% blocktrans %}The {{ bookings_count }} related bookings will also be cancelled.{% endblocktrans %}
16
  {% endif %}
17
  </p>
18
  <input type="hidden" name="next" value="{% firstof request.POST.next request.GET.next %}">
19
  <div class="buttons">
20
    <button class="delete-button">{% trans "Proceed with cancellation" %}</button>
21
    <a class="cancel" href="{{ view.get_success_url }}">{% trans 'Abort' %}</a>
22
  </div>
23
</form>
24
{% endblock %}
chrono/manager/urls.py
74 74
        views.event_delete,
75 75
        name='chrono-manager-event-delete',
76 76
    ),
77
    url(
78
        r'^agendas/(?P<pk>\d+)/events/(?P<event_pk>\d+)/cancel$',
79
        views.event_cancel,
80
        name='chrono-manager-event-cancel',
81
    ),
77 82
    url(
78 83
        r'^agendas/(?P<pk>\d+)/add-resource/$',
79 84
        views.agenda_add_resource,
chrono/manager/views.py
1737 1737
booking_cancel = BookingCancelView.as_view()
1738 1738

  
1739 1739

  
1740
class EventCancelView(ManagedAgendaMixin, DeleteView):
1741
    template_name = 'chrono/manager_confirm_event_cancellation.html'
1742
    model = Event
1743
    pk_url_kwarg = 'event_pk'
1744

  
1745
    def dispatch(self, request, *args, **kwargs):
1746
        self.event = self.get_object()
1747
        return super().dispatch(request, *args, **kwargs)
1748

  
1749
    def delete(self, request, *args, **kwargs):
1750
        self.event.cancel()
1751
        return HttpResponseRedirect(self.get_success_url())
1752

  
1753
    def get_success_url(self):
1754
        day = self.event.start_datetime
1755
        return reverse(
1756
            'chrono-manager-agenda-month-view',
1757
            kwargs={'pk': self.event.agenda.pk, 'year': day.year, 'month': day.month},
1758
        )
1759

  
1760
    def get_context_data(self, **kwargs):
1761
        context = super().get_context_data(**kwargs)
1762
        context['bookings_count'] = self.event.booking_set.filter(cancellation_datetime__isnull=True).count()
1763
        return context
1764

  
1765

  
1766
event_cancel = EventCancelView.as_view()
1767

  
1768

  
1740 1769
def menu_json(request):
1741 1770
    label = _('Agendas')
1742 1771
    json_str = json.dumps(
tests/test_manager.py
3455 3455

  
3456 3456
    resp = resp.follow()
3457 3457
    assert 'Bookings (0/10)' in resp.text
3458

  
3459

  
3460
def test_event_cancellation(app, admin_user):
3461
    agenda = Agenda.objects.create(label='Events', kind='events')
3462
    event = Event(label='xyz', start_datetime=now() + datetime.timedelta(days=1), places=10, agenda=agenda)
3463
    event.save()
3464
    day = event.start_datetime
3465

  
3466
    login(app)
3467
    resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
3468
    assert '0 booked place' in resp.text
3469

  
3470
    resp = resp.click('Cancel')
3471
    assert not 'related bookings' in resp.text
3472

  
3473
    booking = Booking.objects.create(event=event)
3474
    booking2 = Booking.objects.create(event=event)
3475

  
3476
    resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, day.year, day.month))
3477
    assert '2 booked places' in resp.text
3478

  
3479
    resp = resp.click('Cancel')
3480
    assert '2 related bookings will also be cancelled.'
3481

  
3482
    resp = resp.form.submit().follow()
3483
    assert 'Cancelled' in resp.text
3484
    assert '0 booked places' in resp.text
3485
    assert Booking.objects.filter(event=event, cancellation_datetime__isnull=False).count() == 2
3458
-