Skip to content
Snippets Groups Projects
Commit 4c51ae20 authored by Tom Teichler's avatar Tom Teichler :beers:
Browse files

Merge branch 'master' into registration-mailing

parents aa7f7b9c 5f03d499
No related branches found
No related tags found
1 merge request!35Send notification on registration
Showing
with 879 additions and 733 deletions
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from aleksis.core.data_checks import DataCheck, IgnoreSolveOption, SolveOption
......
from django import forms
from django.forms import fields
from django.utils import dateformat, formats
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allauth.account.views import SignupForm
from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget
......@@ -461,7 +461,7 @@ class EditInfoMailingForm(forms.ModelForm):
layout = Layout(
Row("sender", "reply_to", "active"),
Row("send_to_person", "send_to_guardians"),
Row("send_to_person", "send_to_guardians", "send_to_retracted", "send_to_not_checked_in"),
Row("subject"),
Row("text"),
)
......@@ -507,11 +507,13 @@ class PersonGroupFormPerson(forms.Form):
class EventCheckpointForm(forms.Form):
class Media:
js = ("https://unpkg.com/html5-qrcode", "js/paweljong/qrscanner.js", "js/paweljong/checkpoint.js")
js = (
"https://unpkg.com/html5-qrcode",
"js/paweljong/qrscanner.js",
"js/paweljong/checkpoint.js",
)
layout = Layout(
"comment", "use_latlon", "username"
)
layout = Layout("comment", "use_latlon", "username")
comment = forms.CharField(
required=True,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
from datetime import datetime
from datetime import datetime, timedelta
from decimal import Decimal
from django.contrib.contenttypes.models import ContentType
......@@ -51,9 +51,12 @@ class InfoMailing(ExtensibleModel):
sender = models.EmailField(verbose_name=_("Sender"), blank=True)
send_to_person = models.BooleanField(verbose_name=_("Send to registered person"), default=True)
send_to_guardians = models.BooleanField(verbose_name=_("Send to guardians"), default=False)
send_to_retracted = models.BooleanField(verbose_name=_("Send to participants who retracted"), default=False)
send_to_not_checked_in = models.BooleanField(verbose_name=_("Send to participants who did not check in"), default=True)
send_to_retracted = models.BooleanField(
verbose_name=_("Send to participants who retracted"), default=False
)
send_to_not_checked_in = models.BooleanField(
verbose_name=_("Send to participants who did not check in"), default=True
)
def __str__(self) -> str:
return self.subject
......@@ -188,6 +191,14 @@ class Event(ExtensibleModel):
def get_absolute_url(self):
return reverse("event_by_name", kwargs={"slug": self.slug})
def individual_cost(self, request=None):
if request and request.user.is_authenticated and Voucher.objects.filter(event=self, person=request.user.person, used=False).exists():
voucher = Voucher.objects.get(event=self, person=request.user.person, used=False)
individual_cost = (100 - voucher.discount) * self.cost / 100
return individual_cost
else:
return self.cost
@property
def booked_percentage(self):
return self.linked_group.members.count() / self.max_participants * 100
......@@ -339,6 +350,7 @@ class EventRegistration(ExtensibleModel):
"number": f"HNF-{self.date_registered.strftime('%Y-%m')}-{self.id}",
"currency": "EUR",
"total": self._get_total_amount()[0],
"due_date": now().date() + timedelta(days=7),
"tax": self._get_total_amount()[1],
"description": _("Participation of {} in event {}").format(
self.person.addressing_name, self.event.display_name
......@@ -418,13 +430,28 @@ class EventRegistration(ExtensibleModel):
class Checkpoint(ExtensibleModel):
event = models.ForeignKey(Event, verbose_name=_("Related event"), related_name="checkpoints", on_delete=models.CASCADE)
person = models.ForeignKey(Person, verbose_name=_("Checked person"), related_name="event_checkpoints", on_delete=models.CASCADE)
checked_by = models.ForeignKey(Person, verbose_name=_("Checked by person"), related_name="event_checkpoints_created", on_delete=models.CASCADE)
event = models.ForeignKey(
Event, verbose_name=_("Related event"), related_name="checkpoints", on_delete=models.CASCADE
)
person = models.ForeignKey(
Person,
verbose_name=_("Checked person"),
related_name="event_checkpoints",
on_delete=models.CASCADE,
)
checked_by = models.ForeignKey(
Person,
verbose_name=_("Checked by person"),
related_name="event_checkpoints_created",
on_delete=models.CASCADE,
)
comment = models.CharField(max_length=60, verbose_name=_("Comment"))
timestamp = models.DateTimeField(verbose_name=_("Date and time of check"), auto_now_add=True)
lat = models.DecimalField(max_digits=10, decimal_places=8, verbose_name=_("Latitude of check"), blank=True, null=True)
lon = models.DecimalField(max_digits=11, decimal_places=8, verbose_name=_("Longitude of check"), blank=True, null=True)
lat = models.DecimalField(
max_digits=10, decimal_places=8, verbose_name=_("Latitude of check"), blank=True, null=True
)
lon = models.DecimalField(
max_digits=11, decimal_places=8, verbose_name=_("Longitude of check"), blank=True, null=True
)
......@@ -59,3 +59,12 @@ time.icon span {
#event-detail-table {
table-layout: fixed;
}
p {
margin-bottom: 1em;
}
p.important-info {
font-weight: bold;
color: red;
}
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables
from django_tables2.utils import A
......
......@@ -50,7 +50,7 @@
<tr>
<td><i class="material-icons small">money</i></td>
<td colspan="2">{% trans "Participation fee (all inclusive)" %}</td>
<td>{{ event.cost }}</td>
<td>{{ individual_cost }}</td>
</tr>
<tr>
<td><i class="material-icons small">group</i></td>
......
......@@ -34,7 +34,7 @@
<tr>
<td><i class="material-icons small">money</i></td>
<td colspan="2">{% trans "Participation fee (all inclusive)" %}</td>
<td>{{ event.cost }}</td>
<td>{{ individual_cost }}</td>
</tr>
<tr>
<td><i class="material-icons small">group</i></td>
......
......@@ -24,16 +24,24 @@
guardian).
{% endblocktrans %}
</p>
<p>
<p class="important-info">
{% blocktrans %}
We ask parents to not fill in the registration on behalf of their child.
It is a requirement that our participants can freely access and
manage their accounts and inboxes, and that parents allow their
children to keep their passwords secret. We kindly ask parents to
get in contact with us if they have questions about this rule,
and of course, we encourage all children to show everything they
do not understand or have questions about to their parents.
{% endblocktrans %}
</p>
<p>
{% blocktrans %}
Every participant needs a personal e-mail address. This address must be one
that you, the participating child, check and read yourself, not one owned by your
parents. Of course, we will always send important information to your parents as well.
parents. Of course, we will always send important information to your parents as
well, and of course you should always talk to your parents if you
have questions or concerns while reading your e-mail.
{% endblocktrans %}
</p>
<p>
......@@ -44,11 +52,11 @@
register an e-mail address with us.
{% endblocktrans %}
</p>
<p>
<p class="important-info">
{% blocktrans %}
If you already have a user account with Teckids, do not register a new one. Login
with your existing username and password. If you have forgotten your password, please
send us an e-mail (pelase do this yourself, with the help of your parents, if needed).
send us an e-mail (please do this yourself, with the help of your parents, if needed).
{% endblocktrans %}
</p>
</div>
......
......@@ -50,7 +50,11 @@ urlpatterns = [
),
path("event/<slug:slug>", views.EventFullView.as_view(), name="event_by_name"),
path("event/<slug:slug>/detail", views.EventDetailView.as_view(), name="event_detail_by_name"),
path("event/<slug:slug>/checkpoint", views.EventCheckpointView.as_view(), name="event_by_name_checkpoint"),
path(
"event/<slug:slug>/checkpoint",
views.EventCheckpointView.as_view(),
name="event_by_name_checkpoint",
),
path(
"event/<slug:slug>/start",
views.RegisterEventStart.as_view(),
......
......@@ -11,7 +11,7 @@ from django.utils import timezone
from django.utils.decorators import method_decorator
from django.utils.http import urlencode
from django.utils.text import slugify
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from django.views.decorators.cache import never_cache
from django.views.generic import FormView, TemplateView, View
from django.views.generic.detail import DetailView
......@@ -44,7 +44,15 @@ from .forms import (
RegistrationNotificationForm,
RegistrationStatesForm,
)
from .models import Checkpoint, Event, EventRegistration, InfoMailing, RegistrationState, Terms, Voucher
from .models import (
Checkpoint,
Event,
EventRegistration,
InfoMailing,
RegistrationState,
Terms,
Voucher,
)
from .tables import (
AdditionalFieldsTable,
ChildGroupsTable,
......@@ -149,7 +157,7 @@ class EventRegistrationCreateView(PermissionRequiredMixin, AdvancedCreateView):
form_class = EditEventRegistrationForm
permission_required = "paweljong.create_registration_rule"
template_name = "paweljong/event_registration/create.html"
success_url = reverse_lazy("registrations")
success_url = reverse_lazy("manage_events")
success_message = _("The event registration has been created.")
......@@ -340,6 +348,7 @@ class AccountRegisterWizardView(SessionWizardView):
cleaned_data_register = self.get_cleaned_data_for_step("register")
# Create email address
_email = None
if cleaned_data_email:
_email = MailAddress.objects.create(
local_part=cleaned_data_email["local_part"],
......@@ -382,6 +391,10 @@ class AccountRegisterWizardView(SessionWizardView):
context=context,
)
if _email:
_email.person = person
_email.save()
return redirect("index")
......@@ -522,6 +535,14 @@ class RegisterEventWizardView(SessionWizardView):
}
)
if step == "financial":
if getattr(self.request.user, "person", None):
vouchers = Voucher.objects.filter(
person=self.request.user.person, event__slug=self.kwargs["slug"], used=False
)
if vouchers:
initial.update({"voucher_code": vouchers.first().code})
return self.initial_dict.get(step, initial)
def done(self, form_list, **kwargs):
......@@ -536,13 +557,14 @@ class RegisterEventWizardView(SessionWizardView):
cleaned_data_consent = self.get_cleaned_data_for_step("consent")
if cleaned_data_financial["voucher_code"]:
vouchers = Voucher.objects.filter(
person=person, event=event, used=False, code=cleaned_data_financial["voucher_code"]
)
if vouchers:
voucher = vouchers.first()
else:
messages.error(self.request, _("You entered an invalid voucher code!"))
if getattr(self.request.user, "person", None):
vouchers = Voucher.objects.filter(
person=self.request.user.person, event=event, used=False, code=cleaned_data_financial["voucher_code"]
)
if vouchers:
voucher = vouchers.first()
else:
messages.error(self.request, _("You entered an invalid voucher code!"))
# Create email address
if cleaned_data_email:
......@@ -707,6 +729,8 @@ class EventFullView(PermissionRequiredMixin, DetailView):
context["can_register"] = context["event"].can_register(request=self.request)
context["is_authenticated"] = self.request.user.is_authenticated
context["individual_cost"] = context["event"].individual_cost(request=self.request)
return context
......@@ -1020,12 +1044,21 @@ class EventCheckpointView(PermissionRequiredMixin, FormView):
checkpoint.lon = form.cleaned_data["lon"]
checkpoint.save()
messages.success(self.request, _("{} successfully checked for {}.").format(str(checkpoint.person), str(checkpoint.comment)))
messages.success(
self.request,
_("{} successfully checked for {}.").format(
str(checkpoint.person), str(checkpoint.comment)
),
)
self._comment = checkpoint.comment
return super().form_valid(self)
def get_success_url(self):
return reverse("event_by_name_checkpoint", kwargs={"slug": self.kwargs["slug"]}) + "?" + urlencode({"comment": self._comment})
return (
reverse("event_by_name_checkpoint", kwargs={"slug": self.kwargs["slug"]})
+ "?"
+ urlencode({"comment": self._comment})
)
class ViewTerms(PermissionRequiredMixin, DetailView):
......
[tool.poetry]
name = "AlekSIS-App-Paweljong"
version = "1.11"
version = "1.12.5"
packages = [
{ include = "aleksis" }
]
......@@ -25,9 +25,9 @@ secondary = true
[tool.poetry.dependencies]
python = "^3.9"
aleksis-core = "^2.8.1"
aleksis-core = "^2.12.2"
django-iban-field = "^0.8"
django-formtools = "^2.3"
django-formtools = "2.3"
django-starfield = "^1.0"
aleksis-app-postbuero = "1.0+20220218233830.a212f707"
aleksis-app-tezor = "^1.0"
......
......@@ -10,7 +10,7 @@ skip_install = true
envdir = {toxworkdir}/globalenv
commands_pre =
poetry install
poetry run aleksis-admin yarn install
poetry run aleksis-admin webpack_bundle
poetry run aleksis-admin collectstatic --no-input
commands =
poetry run pytest --cov=. {posargs} aleksis/
......@@ -49,13 +49,13 @@ commands =
[testenv:makemessages]
commands =
poetry run aleksis-admin makemessages --no-wrap -e html,txt,py,email -i static -l ar -l de_DE -l fr -l nb_NO -l tr_TR -l la
poetry run aleksis-admin makemessages --no-wrap -d djangojs -i **/node_modules -l ar -l de_DE -l fr -l nb_NO -l tr_TR -l la
poetry run aleksis-admin makemessages --no-wrap -e html,txt,py,email -i static -l ar -l de_DE -l fr -l nb_NO -l tr_TR -l la -l uk -l ru
poetry run aleksis-admin makemessages --no-wrap -d djangojs -i **/node_modules -l ar -l de_DE -l fr -l nb_NO -l tr_TR -l la -l uk -l ru
[flake8]
max_line_length = 100
exclude = migrations,tests
ignore = BLK100,E203,E231,E266,W503,D100,D101,D102,D103,D104,D105,D106,D107,RST215,RST214,F821,F841,S106,T100,T101,DJ05
ignore = BLK100,E203,E231,W503,D100,D101,D102,D103,D104,D105,D106,D107,RST215,RST214,F821,F841,S106,T100,T101,DJ05
[isort]
profile = black
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment