import secrets from typing import Any from django import forms 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.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): def __init__(self, *args, **kwargs): initial = kwargs.pop("initial", {}) 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) 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 """ __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"] class Meta: model = Subscription fields = ["subscription_type", "payment_method", "location"] 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]: 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"), ) 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.""" class Meta: model = Subscription fields = ["member", "subscription_type", "payment_method", "location"] widgets = {"member": AutoCompleteSelectUser}