from django.db import transaction, IntegrityError from django.contrib.auth.models import User 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) 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() @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) 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.")) 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: 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: 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"]: 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: 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"], 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"]: pk = field term = Terms.objects.get(id=pk) registration.accepted_terms.add(term) registration.cost = event.cost if event.max_cost is None or event.max_cost > 0: amount = event_registration["payment"]["amount"] if amount is None: raise ValidationError(_("The field 'Amount paid by you' is required.")) if amount < event.cost: voucher_amount = event.cost - amount discount = voucher_amount / event.cost * 100 voucher = Voucher.objects.create( person=person, event=event, used=True, discount=discount, ) 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)