Merge pull request 'FIX #15 and more' (#32) from heinzel into master

Reviewed-on: #32
This commit was merged in pull request #32.
This commit is contained in:
2020-12-18 15:38:24 +01:00
17 changed files with 351 additions and 74 deletions

View File

@@ -210,6 +210,17 @@
<form action="" method="post" class="form-inline"> <form action="" method="post" class="form-inline">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="id" value="{{ participant.id }}"> <input type="hidden" name="id" value="{{ participant.id }}">
{% if event.charge and has_permission_payment %}
<button name="action" value="toggle_reduced_fee"
title="{% trans 'Hier klicken, um zwischen voller und reduzierter Teilnahmegebühr umzuschalten' %}"
class="btn btn-link no-padding">
<span class="text-primary">
{% if participant.apply_reduced_fee %}{% bootstrap_icon 'check' %}{% else %}{% bootstrap_icon 'unchecked' %}{% endif %}
Reduzierte Teilnamegebühr
</span>
</button>
&nbsp;
{% endif %}
{% if has_permission_update_participants %} {% if has_permission_update_participants %}
<button name="action" value="moveup_participant" <button name="action" value="moveup_participant"
title="{% trans 'Nach oben verschieben' %}" title="{% trans 'Nach oben verschieben' %}"
@@ -229,30 +240,35 @@
{% endif %} {% endif %}
{% if event.charge and participant.paid and has_permission_payment %} {% if event.charge and participant.paid and has_permission_payment %}
&nbsp; &nbsp;
<span class="text-success"><strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong></span><button <span class="text-success {% if not participant.apply_reduced_fee %}invisible{% endif %}"
title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><button
name="action" value="revoke_payment" name="action" value="revoke_payment"
title="{% trans 'Geldeingang wurde bestätigt' %} - {% trans 'Bestätigung des Geldeingangs zurückziehen' %}" title="{% trans 'Geldeingang wurde bestätigt' %} - {% trans 'Bestätigung des Geldeingangs zurückziehen' %}"
class="btn btn-link no-padding"><span class="text-success">{% bootstrap_icon 'piggy-bank' %}</span></button> class="btn btn-link no-padding"><span class="text-success">{% bootstrap_icon 'piggy-bank' %}</span></button>
{% elif event.charge and participant.paid %} {% elif event.charge and participant.paid %}
&nbsp; &nbsp;
<span class="text-success" title="{% trans 'Geldeingang bestätigt' %}"> <span class="text-success {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="text-success"
title="{% trans 'Geldeingang bestätigt' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% elif event.charge and has_permission_payment %} {% elif event.charge and has_permission_payment %}
&nbsp; &nbsp;
<span class="text-danger"><strong>{% if participant.apply_reduced_fee %}%{% elif participant.created_at|date:'U' < '1608764400' %}? {% else %}&emsp;{% endif %}</strong></span><button <span class="text-danger {% if not participant.apply_reduced_fee and participant.created_at|date:'U' > '1608764400' %}invisible{% endif %}"
title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>{% if participant.apply_reduced_fee %}%{% else %}? {% endif %}</strong></span><button
name="action" value="confirm_payment" name="action" value="confirm_payment"
title="{% trans 'Geldeingang bestätigen' %}" title="{% trans 'Geldeingang bestätigen' %}"
class="btn btn-link no-padding"><span class="text-danger">{% bootstrap_icon 'piggy-bank' %}</span></button> class="btn btn-link no-padding"><span class="text-danger">{% bootstrap_icon 'piggy-bank' %}</span></button>
{% elif event.charge %} {% elif event.charge %}
&nbsp; &nbsp;
<span class="text-danger" title="{% trans 'Geldeingang unbestätigt' %}"> <span class="text-danger {% if not participant.apply_reduced_fee and participant.created_at|date:'U' > '1608764400' %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% elif participant.created_at|date:'U' < '1608764400' %}? {% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>{% if participant.apply_reduced_fee %}%{% else %}? {% endif %}</strong></span><span
</span> class="text-danger"
title="{% trans 'Geldeingang unbestätigt' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% else %} {% else %}
<span class="hidden" title="{% trans 'Keine Teilnehmergebühr gefordert' %}"> <span class="hidden {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>&emsp;</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="hidden"
title="{% trans 'Keine Teilnehmergebühr gefordert' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% endif %} {% endif %}
</form> </form>
</div> </div>
@@ -287,6 +303,11 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
<div class="panel panel-default">
<div class="panel-body">
<strong title="Summe der bestätigten Geldeingänge (theoretisch!, da wir hier nur die Gebühren, aber nicht die tatsächlich überwiesenen Beträge kennen)">{% trans 'Gebuchte Teilnahmegebühren' %}:</strong> {{ earnings|floatformat:2 }} €
</div>
</div>
{% if participant_emails %} {% if participant_emails %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-body"> <div class="panel-body">
@@ -380,14 +401,16 @@
</span> </span>
{% if event.charge and participant.paid %} {% if event.charge and participant.paid %}
&nbsp; &nbsp;
<span class="text-success" title="{% trans 'Geldeingang bestätigt' %}"> <span class="text-success {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="text-success"
title="{% trans 'Geldeingang bestätigt' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% elif event.charge %} {% elif event.charge %}
&nbsp; &nbsp;
<span class="text-danger" title="{% trans 'Geldeingang unbestätigt' %}"> <span class="text-danger {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="text-danger"
title="{% trans 'Geldeingang unbestätigt' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% endif %} {% endif %}
</span> </span>
</div> </div>

View File

@@ -71,24 +71,37 @@
<form action="" method="post" class="form-inline"> <form action="" method="post" class="form-inline">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="id" value="{{ participant.id }}"> <input type="hidden" name="id" value="{{ participant.id }}">
{% if event.charge %}
<button name="action" value="toggle_reduced_fee"
title="{% trans 'Hier klicken, um zwischen voller und reduzierter Teilnahmegebühr umzuschalten' %}"
class="btn btn-link no-padding">
<span class="text-primary">
{% if participant.apply_reduced_fee %}{% bootstrap_icon 'check' %}{% else %}{% bootstrap_icon 'unchecked' %}{% endif %}
</span>
</button>
&nbsp;
{% endif %}
{% if event.charge and participant.paid %} {% if event.charge and participant.paid %}
<span class="text-success"><strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong></span><button <span class="text-success {% if not participant.apply_reduced_fee %}invisible{% endif %}"
title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><button
name="action" value="revoke_payment" name="action" value="revoke_payment"
title="{% trans 'Geldeingang wurde bestätigt' %} - {% trans 'Bestätigung des Geldeingangs zurückziehen' %}" title="{% trans 'Geldeingang wurde bestätigt' %} - {% trans 'Bestätigung des Geldeingangs zurückziehen' %}"
class="btn btn-link no-padding"><span class="text-success">{% bootstrap_icon 'piggy-bank' %}</span></button> class="btn btn-link no-padding"><span class="text-success">{% bootstrap_icon 'piggy-bank' %}</span></button>
&nbsp; &nbsp;
({{ event.charge|floatformat:'-2' }}{% if participant.apply_reduced_fee %} / 2{% endif %} €) ({{ event.charge|floatformat:'-2' }}{% if participant.apply_reduced_fee %} / 2{% endif %} €)
{% elif event.charge %} {% elif event.charge %}
<span class="text-danger"><strong>{% if participant.apply_reduced_fee %}%{% elif participant.created_at|date:'U' < '1608764400' %}? {% else %}&emsp;{% endif %}</strong></span><button <span class="text-danger {% if not participant.apply_reduced_fee and participant.created_at|date:'U' > '1608764400' %}invisible{% endif %}"
title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>{% if participant.apply_reduced_fee %}%{% else %}? {% endif %}</strong></span><button
name="action" value="confirm_payment" name="action" value="confirm_payment"
title="{% trans 'Geldeingang bestätigen' %}" title="{% trans 'Geldeingang bestätigen' %}"
class="btn btn-link no-padding"><span class="text-danger">{% bootstrap_icon 'piggy-bank' %}</span></button> class="btn btn-link no-padding"><span class="text-danger">{% bootstrap_icon 'piggy-bank' %}</span></button>
&nbsp; &nbsp;
({{ event.charge|floatformat:'-2' }}{% if participant.apply_reduced_fee %} / 2{% endif %} €) ({{ event.charge|floatformat:'-2' }}{% if participant.apply_reduced_fee %} / 2{% endif %} €)
{% else %} {% else %}
<span class="text-muted" title="{% trans 'Keine Teilnehmergebühr gefordert' %}"> <span class="hidden {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>&emsp;</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="hidden"
title="{% trans 'Keine Teilnehmergebühr gefordert' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% endif %} {% endif %}
</form> </form>
</td> </td>

View File

@@ -53,6 +53,11 @@ class ParticipantListView(generic.ListView):
participant = get_object_or_404(Participant, pk=participant_id) participant = get_object_or_404(Participant, pk=participant_id)
participant.paid = False participant.paid = False
participant.save() participant.save()
elif action == 'toggle_reduced_fee':
participant_id = request.POST.get('id')
participant = get_object_or_404(Participant, pk=participant_id)
participant.apply_reduced_fee = not participant.apply_reduced_fee
participant.save()
else: else:
messages.error(request, 'unsupported action: {}'.format(action)) messages.error(request, 'unsupported action: {}'.format(action))
return HttpResponseRedirect(reverse('dav_event_office:participant-list')) return HttpResponseRedirect(reverse('dav_event_office:participant-list'))

View File

@@ -1,3 +1,4 @@
from . import generic from . import generic
from . import events from . import events
from . import participant from . import participant
from . import registration

View File

@@ -7,7 +7,9 @@ from ..models import Participant
class ParticipantForm(forms.ModelForm): class ParticipantForm(forms.ModelForm):
class Meta: class Meta:
model = Participant model = Participant
exclude = ['event', 'created_at', 'position', 'purge_at'] exclude = ['event', 'created_at', 'position',
'privacy_policy', 'privacy_policy_accepted',
'paid', 'purge_at']
widgets = { widgets = {
'emergency_contact': forms.Textarea(attrs={'rows': 4}), 'emergency_contact': forms.Textarea(attrs={'rows': 4}),
'experience': forms.Textarea(attrs={'rows': 5}), 'experience': forms.Textarea(attrs={'rows': 5}),

View File

@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
from django import forms
from django.utils.translation import ugettext_lazy as _
class RegistrationResponseForm(forms.Form):
apply_reduced_fee = forms.BooleanField(required=False,
label=_(u'Reduzierte Teilnahmegebühr'))

View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2020-12-15 10:55
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dav_events', '0038_auto_20201209_1542'),
]
operations = [
migrations.AlterField(
model_name='participant',
name='apply_reduced_fee',
field=models.BooleanField(default=False, help_text='Für Jugendliche und Junioren (bis zum vollendeten 25. Lebensjahr), sowie Mitglieder mit geringen finanziellen Mitteln (Nachweis durch "Karlsruher Pass"), wird die Teilnahmegebühr auf 50% ermäßigt.', verbose_name='Antrag auf reduzierte Teilnahmegebühr'),
),
migrations.AlterField(
model_name='participant',
name='year_of_birth',
field=models.IntegerField(help_text='Vierstellige Jahreszahl', verbose_name='Geburtsjahr'),
),
migrations.AlterField(
model_name='trashedparticipant',
name='apply_reduced_fee',
field=models.BooleanField(default=False, help_text='Für Jugendliche und Junioren (bis zum vollendeten 25. Lebensjahr), sowie Mitglieder mit geringen finanziellen Mitteln (Nachweis durch "Karlsruher Pass"), wird die Teilnahmegebühr auf 50% ermäßigt.', verbose_name='Antrag auf reduzierte Teilnahmegebühr'),
),
migrations.AlterField(
model_name='trashedparticipant',
name='year_of_birth',
field=models.IntegerField(help_text='Vierstellige Jahreszahl', verbose_name='Geburtsjahr'),
),
]

View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2020-12-16 16:12
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dav_events', '0039_auto_20201215_1155'),
]
operations = [
migrations.AddField(
model_name='participant',
name='privacy_policy',
field=models.TextField(blank=True, verbose_name='Erklärung zur Datenspeicherung'),
),
migrations.AddField(
model_name='participant',
name='privacy_policy_accepted',
field=models.BooleanField(default=False, verbose_name='Einwilligung zur Datenspeicherung'),
),
migrations.AddField(
model_name='trashedparticipant',
name='privacy_policy',
field=models.TextField(blank=True, verbose_name='Erklärung zur Datenspeicherung'),
),
migrations.AddField(
model_name='trashedparticipant',
name='privacy_policy_accepted',
field=models.BooleanField(default=False, verbose_name='Einwilligung zur Datenspeicherung'),
),
]

View File

@@ -53,6 +53,11 @@ class AbstractParticipant(models.Model):
verbose_name=_('Anmerkung'), verbose_name=_('Anmerkung'),
help_text=_('Kann frei gelassen werden.')) help_text=_('Kann frei gelassen werden.'))
privacy_policy = models.TextField(blank=True,
verbose_name=_('Erklärung zur Datenspeicherung'))
privacy_policy_accepted = models.BooleanField(default=False,
verbose_name=_('Einwilligung zur Datenspeicherung'))
paid = models.BooleanField('Teilnehmerbeitrag bezahlt', default=False) paid = models.BooleanField('Teilnehmerbeitrag bezahlt', default=False)
purge_at = models.DateTimeField() purge_at = models.DateTimeField()

View File

@@ -40,11 +40,9 @@
{% bootstrap_icon 'remove' %}&thinsp; {% bootstrap_icon 'remove' %}&thinsp;
{% trans 'Abbrechen' %} {% trans 'Abbrechen' %}
</a> </a>
<!--
<button id="btn-form-save" type="submit" name="save" class="btn btn-info"> <button id="btn-form-save" type="submit" name="save" class="btn btn-info">
{% bootstrap_icon 'hdd' %}&thinsp; {% bootstrap_icon 'hdd' %}&thinsp;
{% trans 'Als Entwurf speichern' %} {% trans 'Als Entwurf speichern' %}
</button> </button>
-->
{% endbuttons %} {% endbuttons %}
{% endblock form-buttons %} {% endblock form-buttons %}

View File

@@ -272,10 +272,17 @@ Das musst du selbst (per E-Mail oder telefonisch) machen.
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="registration" value="{{ registration.id }}"> <input type="hidden" name="registration" value="{{ registration.id }}">
{% if has_permission_update_participants %} {% if has_permission_update_participants %}
{% if registration.apply_reduced_fee %}
<a href="{% url 'dav_events:respond_registration' registration.pk %}"
class="btn btn-link no-padding" title="zur Teilnehmerliste hinzufügen">
<span class="text-success">{% bootstrap_icon 'plus-sign' %}</span>
</a>
{% else %}
<button type="submit" name="action" value="accept_registration" <button type="submit" name="action" value="accept_registration"
class="btn btn-link no-padding" title="zur Teilnehmerliste hinzufügen"> class="btn btn-link no-padding" title="zur Teilnehmerliste hinzufügen">
<span class="text-success">{% bootstrap_icon 'plus-sign' %}</span> <span class="text-success">{% bootstrap_icon 'plus-sign' %}</span>
</button> </button>
{% endif %}
&nbsp; &nbsp;
<button type="submit" name="action" value="reject_registration" <button type="submit" name="action" value="reject_registration"
class="btn btn-link no-padding" title="Anmeldung löschen"> class="btn btn-link no-padding" title="Anmeldung löschen">
@@ -298,7 +305,7 @@ Das musst du selbst (per E-Mail oder telefonisch) machen.
{% if registration.apply_reduced_fee %} {% if registration.apply_reduced_fee %}
&nbsp; &nbsp;
<span class="text-info"> <span class="text-info">
<strong>%</strong>{% bootstrap_icon 'piggy-bank' %} (reduzierte Gebühr) <strong title="{% trans 'reduzierte Teilnahmegebühr' %}">%</strong>{% bootstrap_icon 'piggy-bank' %} (reduzierte Gebühr)
</span> </span>
{% endif %} {% endif %}
</form> </form>
@@ -392,30 +399,35 @@ Wichtig: das System verschickt keine Bestätigung an dich oder den neuen Teilneh
{% endif %} {% endif %}
{% if event.charge and participant.paid and has_permission_payment %} {% if event.charge and participant.paid and has_permission_payment %}
&nbsp; &nbsp;
<span class="text-success"><strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong></span><button <span class="text-success {% if not participant.apply_reduced_fee %}invisible{% endif %}"
title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><button
name="action" value="revoke_payment" name="action" value="revoke_payment"
title="{% trans 'Geldeingang wurde bestätigt' %} - {% trans 'Bestätigung des Geldeingangs zurückziehen' %}" title="{% trans 'Geldeingang wurde bestätigt' %} - {% trans 'Bestätigung des Geldeingangs zurückziehen' %}"
class="btn btn-link no-padding"><span class="text-success">{% bootstrap_icon 'piggy-bank' %}</span></button> class="btn btn-link no-padding"><span class="text-success">{% bootstrap_icon 'piggy-bank' %}</span></button>
{% elif event.charge and participant.paid %} {% elif event.charge and participant.paid %}
&nbsp; &nbsp;
<span class="text-success" title="{% trans 'Geldeingang bestätigt' %}"> <span class="text-success {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="text-success"
title="{% trans 'Geldeingang bestätigt' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% elif event.charge and has_permission_payment %} {% elif event.charge and has_permission_payment %}
&nbsp; &nbsp;
<span class="text-danger"><strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong></span><button <span class="text-danger {% if not participant.apply_reduced_fee %}invisible{% endif %}"
title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><button
name="action" value="confirm_payment" name="action" value="confirm_payment"
title="{% trans 'Geldeingang bestätigen' %}" title="{% trans 'Geldeingang bestätigen' %}"
class="btn btn-link no-padding"><span class="text-danger">{% bootstrap_icon 'piggy-bank' %}</span></button> class="btn btn-link no-padding"><span class="text-danger">{% bootstrap_icon 'piggy-bank' %}</span></button>
{% elif event.charge %} {% elif event.charge %}
&nbsp; &nbsp;
<span class="text-danger" title="{% trans 'Geldeingang unbestätigt' %}"> <span class="text-danger {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="text-danger"
title="{% trans 'Geldeingang unbestätigt' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% else %} {% else %}
<span class="hidden" title="{% trans 'Keine Teilnehmergebühr gefordert' %}"> <span class="hidden {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="hidden"
title="{% trans 'Keine Teilnehmergebühr gefordert' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% endif %} {% endif %}
</form> </form>
</div> </div>
@@ -580,14 +592,16 @@ von Position {{ participant.position }} der Teilnehmerliste entfernt.
</span> </span>
{% if event.charge and participant.paid %} {% if event.charge and participant.paid %}
&nbsp; &nbsp;
<span class="text-success" title="{% trans 'Geldeingang bestätigt' %}"> <span class="text-success {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="text-success"
title="{% trans 'Geldeingang bestätigt' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% elif event.charge %} {% elif event.charge %}
&nbsp; &nbsp;
<span class="text-danger" title="{% trans 'Geldeingang unbestätigt' %}"> <span class="text-danger {% if not participant.apply_reduced_fee %}invisible{% endif %}"
<strong>{% if participant.apply_reduced_fee %}%{% else %}&emsp;{% endif %}</strong>{% bootstrap_icon 'piggy-bank' %} title="{% trans 'Reduzierte Teilnahmegebühr' %}"><strong>%</strong></span><span
</span> class="text-danger"
title="{% trans 'Geldeingang unbestätigt' %}">{% bootstrap_icon 'piggy-bank' %}</span>
{% endif %} {% endif %}
</span> </span>

View File

@@ -0,0 +1,45 @@
{% extends 'dav_events/base.html' %}
{% load bootstrap3 %}
{% load i18n %}
{% block head-title %}
{% trans 'Anmeldung' %} {{ registration.get_full_name }} - {{ registration.event.number }} - {{ block.super }}
{% endblock head-title %}
{% block page-container %}
<div class="well">
<p>
Hallo {{ registration.event.trainer_firstname }},
</p>
<p>
du hast sicherlich schon gesehen, dass {{ registration.get_full_name }} angekreuzt hat,
die reduzierte Teilnahmegebühr zahlen zu wollen.
</p>
<p>
Für Jugendliche und Junioren sowie Mitglieder mit geringen finanziellen Mitteln (Nachweis durch Karlsruher Paß)
wird die Teilnahmegebühr auf 50% ermäßigt.
</p>
<p>
Wenn ihr bereits darüber gesprochen habt und ihr übereingekommen seid,
dass {{ registration.personal_names }} doch den vollen Betrag zahlen soll,
dann kannst du unten den Haken entfernen.
</p>
</div>
<div class="well">
<h6>
{{ registration.event.number }} - {{ registration.event.title }}<br />
{% trans 'Anmeldung' %} {{ registration.get_full_name }}
</h6>
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" name="action" value="accept_registration"
class="btn btn-success">
{% bootstrap_icon 'plus-sign' %} zur Teilnehmerliste hinzufügen
</button>
<a href="{% url 'dav_events:registrations' registration.event.pk %}" class="btn btn-danger">
{% bootstrap_icon 'remove' %} Zurück
</a>
</form>
</div>
{% endblock page-container %}

View File

@@ -12,6 +12,7 @@ urlpatterns = [
views.events.EventUpdateStatusView.as_view(), name='updatestatus'), views.events.EventUpdateStatusView.as_view(), name='updatestatus'),
url(r'^(?P<pk>\d+)/edit', views.events.EventUpdateView.as_view(), name='update'), url(r'^(?P<pk>\d+)/edit', views.events.EventUpdateView.as_view(), name='update'),
url(r'^(?P<pk>\d+)/', views.events.EventDetailView.as_view(), name='detail'), url(r'^(?P<pk>\d+)/', views.events.EventDetailView.as_view(), name='detail'),
url(r'^registration/(?P<pk>\d+)/', views.events.RespondRegistrationView.as_view(), name='respond_registration'),
url(r'^action/(?P<pk>[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})/', url(r'^action/(?P<pk>[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})/',
views.actions.OneClickActionRunView.as_view(), name='action_run'), views.actions.OneClickActionRunView.as_view(), name='action_run'),
] ]

View File

@@ -2,6 +2,7 @@
import datetime import datetime
import logging import logging
import os import os
from django.apps import apps
from django.contrib import messages from django.contrib import messages
from django.contrib.auth import login from django.contrib.auth import login
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
@@ -218,6 +219,16 @@ class EventRegistrationsView(EventPermissionMixin, generic.DetailView):
participants_trash = event.trashed_participants.all() participants_trash = event.trashed_participants.all()
context['participants_trash'] = participants_trash context['participants_trash'] = participants_trash
earnings = 0
if event.charge:
for participant in participants:
if participant.paid:
if participant.apply_reduced_fee:
earnings += event.charge / 2
else:
earnings += event.charge
context['earnings'] = earnings
if participants.count() > 1: if participants.count() > 1:
email_list = [u'"{}" <{}>'.format(p.get_full_name(), p.email_address) for p in participants] email_list = [u'"{}" <{}>'.format(p.get_full_name(), p.email_address) for p in participants]
email_list.sort() email_list.sort()
@@ -271,30 +282,13 @@ class EventRegistrationsView(EventPermissionMixin, generic.DetailView):
messages.success(request, _(u'Der Anmeldeschluss wurde gelöscht')) messages.success(request, _(u'Der Anmeldeschluss wurde gelöscht'))
def _accept_registration(self, request, registration): def _accept_registration(self, request, registration):
event = registration.event data = registration.get_data_dict()
del data['created_at']
del data['answered_obsolete']
data['position'] = registration.event.participants.count() + 1
position = event.participants.count() + 1
data = {
'event': event,
'position': position,
'personal_names': registration.personal_names,
'family_names': registration.family_names,
'address': registration.address,
'postal_code': registration.postal_code,
'city': registration.city,
'email_address': registration.email_address,
'year_of_birth': registration.year_of_birth,
'apply_reduced_fee': registration.apply_reduced_fee,
'phone_number': registration.phone_number,
'dav_member': registration.dav_member,
'dav_number': registration.dav_number,
'emergency_contact': registration.emergency_contact,
'experience': registration.experience,
'note': registration.note,
'purge_at': registration.purge_at,
}
participant = models.Participant.objects.create(**data) participant = models.Participant.objects.create(**data)
registration.status.set_accepted() registration.status.set_accepted()
messages.success(request, _(u'Teilnehmer hinzugefügt: {}'.format(participant.get_full_name()))) messages.success(request, _(u'Teilnehmer hinzugefügt: {}'.format(participant.get_full_name())))
@@ -360,6 +354,12 @@ class EventRegistrationsView(EventPermissionMixin, generic.DetailView):
self._reset_registration(registration) self._reset_registration(registration)
else: else:
raise FieldDoesNotExist('Event has no registrations') raise FieldDoesNotExist('Event has no registrations')
elif action == 'toggle_reduced_fee':
self.enforce_permission(event, permission='payment')
participant_id = request.POST.get('id')
participant = event.participants.get(id=participant_id)
participant.apply_reduced_fee = not participant.apply_reduced_fee
participant.save()
elif action == 'confirm_payment': elif action == 'confirm_payment':
self.enforce_permission(event, permission='payment') self.enforce_permission(event, permission='payment')
participant_id = request.POST.get('id') participant_id = request.POST.get('id')
@@ -455,6 +455,62 @@ class EventRegistrationsView(EventPermissionMixin, generic.DetailView):
return super(EventRegistrationsView, self).dispatch(request, *args, **kwargs) return super(EventRegistrationsView, self).dispatch(request, *args, **kwargs)
class RespondRegistrationView(EventPermissionMixin, generic.DetailView, generic.FormView):
permission = 'update-participants'
context_object_name = 'registration'
template_name = 'dav_events/registration_response.html'
form_class = forms.registration.RegistrationResponseForm
def _accept_registration(self, request, registration):
data = registration.get_data_dict()
del data['created_at']
del data['answered_obsolete']
data['position'] = registration.event.participants.count() + 1
participant = models.Participant.objects.create(**data)
registration.status.set_accepted()
messages.success(request, _(u'Teilnehmer hinzugefügt: {}'.format(participant.get_full_name())))
def has_permission(self, permission, obj):
user = self.request.user
return obj.event.workflow.has_permission(user, permission)
def get_queryset(self):
model = apps.get_model(app_label='dav_registration', model_name='Registration')
return model.objects.all()
def get_success_url(self):
return reverse('dav_events:registrations', args=[self.object.event.pk])
def get_initial(self):
return {
'apply_reduced_fee': self.object.apply_reduced_fee,
}
def form_valid(self, form):
registration = self.object
registration.apply_reduced_fee = form.cleaned_data['apply_reduced_fee']
registration.save()
self._accept_registration(self.request, registration)
return HttpResponseRedirect(self.get_success_url())
def get(self, request, *args, **kwargs):
self.object = self.get_object()
self.enforce_permission(self.object)
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
self.enforce_permission(self.object)
return super(RespondRegistrationView, self).post(request, *args, **kwargs)
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(RespondRegistrationView, self).dispatch(request, *args, **kwargs)
class EventUpdateStatusView(EventPermissionMixin, generic.DetailView): class EventUpdateStatusView(EventPermissionMixin, generic.DetailView):
model = models.Event model = models.Event
@@ -487,6 +543,18 @@ class EventUpdateStatusView(EventPermissionMixin, generic.DetailView):
messages.error(request, message) messages.error(request, message)
return HttpResponseRedirect(event.get_absolute_url()) return HttpResponseRedirect(event.get_absolute_url())
if not event.workflow.has_reached_status('publishing*') and not event.workflow.has_reached_status('published*'):
cur_pub_date = event.planned_publication_date
real_pub_date, real_pub_issue = event.workflow.plan_publication(event.first_day, event.deadline)
if cur_pub_date != real_pub_date:
if real_pub_date is None:
real_pub_str = _(u'Unverzüglich')
else:
real_pub_str = u'%s (%s)' % (real_pub_date.strftime('%d.%m.%Y'), real_pub_issue)
event.planned_publication_date = real_pub_date
event.save()
messages.warning(request, _(u'Veröffentlichungsdatum wurde angepasst: %s') % real_pub_str)
event.workflow.update_status(status, request.user) event.workflow.update_status(status, request.user)
if status.startswith('submit'): if status.startswith('submit'):
@@ -546,7 +614,21 @@ class EventUpdateView(EventPermissionMixin, generic.UpdateView):
def form_valid(self, form): def form_valid(self, form):
form.instance.editor = self.request.user form.instance.editor = self.request.user
self.object = form.save() event = form.save()
self.object = event
if not event.workflow.has_reached_status('publishing*') and not event.workflow.has_reached_status('published*'):
cur_pub_date = event.planned_publication_date
real_pub_date, real_pub_issue = event.workflow.plan_publication(event.first_day, event.deadline)
if cur_pub_date != real_pub_date:
if real_pub_date is None:
real_pub_str = _(u'Unverzüglich')
else:
real_pub_str = u'%s (%s)' % (real_pub_date.strftime('%d.%m.%Y'), real_pub_issue)
event.planned_publication_date = real_pub_date
event.save()
messages.warning(self.request, _(u'Veröffentlichungsdatum wurde angepasst: %s') % real_pub_str)
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())
@method_decorator(login_required) @method_decorator(login_required)

View File

@@ -489,9 +489,8 @@ class BasicWorkflow(object):
# #
# Misc logic # Misc logic
# #
# TODO: is a class method a good idea? @staticmethod
@classmethod def plan_publication(first_day, deadline=None):
def plan_publication(cls, first_day, deadline=None):
app_config = apps.get_containing_app_config(__package__) app_config = apps.get_containing_app_config(__package__)
if deadline: if deadline:

View File

@@ -11,10 +11,14 @@ logger = logging.getLogger(__name__)
class RegistrationForm(forms.ModelForm): class RegistrationForm(forms.ModelForm):
not_dav_member = forms.BooleanField(required=False, not_dav_member = forms.BooleanField(required=False,
label=_('Ich bin noch kein DAV Mitglied.'), label=_(u'Ich bin noch kein DAV Mitglied.'),
help_text=_('Wenn du noch kein DAV Mitglied bist,' help_text=u'%s<br />\n%s' % (
' oder deine Aufnahme noch in Arbeit ist,' _(u'Wenn du noch kein DAV Mitglied bist,'
' kreuze dieses Feld hier an.')) u' oder deine Aufnahme noch in Arbeit ist,'
u' kreuze dieses Feld hier an.'),
_(u'Spätestens zu Veranstaltungsbeginn muss'
u' jedoch eine Mitgliedschaft bestehen.')
))
class Meta: class Meta:
model = Registration model = Registration
@@ -26,7 +30,7 @@ class RegistrationForm(forms.ModelForm):
'note': forms.Textarea(attrs={'rows': 5}), 'note': forms.Textarea(attrs={'rows': 5}),
} }
labels = { labels = {
'apply_reduced_fee': _('Ich bin noch keine 25 Jahre alt oder besitze einen "Karlsruher Pass".'), 'apply_reduced_fee': _(u'Ich bin noch keine 25 Jahre alt oder besitze einen "Karlsruher Pass".'),
} }
def clean_year_of_birth(self): def clean_year_of_birth(self):

View File

@@ -164,6 +164,13 @@ Anmerkung:
note=self.note, note=self.note,
) )
def get_data_dict(self):
data = {}
for field in self._meta.fields:
if not field.primary_key:
data[field.name] = getattr(self, field.name)
return data
def clean(self): def clean(self):
if self.dav_member and not self.dav_number: if self.dav_member and not self.dav_number:
raise ValidationError({'dav_number': _('Wenn du DAV Mitglied bist, brauchen wir deine Mitgliedsnummer.')}) raise ValidationError({'dav_number': _('Wenn du DAV Mitglied bist, brauchen wir deine Mitgliedsnummer.')})