Skip to content
Snippets Groups Projects
event_registration.py 9.26 KiB
Newer Older
from django.db import transaction, IntegrityError
from django.contrib.auth.models import User
magicfelix's avatar
magicfelix committed
from django.core.exceptions import ValidationError
from django.utils.text import slugify
from django.utils.translation import gettext as _

import graphene
from graphene_django import DjangoObjectType
from templated_email import send_templated_mail
from aleksis.apps.postbuero.models import MailAddress, MailDomain
from aleksis.apps.postbuero.schema import MailAddressInputType
from aleksis.core.models import Activity, Person
from aleksis.core.schema.base import PermissionsTypeMixin
from aleksis.core.schema.person import PersonInputType
from aleksis.core.schema.user import UserInputType
from aleksis.core.util.core_helpers import get_site_preferences
from ..models import Event, EventRegistration, Terms, Voucher


class EventRegistrationType(PermissionsTypeMixin, DjangoObjectType):
    class Meta:
        model = EventRegistration


class PaymentInputType(graphene.InputObjectType):
    payment_method = graphene.String(required=True)
    voucher_code = graphene.String(required=False)
magicfelix's avatar
magicfelix committed
    amount = graphene.Int(required=False) # FIXME: Fix frontend to allow 0, then make field required again
class EventRegistrationInputType(graphene.InputObjectType):
    email = graphene.Field(MailAddressInputType, required=False)
    person = graphene.Field(PersonInputType, required=False)
    user = graphene.Field(UserInputType, required=False)
    school = graphene.String(required=False)
    school_place = graphene.String(required=False)
    school_class = graphene.String(required=False)
    payment = graphene.Field(PaymentInputType, required=False)
    medical_information = graphene.String(required=False)
    comment = graphene.String(required=False)
    additional_fields = graphene.JSONString(required=False)
    terms = graphene.JSONString(required=False)
    retraction_consent = graphene.Boolean(required=True)


class SendEventRegistrationMutation(graphene.Mutation):
    class Arguments:
        event = graphene.ID(required=True)
        event_registration = EventRegistrationInputType(required=True)

    ok = graphene.Boolean()

magicfelix's avatar
magicfelix committed
    @transaction.atomic
    def mutate(self, info, event: graphene.ID, event_registration: EventRegistrationInputType, **kwargs):
        if not event_registration["retraction_consent"]:
            raise ValidationError(_("Retraction consent is required"))
        event = Event.objects.get(pk=event)
magicfelix's avatar
magicfelix committed
        email = None

        if event_registration["email"] is not None:
            try:
                domain = MailDomain.objects.get(pk=event_registration["email"]["domain"])
            except IntegrityError:
                raise ValidationError(_("Mail domain does not exist."))
            try:
                _mail_address = MailAddress.objects.create(
                    local_part=event_registration["email"]["local_part"],
                    domain=domain,
                )
            except IntegrityError:
                raise ValidationError(_("Mail address already in use."))

magicfelix's avatar
magicfelix committed
            email = str(_mail_address)
        elif event_registration["user"] is not None:
            email = event_registration["user"]["email"]

        # Create user
        if event_registration["user"] is not None:
            try:
                user = User.objects.create(
                    username=event_registration["user"]["username"],
                    email=event_registration["user"]["email"],
                )
            except IntegrityError:
                raise ValidationError(_("A user with this username or e-mail already exists."))

            user.set_password(event_registration["user"]["password"])
            user.save()
        else:
Hangzhi Yu's avatar
Hangzhi Yu committed
            user = info.context.user
        try:
            person, created = Person.objects.get_or_create(
                user=user,
                defaults={
                    "email": email,
                    "first_name": event_registration["person"]["first_name"],
                    "last_name": event_registration["person"]["last_name"],
                },
            )
        except IntegrityError:
magicfelix's avatar
magicfelix committed
            raise ValidationError(_("A person using the e-mail address %s already exists.") % email)

        # Store contact information in database
        for field_name in ["date_of_birth", "sex", "address", "mobile_number"]:
magicfelix's avatar
magicfelix committed
            if event_registration["person"] is not None and event_registration["person"][field_name] is not None and event_registration["person"][field_name] != "":
                if field_name == "address":
                    for addr_field in ["street", "housenumber", "postal_code", "place"]:
                        setattr(person, addr_field, event_registration["person"]["address"][addr_field])
                else:
                    setattr(person, field_name, event_registration["person"][field_name])
        person.save()

        if event_registration["person"] is not None:
            for guardian_data in event_registration["person"]["guardians"]:
                if "id" in guardian_data:
                    guardian = Person.objects.get(pk=guardian_data["id"])
                    guardian.first_name=guardian_data["first_name"]
                    guardian.last_name=guardian_data["last_name"]
                    guardian.email=guardian_data["email"]
                    guardian.mobile_number=guardian_data["mobile_number"]
                    
                    guardian.save()
                else:
                    try:
                        guardian, created = Person.objects.get_or_create(
                            defaults={
                                "mobile_number": guardian_data["mobile_number"],
                            },
                            first_name=guardian_data["first_name"],
                            last_name=guardian_data["last_name"],
                            email=guardian_data["email"],
                        )
                    except IntegrityError:
magicfelix's avatar
magicfelix committed
                        raise ValidationError(_("A person using the e-mail address %s already exists.") % guardian_data["email"])

                    person.guardians.add(guardian)
            person.save()

        if event_registration["email"] is not None:
            _mail_address.person = person
            _mail_address.save()

        school_details = {}
        for field_name in ["school", "school_class", "school_place"]:
            if event_registration[field_name] is not None:
                school_details[field_name] = event_registration[field_name]

        registration = EventRegistration.objects.create(
            managed_by_app_label="",
            event=event,
            person=person,
            medical_information=event_registration["medical_information"],
magicfelix's avatar
magicfelix committed
            donation=0,
            **school_details,
        )
        for field in event.additional_fields.all():
            if hasattr(event_registration["additional_fields"], str(field.id)):
                registration.extended_data[
                    slugify(field.title).replace("-", "_")
                ] = event_registration["additional_fields"][str(field.id)]

        for field in event_registration["terms"]:
magicfelix's avatar
magicfelix committed
            pk = field
            term = Terms.objects.get(id=pk)
            registration.accepted_terms.add(term)

        registration.cost = event.cost

magicfelix's avatar
magicfelix committed
        if event.max_cost is None or event.max_cost > 0:
magicfelix's avatar
magicfelix committed
            amount = event_registration["payment"]["amount"]
magicfelix's avatar
magicfelix committed
            if amount is None:
                raise ValidationError(_("The field 'Amount paid by you' is required."))

            if amount < event.cost:
                voucher_amount = event.cost - amount
magicfelix's avatar
magicfelix committed
                discount = voucher_amount / event.cost * 100
                voucher = Voucher.objects.create(
                    person=person,
                    event=event,
                    used=True,
                    discount=discount,
                )
magicfelix's avatar
magicfelix committed
                registration.voucher = voucher
            elif amount > event.cost:
                registration.donation = amount - event.cost

            # TODO Implement existing voucher handling

            invoice = registration.get_invoice()
            if amount == 0:
                invoice.variant = "pledge"
            else:
                invoice.variant = event_registration["payment"]["payment_method"]
                if invoice.variant == "" or invoice.variant is None:
                    raise ValidationError(_("The field 'Payment method' is required."))
            invoice.save()

        registration.save()

        context = {}
        context["registration"] = registration

#        send_templated_mail(
#            template_name="event_registered",
#            from_email=get_site_preferences()["mail__address"],
#            recipient_list=[get_site_preferences()["paweljong__event_notification_recipient"]],
#            headers={
#                "reply_to": [
#                    person.email,
#                    person.guardians.first().email,
#                ],
#                "X-Zammad-Customer-Email": person.email,
#            },
#            context=context,
#        )

        _act = Activity(
            title=_("You registered for an event"),
            description=_("You registered for the event %s" % event.display_name),
            app="Paweljong",
            user=person,
        )

        return SendEventRegistrationMutation(ok=True)