mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-11-04 11:03:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			200 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import secrets
 | 
						|
from typing import Any
 | 
						|
 | 
						|
from django import forms
 | 
						|
from django.conf import settings
 | 
						|
from django.core.exceptions import ValidationError
 | 
						|
from django.utils.translation import gettext_lazy as _
 | 
						|
 | 
						|
from core.models import User
 | 
						|
from core.views.forms import SelectDate, SelectDateTime
 | 
						|
from core.views.widgets.ajax_select import AutoCompleteSelectUser
 | 
						|
from subscription.models import Subscription
 | 
						|
 | 
						|
 | 
						|
class SelectionDateForm(forms.Form):
 | 
						|
    def __init__(self, *args, **kwargs):
 | 
						|
        super().__init__(*args, **kwargs)
 | 
						|
        self.fields["start_date"] = forms.DateTimeField(
 | 
						|
            label=_("Start date"), widget=SelectDateTime, required=True
 | 
						|
        )
 | 
						|
        self.fields["end_date"] = forms.DateTimeField(
 | 
						|
            label=_("End date"), widget=SelectDateTime, required=True
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
class SubscriptionForm(forms.ModelForm):
 | 
						|
    allowed_payment_methods = ["CARD", "CASH", "AE_ACCOUNT"]
 | 
						|
 | 
						|
    class Meta:
 | 
						|
        model = Subscription
 | 
						|
        fields = ["subscription_type", "payment_method", "location"]
 | 
						|
        widgets = {"payment_method": forms.RadioSelect}
 | 
						|
 | 
						|
    def __init__(self, *args, initial=None, **kwargs):
 | 
						|
        initial = initial or {}
 | 
						|
        if "subscription_type" not in initial:
 | 
						|
            initial["subscription_type"] = "deux-semestres"
 | 
						|
        if "payment_method" not in initial:
 | 
						|
            initial["payment_method"] = "CARD"
 | 
						|
        super().__init__(*args, initial=initial, **kwargs)
 | 
						|
        self.fields["payment_method"].choices = [
 | 
						|
            m
 | 
						|
            for m in settings.SITH_SUBSCRIPTION_PAYMENT_METHOD
 | 
						|
            if m[0] in self.allowed_payment_methods
 | 
						|
        ]
 | 
						|
        self.fields["location"].choices = [
 | 
						|
            m for m in settings.SITH_SUBSCRIPTION_LOCATIONS if m[0] != "EBOUTIC"
 | 
						|
        ]
 | 
						|
 | 
						|
    def save(self, *args, **kwargs):
 | 
						|
        if self.errors:
 | 
						|
            # let django deal with the error messages
 | 
						|
            return super().save(*args, **kwargs)
 | 
						|
 | 
						|
        duration, user = self.instance.semester_duration, self.instance.member
 | 
						|
        self.instance.subscription_start = self.instance.compute_start(
 | 
						|
            duration=duration, user=user
 | 
						|
        )
 | 
						|
        self.instance.subscription_end = self.instance.compute_end(
 | 
						|
            duration=duration, start=self.instance.subscription_start, user=user
 | 
						|
        )
 | 
						|
        return super().save(*args, **kwargs)
 | 
						|
 | 
						|
 | 
						|
class SubscriptionNewUserForm(SubscriptionForm):
 | 
						|
    """Form to create subscriptions with the user they belong to.
 | 
						|
 | 
						|
    Examples:
 | 
						|
        ```py
 | 
						|
        assert not User.objects.filter(email=request.POST.get("email")).exists()
 | 
						|
        form = SubscriptionNewUserForm(request.POST)
 | 
						|
        if form.is_valid():
 | 
						|
            form.save()
 | 
						|
 | 
						|
        # now the user exists and is subscribed
 | 
						|
        user = User.objects.get(email=request.POST.get("email"))
 | 
						|
        assert user.is_subscribed
 | 
						|
    """
 | 
						|
 | 
						|
    allowed_payment_methods = ["CARD", "CASH"]
 | 
						|
    template_name = "subscription/forms/create_new_user.jinja"
 | 
						|
 | 
						|
    __user_fields = forms.fields_for_model(
 | 
						|
        User,
 | 
						|
        ["first_name", "last_name", "email", "date_of_birth"],
 | 
						|
        widgets={"date_of_birth": SelectDate},
 | 
						|
    )
 | 
						|
    first_name = __user_fields["first_name"]
 | 
						|
    last_name = __user_fields["last_name"]
 | 
						|
    email = __user_fields["email"]
 | 
						|
    date_of_birth = __user_fields["date_of_birth"]
 | 
						|
 | 
						|
    field_order = [
 | 
						|
        "first_name",
 | 
						|
        "last_name",
 | 
						|
        "email",
 | 
						|
        "date_of_birth",
 | 
						|
        "subscription_type",
 | 
						|
        "payment_method",
 | 
						|
        "location",
 | 
						|
    ]
 | 
						|
 | 
						|
    def clean_email(self):
 | 
						|
        email = self.cleaned_data["email"]
 | 
						|
        if User.objects.filter(email=email).exists():
 | 
						|
            raise ValidationError(_("A user with that email address already exists"))
 | 
						|
        return email
 | 
						|
 | 
						|
    def clean(self) -> dict[str, Any]:
 | 
						|
        """Initialize the [User][core.models.User] linked to this subscription.
 | 
						|
 | 
						|
        Warning:
 | 
						|
            The `User` is initialized, but not saved.
 | 
						|
            Don't use it for operations that expect
 | 
						|
            a persisted object.
 | 
						|
        """
 | 
						|
        member = User(
 | 
						|
            first_name=self.cleaned_data.get("first_name"),
 | 
						|
            last_name=self.cleaned_data.get("last_name"),
 | 
						|
            email=self.cleaned_data.get("email"),
 | 
						|
            date_of_birth=self.cleaned_data.get("date_of_birth"),
 | 
						|
        )
 | 
						|
        if self.cleaned_data.get("subscription_type") in [
 | 
						|
            "un-semestre",
 | 
						|
            "deux-semestres",
 | 
						|
            "cursus-tronc-commun",
 | 
						|
            "cursus-branche",
 | 
						|
        ]:
 | 
						|
            member.role = "STUDENT"
 | 
						|
        member.generate_username()
 | 
						|
        member.set_password(secrets.token_urlsafe(nbytes=10))
 | 
						|
        self.instance.member = member
 | 
						|
        return super().clean()
 | 
						|
 | 
						|
    def save(self, *args, **kwargs):
 | 
						|
        if self.errors:
 | 
						|
            # let django deal with the error messages
 | 
						|
            return super().save(*args, **kwargs)
 | 
						|
        self.instance.member.save()
 | 
						|
        return super().save(*args, **kwargs)
 | 
						|
 | 
						|
 | 
						|
class SubscriptionExistingUserForm(SubscriptionForm):
 | 
						|
    """Form to add a subscription to an existing user."""
 | 
						|
 | 
						|
    template_name = "subscription/forms/create_existing_user.jinja"
 | 
						|
    required_css_class = "required"
 | 
						|
 | 
						|
    birthdate = forms.fields_for_model(
 | 
						|
        User,
 | 
						|
        ["date_of_birth"],
 | 
						|
        widgets={"date_of_birth": SelectDate(attrs={"hidden": True})},
 | 
						|
        help_texts={"date_of_birth": _("This user didn't fill its birthdate yet.")},
 | 
						|
    )["date_of_birth"]
 | 
						|
 | 
						|
    class Meta(SubscriptionForm.Meta):
 | 
						|
        fields = ["member", *SubscriptionForm.Meta.fields]
 | 
						|
        widgets = SubscriptionForm.Meta.widgets | {"member": AutoCompleteSelectUser}
 | 
						|
 | 
						|
    field_order = [
 | 
						|
        "member",
 | 
						|
        "birthdate",
 | 
						|
        "subscription_type",
 | 
						|
        "payment_method",
 | 
						|
        "location",
 | 
						|
    ]
 | 
						|
 | 
						|
    def __init__(self, *args, initial=None, **kwargs):
 | 
						|
        super().__init__(*args, initial=initial, **kwargs)
 | 
						|
        self.fields["birthdate"].required = True
 | 
						|
        if not initial:
 | 
						|
            return
 | 
						|
        member: str | None = initial.get("member")
 | 
						|
        if member and member.isdigit():
 | 
						|
            member: User | None = User.objects.filter(id=int(member)).first()
 | 
						|
        else:
 | 
						|
            member = None
 | 
						|
        if member and member.date_of_birth:
 | 
						|
            # if there is an initial member with a birthdate,
 | 
						|
            # there is no need to ask this to the user
 | 
						|
            self.fields["birthdate"].initial = member.date_of_birth
 | 
						|
        elif member:
 | 
						|
            # if there is an initial member without a birthdate,
 | 
						|
            # then the field must be displayed
 | 
						|
            self.fields["birthdate"].widget.attrs.update({"hidden": False})
 | 
						|
        # if there is no initial member, it means that it will be
 | 
						|
        # dynamically selected using the AutoCompleteSelectUser widget.
 | 
						|
        # JS will take care of un-hiding the field if necessary
 | 
						|
 | 
						|
    def save(self, *args, **kwargs):
 | 
						|
        if self.errors:
 | 
						|
            return super().save(*args, **kwargs)
 | 
						|
        if (
 | 
						|
            self.cleaned_data["birthdate"] is not None
 | 
						|
            and self.instance.member.date_of_birth is None
 | 
						|
        ):
 | 
						|
            self.instance.member.date_of_birth = self.cleaned_data["birthdate"]
 | 
						|
            self.instance.member.save()
 | 
						|
        return super().save(*args, **kwargs)
 |