from django import forms from django.forms import fields from django.utils import dateformat, formats from django.utils.translation import gettext_lazy as _ from allauth.account.views import SignupForm from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget from material import Fieldset, Layout, Row from phonenumber_field.formfields import PhoneNumberField from aleksis.apps.tezor.models.base import Client from aleksis.apps.tezor.models.invoice import InvoiceGroup from aleksis.core.mixins import ExtensibleForm from aleksis.core.models import Group, Person from .models import Event, EventRegistration, InfoMailing, RegistrationState, Terms, Voucher COMMENT_CHOICES = [ ("first", _("Only first name")), ("first_age", _("First name and age")), ("first_last_age", _("First name, last name and age")), ] TEMPLATE_CHOICES = [ ("list_sign", _("Signature list")), ("list_participants", _("Participants list")), ("corona", _("Corona attendance list")), ] LICENCE_CHOICES = [ ("CC-BY-4.0+", _("Creative Commons with attribution, 4.0 or later")), ( "CC-BY-SA-4.0+", _( "Creative Commons with attribution and distribution only " "under the same conditions, 4.0 or later" ), ), ] class EditEventForm(ExtensibleForm): """Form to create or edit an event.""" layout = Layout( Fieldset( _("Base data"), "linked_group", Row("display_name", "slug", "description"), Row("place", "published"), Fieldset(_("Date data"), Row("date_event", "date_registration", "date_retraction")), Fieldset(_("Event details"), Row("cost", "max_participants"), "information"), Fieldset(_("Terms"), "terms"), Fieldset(_("Info mailings"), "info_mailings"), ), ) class Meta: model = Event fields = [ "linked_group", "display_name", "description", "slug", "place", "published", "date_event", "date_registration", "date_retraction", "cost", "max_participants", "terms", "information", "info_mailings", ] widgets = { "linked_group": ModelSelect2Widget( search_fields=["name__icontains"], attrs={"data-minimum-input-length": 0, "class": "browser-default"}, ), "terms": ModelSelect2MultipleWidget( search_fields=["aspect__icontains"], attrs={"data-minimum-input-length": 0, "class": "browser-default"}, ), "info_mailings": ModelSelect2MultipleWidget( search_fields=["subject__icontains"], attrs={"data-minimum-input-length": 0, "class": "browser-default"}, ), } class EditVoucherForm(forms.ModelForm): """Form to edit and create vouchers.""" class Meta: model = Voucher exclude = ["code", "used_person_uid", "used", "deleted"] # noqa widgets = { "event": ModelSelect2Widget( search_fields=["display_name__icontains"], attrs={"data-minimum-input-length": 0, "class": "browser-default"}, ), "person": ModelSelect2Widget( search_fields=["first_name__icontains", "last_name__icontains"], attrs={"data-minimum-input-length": 0, "class": "browser-default"}, ), } help_texts = { "event": _("Event the voucher is valid for"), "person": _("Person the voucher is valid for"), "discount": _("Voucher discount"), } class GenerateListForm(forms.Form): """Form to create a list of participants of a group.""" group = forms.ModelChoiceField( label=_("Group"), queryset=Group.objects.all(), help_text=_("Select group to generate list"), ) template = forms.ChoiceField( label=_("Template"), choices=TEMPLATE_CHOICES, help_text=_("Select template to generate list"), ) landscape = forms.BooleanField( label=_("Landscape"), help_text=_("Select if output should be in landscape"), required=False, ) class RegisterEventGuardians(ExtensibleForm): class Meta: model = EventRegistration fields = [] layout = Layout( Fieldset( _("Guardians personal data"), Row("guardian_first_name", "guardian_last_name"), ), Fieldset( _("Guardians contact details"), Row("guardian_email", "guardian_mobile_number"), ), ) guardian_first_name = forms.CharField( label=_("Guardian's first name"), help_text=_( "Please enter the first name of the legal guardian who will fill in the registration " "with you and who can be reached during the event in an emergency." ), ) guardian_last_name = forms.CharField( label=_("Guardian's last name"), help_text=_( "Please enter the last name of the legal guardian who will fill in the registration " "with you and who can be reached during the event in an emergency." ), ) guardian_mobile_number = PhoneNumberField( label=_("Guardian's mobile number"), help_text=_( "We need the mobile phone number for emergencies if we " "urgently need to reach your parents during the event." ), ) guardian_email = forms.EmailField( label=_("Guardian's email address"), ) class RegisterEventContactDetails(ExtensibleForm): class Meta: model = Group fields = [] layout = Layout( Fieldset( _("Personal data"), Row("first_name", "last_name"), Row("date_of_birth", "sex"), ), Fieldset( _("Address data"), Row("street", "housenumber"), Row("postal_code", "place"), ), Fieldset( _("Contact details"), Row("mobile_number", "email"), ), Fieldset( _("School details"), Row("school", "school_place", "school_class"), ), ) first_name = forms.CharField( label=_("First name"), disabled=True, ) last_name = forms.CharField( label=_("Last name"), disabled=True, ) street = forms.CharField( label=_("Street"), ) housenumber = forms.CharField( label=_("Housenumber"), ) postal_code = forms.CharField( label=_("Postal code"), ) place = forms.CharField( label=_("Place"), ) mobile_number = PhoneNumberField( label=_("Mobile number"), required=False, help_text=_( "Your mobile number helps us to reach you in an emergency during the event, e.g. " "if you are alone with your group at a conference or similar. If you don't have a " "cell phone, you can leave the field blank." ), ) date_of_birth = forms.DateField( label=_("Date of birth"), ) sex = forms.ChoiceField( label=_("Sex"), help_text=_( "For various reasons, e.g. because we have to keep gender segregation during the night " "for legal reasons, we need to know if you are a boy or a girl." ), choices=Person.SEX_CHOICES, initial=None, ) email = forms.EmailField( label=_("Email address"), help_text=_( "Please use your personal e-mail address here, which you will check " "personally. Important information will always be sent to your parents " "as well. Do not use an e-mail address owned by your parents here." ), ) school = forms.CharField( label=_("School"), help_text=_("Please enter the name of your school."), ) school_place = forms.CharField( label=_("School place"), help_text=_("Enter the place (city) where your school is located."), ) school_class = forms.CharField( label=_("School class"), help_text=_("Please enter the class you are in (e.g. 8a)."), ) class RegisterEventAdditional(ExtensibleForm): layout = Layout( Fieldset( _("Medical information / intolerances"), Row("medical_information"), ), Fieldset( _("Other remarks"), Row("comment"), ), ) class Meta: model = EventRegistration fields = ["medical_information", "comment"] help_texts = { "medical_information": _( "If there are any medically important things we need to " "consider, e.g. when making food or to make sure you take " "prescribed medication, please enter it here." ), "comment": _("You can write down any remarks you want to tell us here."), } def __init__(self, event, *args, **kwargs): super().__init__(*args, **kwargs) self.__class__.layout_filled = getattr(self.__class__, "layout_filled", False) for field in event.additional_fields.all(): field_instance = getattr(fields, field.field_type)( required=field.required, help_text=field.help_text, ) self.fields[field.title] = field_instance if not self.layout_filled: node = Fieldset(f"{field.title}", f"{field.title}") self.add_node_to_layout(node) self.__class__.layout_filled = True class RegisterEventFinancial(ExtensibleForm): """Form to register for an event.""" layout = Layout( Fieldset( _("Financial data"), "payment_method", Row("voucher_code", "donation"), ), ) voucher_code = forms.CharField( label=_("Voucher code"), help_text=_("If you have a voucher code, type it in here."), required=False, ) payment_method = forms.ChoiceField( label=_("Payment method"), help_text=_( "Please choose a payment method. " "The actual payment will be made after the registration." ), ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # FIXME Maybe do not hard-code this client, __ = Client.objects.get_or_create(name="Teckids e.V.") group, __ = InvoiceGroup.objects.get_or_create( name="Hack'n'Fun-Veranstaltungen", client=client, defaults={ "template_name": "paweljong/invoice_pdf.html", }, ) self.fields["payment_method"].choices = group.get_variant_choices() class Meta: model = EventRegistration fields = ["voucher_code", "donation"] help_texts = { "donation": _( "Our association would like to offer all children and young " "people the opportunity to participate in our events. Sometimes, " "however, families cannot afford the full fee. We therefore have a " "budget from which we can promote participation after we have " "carefully examined the necessity and eligibility. We rely on " "donations for this budget. If you would like to donate a voluntary " "additional amount for this budget, please indicate this here." ), } class RegisterEventConsent(ExtensibleForm): class Meta: model = EventRegistration fields = [] def __init__(self, event, *args, **kwargs): super().__init__(*args, **kwargs) for field in event.terms.all(): field_instance = forms.BooleanField( required=True, label=field.confirmation_text, ) self.fields[f"consent_{field.pk}"] = field_instance node = f"consent_{field.pk}" self.add_node_to_layout(node) if event.date_retraction: field_instance = forms.BooleanField( required=True, label=_( "I confirm that the retraction of the registration is not possible anymore " "after {}" ).format( dateformat.format(event.date_retraction, formats.get_format("DATE_FORMAT")) ), ) self.fields["retraction_deadline"] = field_instance node = "retraction_deadline" self.add_node_to_layout(node) class EditEventRegistrationForm(forms.ModelForm): layout = Layout( Row("event", "person"), Row("comment", "medical_information"), "voucher", Row("donation"), "accepted_terms", Row("school", "school_class", "school_place"), "states", ) class Meta: model = EventRegistration exclude = [] # noqa class EditTermForm(forms.ModelForm): class Meta: model = Terms exclude = [] # noqa class RegisterEventAccount(SignupForm, ExtensibleForm): """Form to register new user accounts.""" class Meta: model = EventRegistration fields = [] layout = Layout( Fieldset( _("Base data"), Row("first_name", "last_name", "date_of_birth"), ), Fieldset( _("Account data"), "username", Row("email", "email2"), Row("password1", "password2"), ), ) first_name = forms.CharField(label=_("First name")) last_name = forms.CharField(label=_("Last name")) date_of_birth = forms.DateField(label=_("Date of birth")) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["username"].help_text = _( "The username must only contain lower case letters and numbers, " "and must begin with a letter." ) class EditInfoMailingForm(forms.ModelForm): layout = Layout( Row("sender", "reply_to", "active"), Row("send_to_person", "send_to_guardians", "send_to_retracted", "send_to_not_checked_in"), Row("subject"), Row("text"), ) class Meta: model = InfoMailing exclude = ["sent_to"] # noqa class RegistrationNotificationForm(forms.ModelForm): layout = Layout( Row("sender", "reply_to"), Row("send_to_person", "send_to_guardians"), Row("subject"), Row("text"), ) class Meta: model = InfoMailing exclude = ["sent_to", "active"] # noqa class RegistrationStatesForm(forms.ModelForm): class Meta: model = RegistrationState exclude = [] # noqa class PersonGroupFormPerson(forms.Form): class Media: js = ("https://unpkg.com/html5-qrcode", "js/paweljong/qrscanner.js") layout = Layout("username") username = forms.CharField( required=True, label=_("Person"), widget=forms.TextInput(attrs={"autofocus": "", "autocomplete": "off"}), help_text=_("Please enter a username."), ) class EventCheckpointForm(forms.Form): class Media: js = ( "https://unpkg.com/html5-qrcode", "js/paweljong/qrscanner.js", "js/paweljong/checkpoint.js", ) layout = Layout("comment", "use_latlon", "username") comment = forms.CharField( required=True, label=_("Comment"), help_text=_("Please enter a comment describing the checkpoint (e.g. Dinner)."), ) username = forms.CharField( required=True, label=_("Person"), help_text=_("Please enter a username."), widget=forms.TextInput(attrs={"autofocus": "", "autocomplete": "off"}), ) use_latlon = forms.BooleanField( required=False, label=_("Submit geolocation"), initial=True, ) lat = forms.DecimalField( required=False, min_value=-90.0, max_value=90.0, max_digits=10, decimal_places=8, widget=forms.HiddenInput(), ) lon = forms.DecimalField( required=False, min_value=-180.0, max_value=180.0, max_digits=11, decimal_places=8, widget=forms.HiddenInput(), )