Source code for organisations.forms
import datetime
import PIL
import bleach
from crispy_forms.helper import FormHelper
from django import forms
from django.core.validators import MinValueValidator
from django.forms import formset_factory
from django_summernote.widgets import SummernoteInplaceWidget
from django.utils import timezone
from PIL import Image
# Moved to avoid circular reference issue on imports
# import accounts.views.admin
from accounts.utils import check_system_number
from cobalt.settings import (
ABF_STATES,
BLEACH_ALLOWED_TAGS,
BLEACH_ALLOWED_ATTRIBUTES,
BLEACH_ALLOWED_STYLES,
)
from notifications.models import EmailAttachment
from payments.models import OrgPaymentMethod
from rbac.core import rbac_user_has_role
from results.models import ResultsFile
from .models import (
Organisation,
MembershipType,
MemberMembershipType,
ClubTag,
OrganisationFrontPage,
OrgVenue,
OrgEmailTemplate,
WelcomePack,
MemberClubDetails,
)
[docs]
def membership_type_choices(club, exclude_id=None):
"""Return membership choices for a club"""
# Get membership type drop down
membership_type_qs = MembershipType.objects.filter(organisation=club)
if exclude_id:
membership_type_qs = membership_type_qs.exclude(
id=exclude_id,
)
membership_types = membership_type_qs.values_list("id", "name")
return [
(membership_type[0], membership_type[1]) for membership_type in membership_types
]
[docs]
def membership_payment_method_choices(club, registered, allow_none=True):
"""Return membership payment method choices for a club
Adds a null choice with value -1, and removes IOU as a valid choice
Removes bridge credits if not registered.
"""
all_methods = OrgPaymentMethod.objects.filter(
organisation=club,
active=True,
).values_list("id", "payment_method")
method_choices = [(-1, "-")] if allow_none else []
for id, desc in all_methods:
if desc != "IOU" and not (desc == "Bridge Credits" and not registered):
method_choices.append((id, desc))
return method_choices
[docs]
def club_email_template_choices(club):
"""Return available club email template choices
Returns a list of (OrgEmailTemplate id, template name)
including a null choice of (-1. '-')
"""
choices = list(
OrgEmailTemplate.objects.filter(organisation=club).values_list(
"id", "template_name"
)
)
return [(-1, "-")] + choices
# TODO: Replace when club admin work complete
[docs]
class OrgFormOld(forms.ModelForm):
[docs]
class Meta:
model = Organisation
fields = (
"name",
"address1",
"address2",
"suburb",
"state",
"postcode",
"bank_bsb",
"bank_account",
)
[docs]
class OrgForm(forms.ModelForm):
[docs]
class Meta:
model = Organisation
fields = (
"secretary",
"name",
"org_id",
"club_email",
"club_website",
"address1",
"address2",
"suburb",
"state",
"postcode",
"bank_bsb",
"bank_account",
"default_secondary_payment_method",
)
# Make State a choice field
choices = [("", "Select State...")]
for state in ABF_STATES:
choices.append((ABF_STATES[state][1], ABF_STATES[state][1]))
widgets = {
"state": forms.Select(
choices=choices,
),
}
def __init__(self, *args, **kwargs):
# Get user parameter so we can check access in validation
user = kwargs.pop("user", None)
# Call Super()
super().__init__(*args, **kwargs)
# Add field
self.user = user
# Handle default_Secondary_payment_methods
instance = kwargs.get("instance")
if instance:
# Org already exists so we can show choices
org_payment_types = (
OrgPaymentMethod.objects.filter(organisation=instance, active=True)
.exclude(payment_method="Bridge Credits")
.values_list("id", "payment_method")
)
self.fields["default_secondary_payment_method"].choices = org_payment_types
if instance.default_secondary_payment_method:
self.fields["default_secondary_payment_method"].initial = (
instance.default_secondary_payment_method.id
)
else:
# New org - remove option
self.fields.pop("default_secondary_payment_method")
[docs]
def clean_state(self):
"""check this user has access to this state"""
from .views.general import get_rbac_model_for_state
state = self.cleaned_data["state"]
if not state:
self.add_error("state", "State cannot be empty")
return state
# See if this has changed
if "state" not in self.changed_data:
return state
# Get model id for this state
rbac_model_for_state = get_rbac_model_for_state(state)
if not rbac_model_for_state:
self.add_error("state", "No state body found for this state.")
return state
# Check access - state or admin both work
if not (
rbac_user_has_role(self.user, "orgs.state.%s.edit" % rbac_model_for_state)
or rbac_user_has_role(self.user, "orgs.admin.edit")
):
self.add_error(
"state",
"You do not have permissions to create or edit a club in this state.",
)
return state
[docs]
class MembershipTypeForm(forms.ModelForm):
[docs]
class Meta:
model = MembershipType
fields = (
"name",
"description",
"annual_fee",
"is_default",
"grace_period_days",
"does_not_renew",
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# {{ form | crispy }} stuffs up checkboxes and {% crispy form %} adds </form>. This prevents this.
self.helper = FormHelper(self)
self.helper.form_tag = False
[docs]
class OrgDatesForm(forms.ModelForm):
[docs]
class Meta:
model = Organisation
fields = (
"membership_renewal_date_day",
"membership_renewal_date_month",
"full_club_admin",
)
[docs]
def clean_membership_renewal_date_month(self):
month = self.cleaned_data.get("membership_renewal_date_month")
if month is None:
raise forms.ValidationError("This field is required.")
if not 1 <= month <= 12:
raise forms.ValidationError("Month must be between 1 and 12.")
return month
[docs]
def clean_membership_renewal_date_day(self):
day = self.cleaned_data.get("membership_renewal_date_day")
if day is None:
raise forms.ValidationError("This field is required.")
if not 1 <= day <= 31:
raise forms.ValidationError("Day must be between 1 and 31.")
return day
[docs]
def clean(self):
"""custom validation"""
cleaned_data = super(OrgDatesForm, self).clean()
month = cleaned_data.get("membership_renewal_date_month")
day = cleaned_data.get("membership_renewal_date_day")
# Only validate the date if both day and month have passed individual validation
if month and day:
try:
datetime.datetime(year=1967, month=month, day=day)
except ValueError:
self.add_error("membership_renewal_date_month", "Invalid date")
self.add_error("membership_renewal_date_day", "Invalid date")
return self.cleaned_data
[docs]
class MemberClubEmailForm(forms.Form):
"""Form for adding or editing a local email address for a club unregistered member"""
email = forms.EmailField(
label="Email address (accessible by this club only)", required=False
)
[docs]
class MemberClubDetailsForm(forms.ModelForm):
"""Form for editing club member details"""
[docs]
class Meta:
model = MemberClubDetails
fields = (
"email",
"address1",
"address2",
"state",
"postcode",
"preferred_phone",
"other_phone",
"dob",
"joined_date",
"left_date",
"club_membership_number",
"emergency_contact",
"notes",
)
[docs]
class ContactNameForm(forms.Form):
"""Simple form to allow contcat names to be edited"""
first_name = forms.CharField(max_length=150, required=True)
last_name = forms.CharField(max_length=150, required=True)
[docs]
class MembershipExtendForm(forms.Form):
"""Form for extending an existing membership"""
new_end_date = forms.DateField(
label="New end date",
widget=forms.DateInput(attrs={"type": "date"}),
required=True,
)
fee = forms.DecimalField(label="Fee", max_digits=10, decimal_places=2)
due_date = forms.DateField(
label="Payment due date",
widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
auto_pay_date = forms.DateField(
label="Auto payment date",
widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
payment_method = forms.ChoiceField(label="Payment method", required=True)
send_notice = forms.BooleanField(
label="Send a renewal notice",
required=False,
)
club_template = forms.ChoiceField(label="Club email template", required=True)
email_subject = forms.CharField(label="Subject", required=False)
email_content = forms.CharField(
label="Renewal message",
required=False,
widget=forms.Textarea(attrs={"rows": 4, "cols": 40}),
)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
registered = kwargs.pop("registered")
super(MembershipExtendForm, self).__init__(*args, **kwargs)
self.fields["payment_method"].choices = membership_payment_method_choices(
self.club, registered
)
self.fields["club_template"].choices = club_email_template_choices(self.club)
[docs]
def clean_fee(self):
fee = self.cleaned_data.get("fee")
if fee is not None and fee < 0:
self.add_error("fee", "Fee cannot be negative.")
return fee
[docs]
def clean(self):
"""custom validation"""
cleaned_data = super(MembershipExtendForm, self).clean()
due_date = cleaned_data.get("due_date")
new_end_date = cleaned_data.get("new_end_date")
if due_date and new_end_date and due_date > new_end_date:
self.add_error("due_date", "Due date must be before end date.")
return self.cleaned_data
[docs]
class MembershipPaymentForm(forms.Form):
"""Form for paying membership fees. Does not provide a no selection option for the payment method"""
payment_method = forms.ChoiceField(label="Payment method", required=True)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
registered = kwargs.pop("registered")
super(MembershipPaymentForm, self).__init__(*args, **kwargs)
self.fields["payment_method"].choices = membership_payment_method_choices(
self.club, registered, allow_none=False
)
[docs]
class MembershipRawEditForm(forms.ModelForm):
"""Form for raw editing of a membership record"""
membership_type = forms.ChoiceField(label="Membership Type", required=True)
payment_method = forms.ChoiceField(label="Payment method", required=True)
membership_state = forms.ChoiceField(
label="Membership State",
choices=MemberMembershipType.MEMBERSHIP_STATE,
required=True,
)
[docs]
class Meta:
model = MemberMembershipType
exclude = [
"system_number",
"home_club",
"last_modified_by",
"membership_type",
"payment_method",
"membership_state",
]
def __init__(self, *args, **kwargs):
if "full_club_admin" in kwargs:
self.full_club_admin = kwargs.pop("full_club_admin")
else:
self.full_club_admin = True
self.club = kwargs.pop("club")
registered = kwargs.pop("registered")
super(MembershipRawEditForm, self).__init__(*args, **kwargs)
self.fields["membership_type"].choices = membership_type_choices(self.club)
self.fields["payment_method"].choices = membership_payment_method_choices(
self.club, registered
)
# handle initialisation of excluded fields
# Set initial values manually if an instance is provided
if self.instance and self.instance.pk:
self.fields["membership_type"].initial = (
self.instance.membership_type.id
if self.instance.membership_type
else None
)
self.fields["payment_method"].initial = (
self.instance.payment_method.id
if self.instance.payment_method
else None
)
self.fields["membership_state"].initial = self.instance.membership_state
# Alternatively, if initial values were passed in the form initialization
if "initial" in kwargs:
self.fields["membership_type"].initial = kwargs["initial"].get(
"membership_type", self.fields["membership_type"].initial
)
self.fields["payment_method"].initial = kwargs["initial"].get(
"payment_method", self.fields["payment_method"].initial
)
self.fields["membership_state"].initial = kwargs["initial"].get(
"membership_state", self.fields["membership_state"].initial
)
[docs]
def clean(self):
cleaned_data = super().clean()
start_date = cleaned_data.get("start_date")
if self.full_club_admin:
if not start_date:
self.add_error("start_date", "Start date is required")
return cleaned_data
[docs]
def clean_fee(self):
fee = self.cleaned_data.get("fee")
if fee is not None and fee < 0:
self.add_error("fee", "Fee cannot be negative.")
return fee
[docs]
def save(self, commit=True):
instance = super(MembershipRawEditForm, self).save(commit=False)
# Update the instance with the form's cleaned data
instance.membership_state = self.cleaned_data.get("membership_state")
if self.cleaned_data.get("membership_type") == -1:
new_membership_type = None
else:
try:
new_membership_type = MembershipType.objects.get(
pk=self.cleaned_data.get("membership_type")
)
except MembershipType.DoesNotExist:
new_membership_type = None
instance.membership_type = new_membership_type
if self.cleaned_data.get("payment_method") == -1:
new_payment_method = None
else:
try:
new_payment_method = OrgPaymentMethod.objects.get(
pk=self.cleaned_data.get("payment_method")
)
except OrgPaymentMethod.DoesNotExist:
new_payment_method = None
instance.payment_method = new_payment_method
if commit:
instance.save()
return instance
[docs]
class MembershipChangeTypeForm(forms.Form):
"""Form for changing or creating a new membership
Membership type options are derived from the club parameter"""
new_system_number = forms.IntegerField(
label="System Number",
required=False,
)
new_email = forms.EmailField(
label="Email Address (accessible by this club only)", required=False
)
membership_type = forms.ChoiceField(label="Membership Type", required=True)
start_date = forms.DateField(
label="Start date",
# widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
end_date = forms.DateField(
label="End date",
# widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
fee = forms.DecimalField(
label="Fee",
max_digits=10,
decimal_places=2,
)
due_date = forms.DateField(
label="Payment due date",
# widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
payment_method = forms.ChoiceField(label="Payment method", required=False)
send_welcome_pack = forms.BooleanField(initial=True, required=False)
def __init__(self, *args, **kwargs):
"""Form initialiser
Note: must have club and registered arguements. Can optionally have
exclude_id.
"""
self.club = kwargs.pop("club")
registered = kwargs.pop("registered")
if "exclude_id" in kwargs:
exclude_id = kwargs.pop("exclude_id")
else:
exclude_id = None
super(MembershipChangeTypeForm, self).__init__(*args, **kwargs)
self.fields["membership_type"].choices = membership_type_choices(
self.club, exclude_id=exclude_id
)
self.fields["payment_method"].choices = membership_payment_method_choices(
self.club, registered
)
[docs]
def clean_start_date(self):
start_date = self.cleaned_data.get("start_date")
if not self.club.full_club_admin:
# No validation in simple membership management
return start_date
if start_date is None:
self.add_error("start_date", "Start date required")
else:
today = timezone.now().date()
if start_date > today + datetime.timedelta(days=1):
# Allow a start date of tomorrow to allow ending current today
self.add_error("start_date", "Start date cannot be in the future")
return start_date
[docs]
def clean_fee(self):
fee = self.cleaned_data.get("fee")
if fee is not None and fee < 0:
self.add_error("fee", "Fee cannot be negative.")
return fee
[docs]
def clean(self):
cleaned_data = super().clean()
start_date = self.cleaned_data.get("start_date")
end_date = self.cleaned_data.get("end_date")
due_date = self.cleaned_data.get("due_date")
if start_date and end_date and start_date > end_date:
self.add_error("end_date", "End date must be after the start date")
if due_date and end_date and due_date > end_date:
self.add_error("due_date", "Due date must be before end date.")
return cleaned_data
[docs]
class UserMembershipForm(forms.Form):
"""Form for getting a registered user and a membership type"""
system_number = forms.IntegerField()
membership_type = forms.ChoiceField()
home_club = forms.BooleanField(initial=False, required=False)
send_welcome_email = forms.BooleanField(initial=True, required=False)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
self.fields["membership_type"].choices = membership_type_choices(self.club)
# If this club doesn't have a membership pack then don't show on form
if not WelcomePack.objects.filter(organisation=self.club).exists():
del self.fields["send_welcome_email"]
# def clean_home_club(self):
# """Check that this user doesn't already have a home club"""
#
# home_club = self.cleaned_data["home_club"]
# member_id = self.cleaned_data["member"]
# member = User.objects.get(pk=member_id)
#
# if home_club:
# other_club = (
# MemberMembershipType.objects.active()
# .filter(system_number=member.system_number)
# .filter(home_club=True)
# .exclude(membership_type__organisation=self.club)
# .first()
# )
# if other_club:
# self.add_error(
# "member",
# f"{member.full_name} already has {other_club.membership_type.organisation} as their home club",
# )
#
# return home_club
[docs]
class UnregisteredUserAddForm(forms.Form):
"""Form for adding an unregistered user along with the email, home club and membership type"""
system_number = forms.IntegerField()
first_name = forms.CharField(max_length=150)
last_name = forms.CharField(max_length=150)
club_email = forms.EmailField(
label="Email Address (accessible by this club only)", required=False
)
membership_type = forms.ChoiceField()
home_club = forms.BooleanField(initial=True, required=False)
send_welcome_email = forms.BooleanField(initial=True, required=False)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
self.fields["membership_type"].choices = membership_type_choices(self.club)
# If this club doesn't have a membership pack then don't show on form
if not WelcomePack.objects.filter(organisation=self.club).exists():
del self.fields["send_welcome_email"]
[docs]
def clean_system_number(self):
system_number = self.cleaned_data["system_number"]
is_valid, is_member, _ = check_system_number(system_number)
if not is_valid:
self.add_error("system_number", "Invalid number")
if is_member:
self.add_error(
"system_number",
"This user is already registered. You can add them as a member, not an unregistered member",
)
return system_number
[docs]
def clean_home_club(self):
"""Users can only have one home club"""
home_club = self.cleaned_data["home_club"]
system_number = self.cleaned_data["system_number"]
if (
home_club
and MemberMembershipType.objects.filter(system_number=system_number)
.filter(home_club=True)
.exclude(membership_type__organisation=self.club)
.exists()
):
self.add_error("home_club", "User already has a home club")
return home_club
[docs]
class ContactAddForm(forms.Form):
"""Form for adding a contact"""
first_name = forms.CharField(max_length=150, initial="", required=True)
last_name = forms.CharField(max_length=150, initial="", required=True)
[docs]
class CSVUploadForm(forms.Form):
"""Form for uploading a CSV to load unregistered members"""
membership_type = forms.ChoiceField()
home_club = forms.BooleanField(initial=True, required=False)
overwrite = forms.BooleanField(initial=False, required=False)
file_type = forms.ChoiceField(
choices=[
("CSV", "Generic CSV"),
("CS2", "Compscore"),
("Pianola", "Pianola Export"),
]
)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
self.fields["membership_type"].choices = membership_type_choices(self.club)
[docs]
class CSVContactUploadForm(forms.Form):
"""Form for uploading a CSV to load contacts"""
overwrite = forms.BooleanField(initial=False, required=False)
file_type = forms.ChoiceField(
choices=[
("CSV", "Generic CSV"),
("CS2", "Compscore"),
("Pianola", "Pianola Export"),
]
)
[docs]
class MPCForm(forms.Form):
"""Form for uploading a CSV to load unregistered members"""
membership_type = forms.ChoiceField()
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
self.fields["membership_type"].choices = membership_type_choices(self.club)
[docs]
class TagForm(forms.Form):
"""Form to add a tag to an organisation"""
tag_name = forms.CharField(
max_length=50,
label="",
widget=forms.TextInput(attrs={"placeholder": "Add new tag"}),
)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
[docs]
def clean_tag_name(self):
tag_name = self.cleaned_data["tag_name"]
if tag_name.lower() == "everyone":
self.add_error(
"tag_name", "No need to add everyone, the system does that for you."
)
if ClubTag.objects.filter(organisation=self.club, tag_name=tag_name).exists():
self.add_error("tag_name", "Duplicate name")
return tag_name
[docs]
class TagMultiForm(forms.Form):
"""Form to select multiple tags"""
selected_tags = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
# Get tags for this club
club_tags = (
ClubTag.objects.filter(organisation=self.club)
.order_by("tag_name")
.values_list("id", "tag_name")
)
# Add as choices
self.fields["selected_tags"].choices = [
(club_tag[0], club_tag[1]) for club_tag in club_tags
]
self.fields["selected_tags"].choices.insert(0, ("0", "EVERYONE"))
[docs]
def clean_tags(self):
tags = self.cleaned_data["selected_tags"]
if len(tags) == 0:
self.add_error("tags", "You must select at least one tag")
return tags
[docs]
class TemplateForm(forms.ModelForm):
"""Form for editing email template"""
[docs]
class Meta:
model = OrgEmailTemplate
fields = (
"footer",
"template_name",
"from_name",
"reply_to",
"box_colour",
"box_font_colour",
)
footer = forms.CharField(
# This shouldn't be needed but is
required=False,
widget=SummernoteInplaceWidget(
attrs={
"summernote": {
"height": "250",
"codemirror": {"theme": "monokai"},
"placeholder": "<br><br>(Optional) Enter your footer here. This will appear at the bottom of your email.",
}
}
),
)
reply_to = forms.EmailField(required=False)
[docs]
class TemplateBannerForm(forms.ModelForm):
"""Form for editing email template banner"""
x = forms.FloatField(widget=forms.HiddenInput())
y = forms.FloatField(widget=forms.HiddenInput())
width = forms.FloatField(widget=forms.HiddenInput())
height = forms.FloatField(widget=forms.HiddenInput())
[docs]
class Meta:
model = OrgEmailTemplate
fields = (
"banner",
"x",
"y",
"width",
"height",
)
widgets = {"file": forms.FileInput(attrs={"accept": "image/*"})}
[docs]
def save(self):
email_template = super(TemplateBannerForm, self).save()
x = self.cleaned_data.get("x")
y = self.cleaned_data.get("y")
w = self.cleaned_data.get("width")
h = self.cleaned_data.get("height")
image = Image.open(email_template.banner)
if image.mode not in ["RGB", "RGBA"]:
image = image.convert("RGB")
cropped_image = image.crop((x, y, w + x, h + y))
resized_image = cropped_image.resize((500, 200), PIL.Image.Resampling.NEAREST)
resized_image.save(email_template.banner.path)
return email_template
# JPG TO DO Deprecated - moved to notifications
[docs]
class EmailAttachmentForm(forms.ModelForm):
"""Form for uploading an attachment for a club"""
[docs]
class Meta:
model = EmailAttachment
fields = ("attachment",)
widgets = {"attachment": forms.FileInput(attrs={"accept": "*/*"})}
[docs]
class ResultsFileForm(forms.ModelForm):
"""Form for uploading a results file"""
[docs]
class Meta:
model = ResultsFile
fields = ("results_file",)
widgets = {"results_file": forms.FileInput(attrs={"accept": "*/*.xml"})}
[docs]
class UnregisteredUserMembershipForm(forms.Form):
"""Form for handling home club and membership type"""
membership_type = forms.ChoiceField()
home_club = forms.BooleanField(initial=True, required=False)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
self.system_number = kwargs.pop("system_number")
super().__init__(*args, **kwargs)
self.fields["membership_type"].choices = membership_type_choices(self.club)
[docs]
def clean_home_club(self):
"""Users can only have one home club"""
home_club = self.cleaned_data["home_club"]
if (
home_club
and MemberMembershipType.objects.filter(system_number=self.system_number)
.filter(home_club=True)
.exclude(membership_type__organisation=self.club)
.exists()
):
self.add_error("home_club", "User already has a home club")
return home_club
[docs]
class FrontPageForm(forms.ModelForm):
"""Form for the front page info for a club"""
summary = forms.CharField(
widget=SummernoteInplaceWidget(
attrs={"summernote": {"placeholder": "<br><br>Build your page here..."}}
)
)
# def clean_summary(self):
# summary = self.cleaned_data["summary"]
#
# summary = bleach.clean(
# summary,
# strip=True,
# tags=BLEACH_ALLOWED_TAGS,
# attributes=BLEACH_ALLOWED_ATTRIBUTES,
# styles=BLEACH_ALLOWED_STYLES,
# )
#
# summary = summary.replace("<", "\n<")
#
# return summary
[docs]
class VenueForm(forms.Form):
"""Form to add a venue to an organisation"""
venue_name = forms.CharField(
max_length=15,
label="",
widget=forms.TextInput(attrs={"placeholder": "Add new venue"}),
)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
[docs]
def clean_venue_name(self):
venue_name = self.cleaned_data["venue_name"]
if OrgVenue.objects.filter(organisation=self.club, venue=venue_name).exists():
self.add_error("venue_name", "Duplicate name")
return venue_name
[docs]
class OrgDefaultSecondaryPaymentMethod(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
# Get payment methods for this club (excluding Bridge Credits)
payment_methods = OrgPaymentMethod.objects.filter(
organisation=self.club, active=True
).exclude(payment_method="Bridge Credits")
our_payment_methods = [
(payment_method.id, payment_method.payment_method)
for payment_method in payment_methods
]
self.fields["default_secondary_payment_method"].choices = our_payment_methods
# Default value if set, or add Select... if not set
if self.club.default_secondary_payment_method:
self.fields["default_secondary_payment_method"].initial = (
self.club.default_secondary_payment_method.id
)
else:
self.fields["default_secondary_payment_method"].choices.insert(
0, (-1, "Select...")
)
[docs]
class PaymentTypeForm(forms.Form):
"""Form to add a payment type to an organisation"""
payment_name = forms.CharField(
max_length=15,
label="",
widget=forms.TextInput(attrs={"placeholder": "Add new method"}),
)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
[docs]
def clean_payment_name(self):
payment_name = self.cleaned_data["payment_name"]
if OrgPaymentMethod.objects.filter(
organisation=self.club, payment_method=payment_name
).exists():
self.add_error("payment_name", "Duplicate name")
return payment_name
[docs]
class WelcomePackForm(forms.ModelForm):
"""Form for the welcome packs for a club"""
welcome_email = forms.CharField(
widget=SummernoteInplaceWidget(
attrs={
"summernote": {
"placeholder": "<br><br>Enter your welcome email here..."
}
}
)
)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super().__init__(*args, **kwargs)
templates = OrgEmailTemplate.objects.filter(organisation=self.club)
our_templates = [
(template.id, template.template_name) for template in templates
]
self.fields["template"].choices = our_templates
[docs]
class ResultsEmailMessageForm(forms.ModelForm):
"""Form for the results email message sent to players for a club"""
results_email_message = forms.CharField(
widget=SummernoteInplaceWidget(
attrs={
"summernote": {
"height": "250",
"placeholder": "<br><br>(Optional) Add a message for your members...",
}
}
)
)
[docs]
class MinimumBalanceAfterSettlementForm(forms.ModelForm):
"""form for minimum_balance_after_settlement"""
[docs]
class BulkRenewalLineForm(forms.Form):
"""Options for bulk renewal of a membership type"""
selected = forms.BooleanField(
label="Selected",
required=False,
)
membership_type_id = forms.IntegerField(
label="Membership type id (hidden)",
)
membership_type_name = forms.CharField(
label="Membership type",
)
fee = forms.DecimalField(
label="Fee",
max_digits=10,
decimal_places=2,
required=False,
)
due_date = forms.DateField(
label="Payment due date",
# widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
auto_pay_date = forms.DateField(
label="Auto pay date",
# widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
start_date = forms.DateField(
label="Start date",
# widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
end_date = forms.DateField(
label="End date",
# widget=forms.DateInput(attrs={"type": "date"}),
required=False,
)
[docs]
def clean(self):
"""custom validation"""
cleaned_data = super(BulkRenewalLineForm, self).clean()
selected = cleaned_data.get("selected")
if selected:
# only performa validation if selected
fee = self.cleaned_data.get("fee")
if fee is not None and fee < 0:
self.add_error("fee", "Fee cannot be negative.")
due_date = cleaned_data.get("due_date")
end_date = cleaned_data.get("end_date")
if due_date and end_date and due_date > end_date:
self.add_error("due_date", "Due date must be before end date.")
return self.cleaned_data
BulkRenewalFormSet = formset_factory(BulkRenewalLineForm, extra=0)
[docs]
class BulkRenewalOptionsForm(forms.Form):
"""A form for the common options for a batch"""
send_notice = forms.BooleanField(label="Send renewal notices", required=False)
club_template = forms.ChoiceField(label="Club email template", required=True)
email_subject = forms.CharField(label="Subject", required=False)
email_content = forms.CharField(
label="Renewal message",
required=False,
widget=forms.Textarea(attrs={"rows": 4, "cols": 40}),
)
def __init__(self, *args, **kwargs):
self.club = kwargs.pop("club")
super(BulkRenewalOptionsForm, self).__init__(*args, **kwargs)
self.fields["club_template"].choices = club_email_template_choices(self.club)