@@ -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>
|
||||||
|
|
||||||
|
{% 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 %}
|
||||||
|
|
||||||
<span class="text-success"><strong>{% if participant.apply_reduced_fee %}%{% else %} {% 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 %}
|
||||||
|
|
||||||
<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 %} {% 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 %}
|
||||||
|
|
||||||
<span class="text-danger"><strong>{% if participant.apply_reduced_fee %}%{% elif participant.created_at|date:'U' < '1608764400' %}? {% else %} {% 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 %}
|
||||||
|
|
||||||
<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 %} {% 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> </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 %}
|
||||||
|
|
||||||
<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 %} {% 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 %}
|
||||||
|
|
||||||
<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 %} {% 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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
{% if event.charge and participant.paid %}
|
{% if event.charge and participant.paid %}
|
||||||
<span class="text-success"><strong>{% if participant.apply_reduced_fee %}%{% else %} {% 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>
|
||||||
|
|
||||||
({{ 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 %} {% 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>
|
||||||
|
|
||||||
({{ 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> </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>
|
||||||
|
|||||||
@@ -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'))
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}),
|
||||||
|
|||||||
8
dav_events/forms/registration.py
Normal file
8
dav_events/forms/registration.py
Normal 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'))
|
||||||
35
dav_events/migrations/0039_auto_20201215_1155.py
Normal file
35
dav_events/migrations/0039_auto_20201215_1155.py
Normal 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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
35
dav_events/migrations/0040_auto_20201216_1712.py
Normal file
35
dav_events/migrations/0040_auto_20201216_1712.py
Normal 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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -40,11 +40,9 @@
|
|||||||
{% bootstrap_icon 'remove' %} 
|
{% bootstrap_icon 'remove' %} 
|
||||||
{% 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' %} 
|
{% bootstrap_icon 'hdd' %} 
|
||||||
{% trans 'Als Entwurf speichern' %}
|
{% trans 'Als Entwurf speichern' %}
|
||||||
</button>
|
</button>
|
||||||
-->
|
|
||||||
{% endbuttons %}
|
{% endbuttons %}
|
||||||
{% endblock form-buttons %}
|
{% endblock form-buttons %}
|
||||||
|
|||||||
@@ -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 %}
|
||||||
|
|
||||||
<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 %}
|
||||||
|
|
||||||
<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 %}
|
||||||
|
|
||||||
<span class="text-success"><strong>{% if participant.apply_reduced_fee %}%{% else %} {% 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 %}
|
||||||
|
|
||||||
<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 %} {% 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 %}
|
||||||
|
|
||||||
<span class="text-danger"><strong>{% if participant.apply_reduced_fee %}%{% else %} {% 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 %}
|
||||||
|
|
||||||
<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 %} {% 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 %} {% 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 %}
|
||||||
|
|
||||||
<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 %} {% 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 %}
|
||||||
|
|
||||||
<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 %} {% 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>
|
||||||
|
|
||||||
|
|||||||
45
dav_events/templates/dav_events/registration_response.html
Normal file
45
dav_events/templates/dav_events/registration_response.html
Normal 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 %}
|
||||||
@@ -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'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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.')})
|
||||||
|
|||||||
Reference in New Issue
Block a user