forms.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import logging
  2. import warnings
  3. from django.core.exceptions import ValidationError
  4. from django.forms import fields
  5. from django.utils.translation import ugettext_lazy as _
  6. from django import forms
  7. from accounts.forms import (
  8. EmailRequiredPersonForm, EmailNotRequiredPersonForm)
  9. from accounts.constants import STATE_CHOICES
  10. from accounts.profile import get_profile
  11. from accounts import utils as account_utils
  12. from catalog.models import Subscription
  13. from store_order.models import OrderItemGiftDetail
  14. from . import constants
  15. from . import renderers
  16. from . import utils
  17. from .templatetags import storefront_tags
  18. LOG = logging.getLogger(__name__)
  19. REQUIRED = (u"There was missing information on your order. Please correct "
  20. u"the errors below.")
  21. class HelpForm(forms.Form):
  22. """ Simple Help Form """
  23. reason_for_message = fields.ChoiceField(
  24. choices=constants.REASONS_FOR_MESSAGE, required=True)
  25. name = forms.CharField(widget=forms.Textarea(
  26. attrs={'rows': 1, 'columns': 45}), required=True)
  27. email = forms.CharField(widget=forms.Textarea(
  28. attrs={'rows': 1, 'columns': 45}), required=True)
  29. message = forms.CharField(widget=forms.Textarea(
  30. attrs={'rows': 5, 'columns': 55}), required=True)
  31. class SubscriptionForm(forms.Form):
  32. """ Subscription form is used to display subscription options. These
  33. include:
  34. title: Title of the newspaper. Available types are calculated using
  35. the SHIPPING TYPE
  36. duration: Duration of the subscription choice
  37. shipping_method: These are typically regular or first class. Foreign
  38. addresses qualify only for Foreign First Class
  39. shipping_type: Shipping type is a function of the users address. If it
  40. can't be calculated, we expect this value to be None. The affect
  41. on the form is that all possible values are returned for all
  42. fields.
  43. """
  44. subscription = None
  45. def __init__(self, *args, **kwargs):
  46. self.shipping_type = kwargs.pop('shipping_type', None)
  47. self.use_account_number = kwargs.pop('use_account_number', None)
  48. self.renewal = kwargs.pop('renewal', False)
  49. super(SubscriptionForm, self).__init__(*args, **kwargs)
  50. self.fields['title'] = forms.ChoiceField(
  51. label=_('Title'), widget=forms.RadioSelect(
  52. renderer=renderers.HorizontalRadioRenderer,
  53. attrs={'onclick': "calculate_price();"}),
  54. choices=utils.unique_titles(self.shipping_type), required=True,
  55. initial=0)
  56. self.fields['duration'] = forms.ChoiceField(
  57. label=_('Duration (months)'), widget=forms.RadioSelect(
  58. renderer=renderers.HorizontalRadioRenderer, attrs={
  59. 'onclick': "calculate_price();"}),
  60. choices=utils.unique_durations(self.shipping_type), required=True,
  61. initial=0)
  62. self.fields['shipping_method'] = forms.ChoiceField(
  63. label=_('Shipping Method'), widget=forms.RadioSelect(
  64. renderer=renderers.HorizontalRadioRenderer,
  65. attrs={'onclick': "calculate_price();"}),
  66. choices=utils.unique_shipping_methods(), required=True, initial=0)
  67. if self.use_account_number:
  68. self.fields['account_number'] = forms.CharField(
  69. label=_('Account Number)'), required=False,
  70. widget=forms.TextInput(attrs={'type': 'text', 'size': 50,
  71. 'maxlength': 7}))
  72. def save(self):
  73. """ Returns the unique subscription calculated by clean """
  74. return self.subscription
  75. def clean(self):
  76. """ Cleans the form data. Uses the form data to determine if the
  77. subscription product exists.
  78. title, shipping method, duration and shipping type are used to
  79. determine if a valid subscription exists. If one does not, a
  80. validation error will be returned
  81. """
  82. LOG.debug("Subscription Form Data: {0}".format(self.cleaned_data))
  83. title = self.cleaned_data.get('title', None)
  84. shipping_method = self.cleaned_data.get('shipping_method', None)
  85. duration = self.cleaned_data.get('duration', None)
  86. shipping_type = self.shipping_type
  87. # recast values from radio button positions to searchable values
  88. title = utils.get_value_by_index(utils.unique_titles(
  89. shipping_type), title)
  90. duration = utils.get_value_by_index(
  91. utils.unique_durations(shipping_type), duration)
  92. shipping_method = utils.get_value_by_index(
  93. utils.unique_shipping_methods(), shipping_method)
  94. try:
  95. LOG.debug("Looking for subscription with: title:{0}, duration:{1},"
  96. " shipping_type:{2}, shipping_method:{3}".format(
  97. title, duration, shipping_type, shipping_method))
  98. self.subscription = Subscription.objects.get(
  99. title=title, duration=duration, shipping_type=shipping_type,
  100. shipping_method=shipping_method, renewal=self.renewal)
  101. except Subscription.DoesNotExist:
  102. message = (u"{0} is not available with for 9-month or 2-year "
  103. u"durations. Please choose a different duration or "
  104. u"shipping method.".format(
  105. storefront_tags.humanize_shipping_method(
  106. shipping_method)))
  107. LOG.debug(message)
  108. raise forms.ValidationError(_(message))
  109. return self.cleaned_data
  110. class GiftInformationForm(forms.ModelForm):
  111. message = forms.CharField(widget=forms.Textarea(
  112. attrs={'cols': 55, 'rows': 3}), required=False, )
  113. class Meta:
  114. model = OrderItemGiftDetail
  115. exclude = ('first_name', 'last_name', 'company', 'address1',
  116. 'address2', 'city', 'region', 'phone', 'country',
  117. 'postal_code', 'plus_four', 'email')
  118. class ChangeOfAddressForm(forms.Form):
  119. account_number = forms.CharField(
  120. required=False, widget=forms.TextInput(
  121. attrs={'type': 'text', 'size': 50}))
  122. date_effective = forms.ChoiceField(
  123. label=_('Date Effective'), widget=forms.RadioSelect(
  124. renderer=renderers.HorizontalRadioRenderer),
  125. choices=constants.DATE_EFFECTIVE_CHOICES, required=True,
  126. initial=constants.NEXT_ISSUE)
  127. from_date = forms.CharField(required=False)
  128. to_date = forms.CharField(required=False)
  129. def __init__(self, *args, **kwargs):
  130. self.type = kwargs.pop('type', None)
  131. super(ChangeOfAddressForm, self).__init__(*args, **kwargs)
  132. self.fields['title'] = forms.ChoiceField(
  133. label=_('Title'), widget=forms.RadioSelect(
  134. renderer=renderers.HorizontalRadioRenderer),
  135. choices=utils.unique_titles(self.type), required=True, initial=0)
  136. def clean(self):
  137. data = self.cleaned_data
  138. date_effective = data.get('date_effective', None)
  139. from_date = data.get('from_date', None)
  140. to_date = data.get('to_date', None)
  141. if date_effective == constants.RANGE and not from_date and not to_date:
  142. raise ValidationError(_("You must add from and to dates if you "
  143. "choose a date range."))
  144. return self.cleaned_data
  145. class AddressForm(EmailNotRequiredPersonForm):
  146. def clean(self):
  147. # We want a single error message. We don't display the validation
  148. # errors for each part of the form
  149. for field in self.fields:
  150. if self.fields[field].required and not self.cleaned_data.get(
  151. field, None):
  152. raise forms.ValidationError(_(REQUIRED))
  153. return self.cleaned_data
  154. class GiftToForm(EmailNotRequiredPersonForm):
  155. def save(self):
  156. """ Saving the recipient should not create a user account """
  157. warnings.warn("deprecated", DeprecationWarning)
  158. def clean(self):
  159. # We want a single error message. We don't display the validation
  160. # errors for each part of the form
  161. for field in self.fields:
  162. if self.fields[field].required and not self.cleaned_data.get(
  163. field, None):
  164. raise forms.ValidationError(_(REQUIRED))
  165. return self.cleaned_data