2024-07-22 10:13:22 +00:00
|
|
|
from django import forms
|
2024-10-22 05:10:07 +00:00
|
|
|
from django.utils.safestring import mark_safe
|
|
|
|
from django.urls import reverse
|
2024-07-22 10:13:22 +00:00
|
|
|
from .models import SustainerOrder
|
|
|
|
|
2024-10-23 07:16:47 +00:00
|
|
|
|
2024-10-22 05:10:07 +00:00
|
|
|
class SustainerFormRenderer(forms.renderers.DjangoTemplates):
|
|
|
|
# Customised layout with labels on own row
|
|
|
|
field_template_name = 'supporters/field.html'
|
|
|
|
|
|
|
|
|
|
|
|
class ButtonRadioSelect(forms.widgets.RadioSelect):
|
|
|
|
"""Radio button styled like a button. BYO CSS."""
|
2024-10-23 07:16:47 +00:00
|
|
|
|
2024-10-22 05:10:07 +00:00
|
|
|
# Extra <span> wrappers to support CSS
|
|
|
|
option_template_name = 'supporters/buttonradio_option.html'
|
|
|
|
use_fieldset = False
|
|
|
|
|
|
|
|
class Media:
|
|
|
|
css = {
|
|
|
|
'all': ['css/buttonradio.css'],
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.attrs['class'] = 'button-select'
|
|
|
|
|
|
|
|
|
2024-07-22 10:13:22 +00:00
|
|
|
class SustainerForm(forms.ModelForm):
|
2024-10-22 05:10:07 +00:00
|
|
|
# Used to pre-fill the price selector
|
|
|
|
amount_option = forms.CharField(required=False)
|
|
|
|
|
|
|
|
template_name = 'supporters/sustainer_form.html'
|
2024-09-18 05:34:59 +00:00
|
|
|
|
2024-10-23 07:10:43 +00:00
|
|
|
MONTH_OPTIONS = [12, 23, 45, 87]
|
|
|
|
YEAR_OPTIONS = [128, 256, 512, 1024]
|
|
|
|
MONTH_MINIMUM = 10
|
|
|
|
YEAR_MINIMUM = 120
|
2024-10-22 12:50:02 +00:00
|
|
|
|
2024-07-22 10:13:22 +00:00
|
|
|
class Meta:
|
|
|
|
model = SustainerOrder
|
|
|
|
fields = [
|
2024-10-22 05:10:07 +00:00
|
|
|
'recurring',
|
|
|
|
'amount',
|
2024-07-22 10:13:22 +00:00
|
|
|
'name',
|
|
|
|
'email',
|
|
|
|
'acknowledge_publicly',
|
|
|
|
'add_to_mailing_list',
|
|
|
|
'tshirt_size',
|
|
|
|
'street',
|
|
|
|
'city',
|
|
|
|
'state',
|
|
|
|
'zip_code',
|
|
|
|
'country',
|
|
|
|
]
|
2024-10-22 05:10:07 +00:00
|
|
|
widgets = {
|
2024-10-23 07:16:47 +00:00
|
|
|
'recurring': ButtonRadioSelect(
|
|
|
|
attrs={
|
|
|
|
'x-model': 'recurring',
|
|
|
|
# Reset the amount field and option when changing monthly/annually.
|
2024-10-24 06:00:24 +00:00
|
|
|
'x-on:change': 'amount = ""; amount_option = null',
|
|
|
|
}
|
|
|
|
),
|
|
|
|
'amount': forms.widgets.NumberInput(
|
|
|
|
# Keeping default widget, just neater to add many attrs here.
|
|
|
|
attrs={
|
|
|
|
# So we can update the amount field from the amount_option selected.
|
|
|
|
'x-model': 'amount',
|
|
|
|
'x-bind:min': 'amount_minimum',
|
|
|
|
'onblur': 'this.reportValidity()',
|
|
|
|
'style': 'width: 5rem',
|
2024-10-23 07:16:47 +00:00
|
|
|
}
|
|
|
|
),
|
2024-10-22 05:10:07 +00:00
|
|
|
}
|
2024-07-22 10:13:22 +00:00
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
2024-10-22 05:10:07 +00:00
|
|
|
|
|
|
|
self.renderer = SustainerFormRenderer()
|
|
|
|
|
|
|
|
self.fields['recurring'].label = ''
|
2024-10-22 12:50:02 +00:00
|
|
|
self.fields['amount'].initial = self.YEAR_OPTIONS[0]
|
2024-07-22 10:13:22 +00:00
|
|
|
self.fields['tshirt_size'].widget.attrs['x-model'] = 'tshirt_size'
|
2024-10-22 05:10:07 +00:00
|
|
|
|
|
|
|
def clean(self):
|
|
|
|
super().clean()
|
|
|
|
recurring = self.cleaned_data.get('recurring', '')
|
|
|
|
amount = self.cleaned_data.get('amount', 0)
|
2024-10-23 07:10:43 +00:00
|
|
|
minimum = self.MONTH_MINIMUM if recurring == 'month' else self.YEAR_MINIMUM
|
2024-10-22 05:10:07 +00:00
|
|
|
donate_url = reverse('donate')
|
|
|
|
if amount < minimum:
|
|
|
|
self.add_error(
|
|
|
|
'',
|
2024-10-23 07:16:47 +00:00
|
|
|
mark_safe(
|
|
|
|
f'${minimum:d} is a minimum for Conservancy Sustainers. <a href="{donate_url}">Donate smaller amounts here</a>.'
|
|
|
|
),
|
2024-10-22 05:10:07 +00:00
|
|
|
)
|
|
|
|
tshirt_size = self.cleaned_data.get('tshirt_size')
|
2024-10-23 07:16:47 +00:00
|
|
|
if tshirt_size and not all(
|
|
|
|
[
|
2024-10-22 05:10:07 +00:00
|
|
|
self.cleaned_data.get('street'),
|
|
|
|
self.cleaned_data.get('city'),
|
2024-10-23 07:16:47 +00:00
|
|
|
self.cleaned_data.get('country'),
|
|
|
|
]
|
|
|
|
):
|
|
|
|
self.add_error('street', 'No address provided')
|