forms.py 8.6 KB

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