import logging import warnings from django.core.exceptions import ValidationError from django.forms import fields from django.utils.translation import ugettext_lazy as _ from django import forms from accounts.forms import EmailRequiredPersonForm, EmailNotRequiredPersonForm from accounts.constants import STATE_CHOICES from accounts.profile import get_profile from accounts import utils as account_utils from catalog.models import Subscription from store_order.models import OrderItemGiftDetail from . import constants from . import renderers from . import utils from .templatetags import storefront_tags LOG = logging.getLogger(__name__) REQUIRED = ( u"There was missing information on your order. Please correct " u"the errors below." ) class HelpForm(forms.Form): """ Simple Help Form """ reason_for_message = fields.ChoiceField( choices=constants.REASONS_FOR_MESSAGE, required=True ) name = forms.CharField( widget=forms.Textarea(attrs={"rows": 1, "columns": 45}), required=True ) email = forms.CharField( widget=forms.Textarea(attrs={"rows": 1, "columns": 45}), required=True ) message = forms.CharField( widget=forms.Textarea(attrs={"rows": 5, "columns": 55}), required=True ) class SubscriptionForm(forms.Form): """ Subscription form is used to display subscription options. These include: title: Title of the newspaper. Available types are calculated using the SHIPPING TYPE duration: Duration of the subscription choice shipping_method: These are typically regular or first class. Foreign addresses qualify only for Foreign First Class shipping_type: Shipping type is a function of the users address. If it can't be calculated, we expect this value to be None. The affect on the form is that all possible values are returned for all fields. """ subscription = None def __init__(self, *args, **kwargs): self.shipping_type = kwargs.pop("shipping_type", None) self.use_account_number = kwargs.pop("use_account_number", None) self.renewal = kwargs.pop("renewal", False) super(SubscriptionForm, self).__init__(*args, **kwargs) self.fields["title"] = forms.ChoiceField( label=_("Title"), widget=forms.RadioSelect( renderer=renderers.HorizontalRadioRenderer, attrs={"onclick": "calculate_price();"}, ), choices=utils.unique_titles(self.shipping_type), required=True, initial=0, ) self.fields["duration"] = forms.ChoiceField( label=_("Duration (months)"), widget=forms.RadioSelect( renderer=renderers.HorizontalRadioRenderer, attrs={"onclick": "calculate_price();"}, ), choices=utils.unique_durations(self.shipping_type), required=True, initial=0, ) self.fields["shipping_method"] = forms.ChoiceField( label=_("Shipping Method"), widget=forms.RadioSelect( renderer=renderers.HorizontalRadioRenderer, attrs={"onclick": "calculate_price();"}, ), choices=utils.unique_shipping_methods(), required=True, initial=0, ) if self.use_account_number: self.fields["account_number"] = forms.CharField( label=_("Account Number)"), required=False, widget=forms.TextInput( attrs={"type": "text", "size": 50, "maxlength": 7} ), ) def save(self): """ Returns the unique subscription calculated by clean """ return self.subscription def clean(self): """ Cleans the form data. Uses the form data to determine if the subscription product exists. title, shipping method, duration and shipping type are used to determine if a valid subscription exists. If one does not, a validation error will be returned """ LOG.debug("Subscription Form Data: {0}".format(self.cleaned_data)) title = self.cleaned_data.get("title", None) shipping_method = self.cleaned_data.get("shipping_method", None) duration = self.cleaned_data.get("duration", None) shipping_type = self.shipping_type # recast values from radio button positions to searchable values title = utils.get_value_by_index(utils.unique_titles(shipping_type), title) duration = utils.get_value_by_index( utils.unique_durations(shipping_type), duration ) shipping_method = utils.get_value_by_index( utils.unique_shipping_methods(), shipping_method ) try: LOG.debug( "Looking for subscription with: title:{0}, duration:{1}," " shipping_type:{2}, shipping_method:{3}".format( title, duration, shipping_type, shipping_method ) ) self.subscription = Subscription.objects.get( title=title, duration=duration, shipping_type=shipping_type, shipping_method=shipping_method, renewal=self.renewal, ) except Subscription.DoesNotExist: message = ( u"{0} is not available with for 9-month or 2-year " u"durations. Please choose a different duration or " u"shipping method.".format( storefront_tags.humanize_shipping_method(shipping_method) ) ) LOG.debug(message) raise forms.ValidationError(_(message)) return self.cleaned_data class GiftInformationForm(forms.ModelForm): message = forms.CharField( widget=forms.Textarea(attrs={"cols": 55, "rows": 3}), required=False, ) class Meta: model = OrderItemGiftDetail exclude = ( "first_name", "last_name", "company", "address1", "address2", "city", "region", "phone", "country", "postal_code", "plus_four", "email", ) class ChangeOfAddressForm(forms.Form): account_number = forms.CharField( required=False, widget=forms.TextInput(attrs={"type": "text", "size": 50}) ) date_effective = forms.ChoiceField( label=_("Date Effective"), widget=forms.RadioSelect(renderer=renderers.HorizontalRadioRenderer), choices=constants.DATE_EFFECTIVE_CHOICES, required=True, initial=constants.NEXT_ISSUE, ) from_date = forms.CharField(required=False) to_date = forms.CharField(required=False) def __init__(self, *args, **kwargs): self.type = kwargs.pop("type", None) super(ChangeOfAddressForm, self).__init__(*args, **kwargs) self.fields["title"] = forms.ChoiceField( label=_("Title"), widget=forms.RadioSelect(renderer=renderers.HorizontalRadioRenderer), choices=utils.unique_titles(self.type), required=True, initial=0, ) def clean(self): data = self.cleaned_data date_effective = data.get("date_effective", None) from_date = data.get("from_date", None) to_date = data.get("to_date", None) if date_effective == constants.RANGE and not from_date and not to_date: raise ValidationError( _("You must add from and to dates if you " "choose a date range.") ) return self.cleaned_data class AddressForm(EmailNotRequiredPersonForm): def clean(self): # We want a single error message. We don't display the validation # errors for each part of the form for field in self.fields: if self.fields[field].required and not self.cleaned_data.get(field, None): raise forms.ValidationError(_(REQUIRED)) return self.cleaned_data class GiftToForm(EmailNotRequiredPersonForm): def save(self): """ Saving the recipient should not create a user account """ warnings.warn("deprecated", DeprecationWarning) def clean(self): # We want a single error message. We don't display the validation # errors for each part of the form for field in self.fields: if self.fields[field].required and not self.cleaned_data.get(field, None): raise forms.ValidationError(_(REQUIRED)) return self.cleaned_data